当前位置: 首页 > news >正文

ESP32 UART select解析json数据,上位机控制LED灯实验

前言:

本实验的目的主要是通过上位机通过UART来控制ESP32端的LED的点亮以及熄灭,整个项目逻辑比较简单,整体架构如下:

上位机(PC)主要是跑在PC端的一个软件,主要作用包含:

1)串口相关配置,串口号,波特率等配置,串口动态识别,打开,关闭串口等

2)发送json指令来控制ESP32 LED等点亮跟熄灭

3)显示ESP32吐出来的log

下位机(ESP32)主要就是ESP32开发板,主要包含作用如下:

1)LED灯的驱动

2)UART select监听上位机发送的指令,从而来控制LED灯的点亮/熄灭

3)发送log到上位机

整个工程链接:esp32_study/2_peripheral/4_pc_control_led at main · sj15712795029/esp32_study · GitHub

一. ESP32下位机端

1. LED、UART select方式

LED驱动我们在前面已经介绍,链接如下:一灯大师,点亮ESP32的LED_esp32点亮led-CSDN博客

UART select方式我们在前面已经介绍,链接如下:

详解ESP32使用select函数来监听串口数据-CSDN博客

2. json基础

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript的一个子集,但独立于语言,广泛用于Web应用中的数据交换。

a. JSON的基本结构

JSON数据由键值对组成,主要有两种结构:

对象(Object)

    • 用花括号 {} 包裹,表示一个无序的键值对集合。
    • 键值对之间用逗号 , 分隔。
    • 键和值之间用冒号 : 分隔。
    • 键必须是字符串,值可以是字符串、数字、布尔值、数组、对象或 null

示例:

{
    "name": "Alice",
    "age": 25,
    "isStudent": false,
    "address": {
        "city": "Beijing",
        "postalCode": "100000"
    },
    "hobbies": ["reading", "traveling"]
}

数组(Array)

    • 用方括号 [] 包裹,表示一个有序的值集合。
    • 值之间用逗号 , 分隔。
    • 值可以是字符串、数字、布尔值、数组、对象或 null

示例:

[
    {
        "name": "Alice",
        "age": 25
    },
    {
        "name": "Bob",
        "age": 30
    }
]

b. JSON的数据类型

JSON支持以下几种数据类型:

  • 字符串(String):用双引号 "" 包裹的文本。
  • 数字(Number):整数或浮点数。
  • 布尔值(Boolean)truefalse
  • 数组(Array):有序的值集合。
  • 对象(Object):无序的键值对集合。
  • null:表示空值。

c. JSON的示例

以下是一个包含多种数据类型的JSON示例:

{
    "name": "Alice",
    "age": 25,
    "isStudent": false,
    "scores": [95, 89, 78],
    "contact": {
        "email": "alice@example.com",
        "phone": "123-456-7890"
    },
    "graduated": null
}

d. JSON的特点

  • 简洁:JSON格式简洁,易于阅读和编写。
  • 跨语言:JSON独立于编程语言,几乎所有主流语言都支持JSON的解析和生成。
  • 轻量级:JSON数据格式比XML更轻量,适合网络传输。

e. JSON的使用场景

  • Web API:JSON常用于Web API的数据交换格式。
  • 配置文件:许多应用程序使用JSON格式来存储配置信息。
  • 数据存储:NoSQL数据库(如MongoDB)使用JSON格式存储数据。

3. json编程

在了解了json的基础后(其实很简单哈,就是格式),我们首先要做的第一件事情就是约定下上位机跟下位机的通讯格式,我自己定出来一个哈·,如下:

以LED_ON为例,发送的格式如下:

{"FUNC":"HW","OPERATE":"LED_ON","PARAM1":null,"PARAM2":null,"PARAM3":null,"PARAM4":null,"PARAM5":null,"PARAM6":null}

后面的PARAM是为了其他硬件功能的扩展,我们在LED灯中没有用到

在ESP IDF中已经集成了json的库,就是cJson,只需要引用这个头文件即可以使用其中的API

#include "cJSON.h"

我们先来看下核心代码

    /* 解析上位机的json格式 */
    cJSON* parse_json = cJSON_Parse((const char *)shell_string);

    if(!parse_json)
    {
        ESP_LOGE(TAG, "Not specific json format:%s\n",shell_string);
        goto exit;
    }

    uint8_t* func_value = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"FUNC"))->valuestring;
    uint8_t* operate_value = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"OPERATE"))->valuestring;
    uint8_t* para1 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM1"))->valuestring;
    uint8_t* para2 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM2"))->valuestring;
    uint8_t* para3 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM3"))->valuestring;
    uint8_t* para4 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM4"))->valuestring;
    uint8_t* para5 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM5"))->valuestring;
    uint8_t* para6 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM6"))->valuestring;
    ESP_UNUSED(para1);
    ESP_UNUSED(para2);
    ESP_UNUSED(para3);
    ESP_UNUSED(para4);
    ESP_UNUSED(para5);
    ESP_UNUSED(para6);
    if(!func_value || !operate_value)
    {
        ESP_LOGE(TAG, "Not specific json format:%s\n",shell_string);
        goto exit;
    }

    if(strcmp((const char *)func_value,"HW") == 0)
    {
        if(strcmp((const char *)operate_value,"LED_ON") == 0)
        {
            ESP_LOGD(TAG, "UART PARSE DEBUG:operate LED_ON\n");
            LED_ON;
            goto exit;
        }

        if(strcmp((const char *)operate_value,"LED_OFF") == 0)
        {
            ESP_LOGD(TAG, "UART PARSE DEBUG:operate LED_OFF\n");
            LED_OFF;
            goto exit;
        }

    }

这里的核心作用就是解析了json格式,来控制了LED灯的点亮系列,其中部分API的使用如下:

cJSON 是一个轻量级的C语言库,用于解析和生成JSON数据。它提供了一系列函数来操作JSON对象和数组。以下是你代码中使用到的 cJSON 函数及其作用的详细介绍:

cJSON_Parse

cJSON* cJSON_Parse(const char *value);
  • 作用:将JSON格式的字符串解析为 cJSON 对象。
  • 参数
    • value:要解析的JSON字符串。
  • 返回值
    • 成功时返回一个指向 cJSON 对象的指针。
    • 失败时返回 NULL

cJSON_GetObjectItem

cJSON* cJSON_GetObjectItem(const cJSON *object, const char *string);
  • 作用:从 cJSON 对象中获取指定键对应的值。
  • 参数
    • object:要查找的 cJSON 对象。
    • string:要查找的键名。
  • 返回值
    • 成功时返回一个指向 cJSON 对象的指针。
    • 如果键不存在或对象不是JSON对象,返回 NULL

cJSON 结构体

cJSON 结构体用于表示JSON数据。常用的字段包括:

  • valuestring:如果 cJSON 对象表示一个字符串,该字段存储字符串的值。
  • valueint:如果 cJSON 对象表示一个整数,该字段存储整数的值。
  • valuedouble:如果 cJSON 对象表示一个浮点数,该字段存储浮点数的值。
  • type:表示 cJSON 对象的类型(如字符串、数字、对象、数组等)。

cJSON_Delete

void cJSON_Delete(cJSON *item);
  • 作用:释放 cJSON 对象及其所有子对象的内存。
  • 参数
    • item:要释放的 cJSON 对象。

代码解析

你的代码片段展示了如何使用 cJSON 库解析JSON字符串并提取其中的值。以下是代码的详细解析:

解析JSON字符串

cJSON* parse_json = cJSON_Parse((const char *)shell_string);

shell_string 解析为 cJSON 对象 parse_json

提取JSON对象中的值

uint8_t* func_value = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"FUNC"))->valuestring;
uint8_t* operate_value = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"OPERATE"))->valuestring;
uint8_t* para1 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM1"))->valuestring;
uint8_t* para2 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM2"))->valuestring;
uint8_t* para3 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM3"))->valuestring;
uint8_t* para4 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM4"))->valuestring;
uint8_t* para5 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM5"))->valuestring;
uint8_t* para6 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM6"))->valuestring;

使用 cJSON_GetObjectItemparse_json 中提取键为 "FUNC""OPERATE""PARAM1""PARAM6" 的值,并将其转换为 uint8_t* 类型。

示例JSON

假设 shell_string 包含以下JSON字符串:

{
    "FUNC": "start",
    "OPERATE": "run",
    "PARAM1": "value1",
    "PARAM2": "value2",
    "PARAM3": "value3",
    "PARAM4": "value4",
    "PARAM5": "value5",
    "PARAM6": "value6"
}

解析后,func_value 将指向 "start"operate_value 将指向 "run"para1para6 将分别指向 "value1""value6"

所有代码如下(包含LED灯的控制,UART的select解析):

/* UART Select Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/errno.h>
#include <sys/unistd.h>
#include <sys/select.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/uart_vfs.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "cJSON.h"

#define LED_PIN    17
#define LED_PIN_SEL  (1<<LED_PIN)

/* Operate LED on/off */
#define LED_OFF	gpio_set_level(LED_PIN, 1)
#define LED_ON	gpio_set_level(LED_PIN, 0)

void bsp_led_init()
{
    gpio_config_t io_conf;
    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pin_bit_mask = LED_PIN_SEL;
    io_conf.pull_down_en = 0;
    io_conf.pull_up_en = 0;
    gpio_config(&io_conf);
}

static const char* TAG = "uart_select_example";

#define UART_JSON_BUFFER_SIZE 512
char uart_json_buf[UART_JSON_BUFFER_SIZE] = {0};

void uart_receive_parse(uint8_t *shell_string)
{
    cJSON* parse_json = cJSON_Parse((const char *)shell_string);

    if(!parse_json)
    {
        ESP_LOGE(TAG, "Not specific json format:%s\n",shell_string);
        goto exit;
    }
    uint8_t* func_value = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"FUNC"))->valuestring;
    uint8_t* operate_value = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"OPERATE"))->valuestring;
    uint8_t* para1 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM1"))->valuestring;
    uint8_t* para2 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM2"))->valuestring;
    uint8_t* para3 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM3"))->valuestring;
    uint8_t* para4 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM4"))->valuestring;
    uint8_t* para5 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM5"))->valuestring;
    uint8_t* para6 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM6"))->valuestring;
    ESP_UNUSED(para1);
    ESP_UNUSED(para2);
    ESP_UNUSED(para3);
    ESP_UNUSED(para4);
    ESP_UNUSED(para5);
    ESP_UNUSED(para6);
    if(!func_value || !operate_value)
    {
        ESP_LOGE(TAG, "Not specific json format:%s\n",shell_string);
        goto exit;
    }

    if(strcmp((const char *)func_value,"HW") == 0)
    {
        if(strcmp((const char *)operate_value,"LED_ON") == 0)
        {
            ESP_LOGD(TAG, "UART PARSE DEBUG:operate LED_ON\n");
            LED_ON;
            goto exit;
        }

        if(strcmp((const char *)operate_value,"LED_OFF") == 0)
        {
            ESP_LOGD(TAG, "UART PARSE DEBUG:operate LED_OFF\n");
            LED_OFF;
            goto exit;
        }

    }

	if(strcmp((const char *)shell_string,"shop220811498.taobao.com") == 0)
		ESP_LOGD(TAG, "welcome to use our stm32f1 camera wifi board\n");
	else
		ESP_LOGD(TAG, "UART PARSE ERR:HW_ERR_SHELL_NO_CMD\n");
	
exit:
    cJSON_Delete(parse_json);
    return;
}

static void uart_select_task(void *arg)
{
    if (uart_driver_install(UART_NUM_0, 2 * 1024, 0, 0, NULL, 0) != ESP_OK) {
        ESP_LOGE(TAG, "Driver installation failed");
        vTaskDelete(NULL);
    }

    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_DEFAULT,
    };

    uart_param_config(UART_NUM_0, &uart_config);

    while (1) {
        int fd;

        if ((fd = open("/dev/uart/0", O_RDWR)) == -1) {
            ESP_LOGE(TAG, "Cannot open UART");
            vTaskDelay(5000 / portTICK_PERIOD_MS);
            continue;
        }

        // We have a driver now installed so set up the read/write functions to use driver also.
        uart_vfs_dev_use_driver(UART_NUM_0);

        while (1) {
            int s;
            fd_set rfds;
            struct timeval tv = {
                .tv_sec = 5,
                .tv_usec = 0,
            };

            FD_ZERO(&rfds);
            FD_SET(fd, &rfds);

            s = select(fd + 1, &rfds, NULL, NULL, &tv);

            if (s < 0) {
                ESP_LOGE(TAG, "Select failed: errno %d (%s)", errno, strerror(errno));
                break;
            } else if (s == 0) {
                ESP_LOGI(TAG, "Timeout has been reached and nothing has been received");
            } else {
                if (FD_ISSET(fd, &rfds)) {
                    memset(uart_json_buf,0,UART_JSON_BUFFER_SIZE);
                    if (read(fd, uart_json_buf, UART_JSON_BUFFER_SIZE) > 0) {
                        // Note: Only one character was read even the buffer contains more. The other characters will
                        // be read one-by-one by subsequent calls to select() which will then return immediately
                        // without timeout.
                        uart_receive_parse((uint8_t *)uart_json_buf);
                    } else {
                        ESP_LOGE(TAG, "UART read error");
                        break;
                    }
                } else {
                    ESP_LOGE(TAG, "No FD has been set in select()");
                    break;
                }
            }
        }

        close(fd);
    }

    vTaskDelete(NULL);
}

void app_main(void)
{
    bsp_led_init();
    xTaskCreate(uart_select_task, "uart_select_task", 4 * 1024, NULL, 5, NULL);
}

二.PC上位机端

1. 上位机介绍

整个上位机比较简单,分为几个区:

1)串口配置区,包括串口的参数,串口的打开,关闭以及UI上体现不出来的支持串口热插拔扫描等

2)LED测试区,主要是发送控制LED灯点亮/熄灭的功能

3)串口调试区,因为我们是通过串口来发送指令,所以ESP32下位机的log也会通过这个串口吐出来,所以要做一个类似其他串口工具的串口调试区用来输出log

上位机的概念知识我们就不在这里介绍了,因为比较庞大,我是用winform来编写的上位机,有非常多的空间,对于写这种搓搓的上位机已经够用了,我们直接贴代码吧

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using Newtonsoft.Json;

namespace led_control
{
    public partial class Form1 : Form
    {
        string hw_func = "HW";

        string operate_led_on = "LED_ON";
        string operate_led_off = "LED_OFF";

        const int PRINTFING_LOG = 0;
        const int PARSEING_JSON = 1;
        int serial_recv_status = PRINTFING_LOG;
        string recv_json_str;

        public const int WM_DEVICE_CHANGE = 0x219;
        public const int DBT_DEVICEARRIVAL = 0x8000;
        public const int DBT_DEVICE_REMOVE_COMPLETE = 0x8004;

        public Form1()
        {
            InitializeComponent();

            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            search_add_serial_port();

            cb_serial_baudrate.SelectedIndex = 0;
        }

        /* 串口搜索 */
        private void search_add_serial_port()
        {
            /* 更新串口按键状态 */

            /*------串口界面参数设置------*/
            int has_port = 0;
            //检查是否含有串口
            string[] str = SerialPort.GetPortNames();


            //添加串口
            foreach (string s in str)
            {
                has_port++;

                if (!cb_serial_port.Items.Contains(s))
                    cb_serial_port.Items.Add(s);
            }

            if (has_port == 0)
            {
                return;
            }
            //设置默认串口选项
            cb_serial_port.SelectedIndex = 0;

        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_DEVICE_CHANGE)        // 捕获USB设备的拔出消息WM_DEVICECHANGE
            {
                switch (m.WParam.ToInt32())
                {
                    case DBT_DEVICE_REMOVE_COMPLETE:    // USB拔出    
                        {
                            b_serial_open.Enabled = true;
                            b_serial_close.Enabled = false;
                        }
                        break;
                    case DBT_DEVICEARRIVAL:             // USB插入获取对应串口名称      
                        {
                            search_add_serial_port();
                        }
                        break;
                }
            }
            base.WndProc(ref m);

        }

        private void b_serial_send_Click(object sender, EventArgs e)
        {

            if (t_data_send.Text == "")
                MessageBox.Show("发送内容为空", "错误提示");
            else
            {
                if (serialPort1.IsOpen)
                    serialPort1.Write(t_data_send.Text);
                else
                    MessageBox.Show("先打开串口", "错误提示");
            }
        }

        private void b_serial_open_Click(object sender, EventArgs e)
        {
            if (!serialPort1.IsOpen)//串口处于关闭状态
            {
                try
                {

                    if (cb_serial_port.SelectedIndex == -1)
                    {
                        MessageBox.Show("Error: 无效的端口,请重新选择", "Error");
                        return;
                    }
                    string strSerialName = cb_serial_port.SelectedItem.ToString();

                    serialPort1.PortName = strSerialName;//串口号
                    serialPort1.BaudRate = Convert.ToInt32(cb_serial_baudrate.SelectedItem.ToString());//波特率
                    serialPort1.DataBits = 8;//数据位
                    serialPort1.StopBits = StopBits.One;
                    serialPort1.Parity = Parity.None;

                    //打开串口
                    serialPort1.Open();

                    b_serial_open.Enabled = false;
                    b_serial_close.Enabled = true;

                }
                catch (System.Exception ex)
                {
                    MessageBox.Show("Error:" + ex.Message, "Error");
                    return;
                }
            }
        }

        private void b_serial_close_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)//串口处于关闭状态
            {
                serialPort1.Close();//关闭串口

                b_serial_open.Enabled = true;
                b_serial_close.Enabled = false;


            }
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (serialPort1.IsOpen)
            {

                try
                {
                    string recv_data_string;
                    int recv_data_count = serialPort1.BytesToRead;
                    while (serialPort1.BytesToRead > 0)
                    {
                        recv_data_string = serialPort1.ReadLine();
                        if (recv_data_string.Contains("{") || (serial_recv_status == PARSEING_JSON))
                        {
                            serial_recv_status = PARSEING_JSON;
                            recv_json_str += recv_data_string;
                            if (recv_data_string.Contains("}"))
                            {
                                serial_recv_status = PRINTFING_LOG;
#if  CONSOLE_DEBUG
                                Console.WriteLine(recv_json_str);
#endif

                                json_status status = JsonConvert.DeserializeObject<json_status>(recv_json_str);

                                json_status_recv_parse(status);
                                recv_json_str = "";
                                //return;
                            }


                        }
                        else
                        {
                            t_data_recv.AppendText(recv_data_string + '\r' + '\n');
                        }
                    }

                }
                catch (Exception ex)
                {
                    return;
                }

            }
        }

        private void b_led_on_Click(object sender, EventArgs e)
        {
            json_construction_send(hw_func, operate_led_on, null, null, null, null, null, null);
        }

        private void b_led_off_Click(object sender, EventArgs e)
        {
            json_construction_send(hw_func, operate_led_off, null, null, null, null, null, null);
        }

        private void json_construction_send(string func, string operate, string param1, string param2, string param3, string param4, string param5, string param6)
        {
            json_commmand cmd = new json_commmand();
            cmd.FUNC = func;
            cmd.OPERATE = operate;
            cmd.PARAM1 = param1;
            cmd.PARAM2 = param2;
            cmd.PARAM3 = param3;
            cmd.PARAM4 = param4;
            cmd.PARAM5 = param5;
            cmd.PARAM6 = param6;
            string json_cmd = JsonConvert.SerializeObject(cmd);
#if  CONSOLE_DEBUG
            Console.WriteLine(json_cmd);
#endif
            if (serialPort1.IsOpen)
            {
                serialPort1.WriteLine(json_cmd);
            }
        }

        private void json_status_recv_parse(json_status status)
        {
#if  CONSOLE_DEBUG
            Console.WriteLine("----------json_status_recv_parse-------------");
            Console.WriteLine("json func:" + status.FUNC);
            Console.WriteLine("json operate:" + status.OPERATE);
            Console.WriteLine("json status:" + status.STATUS);
            Console.WriteLine("json param1:" + status.PARAM1);
            Console.WriteLine("json param2:" + status.PARAM2);
            Console.WriteLine("json param3:" + status.PARAM3);
            Console.WriteLine("json param4:" + status.PARAM4);
            Console.WriteLine("json param5:" + status.PARAM5);
            Console.WriteLine("----------json_status_recv_parse  end--------");
#endif
        }

        private void b_serial_send_Click_1(object sender, EventArgs e)
        {
            if (t_data_send.Text == "")
                MessageBox.Show("发送内容为空", "错误提示");
            else
            {
                if (serialPort1.IsOpen)
                    serialPort1.Write(t_data_send.Text);
                else
                    MessageBox.Show("先打开串口", "错误提示");
            }
        }
    }

    /* JSON定义 */
    public class json_commmand
    {
        public string FUNC { get; set; }
        public string OPERATE { get; set; }
        public string PARAM1 { get; set; }
        public string PARAM2 { get; set; }
        public string PARAM3 { get; set; }
        public string PARAM4 { get; set; }
        public string PARAM5 { get; set; }
        public string PARAM6 { get; set; }
    }

    public class json_status
    {
        public string FUNC { get; set; }
        public string OPERATE { get; set; }
        public string STATUS { get; set; }
        public string PARAM1 { get; set; }
        public string PARAM2 { get; set; }
        public string PARAM3 { get; set; }
        public string PARAM4 { get; set; }
        public string PARAM5 { get; set; }
        public string PARAM6 { get; set; }
    }
}

2. 发送json数据来控制LED灯

每个语言基本都有自己的json库,我们c#用的是:using Newtonsoft.Json;

点击LED ON(蓝色图标)触发的动作如下:

string hw_func = "HW";
string operate_led_on = "LED_ON";

private void b_led_on_Click(object sender, EventArgs e)
{
    json_construction_send(hw_func, operate_led_on, null, null, null, null, null, null);
}

点击LED OFF(红色图标)触发的动作如下:

string hw_func = "HW";
string operate_led_off = "LED_OFF";

private void b_led_off_Click(object sender, EventArgs e)
{
    json_construction_send(hw_func, operate_led_off, null, null, null, null, null, null);
}

其中json_construction_send函数如下 :

private void json_construction_send(string func, string operate, string param1, string param2, string param3, string param4, string param5, string param6)
{
    json_commmand cmd = new json_commmand();
    cmd.FUNC = func;
    cmd.OPERATE = operate;
    cmd.PARAM1 = param1;
    cmd.PARAM2 = param2;
    cmd.PARAM3 = param3;
    cmd.PARAM4 = param4;
    cmd.PARAM5 = param5;
    cmd.PARAM6 = param6;
    string json_cmd = JsonConvert.SerializeObject(cmd);
#if  CONSOLE_DEBUG
    Console.WriteLine(json_cmd);
#endif
    if (serialPort1.IsOpen)
    {
        serialPort1.WriteLine(json_cmd);
    }
}

可以看到这个也是遵循我们指定的json格式,上位机跟下位机的格式是一致的

我们就来看下这个函数,非常简单

创建 JSON 命令对象:

json_commmand cmd = new json_commmand();

这里创建了一个 json_commmand 类的实例 cmdjson_commmand 类应该是一个自定义类,用于存储命令的各个部分。

设置命令属性:

cmd.FUNC = func;
cmd.OPERATE = operate;
cmd.PARAM1 = param1;
cmd.PARAM2 = param2;
cmd.PARAM3 = param3;
cmd.PARAM4 = param4;
cmd.PARAM5 = param5;
cmd.PARAM6 = param6;

将传入的参数赋值给 cmd 对象的相应属性。

将对象序列化为 JSON 字符串:

string json_cmd = JsonConvert.SerializeObject(cmd);

使用 JsonConvert.SerializeObject 方法将 cmd 对象序列化为 JSON 格式的字符串。JsonConvertNewtonsoft.Json 库中的一个类,用于处理 JSON 数据的序列化和反序列化。

通过串口发送 JSON 命令:

if (serialPort1.IsOpen)
{
    serialPort1.WriteLine(json_cmd);
}

相关文章:

  • 如何提取图片文字
  • 高性能算法NGO!北方苍鹰优化算法(Northern Goshawk Optimization,NGO)
  • 解决JDK 序列化导致的 Redis Key 非预期编码问题
  • 手写简易Tomcat核心实现:深入理解Servlet容器原理
  • 萌新学 Python 之面向对象的下划线控制权限访问
  • PHP:phpstudy无法启动MySQL服务问题解决
  • Java基础面试题全集
  • 快速使用MASR V3版不能语音识别框架
  • 动态规划完全背包系列一>完全背包
  • 动态规划详解(二):从暴力递归到动态规划的完整优化之路
  • 使用OpenCV和MediaPipe库——驼背检测(姿态监控)
  • 深度神经网络架构设计与工程实践 ——从理论到产业落地的全方位解析
  • leetcode 95.不同的二叉搜索树 Ⅱ
  • 设计AI芯片架构的入门 研究生入行数字芯片设计、验证的项目 opentitan
  • RISC-V汇编学习(三)—— RV指令集
  • MySQL 5.7.40 主从同步配置教程
  • kettle工具使用从入门到精通(一)
  • 高效计算新篇章:探秘稀疏注意力如何颠覆传统Transformer
  • 从0开始,手搓Tomcat
  • 【Docker】通过 Docker 拉取 Python 镜像并设置远程连接(SSH)
  • 贵州建站互联网科技有限公司/深圳seo博客
  • wordpress全自动赚钱/长沙网络优化产品
  • 注册公司需要注意什么事项/站长工具seo源码
  • 上海网站开发外包公司/广告推广免费
  • 互动的网站/google移动服务应用优化
  • 织梦商城网站模板/他达拉非片和伟哥区别