本帖最后由 sujingliang 于 2025-6-17 10:22 编辑
本文实现用cJSON处理json格式处理,EEPROM驱动及读写,通过串口发送json格式数据,写入EEPROM
板载EEPROM为24C02,容量2k bit
处理json需要用cJSON,可以从:https://gitee.com/tianbeibei/cJSON下载。
同样我没有下载,在自己机器上找到了一份cJSON.c,cJSON.h复制到utilities\cjson下备用,并将cJSON.c加入工程
一、EEPROM驱动
官方例程中关于EEPROM的驱动例程十分丰富,可参考以下路径的例程:
LibSamples_MM32F0120_V1.13.4\Samples\LibSamples\I2C
I2C配置
#define EEPROM_I2C_ADDRESS 0xA0
void eeprom_I2C_Configure(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
I2C_InitTypeDef I2C_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
I2C_DeInit(I2C1);
I2C_StructInit(&I2C_InitStruct);
I2C_InitStruct.I2C_Mode = I2C_MODE_MASTER;
I2C_InitStruct.I2C_OwnAddress = I2C_OWN_ADDRESS;
I2C_InitStruct.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C_InitStruct);
I2C_TargetAddressConfig(I2C1, EEPROM_I2C_ADDRESS);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_1);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStruct);
I2C_Cmd(I2C1, ENABLE);
}
I2C写数据
void I2C_TxData_Polling(uint8_t *Buffer, uint8_t Length)
{
uint8_t i = 0;
for (i = 0; i < Length; i++)
{
I2C_SendData(I2C1, Buffer[i]);
while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE))
{
}
}
}
I2C读数据
void I2C_RxData_Polling(uint8_t *Buffer, uint16_t Length)
{
uint8_t i = 0;
for (i = 0; i < Length; i++)
{
I2C_ReadCmd(I2C1);
while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_RFNE))
{
}
Buffer[i] = I2C_ReceiveData(I2C1);
}
}
EEPROM写页函数
void EEPROM_WritePage(uint8_t Address, uint8_t *Buffer, uint8_t Length)
{
I2C_TxData_Polling((uint8_t *)&Address, 0x01);
I2C_TxData_Polling((uint8_t *)Buffer, Length);
while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE))
{
}
I2C_GenerateSTOP(I2C1);
while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE))
{
}
}
EEPROM读数据函数
void EEPROM_ReadData(uint8_t Address, uint8_t *Buffer, uint8_t Length)
{
I2C_TxData_Polling((uint8_t *)&Address, 0x01);
I2C_RxData_Polling((uint8_t *)Buffer, Length);
I2C_GenerateSTOP(I2C1);
while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE))
{
}
}
EEPROM写数据函数
void EEPROM_WriteData(uint8_t Address, uint8_t *Buffer, uint8_t Length)
{
uint8_t Start = 0;
uint8_t StartCount = 0, PageNumber = 0, FinalCount = 0;
if ((Address % EEPROM_PAGE_SIZE) == 0)
{
StartCount = 0;
PageNumber = Length / EEPROM_PAGE_SIZE;
FinalCount = Length % EEPROM_PAGE_SIZE;
}
else
{
Start = Address % EEPROM_PAGE_SIZE;
if (((Start + Length) / EEPROM_PAGE_SIZE) == 0)
{
StartCount = Length;
PageNumber = 0;
FinalCount = 0;
}
else
{
StartCount = EEPROM_PAGE_SIZE - Start;
PageNumber = (Length - StartCount) / EEPROM_PAGE_SIZE;
FinalCount = (Length - StartCount) % EEPROM_PAGE_SIZE;
}
}
if (StartCount)
{
EEPROM_WritePage(Address, Buffer, StartCount);
Address += StartCount;
Buffer += StartCount;
PLATFORM_DelayMS(50);
}
while (PageNumber--)
{
EEPROM_WritePage(Address, Buffer, EEPROM_PAGE_SIZE);
Address += EEPROM_PAGE_SIZE;
Buffer += EEPROM_PAGE_SIZE;
PLATFORM_DelayMS(50);
}
if (FinalCount)
{
EEPROM_WritePage(Address, Buffer, FinalCount);
}
}
二、json数据处理
数据格式定义:
+--------+--------+-------------------+--------+
| 长度H | 长度L | JSON原始数据 | 校验位|
| (1B) | (1B) | (N字节) | (1B) |
+--------+--------+-------------------+--------+
有效的数据示例:{"device":"MM32F0120","version":1.12,"enable":1}
save_config_to_eeprom()生成初始的json数据保存到EEPROM中
//JSON数据格式化存储
void save_config_to_eeprom(void) {
// 1. 创建JSON对象
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "device", "MM32F0120");
cJSON_AddNumberToObject(root, "version", 1.12);
cJSON_AddBoolToObject(root, "enable", true);
// 2. 序列化为字符串
char *json_str = cJSON_PrintUnformatted(root);
uint16_t json_len = strlen(json_str);
// 3. 添加长度头(2字节)和数据校验(1字节)
uint8_t *buffer = malloc(json_len + 3);
buffer[0] = json_len >> 8; // 长度高字节
buffer[1] = json_len & 0xFF; // 长度低字节
// 计算简单校验和
uint8_t checksum = 0;
for(int i=0; i<json_len; i++) {
buffer[i+2] = json_str[i];
checksum ^= json_str[i]; // XOR校验
}
buffer[json_len+2] = checksum;
// 4. 写入EEPROM
EEPROM_WriteData(JSON_START_ADDR, buffer, json_len+3);
// 5. 释放资源
free(buffer);
free(json_str);
cJSON_Delete(root);
}
load_config_from_eeprom()从EEPROM读取JSON数据
//从EEPROM读取JSON数据
cJSON* load_config_from_eeprom(void) {
// 1. 读取长度头
uint8_t len_buf[2];
EEPROM_ReadData(JSON_START_ADDR, len_buf, 2);
uint16_t json_len = (len_buf[0] << 8) | len_buf[1];
// 2. 读取JSON数据和校验位
uint8_t *buffer = malloc(json_len + 1);
EEPROM_ReadData(JSON_START_ADDR+2, buffer, json_len+1);
printf("%s\r\n",buffer);
// 3. 校验数据
uint8_t checksum = 0;
for(int i=0; i<json_len; i++) {
checksum ^= buffer[i];
}
if(checksum != buffer[json_len]) {
free(buffer);
return NULL; // 校验失败
}
// 4. 解析JSON
buffer[json_len] = '\0'; // 添加字符串结束符
cJSON *root = cJSON_Parse((char*)buffer);
free(buffer);
return root;
}
通过以上实现了向EEPROM写JSON数据和读取数据,可以通过以下程序验证:
void eeprom_Sample(void)
{
eeprom_I2C_Configure()
save_config_to_eeprom();
PLATFORM_DelayMS(500);
// 读取配置
cJSON *config = load_config_from_eeprom();
if(config) {
cJSON *device = cJSON_GetObjectItem(config, "device");
cJSON *version = cJSON_GetObjectItem(config, "version");
printf("Device: %s, Ver: %.2f\n", device->valuestring, version->valuedouble);
cJSON_Delete(config);
} else {
printf("Config load failed!\n");
}
while(1)
{
}
}
三、接收串口发过来的json数据保存到EEPROM
这里使用了UART不定长数据接收,可参考:https://bbs.21ic.com/icview-3461324-1-1.html
UART输入判断
static void Process_Uart_Input(void)
{
uint8_t frame_data[MAX_JSON_LEN];
uint8_t i,frame_len;
if(USART_RxStruct.Buffer[0]=='{'&&USART_RxStruct.Buffer[USART_RxStruct.CurrentCount-3]=='}')
{
frame_len=USART_RxStruct.CurrentCount-2;
for(i = 0; i < frame_len; i++) {
frame_data[i] = USART_RxStruct.Buffer[i];
}
frame_data[frame_len]='\0';
if(is_json_valid(frame_data, frame_len)) {
save_json_to_eeprom(frame_data,frame_len);
}else
{
printf("json format is invalid\r\n");
}
}
USART_RxData_Interrupt(255);
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
}
对UART传过来的数据进行JSON格式验证
// 验证JSON格式
uint8_t is_json_valid(const uint8_t *data, uint16_t len) {
// 确保以NULL结尾
char *json_str = malloc(len + 1);
if(!json_str) return 0;
memcpy(json_str, data, len);
json_str[len] = '\0';
printf("json_str:%s\r\n",json_str);
// 解析JSON
cJSON *root = cJSON_Parse(json_str);
uint8_t result = 0;
if(root) {
// 验证基本结构
cJSON *device = cJSON_GetObjectItem(root, "device");
cJSON *version = cJSON_GetObjectItem(root, "version");
cJSON *enable = cJSON_GetObjectItem(root, "enable");
printf("device=%s,version=%s,enable=%s\r\n",device->valuestring,version->valuestring,enable->valuestring);
if(cJSON_IsString(device) && cJSON_IsNumber(version) &&
(cJSON_IsNumber(enable) || cJSON_IsBool(enable))) {
result = 1;
}
cJSON_Delete(root);
}
free(json_str);
return result;
}
对UART接收的JSON打包,添加长度头和校验
// 封装JSON数据(添加长度头和校验)
uint16_t package_json(const uint8_t *json, uint16_t json_len, uint8_t *output) {
if(json_len > MAX_JSON_LEN) return 0;
// 添加长度头(小端格式)
output[0] = (json_len >> 8) & 0xFF; // 高字节
output[1] = json_len & 0xFF; // 低字节
// 复制JSON数据
memcpy(&output[2], json, json_len);
// 计算并添加校验位(异或校验)
uint8_t checksum = 0;
for(uint16_t i = 0; i < json_len; i++) {
checksum ^= json[i];
}
output[2 + json_len] = checksum;
return json_len + 3; // 总长度 = 2(头) + json_len + 1(校验)
}
保存JSON到EEPROM
// 保存JSON到EEPROM
void save_json_to_eeprom(const uint8_t *json, uint16_t len) {
// 封装数据
uint8_t packaged_data[MAX_JSON_LEN + 3];
uint16_t packaged_len = package_json(json, len, packaged_data);
printf("packaged_data=%s",packaged_data);
if(packaged_len > 0) {
// 写入EEPROM
EEPROM_WriteData(JSON_START_ADDR, packaged_data, packaged_len);
printf("JSON saved successfully\n");
}
}
写个验证程序
void eeprom_Sample(void)
{
USART_RxStruct.CompleteFlag = 0;
USART_TxStruct.CompleteFlag = 1;
USART_Configure(115200);
eeprom_I2C_Configure();
// 保存配置
//save_config_to_eeprom();
PLATFORM_DelayMS(500);
// 读取配置
cJSON *config = load_config_from_eeprom();
if(config) {
cJSON *device = cJSON_GetObjectItem(config, "device");
cJSON *version = cJSON_GetObjectItem(config, "version");
printf("Device: %s, Ver: %.2f\n", device->valuestring, version->valuedouble);
cJSON_Delete(config);
} else {
printf("Config load failed!\n");
}
while(1)
{
if (1== USART_RxStruct.CompleteFlag&&USART_RxStruct.CurrentCount>0)
{
USART_RxStruct.CompleteFlag=0;
Process_Uart_Input();
}
PLATFORM_LED_Toggle(LED1);
PLATFORM_LED_Toggle(LED2);
PLATFORM_DelayMS(100);
}
}
1、上电,显示之前保存的json文件内容,其中"version":3.12
2、通过串口发送{"device":"MM32F0120","version":8.88,"enable":true},改变"version"为8.88
3、再次RESET,显示修改后的"version"为8.88
|