打印
[MM32硬件]

【灵动微电子MM32F0121测评】10、 json格式处理及EEPROM读写

[复制链接]
803|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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








使用特权

评论回复
沙发
AdaMaYun| | 2025-7-31 17:57 | 只看该作者
json格式处理及EEPROM读写很不错

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

147

帖子

3

粉丝