历史上的今天
今天是:2026年03月14日(星期六)
2023年03月14日 | STM32F0单片机快速入门九 用 I2C HAL 库读写24C02
2023-03-14 来源:zhihu
1.24C02介绍
24C02 现在基本是开发板的标配,对于需要掉电存储的应用来说确是不二选择。现在单片机因为内部集成了Flash存储器,一般也都支持数据的掉电保存,但相对于 24C02 这种 EEPROM 来说,使用单片机内部的 Flash 有一些需要注意的问题:
Flash 写入数据之前需要先执行擦除操作,而且擦除以扇区为单位。
Flash读写次数比 EEPROM 少很多。
容易误操作,把 Flash 内部的代码擦除掉。
影响中断的响应时间。
24C02 有 256 字节的数据,一般说来也够用了。它的地址是可以通过引脚配置的,这样一条 I2C 总线上就可以挂多个 24C02。如下:

我们把 A2,A1,A0 都接地,这样地址为 A0。然后 SCL,SDA 脚接 MCU 的 PB8 和 PB9。需要注意 SCL,和 SDA 需要加上拉电阻。

代码
下面我们在一个 I2C 例程上面修改代码来实现 24C02 的读写。大家可以看到使用库函数的好处,基本上不用看 STM32F030 的手册,很快就能实现我们想要实现的功能。
我们用 Keil 打开下面这个工程:
STM32Cube_FW_F0_V1.11.0ProjectsSTM32F030R8-NucleoExamplesI2CI2C_TwoBoards_ComPollingMDK-ARMProject.uvprojx
Step 1, 把 I2C 地址改为跟我们硬件一致:

Step 2, 根据实际使用的 I2C 模块和引脚进行配置:

Step 3, 把地址模式改为 7BIT:

Step 4, 操作EEPROM,我们不使用例子中的 HAL_I2C_Master_Transmit 和 HAL_I2C_Master_Receive,这两个函数适用于两个 I2C 器件之间进行数据传输。我们这里要用的是下面这两个函数:
HAL_I2C_Mem_Write(
I2C_HandleTypeDef *hi2c, // 使用的 I2C 模块的 Handle 的指针
uint16_t DevAddress, // I2C 器件的地址,这里是 24C02 的地址 0xA0
uint16_t MemAddress, // 存储器内部地址
uint16_t MemAddSize, // 存储器内部地址位数 8BIT or 16BIT ?
uint8_t *pData, // 发送数据缓冲区指针
uint16_t Size, // 数据长度
uint32_t Timeout // 超时设置
);
HAL_I2C_Mem_Read(
I2C_HandleTypeDef *hi2c, // 使用的 I2C 模块的 Handle 的指针
uint16_t DevAddress, // I2C 器件的地址,这里是 24C02 的地址 0xA0
uint16_t MemAddress, // 存储器内部地址
uint16_t MemAddSize, // 存储器内部地址位数 8BIT or 16BIT ?
uint8_t *pData, // 接收数据缓冲区指针
uint16_t Size, // 接收数据长度
uint32_t Timeout // 超时设置
);

在此我们写入数据用的 24C02 的 Page Write 命令,每次写入 8个字节的数据,然后存储器写入地址加 8。要注意每次执行完写入命令后,需要有一个延时,等待 EEPROM 内部处理完该指令后才能继续写入。这个延时要查手册,不同的厂家可能有不同的数值。读出时可以连续的读出数据,无需等待。

下面是写入数据的波形,0xA0 是器件地址,0x28 是 24C02 内部存储器地址,之后是 8个字节数据。

读出数据的波形:

注意:
在使用硬件 I2C 操作时,有时候会遇到死锁问题。在此情况下,可以把 SCL,SDA 引脚初始化为 GPIO,如此例中的 PB8, PB9 然后连续翻转 SCL 引脚送出 9 个时钟脉冲,既可以使 I2C 从死锁的状态复位。然后再重新初始化 I2C 模块,进入正常 I2C 操作。
参考资料:
PM0215 STM32F0xxx Cortex-M0 programming manual
UM1785 Description of STM32F0 HAL and low-layer drivers
24C02 Datasheet
STM32F030 Datasheet
STM32F030 Reference Manual
史海拾趣
|
单片机是一门实践性非常强的学科,没有实践一切都是“空中楼阁”,花点钱买块开发板是非常必要的。(“开发板就好比农民种地的种子,只要能合理利用,它便会生根发芽,最后定能收获丰盛的果实。想要种好地,不要不舍得去买好种子”。)学习单片机, ...… 查看全部问答> |
|
混频器输出fout=(fin+flo)+(fin-flo),如果(fin-flo)为负值,fout将如何输出?例如,输入频率fin=100M,本振flo=200M,混频器是否只输出和频300M?现在有信号500M-1G,如果本振是750M,比如说600M和900M的频率差频后是否会混叠在一起?… 查看全部问答> |
|
+WIND: 13 +WIND: 1 +WIND: 7 +WIND: 16 +WIND: 4 +WIND: 10,\"SM\",0,\"FD\",0,\"ON\",0,\"EN\",0 +WIND: 11,,,,,\"D345E47A9F980A6A5C893FB80A96E687\",\"4474953C9BED9FD258B1D86EAD46FA25\" 比如我输入ATDXXXXX; 呼叫号码,他就会在呼 ...… 查看全部问答> |
|
上海诚聘vxworks开发人员 工作地点上海 通信行业的底层嵌入式研发 要求:2年左右工作经验,大专以上学历,英语读写 联系方式:36673167 EMAIL:wangjx912@163.com… 查看全部问答> |
|
在Wince4.2中,用PPPOE进行ADSL拨号,刚安装、设置好软件后第一次拨号使用完全没有问题。之后就总是可以拨上去,但就是网络不起作用。拨号后提示信息为已连接,查看拨号结果,拨号肯定是成功了,IP地址、网关、DNS地址都正确获得了,但就是Ping公网 ...… 查看全部问答> |
|
12MByte/s的采样速率通过MCBSP传输给 tms320c6416T可以吗? 6416T 1G的主频,mcbsp的速率是可以支持到12MByte/s的速率(96Mbps), 但是不知道做是不是会不稳定。 [ 本帖最后由 dsp_comm 于 2011-5-15 19:23 编辑 ]… 查看全部问答> |
|
Grlib代码简洁,比uCGUI简单多了,移植的时候 不需考虑太多的东西,容易上手 // UARTStdioInit(0); //初始化串口0// UARTprintf(\"Hello, world!\\n\"); //直接打印输出,前提必须是上面 ...… 查看全部问答> |




