STM32的IIC串口通信_读写EEPROM实验
IIC简介
IIC通信原理
-
IIC原理简述
IIC又称I2C或I2C,全称Inter IC总线,实现IC集成芯片之间的同步串行通信
IIC与异步的UART一样也可以只用两根通讯线:数据线SDA与时钟线SCL,但只有一根数据线情况下实现的是半双工通信
对IIC总线通信系统,可以有多个IIC总线器件同时接在IIC总线上,通过器件地址来区分各个设备,能够实现一主多从以及多主的通信系统,在蓝桥杯开发板上IIC连接了24C02与MCP4017两个IC
-
IIC工作流程
-
主机发送起始信号启动总线
-
发送从机地址(7位长)与读写控制位(决定传输方向,读1写0)
因为读写控制位占用一位,因此一个8位地址的IIC总线理论可挂载的从机数为27-1=128-1=127个(纯0不能作地址)
-
等待从机回复一个应答位
-
发送数据,每发送一个字节(8位长)等待从机回复一个应答位
-
发送完成,主机发送停止位,释放总线
更具体的工作原理参阅本人STM8教程的I2C章节
-
-
24C02储存器原理
在IIC读写实验中,我们使用24C02芯片,这是一款使用I2C通信协议的EEPROM非易失性储存芯片,掉电后数据不丢失
其设备地址由A0/A1/A2三个引脚配置,在开发板上这三个引脚都接地,为000
具体应该发送的第一个字节是:MSB:1-0-1-A0-A1-A2-R/W:LSB
IIC的初始化配置
-
IIC的引脚配置
PA6为SCL,PA7为SDA,两个引脚配置为GPIO_Output
在后续导入的IIC驱动中已经配置好了这两个引脚,但为了防止出错,建议在CubeMX中配置好
-
IIC的驱动导入
从将硬件配置为GPIO功能可看出,我们不使用芯片上的硬件I2C,而是使用GPIO输出模拟I2C,但我们不需要像在STM8教程中那样亲自配置读写的每一个位,而是使用提供的驱动文件中的函数来完成对IIC时序的模拟
在工程中导入蓝桥杯嵌入式资源包提供的
i2c_hal.c并在主函数中引入i2c_hal.h,导入驱动的方法见LCD一章 -
编译器优化对IIC的影响
在使用之前,在工程的Options(魔法棒按钮)C/C++(AC6)标签页中的Optimization选为-O0
把编译器的优化等级调低,这样IIC才能正常工作
这样因为IIC驱动中的延时函数使用了原始的CPU空转延时,会被编译器优化掉,导致IIC工作出错
IIC的使用
IIC使用的库函数
-
初始化函数I2CInit
在使用之前,要先对I2C进行初始化
void I2CInit(void); -
封装IIC读取函数
虽然驱动提供了各个库函数让我们不必关注各个不同的工作时序,但每次进行通信操作都要频繁调用发送起始信号、发送字节数据、等待答应信号一系列函数,过程依旧繁琐
因此我们封装一个功能为读取IIC的函数,只要给出读取到数据的缓冲区,要读取的内存地址和读取字节数,就能自动完成IIC的读取数据流程
//将函数写到i2c_hal.c中,记得将函数原型放到i2c_hal.h //因为是半双工通信,所以只需要一个公共的缓冲区 //通过使用不同的函数决定发送区中字节还是接收字节存到区中 void MEM_Read(uint8_t* pucBuf, uint8_t ucAddr, uint8_t ucNum) { I2CStart();//I2C起始信号 I2CSendByte(0xa0);//1010 0000,后三位地址为000,控制位为0,写模式 I2CWaitAck();//等答应信号 I2CSendByte(ucAddr);//先把要读取的地址发送给24C02 I2CWaitAck(); I2CStart(); I2CSendByte(0xa1);//控制位为1,切换为读模式 I2CWaitAck(); while(ucNum--)//逐个字节地接收 { *pucBuf++=I2CReceiveByte();//把接收到的数据存放到缓冲区 if(ucNum)//如果还未读到最后一个,应该给24C02回复答应信号 I2CSendAck(); else//读完最后一个就不必发送答应信号了 I2CSendNotAck(); } I2CStop();//发送停止位 } -
封装IIC写入数据
同上,也能封装一个用于IIC写入的函数
void MEM_Write(uint8_t* pucBuf, uint8_t ucAddr, uint8_t ucNum) { I2CStart(); I2CSendByte(0xa0); I2CWaitAck(); I2CSendByte(ucAddr); I2CWaitAck(); while(ucNum--)//逐个字节地发送 { I2CSendByte(*pucBuf++);//发送一个字节后偏移指针以发送下一个字节 I2CWaitAck(); } I2CStop(); delay1(500);//增加延时避免写入太快导致出错 //delay1是i2c_hal.c定义的延时 } /* USER CODE END 2 */
代码实现
-
写入与读取实验
进行一个简单的实验同时检测刚刚封装好的I2C函数以及EEPROM掉电后保存数据的能力
实验设计如下:声明一个变量
uint8_t cnt,每次上电后对其读取,并将其数值加1后再写入,烧录后开关单片机,如果能观察到这个变量(借助LCD)在每次开关后加1,实验成功MEM_Read((uint8_t *)&cnt,0,1); cnt++; MEM_Write((uint8_t *)&cnt,0,1); /* USER CODE END 2 */ -
注意:一个地址只能存8bit,也就是一个uint8_t类型的变量,如果是16位或32位数据类型需要按数值或者按位进行分割
本文来自博客园,作者:无术师,转载请注明原文链接:https://www.cnblogs.com/artlessist/p/18999620
本文使用知识共享4.0协议许可 CC BY-NC-SA 4.0
特别说明版权归属的文章以及不归属于本人的转载内容(如引用的文章与图片)除外
浙公网安备 33010602011771号