在之前我们已经编写了关于SPI, I2C, CAN等通信方式的笔记,在此就不再次单独介绍I2C的通讯原理了,参考链接如下:
--------------------------------------------------------------------------------------------------------------
简单介绍起始信号和结束信号发送原理:当时钟线处于高电平的时候,把数据线从空闲状态的高电平(由上拉电阻造成)拉低,形成一个下降沿触发信号,这就是起始信号;反之,当时钟线处于高电平的时候,把数据线从忙时的低电平信号拉高,形成一个上升沿触发信号,这就是结束信号。
首先是我们的起始信号和停止信号函数:
void iic_start(void){
//SCL为高电平时,SDA从高电平向低电平跳变,制造起始信号
IIC_SDA(1);
IIC_SCL(1);
delay_ms();
IIC_SDA(0);
delay_ms();
IIC_SCL(0);
delay_ms();//钳住总线,准备发送或者接受数据
}
void iic_stop(void){
//SCL为高电平的适合,SDA从低电平向高电平跳变,制造停止信号
IIC_SDA(0);
delay_ms();
IIC_SCL(1);
delay_ms();
IIC_SDA(1);
delay_ms();
}
简单介绍ACK的应答信号原理:主机数据线拉高,表示一个高电平的状态,而此时如果从机发送一个低电平信号时,主机的高电平就会被导入到从机的低电平中,从而使得主机得数据线读取PIN值的函数读取到的是低电平,表示收到ACK应答信号,继续传输数据;反之,如果从机继续发送上拉电阻的高电平,则主机的数据线将保持高电平状态,主机数据线PIN值读取函数读取到的是高电平,表示读取到的是NACK非应答信号,不再发送数据,发送结束信号结束此次IIC通讯传输。
接下来对应答信号做出相应反应的函数:
uint8_t iic_wait_ack(void){ //主机检测应答信号
IIC_SDA(1); //主机释放SDA线
delay_ms();
IIC_SCL(1); //从机返回ACK
delay_ms();
if(IIC_READ_SDA){ //SDA高电平表示读取到高电平,从机未作出应答,由于上拉电阻有高电平阻塞效果,表示读取到非应答信号
iic_stop();
return 1;
}
IIC_SCL(0);
delay_ms();
return 0;
}
void iic_ack(void){ //从机发送低电平应答信号,将主机发送的高电平信号导入至此,使主机的数据线检测函数得到的是低电平,继续要求数据
IIC_SCL(0);
delay_ms();
IIC_SDA(0);
delay_ms();
IIC_SCL(1);
delay_ms();
}
void iic_nack(void){ //从机发送非应答信号,不再要求数据
IIC_SCL(0);
delay_ms();
IIC_SDA(1);
delay_ms();
IIC_SCL(1);
delay_ms();
}
接下来简单介绍数据发送的原理:由于I2C通讯是MSB first通讯,先发送最高位的数据,于是我们可以通过左移位移操作来实现数据的不断读取。
void iic_send_byte(uint8_t data){
for(uint8_t t = 0; t < 8; t++){
//高位先发
IIC_SDA((data & 0x80) >> 7);
IIC_SCL(1);
delay_ms();
IIC_SCL(0);
data <<= 1; //左移一位,进行下一次发送
}
IIC_SDA(1); //完成后,释放数据线,进行应答检测
}
uint8_t iic_read_byte(uint8_t ack){
uint8_t receive = 0;
for(uint8_t i = 0; t < 8; t++){
//高位先被输入,左移以腾空右边的位置给下一低位数据
receive <<= 1;
IIC_SCL(1);
delay_ms();
if(IIC_READ_SDA) receive++;
IIC_SCL(0);
delay_ms();
}
if(!ack) iic_nack();
else iic_ack();
return receive;
}
以上就是I2C通讯方式中比较基础的一些操作。
文章详细介绍了I2C通信协议中的起始和停止信号的生成原理,以及ACK应答信号的处理。通过提供的函数展示了如何实现这些基本操作,包括数据的发送和接收。内容还包括了对非应答信号的处理,以及I2C协议中MSB优先的数据传输方式。
636

被折叠的 条评论
为什么被折叠?



