当前位置: 首页 > news >正文

软件模拟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。编写测试用例覆盖连续读写、边界地址等场景。
http://www.gsyq.cn/news/1344238.html

相关文章:

  • SketchUp STL插件终极指南:高效实现3D打印模型转换的完整实战方案
  • 基于Java Web的退休人才求职网站设计与开发
  • 米哈游游戏字体完整指南:11款精美架空文字字体一键获取与使用
  • 一周AI新鲜事(2026.05.11—2026.05.17):AI世界正在进入“全面战争时代”
  • 科技中介机构如何提升服务效率与转化率?
  • java springboot-vue的婚庆服务平台的功能设计
  • Mos:macOS 鼠标滚轮太生硬?这款免费开源工具让你的滚轮爽如触控板
  • 蓝绿环境 灰度环境 极简区别
  • 如何免费实现本地视频字幕提取:你的完整指南
  • QGraphicsView的记录
  • (Pytorch、pandas、matplotlib)数据操作
  • 手机上还有免费编辑pdf文本的软件?!
  • 3分钟掌握PlantUML Editor:用代码思维绘制专业UML图表的终极指南
  • 短信验证码5大常见漏洞与防御实战
  • 罗技鼠标宏压枪脚本:基于Lua的游戏后坐力控制系统架构
  • 现代Qt开发教程(新手篇)2.4——QFont 与文本渲染基础
  • ViGEmBus虚拟游戏控制器驱动:Windows游戏输入的终极解决方案
  • CANN 异构编程:CPU-NPU 协同计算实战
  • Unity动态设置Layer与摄像机屏蔽的完整闭环方案
  • FreeMove终极指南:Windows磁盘空间优化利器,轻松释放C盘数十GB空间
  • NGINX明文注入漏洞CVE-2026-1642原理与防御实战
  • G-Helper终极指南:彻底释放华硕笔记本性能的轻量级开源神器
  • 工业智能网关:三菱FX3U PLC数据采集
  • NHSE终极指南:掌握动物森友会存档编辑的5大核心技术
  • Unity Android构建中NDK 19.0.5232133稳定实践指南
  • 2026年12款客户管理系统推荐:国内企业热门CRM盘点
  • 机器学习深度学习实战项目推荐!(附项目代码)
  • 3分钟快速上手:罗技鼠标PUBG压枪宏终极配置指南
  • 群晖SSH远程访问全链路打通指南
  • 群晖NAS远程SSH配置全解:从权限控制到独立模式实战