问题:如何正确使用IIC这么优秀的通讯协议呢?
解决:
第一步:知道起始信号和终止信号
当SCL为1的时候,SDA从1变成0,这个就是起始信号,说明可以开始传输;当SCL为1的时候,SDA从0变成1,这个就是终止信号,说明传输停止。可想而知需要操作很多次,我们要编写相关函数。
第二步:知道ACK应答和NACK非应答
当传输完一个字节的数据的时候,如果还需要继续继续传输数据,那么从机需要给主机发送对应的信号,当还要继续传输的时候,SDA从1变成0;当SDA一直是1的时候,表示可以结束传输。
另外:应答的时候,SDA=0,SCL需要等于1,非应答的时候,SDA=1,SCL也需要等于1。
第三步:IIC到底是如何读写数据的呢?
一般而言,从机的设备地址为七位,剩下的一位表示读写,0表示写,1表示读.
例如图2 24c02,1010 0000表示给这个从机写入,1010 0001表示从这个从机读出。
第四步:其他,怎么连接?
这样接即可,需要接上拉电阻。图2说的是,当SCL=0的时候,数据才可以传递。
具体配置:起始,结束,应答,非应答
问题来了,从机发送信号给主机,是否继续传输信号,那么主机如何判断呢?没有接收到应答信号应该如何?这个时候就要写一个等待应答函数,没有应答超过一定时间,就停止传输。如下
那么数据到底是如何写和读的呢?如下
//产生IIC起始信号函数,具体配置如下
void IIC_start()
{
SDA=1;
delay_10us(1);
SCL=1;
delay_10us(1);
SDA=0;
delay_10us(1);
SCL=0; //为传输数据做准备
delay_10us(1);
}
//产生IIC停止信号函数
void IIC_stop()
{
SDA=0;
delay_10us(1);
SCL=1;
delay_10us(1);
SDA=1;
delay_10us(1);
}
//产生ACK应答信号函数
void IIC_ack()
{
SCL=0; //产生ACK需要保证SCL=0
SDA=0; //低电平表示应答
delay_10us(1);
SCL=1;
delay_10us(1);
SCL=0;
}
//产生NACK非应答信号函数
void IIC_nack()
{
SCL=0; //产生ACK需要保证SCL=0
SDA=1; //高电平表示非应答
delay_10us(1);
SCL=1;
delay_10us(1);
SCL=0;
}
//等待接收ACK应答函数,如果接收到了返回1,没有接收到,返回0,等待应答是为了进行下次传输
u8 IIC_wait_ack()
{
u8 num_time=0;
SCL=1;
delay_10us(1);
while(SDA)
{
num_time++;
if(num_time>100)
{
IIC_stop();//停止传输
return 0;
}
}
SCL=0;//允许传输
return 1;
}
//IIC发送一个字节
void IIC_write_byte(u8 dat)
{
u8 num_f;
SCL=0;
for(num_f=0;num_f<8;num_f++)
{
if((dat&0x80)>0) SDA=1;//表示1高电平
else SDA=0;//表示低电平
dat=dat<<1; //从高位依次写入
delay_10us(1);
SCL=1;
delay_10us(1);
SCL=0;
delay_10us(1);
}
}
//IIC接收一个字节,将接收到的返回,ack=1,表示应答,ack=0表示非应答
u8 IIC_read_byte(u8 ack)
{
u8 num_f,receive=0;
for(num_f=0;num_f<8;num_f++)
{
SCL=0;
delay_10us(1);
SCL=1;
receive=receive<<1;//从高位依次读出
if(SDA) receive++;
delay_10us(1);
}
if(!ack) IIC_nack();
else IIC_ack();
return receive;
}
实际应用:
对到这个图理解效果会更好.
//往24c02里指定地址写入一个字节的数据
void AT24C02_write_byte(u8 address,u8 dat)
{
IIC_start();//起始条件
IIC_write_byte(0xA0);//从设备地址,并且是写入
IIC_wait_ack();//等待应答
IIC_write_byte(address);//写入地址数据
IIC_wait_ack();//等待应答
IIC_write_byte(dat);//发送数据
IIC_wait_ack();//等待应答
IIC_stop();//写入一个字节,停止一下
delay_ms(10);
}
//在24c02里指定地址读出一个字节的数据
u8 AT24c02_read_byte(u8 address)
{
u8 temp=0;
IIC_start();//起始条件
IIC_write_byte(0xA0);//从设备地址,表示读出
IIC_wait_ack();//等待应答
IIC_write_byte(address);//写入地址数据
IIC_wait_ack();//等待应答,否则停止传输
IIC_start();
IIC_write_byte(0xA1);//发送读命令
IIC_wait_ack();//等待应答
temp=IIC_read_byte(0);//将读出的数据给temp,并且0表示非应答,表示结束
IIC_stop();
return temp;
}
注意:当SCL为0的时候,SDA状态可以变,用于传输数据,SCL为1的时候,SDA状态不能变,只能读。