小熊派gd32f303实战指南(9)— 硬件I2C驱动AT24C02 EEPROM从零到一
1. 硬件I2C与AT24C02基础认知第一次接触硬件I2C时我也被那些专业术语搞得一头雾水。简单来说I2C就像两个人用摩斯密码交流——只需要两根线SDA数据线和SCL时钟线就能让主设备GD32F303和从设备AT24C02说上话。AT24C02这个小本本能存储256字节的数据断电也不会丢失特别适合保存设备配置参数。硬件I2C和软件模拟最大的区别就像专业厨师和家常做菜硬件I2C是芯片内置的专业厨房有专门的电路处理起止信号、应答位等细节而软件模拟则是用GPIO口手动翻炒需要自己控制每个时序。实测下来硬件I2C的速度能轻松达到400kHz快速模式而软件模拟通常超不过100kHz。2. 硬件I2C环境搭建2.1 硬件连接要点我的小熊派开发板上GD32F303的I2C0默认引脚是PB6(SCL)和PB7(SDA)。连接AT24C02时要注意三点第一模块的A0-A2地址引脚要接地地址设为0x50第二记得接上拉电阻通常4.7kΩ第三VCC电压要匹配GD32是3.3VAT24C02也支持3.3V。注意如果读写不稳定优先检查硬件连接。我就曾因为忘记上拉电阻调试了一整天。2.2 软件环境准备使用Keil MDK开发时需要先安装GD32F30x系列支持包。关键是要在工程中包含这两个文件#include gd32f30x_i2c.h #include gd32f30x_rcu.h建议直接使用官方提供的标准外设库比HAL库更贴近寄存器操作方便理解底层原理。3. 硬件I2C初始化详解3.1 时钟配置时钟就像I2C通信的心跳。配置步骤如下rcu_periph_clock_enable(RCU_I2C0); // 开启I2C0时钟 rcu_periph_clock_enable(RCU_GPIOB); // 开启GPIOB时钟 rcu_periph_clock_enable(RCU_AF); // 开启复用功能时钟3.2 引脚复用配置把PB6/PB7设置为I2C功能模式gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);这里用开漏输出OD模式是关键I2C总线需要线与特性。3.3 I2C参数设置配置为400kHz快速模式i2c_clock_config(I2C0, 400000, I2C_DTCY_2); i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x50); i2c_enable(I2C0);特别注意GD32的I2C时钟配置比较特殊需要根据APB1时钟频率计算。我的板子上APB1是60MHz所以分频系数设为3060MHz/302MHz再除以5得到400kHz。4. AT24C02驱动实现4.1 单字节写入写一个字节到指定地址void EEPROM_WriteByte(uint8_t addr, uint8_t data) { while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY)); // 等待总线空闲 i2c_start_on_bus(I2C0); // 发送起始条件 while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)); i2c_master_addressing(I2C0, 0xA0, I2C_TRANSMITTER); // 发送设备地址写 while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); i2c_data_transmit(I2C0, addr); // 发送内存地址 while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); i2c_data_transmit(I2C0, data); // 发送数据 while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); i2c_stop_on_bus(I2C0); // 发送停止条件 delay_ms(5); // 等待写入完成 }AT24C02每次写入需要约5ms实测不加延迟会导致下次操作失败。4.2 页写入模式AT24C02支持连续写入8字节一页void EEPROM_PageWrite(uint8_t addr, uint8_t *data, uint8_t len) { // 起始序列与单字节写入相同... for(int i0; ilen; i) { i2c_data_transmit(I2C0, data[i]); while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); } // 停止序列... }注意地址会自动递增但跨页时需要分多次写入。4.3 随机读取从指定地址读取一个字节uint8_t EEPROM_ReadByte(uint8_t addr) { // 先发送写操作设置地址 i2c_start_on_bus(I2C0); while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)); i2c_master_addressing(I2C0, 0xA0, I2C_TRANSMITTER); while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); i2c_data_transmit(I2C0, addr); while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); // 重新启动并切换为读模式 i2c_start_on_bus(I2C0); while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)); i2c_master_addressing(I2C0, 0xA0, I2C_RECEIVER); while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); i2c_ack_config(I2C0, I2C_ACK_DISABLE); // 最后一个字节不应答 while(!i2c_flag_get(I2C0, I2C_FLAG_RBNE)); uint8_t data i2c_data_receive(I2C0); i2c_stop_on_bus(I2C0); return data; }这个伪写入重启真读取的流程是I2C随机读取的标准操作。5. 实战调试技巧5.1 常见问题排查遇到通信失败时建议按这个顺序检查用逻辑分析仪抓取波形确认起始信号、地址位、数据位是否正常检查上拉电阻值太大导致上升沿缓慢太小耗电增加验证设备地址AT24C02系列地址是0xA0/0xA1确认时序延迟特别是停止信号后的等待时间5.2 性能优化建议如果追求极致速度可以使用DMA传输连续数据将频繁访问的数据缓存在RAM中采用非阻塞式编程配合中断或事件机制我在项目中实测硬件I2C比软件模拟节省约30%的CPU资源。对于需要实时响应的系统这个优化非常关键。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2607201.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!