之前大二在学习ST单片机的时候有学习到过I2C,但是当时没有去注意到它的原理,说是学习倒不如说只是拿了个开发板跑了一下例程。最近因为在实习,也感觉到了学东西不但要会用还得知道其中的原理才行,,,说了很多废话,来看一下I2C到底是什么吧(基于我个人学习理解,不一定完全正确哈[狗头保命])
首先I2C是基于2线通信的 分别是 SDA(数据线) SCL(时钟线)
三个重要的信号
开始信号: SCL 为高电平时, SDA 由高电平向低电平跳变,开始传送数据。
结束信号: SCL 为高电平时, SDA 由低电平向高电平跳变,结束传送数据。
应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。 CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号, CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
I2C的总线时序图
知道了I2C通信协议,接下来就是应用I2C将我们的单片机和存储器进行通信了
这里我是用的是正点原子F103系列的板子然后后面也是结合原子哥的例程代码,他上面使用的EEPROM存储器是AT24C02通过查阅该芯片的数据手册可以得知它的容量是 256 X 8bit 也就是256个字节容量的大小
我们使用单片机和存储器进行通信一般的步骤是 开始-寻址-(读)写数据-结束
我们使用的这款存储芯片是可以进行硬件寻址也就是 A2 A1 A0 这三个引脚,正点原子这里是将它们直接接地
然后通过参考AT24C02的芯片手册可以知道 它的高四位其实是已经固定了的
所以说设备地址就是 0XA0 + 0(1)【读写使能位】 最后一位为 读写操作位
写时序图 如图可以看出写操作位是低电平有效
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{
IIC_Start();
if(EE_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr>>8);//发送高地址
}else IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //发送器件地址0XA0,写数据
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr%256); //发送低地址 前面的是设备地址 还有数据地址
IIC_Wait_Ack();
IIC_Send_Byte(DataToWrite); //发送字节
IIC_Wait_Ack();
IIC_Stop();//产生一个停止条件
delay_ms(10);
}
上面是来自正点原子例程的代码,首先可以看出 先是发出了一个开始信号对单片机进行通信
然后下面的 if(EE_TYPE>AT24C16) 这条判断语句是为了让代码兼容各种24CXX系列不同容量的代码,因为我们使用的2K大小所以if中的条件为假执行下面的语句
然后就是寻址
IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //发送器件地址0XA0,写数据
这个代码的意思是确定页地址的位置 右移一位是因为我们最后一位表示的是读写位所以右移
然后找到地址之后还要发送第八位寻找 数据的地址 相当于你要在这页的哪个位置进行写操作
IIC_Send_Byte(WriteAddr%256); //发送低地址 前面的是设备地址 还有数据地址
最后就是写我们要输入的数据了
IIC_Send_Byte(DataToWrite); //发送字节
逻辑分析仪抓取 波形分析
首先代码这里我发送的是"STM32....."这段信息然后我使用逻辑分析仪进行抓取信号看对不对
这里我抓取的是第一段波形 后面的就不发出来了 分析一个即可 举一反三
可以看到 设备地址 0xA0 起始地址0x00 数据位 0x53 (S的ASCII 83)对应,和我们实验之前预想的是一样的 实验成功^_^
然后读时序起始也是一样的,大家可以去做一下
I2C是可以进行连续写入数据的 , 但是只能一次写入一个字节,正点原子采用了一个很妙的方法使用的是一个指针递增的方法使得每次写入一个字节 有兴趣的可以去看看原子哥的源码。
好了分享就到这了 祝大家学得顺利ヾ(◍°∇°◍)ノ゙