ESP32 IDF优雅解析陶晶驰串口屏WiFi配置

项目概述

实现ESP32通过UART优雅地接收和解析陶晶驰串口屏发送的WiFi配置信息,采用JSON格式进行数据通信。

硬件连接

- ESP32 UART1 RX → 串口屏 TX (GPIO5)

- ESP32 UART1 TX → 串口屏 RX (GPIO4)

- 共地连接

陶晶驰串口屏代码

// 在触摸事件中构建并发送JSON

prints "{\"cmd\":\"wifi_connect\",\"ssid\":\"",0

prints t0.txt,0

prints "\",\"pass\":\"",0

prints t1.txt,0

prints "\"}",0

ESP端代码

头文件 data_parser.h

#ifndef DATA_PARSER_H
#define DATA_PARSER_H

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "cJSON.h"

// UART配置
#define UART_NUM UART_NUM_1
#define UART_TX_PIN  GPIO_NUM_4
#define UART_RX_PIN  GPIO_NUM_5
#define BUF_SIZE (1024)

// WiFi配置结构体
typedef struct {
    char ssid[32];
    char password[64];
    int8_t rssi;
} wifi_config_t;

// 解析回调函数类型
typedef void (*wifi_config_callback_t)(const wifi_config_t *config);

// 函数声明
void uart_parser_init(wifi_config_callback_t callback);
void uart_parser_deinit(void);
void parse_json_data(const char *json_str, wifi_config_t *config);

#endif

数据解析核心文件 data_parser.c

#include "data_parser.h"

static const char *TAG = "Data_Parser";

static wifi_config_callback_t user_callback = NULL;
static TaskHandle_t uart_task_handle = NULL;

// UART初始化
static void uart_init(void) {
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_APB,
    };
    
    ESP_ERROR_CHECK(uart_driver_install(UART_NUM, BUF_SIZE * 2, 0, 0, NULL, 0));
    ESP_ERROR_CHECK(uart_param_config(UART_NUM, &uart_config));
    ESP_ERROR_CHECK(uart_set_pin(UART_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
    
    ESP_LOGI(TAG, "UART初始化完成");
}

// JSON数据解析函数
void parse_json_data(const char *json_str, wifi_config_t *config) {
    if (json_str == NULL || config == NULL) {
        ESP_LOGE(TAG, "解析参数错误");
        return;
    }
    
    ESP_LOGI(TAG, "开始解析JSON: %s", json_str);
    
    cJSON *root = cJSON_Parse(json_str);
    if (root == NULL) {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL) {
            ESP_LOGE(TAG, "JSON解析错误前: %s", error_ptr);
        }
        return;
    }
    
    // 清理配置结构体
    memset(config, 0, sizeof(wifi_config_t));
    
    // 解析cmd字段
    cJSON *cmd = cJSON_GetObjectItemCaseSensitive(root, "cmd");
    if (cJSON_IsString(cmd) && (cmd->valuestring != NULL)) {
        ESP_LOGI(TAG, "命令: %s", cmd->valuestring);
        
        if (strcmp(cmd->valuestring, "wifi_connect") == 0) {
            // 解析SSID
            cJSON *ssid = cJSON_GetObjectItemCaseSensitive(root, "ssid");
            if (cJSON_IsString(ssid) && (ssid->valuestring != NULL)) {
                strncpy(config->ssid, ssid->valuestring, sizeof(config->ssid) - 1);
                config->ssid[sizeof(config->ssid) - 1] = '\0';
                ESP_LOGI(TAG, "解析到SSID: %s", config->ssid);
            } else {
                ESP_LOGW(TAG, "SSID字段缺失或格式错误");
            }
            
            // 解析密码
            cJSON *pass = cJSON_GetObjectItemCaseSensitive(root, "pass");
            if (cJSON_IsString(pass) && (pass->valuestring != NULL)) {
                strncpy(config->password, pass->valuestring, sizeof(config->password) - 1);
                config->password[sizeof(config->password) - 1] = '\0';
                ESP_LOGI(TAG, "解析到密码, 长度: %d", strlen(config->password));
            } else {
                ESP_LOGW(TAG, "密码字段缺失或格式错误");
            }
        } else {
            ESP_LOGW(TAG, "未知命令: %s", cmd->valuestring);
        }
    } else {
        ESP_LOGE(TAG, "cmd字段缺失或格式错误");
    }
    
    cJSON_Delete(root);
}

// UART数据接收任务
static void uart_receive_task(void *pvParameter) {
    uint8_t data[BUF_SIZE];
    char json_buffer[BUF_SIZE];
    int json_index = 0;
    bool in_json = false;
    int json_brace_count = 0;
    
    ESP_LOGI(TAG, "UART数据接收任务启动");
    
    while (1) {
        int length = uart_read_bytes(UART_NUM, data, BUF_SIZE - 1, 20 / portTICK_PERIOD_MS);
        
        if (length > 0) {
            data[length] = '\0'; // 添加字符串结束符
            
            for (int i = 0; i < length; i++) {
                char c = data[i];
                
                // 检测JSON开始
                if (c == '{') {
                    if (!in_json) {
                        in_json = true;
                        json_index = 0;
                        json_brace_count = 0;
                    }
                    json_brace_count++;
                }
                
                // 累积JSON数据
                if (in_json) {
                    // 防止缓冲区溢出
                    if (json_index < BUF_SIZE - 1) {
                        json_buffer[json_index++] = c;
                    } else {
                        ESP_LOGE(TAG, "JSON缓冲区溢出,重置解析状态");
                        in_json = false;
                        json_index = 0;
                        json_brace_count = 0;
                    }
                    
                    // 检测JSON结束
                    if (c == '}') {
                        json_brace_count--;
                        if (json_brace_count == 0) {
                            json_buffer[json_index] = '\0';
                            in_json = false;
                            
                            ESP_LOGI(TAG, "收到完整JSON数据");
                            ESP_LOGD(TAG, "JSON内容: %s", json_buffer);
                            
                            // 解析数据
                            wifi_config_t wifi_config;
                            parse_json_data(json_buffer, &wifi_config);
                            
                            // 如果有有效数据且用户注册了回调,则调用
                            if (user_callback != NULL && strlen(wifi_config.ssid) > 0) {
                                user_callback(&wifi_config);
                            }
                            
                            json_index = 0;
                        }
                    }
                }
                
                // 调试输出非JSON字符
                if (!in_json && c != '\r' && c != '\n' && c != ' ') {
                    ESP_LOGV(TAG, "非JSON字符: 0x%02x '%c'", c, (c >= 32 && c <= 126) ? c : '?');
                }
            }
        }
        
        // 处理JSON解析超时(防止半截JSON卡住)
        if (in_json) {
            static uint32_t json_timeout = 0;
            static uint32_t last_receive_time = 0;
            uint32_t current_time = xTaskGetTickCount();
            
            if (length > 0) {
                last_receive_time = current_time;
                json_timeout = 0;
            } else {
                if (current_time - last_receive_time > pdMS_TO_TICKS(1000)) {
                    json_timeout++;
                    if (json_timeout > 3) { // 3秒超时
                        ESP_LOGW(TAG, "JSON解析超时,重置状态");
                        in_json = false;
                        json_index = 0;
                        json_brace_count = 0;
                        json_timeout = 0;
                    }
                }
            }
        }
        
        vTaskDelay(10 / portTICK_PERIOD_MS);
    }
}

// 初始化数据解析器
void uart_parser_init(wifi_config_callback_t callback) {
    user_callback = callback;
    
    // 初始化UART
    uart_init();
    
    // 创建UART接收任务
    xTaskCreate(uart_receive_task, "uart_receive_task", 4096, NULL, 10, &uart_task_handle);
    
    ESP_LOGI(TAG, "数据解析器初始化完成");
}

// 反初始化数据解析器
void uart_parser_deinit(void) {
    if (uart_task_handle != NULL) {
        vTaskDelete(uart_task_handle);
        uart_task_handle = NULL;
    }
    
    uart_driver_delete(UART_NUM);
    user_callback = NULL;
    
    ESP_LOGI(TAG, "数据解析器已卸载");
}

// 工具函数:打印配置信息
void print_wifi_config(const wifi_config_t *config) {
    if (config == NULL) return;
    
    ESP_LOGI(TAG, "=== WiFi配置信息 ===");
    ESP_LOGI(TAG, "SSID: %s", config->ssid);
    ESP_LOGI(TAG, "密码: %s", config->password);
    ESP_LOGI(TAG, "密码长度: %d", strlen(config->password));
    ESP_LOGI(TAG, "====================");
}

使用示例 main.c

#include "data_parser.h"

static const char *TAG = "Main";

// WiFi配置回调函数
static void wifi_config_callback(const wifi_config_t *config) {
    ESP_LOGI(TAG, "收到WiFi配置回调");
    
    // 打印配置信息
    print_wifi_config(config);
    
    // 这里可以添加连接WiFi的逻辑
    if (strlen(config->ssid) > 0) {
        ESP_LOGI(TAG, "准备连接WiFi: %s", config->ssid);
        // wifi_connect(config->ssid, config->password);
    }
}

void app_main(void) {
    ESP_LOGI(TAG, "启动数据提取测试程序");
    
    // 初始化数据解析器
    uart_parser_init(wifi_config_callback);
    
    // 保持任务运行
    while (1) {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        ESP_LOGD(TAG, "系统运行中...");
    }
    
    // 清理(通常不会执行到这里)
    uart_parser_deinit();
}

输出示例

当串口屏发送数据时,ESP32会输出类似以下日志:

I (1254) Data_Parser: 收到完整JSON数据

I (1254) Data_Parser: JSON内容: {"cmd":"wifi_connect","ssid":"MyWiFi","pass":"12345678"}

I (1264) Data_Parser: 开始解析JSON: {"cmd":"wifi_connect","ssid":"MyWiFi","pass":"12345678"}

I (1274) Data_Parser: 命令: wifi_connect

I (1284) Data_Parser: 解析到SSID: MyWiFi

I (1294) Data_Parser: 解析到密码, 长度: 8

I (1304) Main: 收到WiFi配置回调

I (1304) Data_Parser: === WiFi配置信息 ===

I (1314) Data_Parser: SSID: MyWiFi

I (1324) Data_Parser: 密码: 12345678

I (1334) Data_Parser: 密码长度: 8