几个原则:
IIC通信,高位在先,低位在后
开始信号
在时钟信号线为为高时,拉低SDA
结束信号
在时钟信号线为为高时,拉高SDA
Ack信号
ACK信号为每次传输8bit(1字节)数据后,必须要有的响应信号,由接收方来发出
在SCK为高时(一个脉冲内),将SDA拉低(管脚开漏输出只能拉低,来表示回复)
NACK信号
在SCK为高时(一个脉冲内),将SDA置高(管脚开漏输出只能拉低,不操作时默认为高电平)
写数据
设备地址:设备地址为7位,发送的数据中一共八位,前七位是设备地址,最后一位是读写控制位,0是写,1是读
从设备写取数据的过程如下:
- 发送起始信号
- 输出从机的地址(写位),获取从机的应答信号,没有应答则发送STOP信号,释放总线
- 先发送要写入的寄存器高八位的地址,获取从机的应答信号,同上
- 再发送要写入的寄存器低八位的地址,获取应答信号
- 接下来发送要写入的数据,字节数任意
- 不想发的时候,发送STOP信号,结束通信
读数据
- 发送开始信号
- 发送设备地址(写命令),并获取设备的应答信号
- 发送设备的高八位地址,等待应答信号
- 发送设备的低八位地址,等待应答信号
- 发送停止信号
- 重新发送开始信号(重启通信)
- 发送设备地址(读命令),等待设备应答信号
- 读取数据,读到数据后主机回复ACK信号
- 若主机不想接收数据了,给设备回复NACK 或者 发送停止信号
底层驱动函数有:
- IIC_Start
- IIC_Stop
- IIC_SendAck
- IIC_SendNack
- IIC_ReadAck:读取不到ACK信号时,要发送IIC_Stop
- IIC_WriteByte
- IIC_ReadByte
接收Ack
void delay(unsigned int t)
{//延时函数
while(t){t--;}; //延时循环计数
}
//-------------------------------------------------------------------
void delay_IIC(void)
{//IIC总线限速延时函数。
//该函数是空函数,延时4个机器周期。
;;
}
//-------------------------------------------------------------------
void IIC_Init(void)
{//IIC总线初始化函数
IIC_SDA=1;//释放IIC总线的数据线。
IIC_SCL=1;//释放IIC总线的时钟线。
}
//-------------------------------------------------------------------
void IIC_start(void)
{//IIC总线产生起始信号函数
IIC_SDA=1;//拉高数据线
IIC_SCL=1;//拉高时钟线
delay_IIC();
IIC_SDA=0;//在时钟线为高电平时,拉低数据线,产生起始信号。
delay_IIC();
IIC_SCL=0;//拉低时钟线
}
//-------------------------------------------------------------------
void IIC_stop(void)
{//IIC总线产生停止信号函数
IIC_SDA=0;//拉低数据线
delay_IIC();
IIC_SCL=1;//拉高时钟线。
delay_IIC();
IIC_SDA=1;//时钟时线为高电平时,拉高数据线,产生停止信号。
delay_IIC();
}
//-------------------------------------------------------------------
bit IIC_Tack(void)
{//接收应答信号函数
bit ack;//定义一个位变量,来暂存应答状态。
IIC_SDA=1;//释放数据总线,准备接收应答信号。
delay_IIC();
IIC_SCL=1;//拉高时钟线。
delay_IIC();
ack=IIC_SDA;//读取应答信号的状态。
delay_IIC();
IIC_SCL=0;//拉低时钟线。
delay_IIC();
return ack;//返回应答信号的状态,0表示应答,1表示非应答。
}
//-------------------------------------------------------------------
void IIC_write_byte(unsigned char Data)
{//向IIC总线写入一个字节的数据函数
unsigned char i;
for(i=0;i<8;i++)//有8位数据
{
IIC_SDA=Data&0x80;//写最高位的数据
delay_IIC();
IIC_SCL=1; //拉高时钟线,将数写入到设备中。
delay_IIC();
IIC_SCL=0;//拉低时钟线,允许改变数据线的状态
delay_IIC();
Data=Data<<1;//数据左移一位,把次高位放在最高位,为写入次高位做准备
}
}
//-------------------------------------------------------------------
unsigned char IIC_read_byte()
{//从IIC总线读取一个字节的数据函数
unsigned char i;
unsigned char Data; //定义一个缓冲寄存器。
for(i=0;i<8;i++)//有8位数据
{
IIC_SCL=1;//拉高时钟线,为读取下一位数据做准备。
delay_IIC();
Data=Data<<1;//将缓冲字节的数据左移一位,准备读取数据。
delay_IIC();
if(IIC_SDA)//如果数据线为高平电平。
Data=Data|0x1;//则给缓冲字节的最低位写1。
IIC_SCL=0;//拉低时钟线,为读取下一位数据做准备。
delay_IIC();
}
return Data;//返回读取的一个字节数据。
}
//-------------------------------------------------------------------
void IIC_single_byte_write(unsigned char Daddr,unsigned char Waddr,unsigned char Data)
{//向任意地址写入一个字节数据函数
IIC_start();//产生起始信号
IIC_write_byte(Daddr);//写入设备地址(写)
IIC_Tack();//等待设备的应答
IIC_write_byte(Waddr);//写入要操作的单元地址。
IIC_Tack();//等待设备的应答。
IIC_write_byte(Data);//写入数据。
IIC_Tack();//等待设备的应答。
IIC_stop();//产生停止符号。
}
//-------------------------------------------------------------------
unsigned char IIC_single_byte_read(unsigned char Daddr,unsigned char Waddr)
{//从任意地址读取一个字节数据函数
unsigned char Data;//定义一个缓冲寄存器。
IIC_start();//产生起始信号
IIC_write_byte(Daddr);//写入设备地址(写)
IIC_Tack();//等待设备的应答
IIC_write_byte(Waddr);//写入要操作的单元地址。
IIC_Tack();//等待设备的应答。
IIC_start();//产生起始信号
IIC_write_byte(Daddr+1);//写入设备地址(读)。
IIC_Tack();//等待设备的应答。
Data=IIC_read_byte();//写入数据。
IIC_stop();//产生停止符号。
//-------------------返回读取的数据--------------------
return Data;//返回读取的一个字节数据。
}
读取触摸坐标分为 中断方式 和 轮询方式
1. 中断方式
TP的INT引脚接在芯片的中断引脚上,触摸后,TP的INT引脚会输出高电平,触发芯片的中断,芯片进入中断服务函数ISR,ISR中读取TP指定寄存器的数据,将数据存在栈存储结构中,中断外再处理数据
2. 轮询方式
不使用TP的INT引脚,使用空闲任务读取TP的坐标等信息,可以在程序中处理数据
IIC最多支持多少个设备地址?
127个,八位中的最后一位是读写位,读1,写0
上拉电阻的阻值
4.7K,10K
一般TP初始化过程
- 通过RESET引脚硬件复位
- 延时一段时间
- 结束复位
- 通过INT引脚的电平设置设备地址
- 延时
- 软复位
- 若需要则要更新配置(分辨率等)
- 结束软复位
某些TP读寄存器坐标之后,要对其寄存器清零