软件模拟iic+BL24C512

软件模拟iic+BL24C512 硬件连接与初始化确认MCU的GPIO引脚配置选择两个通用IO分别作为SCL时钟线和SDA数据线。上拉电阻需接至电源通常4.7kΩ确保信号稳定性。初始化时设置GPIO为开漏输出模式SDA线初始状态为高电平。I2C_SCL_HIGH GPIO_SetBits(EEROM_I2C_PORT,EEROM_I2C_SCL_PIN)I2C_SCL_LOW GPIO_ResetBits(EEROM_I2C_PORT,EEROM_I2C_SCL_PIN)I2C_SDA_HIGH GPIO_SetBits(EEROM_I2C_PORT,EEROM_I2C_SDA_PIN)I2C_SDA_LOW GPIO_ResetBits(EEROM_I2C_PORT,EEROM_I2C_SDA_PIN)I2C_SDA_READ GPIO_ReadInputDataBit(EEROM_I2C_PORT,EEROM_I2C_SDA_PIN)I2C时序模拟根据BL24C512的时序要求编写以下基本函数起始条件SCL高电平时SDA从高到低跳变。停止条件SCL高电平时SDA从低到高跳变。数据发送SCL低电平时改变SDASCL高电平时保持数据稳定。数据接收读取SDA状态需在SCL高电平期间完成。数据读写协议BL24C512的地址为0xA0读写操作需遵循以下流程写操作发送起始信号→设备地址写模式→内存地址2字节→数据→停止信号。读操作发送起始信号→设备地址写模式→内存地址2字节→重复起始信号→设备地址读模式→读取数据→停止信号。错误处理与超时机制检测ACK/NACK响应若未收到ACKSDA为高需重试或报错。加入超时判断防止总线死锁。典型超时时间为几毫秒具体根据MCU时钟调整。页写入与跨页处理BL24C512页大小为128字节。跨页写入时需分多次操作每次写入后等待EEPROM内部写入完成典型延时5ms。可通过轮询ACK或固定延时实现。示例代码片段#include bsp_eerom.h #include delay.h #include bsp_wdt.h /****************************************************************************************** * 定义串口所用的变量 ******************************************************************************************/ uint16_t eeprom_address; /************************************************ 函数名称 EEROM_Init_Config 功 能 EEROM的初始化函数 参 数 返 回 值 作 者 *************************************************/ void EEROM_Init_Config(void) { /* ########################## 初始化时钟 #################################### */ /* GPIO: enable GPIO and PWR clock enable */ RCC_EnableAHB5PeriphClk1(RCC_AHB5_PERIPHEN_M7_GPIOB, ENABLE); /* ########################## 初始化端口 #################################### */ GPIO_InitType GPIO_InitStructure; GPIO_InitStruct(GPIO_InitStructure); GPIO_InitStructure.Pin EEROM_I2C_SCL_PIN ; GPIO_InitStructure.GPIO_Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.GPIO_Pull GPIO_PULL_DOWN; GPIO_InitPeripheral(EEROM_I2C_PORT, GPIO_InitStructure); GPIO_InitStructure.Pin EEROM_I2C_SDA_PIN ; GPIO_InitStructure.GPIO_Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.GPIO_Pull GPIO_PULL_DOWN; GPIO_InitPeripheral(EEROM_I2C_PORT, GPIO_InitStructure); GPIO_InitStructure.Pin EEROM_I2C_WP_PIN; GPIO_InitStructure.GPIO_Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.GPIO_Pull GPIO_PULL_DOWN; GPIO_InitPeripheral(EEROM_I2C_WP_PORT, GPIO_InitStructure); GPIO_SetBits(EEROM_I2C_PORT,EEROM_I2C_SCL_PIN); GPIO_SetBits(EEROM_I2C_PORT,EEROM_I2C_SDA_PIN); } /************************************************ 函数名称 I2C_SDA_SetOutput 功 能 I2C_SDA设置为输出 参 数 无 返 回 值 无 作 者 *************************************************/ void i2c_sda_out(void) { GPIO_InitType GPIO_InitStructure; GPIO_InitStruct(GPIO_InitStructure); GPIO_InitStructure.Pin EEROM_I2C_SDA_PIN ; GPIO_InitStructure.GPIO_Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.GPIO_Pull GPIO_PUPD_NO_PULL; GPIO_InitPeripheral(EEROM_I2C_PORT, GPIO_InitStructure); } /************************************************ 函数名称 I2C_SDA_SetInput 功 能 I2C_SDA设置为输入 参 数 无 返 回 值 无 作 者 *************************************************/ void i2c_sda_in(void) { GPIO_InitType GPIO_InitStructure; GPIO_InitStruct(GPIO_InitStructure); GPIO_InitStructure.Pin EEROM_I2C_SDA_PIN ; GPIO_InitStructure.GPIO_Mode GPIO_MODE_INPUT; GPIO_InitStructure.GPIO_Pull GPIO_PUPD_NO_PULL; GPIO_InitPeripheral(EEROM_I2C_PORT, GPIO_InitStructure); } /************************************************ 函数名称 I2C_Start 功 能 I2C开始 * SCL: __________ * \__________ * SDA: _____ * \_______________ 参 数 无 返 回 值 无 作 者 *************************************************/ void i2c_start(void) { i2c_sda_out(); I2C_SCL_HIGH; //SCL高 delay_us(5); I2C_SDA_HIGH; //SDA高 - 低 delay_us(5); I2C_SDA_LOW; //SDA低 delay_us(5); I2C_SCL_LOW; //SCL低(待写地址/数据) delay_us(5); } /************************************************ 函数名称 dri_i2c_stop 功 能 I2C停止 * SCL: ____________________ * __________ * SDA: _________/ 参 数 无 返 回 值 无 作 者 *************************************************/ void i2c_stop(void) { i2c_sda_out(); I2C_SCL_LOW; //SCL低 - 高 delay_us(5); I2C_SDA_LOW; //SDA低 - 高 delay_us(5); I2C_SCL_HIGH; //SCL高 delay_us(5); I2C_SDA_HIGH; //SDA高 delay_us(5); } /************************************************ 函数名称 I2C_PutAck 功 能 I2C主机产生应答(或非应答)位 参 数 Ack: I2C_ACK ----- 0: 应答 I2C_NOACK --- 1:非应答 注意从机的应答电平 返 回 值 无 作 者 *************************************************/ uint8_t i2c_wait_ack(void) { uint8_t errTimer 0; i2c_sda_in(); I2C_SDA_HIGH; delay_us(1); I2C_SCL_HIGH; delay_us(1); while(I2C_SDA_READ){ errTimer; if(errTimer250) { i2c_stop(); return 1; } } I2C_SCL_LOW; //SCL低 delay_us(1); return 0; } //产生ACK应答 void IIC_Ack(void) { I2C_SCL_LOW; i2c_sda_out(); I2C_SDA_LOW; delay_us(2); I2C_SCL_HIGH; delay_us(2); I2C_SCL_LOW; } //不产生ACK应答 void IIC_NAck(void) { I2C_SCL_LOW; i2c_sda_out(); I2C_SDA_HIGH; delay_us(2); I2C_SCL_HIGH; delay_us(2); I2C_SCL_LOW; } /************************************************ 函数名称 I2C_WriteByte 功 能 I2C写一字节 参 数 Data -------- 数据 返 回 值 I2C_ACK ----- 应答 I2C_NOACK --- 非应答 作 者 *************************************************/ void i2c_write_byte(uint8_t Data)//0xA0 { uint8_t cnt 0; i2c_sda_out(); I2C_SCL_LOW; //拉低时钟 开始传输数据 delay_us(1); for(cnt 0; cnt 8; cnt) { if((Data 0x80) 7) { I2C_SDA_HIGH; }else{ I2C_SDA_LOW; } Data1; delay_us(2); I2C_SCL_HIGH; delay_us(2); I2C_SCL_LOW; delay_us(2); } } /************************************************ 函数名称 I2C_ReadByte 功 能 I2C读一字节 参 数 ack --------- 产生应答(或者非应答)位 返 回 值 data -------- 读取的一字节数据 作 者 *************************************************/ uint8_t i2c_read_byte(uint8_t ack) { uint8_t cnt 0; uint8_t data 0; i2c_sda_in(); //SDA配置为输入模式 for(cnt0;cnt8;cnt ) { I2C_SCL_LOW; delay_us(2); I2C_SCL_HIGH; data1; if(I2C_SDA_READ){ data; } delay_us(1); } if (!ack) { IIC_NAck(); //发送nACK } else{ IIC_Ack(); //发送ACK } return data; //返回数据 } uint8_t BL24C512_ReadOneByte(uint16_t ReadAddr) { uint8_t temp0; i2c_start(); i2c_write_byte(0xA0); //发送写命令 i2c_wait_ack(); i2c_write_byte((ReadAddr8)0xff);//发送高地址 i2c_wait_ack(); i2c_write_byte(ReadAddr0xff); //发送低地址 i2c_wait_ack(); i2c_start(); i2c_write_byte(0xA1);//进入接收模式 i2c_wait_ack(); tempi2c_read_byte(0); i2c_stop();//产生一个停止条件 return temp; } void BL24C512_WriteOneByte(uint16_t WriteAddr,uint8_t DataToWrite) { i2c_start(); i2c_write_byte(0xA0);//发送设备地址 i2c_wait_ack(); i2c_write_byte((WriteAddr8)0xff);//发送字节地址 i2c_wait_ack(); i2c_write_byte(WriteAddr0xff); //发送要写入的数据 i2c_wait_ack(); i2c_write_byte(DataToWrite); //发送要写入的数据 i2c_wait_ack(); i2c_stop();//产生一个停止条件 delay_ms(10); } void BL24C512_WriteOneByteNoDelay(uint16_t WriteAddr,uint8_t DataToWrite) { i2c_start(); i2c_write_byte(0xA0);//发送设备地址 i2c_wait_ack(); i2c_write_byte((WriteAddr8)0xff);//发送字节地址 i2c_wait_ack(); i2c_write_byte(WriteAddr0xff); //发送要写入的数据 i2c_wait_ack(); i2c_write_byte(DataToWrite); //发送要写入的数据 i2c_wait_ack(); i2c_stop();//产生一个停止条件 //delay_ms(10); } void BL24C512_WritePage(uint16_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite) { uint16_t pageRemain BL24C512_Page_Size - (WriteAddr % BL24C512_Page_Size); // 当前页剩余空间 // 不能跨页写 if (NumToWrite pageRemain) NumToWrite pageRemain; i2c_start(); i2c_write_byte(0xA0); // 器件地址注意根据A0~A2位配置调整 i2c_wait_ack(); i2c_write_byte((WriteAddr 8) 0xFF); // 地址高字节 i2c_wait_ack(); i2c_write_byte(WriteAddr 0xFF); // 地址低字节 i2c_wait_ack(); // 连续写多个字节 for (uint16_t i 0; i NumToWrite; i) { i2c_write_byte(pBuffer[i]); i2c_wait_ack(); } i2c_stop(); //delay_ms(10); // 等待写入完成 } void BL24C512_Read(uint16_t ReadAddr,uint8_t *pBuffer,uint16_t NumToRead) { while(NumToRead) { *pBufferBL24C512_ReadOneByte(ReadAddr); NumToRead--; } } uint32_t timeEEWrite0; uint32_t DelayGap10; void BL24C512_Write(uint16_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite) { while(NumToWrite--) { BL24C512_WriteOneByte(WriteAddr,*pBuffer); WriteAddr; pBuffer; WDT_Clear(); } } void BL24C512_WriteNoBlock(uint16_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite) { while(NumToWrite--) { if(systime - timeEEWriteDelayGap) { timeEEWrite systime; BL24C512_WriteOneByteNoDelay(WriteAddr,*pBuffer); WriteAddr; pBuffer; } } } /*************************************************** *外部EE写使能 ***************************************************/ void EEEnable(uint8_t EN) { if(EN 0){ GPIO_SetBits(GPIOB,GPIO_PIN_12); }else{ GPIO_ResetBits(GPIOB,GPIO_PIN_12); } } /* 测试 */ void i2c_test(void) { uint8_t i; uint8_t buf[128]{0},buf2[128]{0}; for(i0; i 128; i) { buf2[i] 1; } BL24C512_Write(0x0000,buf2, 128); delay_ms(5); BL24C512_Read(0x0000,buf,128); printf(%x,buf[0]); printf(%x,buf[100]); } /**** END OF FILE ****/测试与验证通过逻辑分析仪或示波器抓取波形确认时序符合标准如SCL频率≤400kHz。编写测试用例覆盖连续读写、边界地址等场景。