第四章 STM32 串口通信进阶:控制指令与数据存储实战----EEPROM配置
“一套基于真实工业协议的 STM32 通信开发实战指南,涵盖从串口基础到 Bootloader 升级的全流程, EEPROM 存储、Flash 故障记录等功能实现,可直接用于项目开发或竞赛实战。
·
文章目录
前言
本章聚焦 STM32 串口通信进阶应用,重点讲解 AT24C02 EEPROM 的配置与实战。从 I2C 总线初始化到参数掉电存储,将详细解析如何通过自定义协议实现温度告警参数的读写管理,让 STM32 具备数据 “记忆” 能力,适合想掌握工业级数据持久化方案的开发者学习。
本项目所有功能效果展示视频链接
一、AT24C02 EEPROM 驱动开发(I2C 通信核心)
模块定位:实现 STM32 与 AT24C02 的 I2C 通信,提供参数持久化存储能力。
1.I2C 总线初始化(底层通信基础):
void I2C1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
I2C_InitTypeDef I2C_InitStruct;
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// 2. 配置 SCL (PB6) 和 SDA (PB7)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; // 复用开漏
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
// 3. 配置 I2C
I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStruct.I2C_OwnAddress1 = 0x00; // 主模式,地址随意
I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStruct.I2C_ClockSpeed = 100000; // 100kHz
I2C_Init(I2C1, &I2C_InitStruct);
// 4. 使能 I2C
I2C_Cmd(I2C1, ENABLE);
}
说明:
- 开漏模式:I2C 总线需外接上拉电阻,确保总线空闲时为高电平,支持多设备共享总线。
- 100kHz 速率:兼容 AT24C02 的标准模式(最高 100kHz),高速模式(400kHz)需额外配置。
2.EEPROM 读写操作
//读一个字节
uint8_t AT24C02_ByteRead(uint8_t RegAdd)
{
uint8_t Data;
I2C_GenerateSTART(I2C1, ENABLE);
AT24C02_WaitEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT);//EV5
I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter);
AT24C02_WaitEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//EV6
I2C_Cmd(I2C1, ENABLE);
I2C_SendData(I2C1, RegAdd);
AT24C02_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//EV8_2
I2C_GenerateSTART(I2C1, ENABLE);
AT24C02_WaitEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT);//EV5
I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Receiver);
AT24C02_WaitEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//EV6
I2C_AcknowledgeConfig(I2C1, DISABLE); //在接收最后一个字节之前提前将应答失能
I2C_GenerateSTOP(I2C1, ENABLE); //在接收最后一个字节之前提前申请停止条件
AT24C02_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED);//EV7
Data = I2C_ReceiveData(I2C1);
I2C_AcknowledgeConfig(I2C1, ENABLE); //将应答恢复为使能,为了不影响后续可能产生的读取多字节操作
return Data;
}
//写入多个字节
/**
* @brief 向EEPROM写入一页数据(最大8字节)
* @param pBuffer: 要写入的数据缓冲区
* @param WriteAddr: 写入起始地址 (0-255)
* @param NumByteToWrite: 要写入的字节数(不超过 I2C_PageSize)
* @retval 无
*/
void I2C_EE_PageWrite(uint8_t* pBuffer, uint8_t WriteAddr, uint8_t NumByteToWrite)
{
/* 启动I2C通信 */
I2C_GenerateSTART(I2C1, ENABLE);
AT24C02_WaitEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT); // EV5: 检测START条件成功
/* 发送设备地址(写模式) */
I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter);
AT24C02_WaitEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); // EV6: 地址发送成功
/* 发送要写入的EEPROM内部地址 */
I2C_SendData(I2C1, WriteAddr);
AT24C02_WaitEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING); // EV8: 数据发送中
/* 循环写入数据 */
while (NumByteToWrite--)
{
I2C_SendData(I2C1, *pBuffer++);
if (NumByteToWrite == 0) // 如果是最后一个字节,等待传输完成
{
AT24C02_WaitEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED); // EV8_2: 数据发送完成
}
else // 否则等待继续发送
{
AT24C02_WaitEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING); // EV8: 数据发送中
}
}
/* 停止I2C通信 */
I2C_GenerateSTOP(I2C1, ENABLE);
}
说明:
- 设备地址:AT24C02 的 8 位地址为0xA0。
- 页写入限制:AT24C02 每页 8 字节(I2C_PageSize=8),超过页大小需分多次写入,避免数据覆盖。
3.分页写入优化(提升批量写入效率)
/**
* @brief 向EEPROM写入任意长度数据(自动处理跨页)
* @param pBuffer: 要写入的数据缓冲区
* @param WriteAddr: 写入起始地址 (0-255)
* @param NumByteToWrite: 要写入的字节数
* @retval 无
*/
void I2C_EE_BufferWrite(uint8_t* pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite)
{
uint8_t remainingInPage; // 当前页剩余可写入字节数
uint8_t writeSize; // 本次写入的字节数
while (NumByteToWrite > 0)
{
/* 计算当前页剩余空间 */ //假设写入
remainingInPage = I2C_PageSize - (WriteAddr % I2C_PageSize);
/* 本次写入的字节数 = min(剩余数据, 当前页剩余空间) */
if (NumByteToWrite > remainingInPage)
{
writeSize = remainingInPage; // 本次只能写满当前页剩余空间
}
else
{
writeSize = NumByteToWrite; // 剩余数据不足一页,全部写完
}
/* 执行页写入 */
I2C_EE_PageWrite(pBuffer, WriteAddr, writeSize);
/* 等待EEPROM内部写入完成(AT24C02需要约5ms) */
Delay_ms(5); // 或者用 AT24C02_WaitStandby() 检测ACK
/* 更新指针、地址和剩余字节数 */
pBuffer += writeSize;
WriteAddr += writeSize;
NumByteToWrite -= writeSize;
}
}
说明:
- 页写入特性:AT24C02 支持每页 8 字节连续写入,超过页边界会触发 “页翻转”,导致前半页数据被覆盖。
- 延时必要性:EEPROM 内部写入需要时间(约 5ms),必须等待完成才能进行下一次写入。
二、参数初始化与掉电保护(系统数据管理)
模块定位:实现系统参数的上电初始化与掉电持久化,确保设备重启后参数不丢失。
1.上电初始化逻辑(首次配置参数)
// 上电检测与参数初始化
void Power_On_Write_Para(void)
{
uint8_t checkFlag[2] = {0};
// 读取EEPROM中的初始化标志位(地址:EEP_INIT_WRITEPARA_ADDR)
Flash_Read_Fun(EEP_INIT_WRITEPARA_ADDR, checkFlag, 2);
// 若标志位不是0x5D 0x5D,说明首次上电或参数异常
if ((checkFlag[0] != 0x5D) || (checkFlag[1] != 0x5D)) {
Write_Para(); // 写入默认参数
USART1_WritePara_Fun(); // 通过串口上报参数
}
}
// 上电参数读取
void Power_On_Read_Para(void)
{
uint8_t i;
// 从EEPROM读取参数存入全局数组Para_Buf
for (i = 0; i <= sizeof(threshold_params); i++) {
Para_Buf[i] = AT24C02_ByteRead(SYSTEM_PARA_TEMP_ADDR + i);
}
}
说明:
- 标志位机制:通过检测特定地址的标志位(0x5D 0x5D)判断是否需要初始化,避免重复写入。
- 数据一致性:参数读取后存入全局数组Para_Buf,供系统各模块共享访问。
三、温度告警参数管理(业务逻辑实现)
模块定位:基于自定义协议实现温度告警参数的串口传输与本地存储
1协议帧构造与发送(参数上报)
void SendTempParaData(void)
{
uint8_t i = 0;
ShareBuf[0] = 0x7E; // 起始符
ShareBuf[1] = 0x46; // CID1
ShareBuf[2] = 0x02; // RNT
ShareBuf[3] = 0x20; // Len
for(i=0;i<32;i++)
{
ShareBuf[4+i] = Para_Buf[i];
}
ShareBuf[36] = CalculateCRC8(&ShareBuf[1], ShareBuf[3] + 3);; // CRC
ShareBuf[37] = 0xEF; // 结束符
Usart1_Transmitter(ShareBuf, ShareBuf[3] + 6); // 发送数据
}
说明:
- 协议帧结构:遵循 “SOI+CID1+CID2+LENGTH+INFO+CRC+EOI” 格式,与第二章定义一致。
- CRC 校验范围:仅校验 CID1、CID2、LENGTH、INFO,不包含 SOI 和 EOI。
2.参数修改与存储
void Wirte_TempParameter(void)
{
uint8_t i = 0;
for(i=0;i<32;i++)
{
Para_Buf[i] = Calibrate_Buf[i];
}
I2C_EE_BufferWrite(&Para_Buf[0],SYSTEM_PARA_TEMP_ADDR,32);
Delay(5000);
}
说明:
- 双缓冲区机制:Calibrate_Buf用于暂存修改参数,确认后同步到Para_Buf并写入 EEPROM
- 延时保障:5ms 延时确保 EEPROM 完成内部写入,避免断电导致数据丢失。
四、模块协同工作流程(整体逻辑串联)
1.系统启动流程
上电 → I2C初始化 → 读取初始化标志位 → 若未初始化则写入默认参数 → 读取EEPROM参数到内存
2.参数修改流程
串口接收修改指令 → 解析参数存入Calibrate_Buf → 同步到Para_Buf → 分页写入EEPROM → 发送确认响应
2.参数上报流程
串口接收读取指令 → 从Para_Buf读取参数 → 构造协议帧 → 计算CRC → 串口发送响应帧
五、后续内容更新
- 下期预告 :
CSDN栏 模块一章节一《STM32 串口通信进阶:控制指令与数据存储实战----故障存储配置》 - 互动福利 :
评论区留言 “协议”,赠送《本系列通信协议》PDF。
B站搜索相同ID:通信翻车员,可查看相关视频讲解
STM32 串口通信协议开发实战全攻略:STM32 串口通信・数据存储・Bootloader 全案例解析

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)