| 
 
| 一、IIC总线技术概述 1.1 IIC总线的发展历史
 IIC(Inter-Integrated Circuit)总线,又称I²C总线,是由飞利浦半导体公司(现为恩智浦NXP)在1980年代开发的一种串行通信总线。最初设计目的是为电视机内的集成电路提供简单的控制接口,后来因其简洁性和高效性在各种嵌入式系统中得到广泛应用。
 
 随着技术的发展,IIC总线标准经历了多次更新:
 
 1982年:首次推出,标准模式速度100kbps
 
 1992年:推出快速模式(400kbps)
 
 1998年:推出高速模式(3.4Mbps)
 
 2007年:推出超快速模式(5Mbps)
 
 1.2 IIC总线的基本特性
 IIC总线具有以下显著特点:
 
 两线制结构:仅需串行数据线(SDA)和串行时钟线(SCL)两根信号线
 
 多主多从架构:支持多个主设备和多个从设备连接在同一总线上
 
 地址寻址:每个从设备有唯一的7位或10位地址
 
 半双工通信:同一时间只能进行发送或接收
 
 速率可调:支持从标准模式到高速模式多种传输速率
 
 硬件简单:无需复杂的接口电路,节省PCB空间和成本
 
 1.3 IIC总线的电气特性
 IIC总线采用开漏输出结构,需要外接上拉电阻(通常为4.7kΩ)。这种设计具有以下优势:
 
 实现了"线与"逻辑,便于总线仲裁
 
 允许不同电压等级的器件在同一总线上通信
 
 提高了总线的抗干扰能力
 
 工作电压范围通常为1.8V-5V,具体取决于器件规格。总线电容限制一般为400pF,超过此值需要考虑使用总线缓冲器。
 
 二、EEPROM存储器技术
 2.1 EEPROM的基本原理
 EEPROM(Electrically Erasable Programmable Read-Only Memory)是一种非易失性存储器,其主要特点包括:
 
 数据掉电不丢失
 
 可以字节为单位进行擦写
 
 擦写寿命有限(通常10万-100万次)
 
 读取速度较快,写入速度相对较慢
 
 EEPROM通过浮栅晶体管存储数据,利用F-N隧穿效应实现电子注入和释放,从而改变存储单元的阈值电压来表示"0"和"1"。
 
 2.2 EEPROM的分类
 根据接口类型,EEPROM主要分为:
 
 并行EEPROM:数据总线宽度通常为8位,速度快但引脚多
 
 串行EEPROM:包括IIC接口、SPI接口等,节省引脚资源
 
 根据容量大小,常见的EEPROM有:
 
 小容量:1Kbit-64Kbit(如24C01-24C64)
 
 中容量:128Kbit-512Kbit
 
 大容量:1Mbit及以上
 
 2.3 IIC接口EEPROM的特点
 IIC接口EEPROM具有以下优势:
 
 引脚精简:通常只需SCL、SDA、VCC、GND和WP(写保护)五个引脚
 
 易于扩展:通过地址引脚可扩展多个器件
 
 低功耗:工作电流小,适合电池供电设备
 
 标准化接口:与各种MCU兼容性好
 
 常见的IIC EEPROM系列包括Microchip的24系列、ST的M24系列等,容量从1Kbit到1Mbit不等。
 
 三、IIC总线协议详解(摘自正点原子)
 stm32f407探索者开发板V3 — 正点原子资料下载中心 1.0.0 文档
 
 
   
 起始信号:
 
 当 SCL 为高电平期间, SDA 由高到低的跳变。起始信号是一种电平跳变时序信号,而不是
 一个电平信号。该信号由主机发出,在起始信号产生后,总线就处于被占用状态,准备数据传
 输。
 停止信号:
 当 SCL 为高电平期间, SDA 由低到高的跳变。停止信号也是一种电平跳变时序信号,而不
 是一个电平信号。该信号由主机发出,在停止信号发出后,总线就处于空闲状态。
 应答信号:
 发送器每发送一个字节,就在时钟脉冲 9 期间释放数据线,由接收器反馈一个应答信号。
 应答信号为低电平时,规定为有效应答位( ACK 简称应答位),表示接收器已经成功地接收了
 该字节;应答信号为高电平时,规定为非应答位( NACK ),一般表示接收器接收该字节没有成
 功。
 观察上图标号③就可以发现,有效应答的要求是从机在第 9 个时钟脉冲之前的低电平期间
 将 SDA 线拉低,并且确保在该时钟的高电平期间为稳定的低电平。如果接收器是主机,则在它
 收到最后一个字节后,发送一个 NACK 信号,以通知被控发送器结束数据发送,并释放 SDA
 线,以便主机接收器发送一个停止信号。
 数据有效性:
 IIC 总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在
 时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。数据在 SCL 的上
 升沿到来之前就需准备好。并在下降沿到来之前必须稳定。
 
 
   
 
   
 主机向从机读取数据的操作,一开始的操作与写操作有点相似,观察两个图也可以发现,
 都是由主机发出起始信号,接着发送从机地址 +1( 读操作 ) 组成的 8bit 数据,从机接收到数据验
 证是否是自身的地址。 那么在验证是自己的设备地址后,从机就会发出应答信号,并向主机返
 回 8bit 数据,发送完之后从机就会等待主机的应答信号。假如主机一直返回应答信号,那么从
 机可以一直发送数据,也就是图中的( n byte + 应答信号)情况,直到主机发出非应答信号,从
 机才会停止发送数据。
 四、IIC读取eeprom实战讲解
 4.1 软件模拟IIC
 4.11 初始化IIC 的GPIO,既然是软件模拟IIC,开发板所有的引脚都能使用;
 
 void I2C_EE_Init()
 {
 GPIO_InitTypeDef  gpio_init_struct;
 __HAL_RCC_GPIOB_CLK_ENABLE();
 gpio_init_struct.Pin =  GPIO_PIN_8;
 gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;//开漏
 gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
 gpio_init_struct.Pull = GPIO_PULLUP;//上拉
 HAL_GPIO_Init(GPIOB,&gpio_init_struct);
 gpio_init_struct.Pin =  GPIO_PIN_9;
 HAL_GPIO_Init(GPIOB,&gpio_init_struct);
 IIC_Stop();
 }
 4.12 IIC起始结束时序
 
 
   
 void IIC_Start(void)
 {
 SCL_HIGH;
 SDA_HIGH;
 Delay_I2c(4);
 SDA_LOW;
 Delay_I2c(4);
 SCL_LOW;
 Delay_I2c(4);//起始信号
 }
 
 void IIC_Stop(void)
 {
 SDA_LOW;
 Delay_I2c(4);
 SCL_HIGH;
 Delay_I2c(4);
 SDA_HIGH;
 Delay_I2c(4);//停止信号
 }
 
 4.13 IIC发送时序
 
 
   
 void IIC_Send_Byte(uint8_t data)
 {
 uint8_t i;
 for(i = 0 ;i < 8 ;i++)
 {
 if((data & 0x80) >> 7)//高位先发送
 {
 SDA_HIGH;
 }
 else
 {
 SDA_LOW;
 }
 Delay_I2c(4);
 SCL_HIGH;
 Delay_I2c(4);
 SCL_LOW;
 data <<= 1;//下一位
 }
 SDA_HIGH;
 }
 
 4.14 IIC读时序
 
 uint8_t IIC_Recevie_Byte(uint8_t ack)
 {
 uint8_t i,data = 0;
 for(i = 0 ;i < 8 ;i++)
 {
 data <<= 1;//高位先输出
 SCL_HIGH;
 Delay_I2c(4);
 if(SDA_READ())
 {
 data ++;
 }
 
 SCL_LOW;
 Delay_I2c(4);
 }
 if(!ack)
 {
 IIC_noack();
 }
 else
 {
 IIC_ack();
 }
 return data;
 }
 
 4.15 应答信号
 
 首先先释放 SDA ,把电平拉高,延时等待从机操作 SDA 线,然后主机拉高时 钟线并延时,确保有充足的时间让主机接收到从机发出的 SDA 信号,这里使用的是 IIC_READ_SDA 宏定义去读取,根据 IIC 协议,主机读取 SDA 的值为低电平,就表示“应答信 号”;读到 SDA 的值为高电平,就表示“非应答信号”。在这个等待读取的过程中加入了超时判 断,假如超过这个时间没有接收到数据,那么主机直接发出停止信号,跳出循环,返回等于 1 的变量。在正常等待到应答信号后,主机会把 SCL 时钟线拉低并延时,返回是否接收到应答信 号。
 uint8_t IIC_Wait_ack(void)
 {
 uint8_t waittime = 0;
 uint8_t rack = 0;
 SDA_HIGH;
 Delay_I2c(4);
 SCL_HIGH;
 Delay_I2c(4);
 
 while(SDA_READ())
 {
 waittime++;
 if(waittime > 250)
 {
 IIC_Stop();
 rack = 1;
 break;
 }
 }
 SCL_LOW;
 Delay_I2c(4);
 return rack;
 
 }
 void IIC_noack()//非应答
 {
 SDA_HIGH;
 Delay_I2c(4);
 SCL_HIGH;
 Delay_I2c(4);
 SCL_LOW;
 Delay_I2c(4);
 }
 
 void IIC_ack()//应答
 {
 SDA_LOW;
 Delay_I2c(4);
 SCL_HIGH;
 Delay_I2c(4);
 SCL_LOW;
 Delay_I2c(4);
 SDA_HIGH;
 Delay_I2c(4);
 }
 
 4.16 IIC读写EEPROM驱动代码
 
 4.161 IIC写操作
 
 void IIC_Write_Byte(uint8_t addr,uint8_t data)
 {
 IIC_Start();//发生起始信号
 
 IIC_Send_Byte(0xA0);//最低位0,表示写入
 IIC_Wait_ack();//每次发完等待应答
 IIC_Send_Byte(addr >> 8);//高字节
 IIC_Wait_ack();
 IIC_Send_Byte(addr % 256);//低字节
 IIC_Wait_ack();
 
 IIC_Send_Byte(data);//发生一字节
 IIC_Wait_ack();
 IIC_Stop();//停止条件
 HAL_Delay(10);
 
 }
 
 4.162 IIC读操作
 
 uint8_t IIC_Read_Byte(uint8_t addr)
 {
 uint8_t data = 0;
 IIC_Start();//起始信号
 
 IIC_Send_Byte(0xA0);//写入地址
 IIC_Wait_ack();
 IIC_Send_Byte(addr >> 8);
 IIC_Wait_ack();
 IIC_Send_Byte(addr % 256);
 IIC_Wait_ack();
 
 IIC_Start();
 IIC_Send_Byte(0xA1);//1代表读
 IIC_Wait_ack();
 data = IIC_Recevie_Byte(0);//接受一字节
 IIC_Stop();
 return data;
 }
 
 附.h代码:
 
 #define  SCL_LOW  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET)
 #define  SCL_HIGH HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET)
 #define  SDA_LOW  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET)
 #define  SDA_HIGH HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET)
 
 #define SDA_READ() HAL_GPIO_ReadPin(GPIOB ,GPIO_PIN_9)
 4.2 硬件IIC(参考野火)
 22. I2C—读写EEPROM — [野火]STM32 HAL库开发实战指南——基于野火F4系列开发板 文档 (embedfire.com)
 
 硬件IIC与软件IIC不一样,必须用IIC引脚;
 
 4.21 初始化
 
 I2C_HandleTypeDef hi2c1;
 
 /* I2C1 init function */
 void MX_I2C1_Init(void)
 {
 
 /* USER CODE BEGIN I2C1_Init 0 */
 
 /* USER CODE END I2C1_Init 0 */
 
 /* USER CODE BEGIN I2C1_Init 1 */
 
 /* USER CODE END I2C1_Init 1 */
 hi2c1.Instance = I2C1;//IIC1
 hi2c1.Init.ClockSpeed = 400000;//速率
 hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;/*指定时钟占空比,可选low/high = 2:1及16:9模式*/
 hi2c1.Init.OwnAddress1 = 0; /*指定自身的I2C设备地址1,可以是7-bit或者10-bit*/
 hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;/*指定地址的长度模式,可以是7bit模式或者10bit模式 \*/
 hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;/*设置双地址模式 \*/
 hi2c1.Init.OwnAddress2 = 0;/*指定自身的I2C设备地址2,只能是 7-bit \*/
 hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;/*指定广播呼叫模式 \*/
 hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;/*指定禁止时钟延长模式*/
 HAL_I2C_Init(&hi2c1);
 
 /* USER CODE BEGIN I2C1_Init 2 */
 /* USER CODE END I2C1_Init 2 */
 
 }
 
 void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
 {
 
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 
 /* USER CODE BEGIN I2C1_MspInit 0 */
 
 /* USER CODE END I2C1_MspInit 0 */
 
 __HAL_RCC_GPIOB_CLK_ENABLE();
 /**I2C1 GPIO Configuration
 PB6     ------> I2C1_SCL
 PB7     ------> I2C1_SDA
 */
 GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;//复用开漏
 GPIO_InitStruct.Pull = GPIO_NOPULL;//上拉
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
 /* I2C1 clock enable */
 __HAL_RCC_I2C1_CLK_ENABLE();
 /* USER CODE BEGIN I2C1_MspInit 1 */
 
 /* USER CODE END I2C1_MspInit 1 */
 
 }
 
 4.22 向EEPROM写入一个字节的数据
 
 uint32_t I2C_EE_ByteWrite(uint8_t* pBuffer, uint8_t WriteAddr)//数据,地址
 {
 HAL_StatusTypeDef status = HAL_OK;
 
 status = HAL_I2C_Mem_Write(&hi2c1, 0xA0, (uint16_t)
 WriteAddr, I2C_MEMADD_SIZE_8BIT, pBuffer, 1, 100);//IIC1,写操作,地址,字节大小,数据,数据大小,超时时间
 
 /* Check the communication status */
 if (status != HAL_OK) {
 /* Execute user timeout callback */
 //I2Cx_Error(Addr);
 }
 while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) {
 
 }
 
 /* Check if the EEPROM is ready for a new operation */
 while (HAL_I2C_IsDeviceReady(&hi2c1, 0xA0,
 300, 300) == HAL_TIMEOUT);//等待IIC已经就绪
 
 /* Wait for the end of the transfer */
 while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) {
 
 }
 return status;
 }
 
 4.23  EEPROM的页写入
 
 // 向 I2C EEPROM 进行页写入操作
 // pBuffer: 指向要写入的数据缓冲区的指针
 // WriteAddr: 要写入的起始地址
 // NumByteToWrite: 要写入的字节数
 // 返回值: HAL 状态类型,用于表示操作的状态
 uint32_t I2C_EE_PageWrite(uint8_t* pBuffer, uint8_t WriteAddr,
 uint8_t NumByteToWrite)
 {
 // 初始化状态为 HAL_OK,表示操作成功
 HAL_StatusTypeDef status = HAL_OK;
 // 调用 HAL_I2C_Mem_Write 函数向 EEPROM 写入数据
 // &hi2c1 是 I2C 句柄,0XA0 是 EEPROM 的设备地址
 // WriteAddr 是要写入的起始地址,I2C_MEMADD_SIZE_8BIT 表示地址大小为 8 位
 // (uint8_t*)(pBuffer) 是要写入的数据缓冲区,NumByteToWrite 是要写入的字节数
 // 100 是超时时间
 status=HAL_I2C_Mem_Write(&hi2c1, 0XA0,WriteAddr,
 I2C_MEMADD_SIZE_8BIT, (uint8_t*)(pBuffer),NumByteToWrite, 100);
 
 // 等待 I2C 总线准备好进行下一次操作
 while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) {
 
 }
 
 // 检查 EEPROM 是否准备好进行新的操作
 // HAL_I2C_IsDeviceReady 函数用于检查设备是否准备好
 // 0xA0 是 EEPROM 的设备地址,300 是重试次数,300 是每次重试的超时时间
 while (HAL_I2C_IsDeviceReady(&hi2c1, 0xA0,
 300, 300) == HAL_TIMEOUT);
 
 // 等待传输结束,确保 I2C 总线处于就绪状态
 while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) {
 
 }
 // 返回操作的状态
 return status;
 }
 
 4.24 多字节写入
 
 // 向 I2C EEPROM 进行缓冲区写入操作
 // pBuffer: 指向要写入的数据缓冲区的指针
 // WriteAddr: 要写入的起始地址
 // NumByteToWrite: 要写入的字节数
 void I2C_EE_BufferWrite(uint8_t* pBuffer, uint8_t WriteAddr,
 uint16_t NumByteToWrite)
 {
 // 定义变量用于存储页数、剩余字节数、地址偏移量和计数器
 uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
 
 // 计算起始地址相对于页大小的偏移量
 Addr = WriteAddr % EEPROM_PAGESIZE;
 // 计算当前页剩余可写入的字节数
 count = EEPROM_PAGESIZE - Addr;
 // 计算要写入的总页数
 NumOfPage =  NumByteToWrite / EEPROM_PAGESIZE;
 // 计算写入所有页后剩余的字节数
 NumOfSingle = NumByteToWrite % EEPROM_PAGESIZE;
 
 // 如果起始地址是页大小对齐的
 if (Addr == 0) {
 // 如果要写入的字节数小于页大小
 if (NumOfPage == 0) {
 // 直接调用页写入函数写入剩余的字节数
 I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
 }
 // 如果要写入的字节数大于页大小
 else {
 // 循环写入所有页
 while (NumOfPage--) {
 // 调用页写入函数写入一页数据
 I2C_EE_PageWrite(pBuffer, WriteAddr, EEPROM_PAGESIZE);
 // 更新写入地址
 WriteAddr +=  EEPROM_PAGESIZE;
 // 更新数据缓冲区指针
 pBuffer += EEPROM_PAGESIZE;
 }
 
 // 如果还有剩余的字节数
 if (NumOfSingle!=0) {
 // 调用页写入函数写入剩余的字节数
 I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
 }
 }
 }
 // 如果起始地址不是页大小对齐的
 else {
 // 如果要写入的字节数小于页大小
 if (NumOfPage== 0) {
 // 直接调用页写入函数写入剩余的字节数
 I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
 }
 // 如果要写入的字节数大于页大小
 else {
 // 减去当前页可写入的字节数
 NumByteToWrite -= count;
 // 重新计算要写入的总页数
 NumOfPage =  NumByteToWrite / EEPROM_PAGESIZE;
 // 重新计算写入所有页后剩余的字节数
 NumOfSingle = NumByteToWrite % EEPROM_PAGESIZE;
 
 // 如果当前页还有可写入的字节数
 if (count != 0) {
 // 调用页写入函数写入当前页剩余的字节数
 I2C_EE_PageWrite(pBuffer, WriteAddr, count);
 // 更新写入地址
 WriteAddr += count;
 // 更新数据缓冲区指针
 pBuffer += count;
 }
 
 // 循环写入所有页
 while (NumOfPage--) {
 // 调用页写入函数写入一页数据
 I2C_EE_PageWrite(pBuffer, WriteAddr, EEPROM_PAGESIZE);
 // 更新写入地址
 WriteAddr +=  EEPROM_PAGESIZE;
 // 更新数据缓冲区指针
 pBuffer += EEPROM_PAGESIZE;
 }
 // 如果还有剩余的字节数
 if (NumOfSingle != 0) {
 // 调用页写入函数写入剩余的字节数
 I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
 }
 }
 }
 }
 
 附.h代码:
 
 /* USER CODE BEGIN Includes */
 #define EEPROM_PAGESIZE 8
 /* USER CODE END Includes */
 
 extern I2C_HandleTypeDef hi2c1;
 
 /* USER CODE BEGIN Private defines */
 void I2C_EE_Init(void);
 uint8_t I2C_Test(void);
 uint32_t I2C_EE_ByteWrite(uint8_t* pBuffer, uint8_t WriteAddr);
 
 uint32_t I2C_EE_PageWrite(uint8_t* pBuffer, uint8_t WriteAddr,
 uint8_t NumByteToWrite);
 
 
 void I2C_EE_BufferWrite(uint8_t* pBuffer, uint8_t WriteAddr,
 uint16_t NumByteToWrite);
 
 uint32_t I2C_EE_BufferRead(uint8_t* pBuffer, uint8_t ReadAddr, uint16_t NumByteToRead);
 
 五. 总结(IIC软件模拟与硬件IIC区别)
 硬件电路
 硬件 IIC:需要使用芯片内部专门的 IIC 硬件模块,该模块具有独立的时钟发生器、数据寄存器等硬件电路,通过特定的引脚(SCL 时钟线和 SDA 数据线)与外部设备连接。
 软件模拟 IIC:利用单片机的普通 I/O 引脚来模拟 IIC 的通信时序,不需要特定的硬件模块,只需要将普通 I/O 引脚配置为输出模式来发送数据和时钟信号,或配置为输入模式来接收数据。
 通信速度
 硬件 IIC:通信速度通常较快,因为硬件模块是专门为 IIC 通信设计的,能够高效地处理数据的发送和接收,并且可以支持较高的时钟频率。
 软件模拟 IIC:速度相对较慢,由于是通过软件程序来模拟通信时序,程序需要执行一系列的指令来控制 I/O 引脚的电平变化,这会花费一定的时间,限制了通信的速度。
 代码复杂度
 硬件 IIC:使用硬件 IIC 时,芯片厂商通常会提供相应的驱动库或寄存器操作手册,开发者只需要按照规定的方式配置寄存器,即可实现 IIC 通信。代码相对简洁,且不需要过多关注底层的通信时序细节。
 软件模拟 IIC:需要开发者自己编写代码来模拟 IIC 的起始信号、停止信号、数据传输、应答信号等各种时序,代码量较大,且需要对 IIC 协议有深入的理解,以确保时序的正确性。
 灵活性
 硬件 IIC:硬件 IIC 的引脚通常是固定的,一旦确定了使用的硬件 IIC 模块,其对应的引脚就不能再用于其他功能,灵活性较差。如果硬件设计已经确定,后期很难更改 IIC 引脚的分配。
 软件模拟 IIC:可以根据实际需求灵活选择任意的普通 I/O 引脚来模拟 IIC 通信,在硬件设计上更加灵活。如果需要更改引脚分配,只需要修改软件代码中的引脚定义即可,而不需要对硬件进行重新设计。
 稳定性
 硬件 IIC:由于是硬件电路实现,其稳定性较高,能够准确地按照 IIC 协议的规范进行通信,不容易受到软件干扰或其他因素的影响。在复杂的系统中,硬件 IIC 能够可靠地与多个 IIC 设备进行通信。
 软件模拟 IIC:稳定性相对较差,容易受到程序中其他代码的影响,例如在模拟 IIC 时序的过程中,如果程序被其他中断打断,可能会导致时序出现错误,从而影响通信的稳定性。
 
 在实际应用中,对于通信速度要求较高、对稳定性要求严格且 IIC 设备数量较多的情况,通常优先选择硬件 IIC;而对于资源有限、对灵活性要求较高或通信速度要求不高的场合,可以考虑使用软件模拟 IIC。
 
 
 ————————————————
 
 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
 
 原文链接:https://blog.csdn.net/m0_75187370/article/details/147099306
 
 
 | 
 |