一、什么是IIC?24C02存储器有什么用?
IIC (IIC 是半双工通信总线。半双工意味着数据在某一时刻只能沿一个方向传输,即发送数据的时候不能接收数据,接收数据的时候不能发送数据)即集成电路总线(Inter-Integrated Circuit),是一种多主机的串行通信总线.它由飞利浦公司在 20 世纪 80 年代开发,主要用于连接微控制器及其外围设备。IIC 总线具有简单、高效、支持多设备连接等特点,在电子电路设计中被广泛应用。
“一主多从” 是一种通信架构模式。在这种模式中,有一个主要的设备(称为主设备),它具有控制和发起通信的能力;同时有多个从属设备(称为从设备),它们被动地响应主设备的指令,与主设备进行数据交互。
IIC 总线的工作原理如下:
- 总线结构与信号3:
- 数据线(SDA):用于传输实际的数据信息,是双向的 I/O 线。在数据传输过程中,主设备和从设备之间的数据交换通过 SDA 线进行。例如,主设备向从设备发送数据时,将数据按位依次放置在 SDA 线上;从设备向主设备发送数据时,也通过 SDA 线传输数据。
- 时钟线(SCL):用于同步通信的时钟信号,由主设备产生。SCL 线的时钟信号决定了数据传输的速率和时序,主设备通过控制 SCL 线的电平变化来协调数据的发送和接收。例如,在每个时钟脉冲的上升沿或下降沿,数据位在 SDA 线上进行传输或接收。
- 上拉电阻:SDA 和 SCL 线都是开漏输出,需要通过上拉电阻接电源 VCC。当总线空闲时,两根线都被上拉电阻拉高,保持着高电平状态。上拉电阻的阻值会影响总线的信号传输质量和速度,一般需要根据具体的总线负载和传输速率要求来选择合适的阻值3。
- 通信过程中的信号状态:
- 起始信号:当 SCL 线为高电平期间,SDA 线由高电平向低电平的跳变,表示产生一个起始条件,标志着一次数据传输的开始3。
- 终止信号:当 SCL 线为高电平期间,SDA 线由低电平向高电平的跳变,表示产生一个停止条件,标志着一次数据传输的结束3。
- 应答信号:每传输一个字节的数据后,接收方需要发送一个应答位。如果接收方成功接收到数据,则会在第 9 个时钟脉冲时将 SDA 线拉低,表示应答;如果接收方没有正确接收数据或者无法接收更多数据,则会将 SDA 线保持高电平,这会引起主设备的相应处理,例如重新发送数据或者终止传输。
- 数据传输格式与方向:
- 数据格式:数据传输以字节(8 位)为单位,先传输最高位(MSB),最后传输最低位(LSB)。每次传输可以发送的字节数量不受限制,但每个字节后必须跟一个响应位。
- 传输方向:主设备在传输有效数据之前要先指定从设备的地址,地址一般为 7 位,然后协议规定再给地址添加一个最低位用来表示接下来数据传输的方向,“0” 表示主设备向从设备写数据,“1” 表示主设备向从设备读数据。
- 主从设备通信模式2:
- 主设备控制:主设备负责启动总线、发送起始信号、发送从设备地址和读写位、发送或接收数据以及发送停止信号等操作,控制整个通信过程。在多主设备的系统中,如果多个主设备同时尝试访问总线,IIC 使用仲裁机制来决定哪个设备能够继续进行通信,其他设备则等待。
- 从设备响应:从设备被动地接受主设备的控制,根据主设备发送的地址和读写位来判断是否需要响应主设备。从设备在接收到主设备的请求后,会按照主设备的要求进行数据的发送或接收,并在合适的时候发送应答信号。
- 时钟同步:所有连接到总线上的主设备在 SCL 线上产生它们自己的时钟来传输 IIC 总线上的报文。由于数据只在时钟的高电平周期有效,因此需要一个确定的时钟进行逐位仲裁和数据传输。时钟同步通过线与连接 IIC 接口到 SCL 线来执行,SCL 线的低电平周期由低电平时钟周期最长的器件决定,而高电平周期由高电平时钟周期最短的器件决定。
如上图E1E2E3都接地,所以读为10100001,写为10100000。
1.主机发送起始信号,启动总线。
2.发送从机地址(7bit)和传送方向(1bit)。
3.从机应答(1bit)。
4发送数据(1B=8bit)。
5.接受,应答(1bit)。
6.循环第4,5步,主机发送停止位释放总线。
二、使用步骤(在LED显示上电次数)
虽然给的函数中开启了PB6,PB7,但是最好在CUBE中开启一下
在main中添加头文件并初始化
/* USER CODE BEGIN Includes */
#include "headfile.h"
#include "i2c_hal.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */
I2CInit();
/* USER CODE END 2 */
在i2c_hal.c添加读写函数
MEM_Read 函数:
I2CStart()
:启动 I2C 通信。I2CSendByte(0xa0)
:发送设备地址(写操作)。I2CWaitAck()
:等待应答信号。I2CSendByte(ucAddr)
:发送要读取数据的地址。I2CWaitAck()
:再次等待应答信号。I2CStart()
:重新启动 I2C 通信。I2CSendByte(0xa1)
:发送设备地址(读操作)。I2CWaitAck()
:等待应答信号。- 通过循环,使用
I2CReceiveByte()
接收数据到*pucBuf++
,并根据剩余数据数量决定发送应答或非应答信号。I2CStop()
:停止 I2C 通信。MEM_Write 函数:
I2CStart()
:启动 I2C 通信。I2CSendByte(0xa0)
:发送设备地址(写操作)。I2CWaitAck()
:等待应答信号。I2CSendByte(ucAddr)
:发送要写入数据的地址。- 通过循环,使用
I2CSendByte(*pucBuf++)
发送数据,并等待应答信号。I2CStop()
:停止 I2C 通信。delay1(500)
:延迟一段时间,写数据不能太快,目的为了确保写入操作完成。
void MEM_Read(uint8_t*pucBuf,uint8_t ucAddr,uint8_t ucNum)//文件读
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(ucAddr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
while(ucNum--)
{
*pucBuf++=I2CReceiveByte();
if(ucNum)
I2CSendAck();
else
I2CSendNotAck();
}
I2CStop();
}
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);
}
在i2c_hal.h声明函数
void MEM_Read(uint8_t*pucBuf,uint8_t ucAddr,uint8_t ucNum);
void MEM_Write(uint8_t*pucBuf,uint8_t ucAddr,uint8_t ucNum);
在main.c中写通信函数
uint8_t sdcount
:定义了一个 8 位无符号整数变量sdcount
。
MEM_Read(&sdcount,0,1)
:使用MEM_Read
函数从地址 0 读取 1 个字节的数据,并将其存储到sdcount
变量中。
sdcount++
:将sdcount
的值增加 1。
MEM_Write(&sdcount,0,1)
:使用MEM_Write
函数将更新后的值(即增加 1 后的sdcount
)写入到地址 0,写入 1 个字节。
存储器地址 0 和地址 1 主要有以下区别:
- 存储位置:它们代表了存储器中不同的位置。
- 存储内容:通常存储在这两个地址的数据可能不同。
- 功能用途:可能被用于存储不同类型的信息或执行不同的操作
uint8_t sdcount;
MEM_Read(&sdcount,0,1);//通信
sdcount++;
MEM_Write(&sdcount,0,1);
在LCD中显示
sprintf(buf," sdcount:%d ",sdcount);
LCD_DisplayStringLine(Line7,(uint8_t*)buf);
三、开源代码
通过网盘分享的文件:20-TEST10-IIC通信--24C02存储器.zip
链接: https://pan.baidu.com/s/1RQ7GbIz72_fHUYoKlLPVgA?pwd=0820 提取码: 0820