文章目录

1- JSON介绍2- 配置添加代码(1)配置(2)usart.c(串口初始化保存获取数据)(2)gpio.c(建立映射关系)(3)main.c(串口接收数据并解析)

3- 调试结果4- 涉及到的函数理解及分析(1)HAL_UART_Transmit()(2)HAL_UART_Receive_IT()(3)JSON_Validate()(4)JSON_Search()(5)strncasecmp()

1- JSON介绍

JSON(JavaScript Object Notation),即 JS对象简谱,是一种轻量级的数据格式。 它采用完全独立于编程语言的文本格式来存储和表示数据,语法简洁、层次结构清晰,易于人阅读和编写,同时也易于机器解析和生成,有效的提升了网络传输效率。

JSON 可以将 JavaScript 对象中表示的一组数据转换为字符串,然后就可以在网络或者程序之间轻松地传递这个字符串,并在需要的时候将它还原为各编程语言所支持的数据格式。

JSON是一种语法,用来序列化对象、数组、数值、字符串、布尔值和NULL值。JSON数据的本质就是一段字符串而已,只不过有不同意义的分隔符将其分割开来而已。 我们看上面的符号,里面有[],{}等符号,其中:

()表示一个对象,它是一个无序的键值对(属性值)集合,里面的不同键值对用逗号隔开冒号:表示一个键值对(key:value),冒号前面是属性的名称(key),后面是属性的值(value)。值可以是双引号括起来的字符串(string)、数值(number)、true,false, null、对象(object)或者数组(array),这些结构可以嵌套。[]表示的是一个数组,它是值的有序集合,值之间使用逗号分隔。

我们使用串口接收PC端下发的JSON格式的LED控制指令报文,解析并实现LED灯的控制: JSON格式控制数据报文定义: {“RedLed”:“on”,“GreenLed”:“on”,“BlueLed”:“on”} {“RedLed”:“off”,“GreenLed”:“off”,“BlueLed”:“off”}

JSON作为广泛使用的数据通信格式吗,每种编程语言都会有很多解析库,而C语言中经常用到的JSON解析库有cJSON,但因为嵌入式单片机中的Flash、RAM有限,这里我们就使用单片机中常用的免费开源操作系统FreeRTOS里自带的coreJSON库:

json文件链接:coreJSON库 提取码:5253

2- 配置添加代码

(1)配置

配置使能串口USART1的中断,使用中断来接收串口上收到的数据。

(2)usart.c(串口初始化保存获取数据)

/* USER CODE BEGIN 0 */

static uint8_t s_uart1_rxch;//获取到的一个字节的数据保存在这里,相当于中转站

char g_uart1_rxbuf[256];//将s_uart1_rxch获取到的每个字节保存在g_uart1_rxbuf中

uint8_t g_uart1_bytes;//一次累加,最大256

/* USER CODE END 0 */

/*MX_USART1_UART_Init()串口初始化函数中添加HAL_UART_Receive_IT()函数*/

/*使能usart1的中断接收,中断接收到的每个字节的数据保存在s_uart1_rxch中*/

void MX_USART1_UART_Init(void)

{

HAL_UART_Receive_IT(&huart1, &s_uart1_rxch, 1);

}

/* USER CODE BEGIN 1 */

/*printf()函数的定义,可以不用管*/

#ifdef __GNUC__

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)/*char类型是以int类型存储的,所以可以用int*/

#else

#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

#endif /* __GNUC__ */

PUTCHAR_PROTOTYPE

{

HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);

return ch;

}

/*在这里添加串口中断接收的回调函数,还要g_uart1_rxbuf没有满,就将中断接收到的1字节数据s_uart1_rxch存储到g_uart1_rxbuf中,并将g_uart1_bytes 自加。*/

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

if(huart -> Instance == USART1 )

{

if( g_uart1_bytes < sizeof(g_uart1_rxbuf) )

{

g_uart1_rxbuf[g_uart1_bytes++] = s_uart1_rxch;

}

HAL_UART_Receive_IT(&huart1, &s_uart1_rxch, 1);

}

}

/* USER CODE END 1 */

usart.h

/* USER CODE BEGIN Includes */

#include

#include

/* USER CODE END Includes */

/* USER CODE BEGIN Private defines */

/*在这里添加uart1接收buffer 相关变量声明,并添加一个宏clear_uart1_rxbuf()用来清除接收buffer里的数据*/

extern char g_uart1_rxbuf[256];

extern uint8_t g_uart1_bytes;

#define clear_uart1_rxbuf() do { memset(g_uart1_rxbuf, 0, sizeof(g_uart1_rxbuf) ); g_uart1_bytes = 0;}while(0)

/* USER CODE END Private defines */

(2)gpio.c(建立映射关系)

/* USER CODE BEGIN 2 */

gpio_t leds[LedMax] =

{

{"SysLed", SysLed_GPIO_Port, SysLed_Pin},

{"BlueLed", BlueLed_GPIO_Port, BlueLed_Pin},

{"RedLed", RedLed_GPIO_Port, RedLed_Pin},

{"GreenLed", GreenLed_GPIO_Port, GreenLed_Pin},

};

void turn_led(int which, int status)

{

GPIO_PinState level;

if( which<0 || which>=LedMax)

{

return ;

}

level = status == OFF ? GPIO_PIN_SET : GPIO_PIN_RESET;

HAL_GPIO_WritePin(leds[which].group, leds[which].pin, level);

}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

if (Key1_Pin == GPIO_Pin)

{

blink_led(BlueLed, 500);

}

else if(Key2_Pin == GPIO_Pin)

{

blink_led(RedLed, 500);

}

}

/* USER CODE END 2 */

gpio.h

/* USER CODE BEGIN Prototypes */

enum

{

SysLed,

BlueLed,

RedLed,

GreenLed,

LedMax,

};

#define OFF 0

#define ON 1

/*将gpio.c中定义的gpio_t结构体定义移到头文件中来,并在它里面添加一个char *name的字段,其它C文件会用到这个结构体。*/

typedef struct gpio_s

{

const char *name;

GPIO_TypeDef *group;

uint16_t pin;

} gpio_t;

extern gpio_t leds[LedMax];

extern void turn_led(int which, int status);

extern void blink_led(int which, uint32_t interval);

void sysled_hearbeat(void);

/* USER CODE END Prototypes */

(3)main.c(串口接收数据并解析)

需要包含core_json.h这个头文件,.h和.c文件网盘有,下载之后在相关路径放进去然后刷新,会看见加载到STM32IDE中了。

/* USER CODE BEGIN Includes */

#include "core_json.h"

/* USER CODE END Includes */

/* USER CODE BEGIN 0 */

static int parser_led_json(char *json_string, int bytes);

static void proc_uart1_recv(void);

/* USER CODE END 0 */

while (1)

{

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

proc_uart1_recv();

}

/* USER CODE BEGIN 4 */

int parser_led_json(char *json_string, int bytes)

{

JSONStatus_t result;

char save;

char *value;

size_t valen;

int i;

printf("BDUG: Start parser JSON string:%s\r\n", json_string);

result = JSON_Validate(json_string, bytes);

if(JSONPartial == result)

{

printf("WARN: JSON document is valid so far but incomplete!\r\n");

return 0;

}

if(JSONSuccess != result )

{

printf("ERROR: JSON doument is not valid JSON!\r\n");

return -1;

}

for(i=0; i

{

result = JSON_Search( json_string, bytes, leds[i].name, strlen(leds[i].name), &value, &valen);

if(JSONSuccess == result)

{

save = value[valen];

value[valen] = '\0';

if( !strncasecmp(value, "on", 2))

{

printf("DBUG: turn %s on\r\n", leds[i].name);

turn_led(i, ON);

}

else if(!strncasecmp(value, "off", 3))

{

printf("DBUG: turn %s off\r\n", leds[i].name);

turn_led(i, OFF);

}

value[valen] = save;

}

}

return 1;

}

void proc_uart1_recv(void)

{

if( g_uart1_bytes > 0)

{

HAL_Delay(200);

if(0 != parser_led_json(g_uart1_rxbuf, g_uart1_bytes) )

{

clear_uart1_rxbuf();

}

}

}

/* USER CODE END 4 */

3- 调试结果

发送{“BlueLed”:“on”,“RedLed”:“on”,“GreenLed”:“on”}会看见三个灯都亮了。

4- 涉及到的函数理解及分析

(1)HAL_UART_Transmit()

HAL_UART_Transmit()是STM32 HAL库串口发送函数,我的理解就是串口需要发送的数据函数,我们在printf重定向的时候就是将输出重定向到这个函数嘛。

C语言中printf函数默认输出设备是显示器,如果要实现在串口或者LCD上显示,必须重定义标准库函数里调用的与输出设备相关的函数。比如使用printf输出到串口,需要将fputc或者__io_putchar里面的输出指向串口。

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

UART_HandleTypeDef *huart:UART的别名,如UART_HandleTypeDef huart1; 别名就是huart1;查看系统定义的句柄结构体,我们的上述代码中就是huart1串口*pData:需要发送的数据uint16_t Size:发送数据的大小uint32_t Timeout:最大发送时间,发送数据超过该时间退出发送

(2)HAL_UART_Receive_IT()

HAL_UART_Receive_IT是STM HAL库的串口中断接收函数,有数据来了就去读取,而且我们这里是一个字节一个字节读取的。并且读取到的数据保存在s_uart1_rxch中,然后调用回调函数将s_uart1_rxch的数据放在了s_uart1_rxchbuf中,最终发送的所有数据都在s_uart1_rxchbuf中。

HAL_UART_Receive_IT(&huart1, &s_uart1_rxch, 1);

函数原型:

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

UART_HandleTypeDef *huart:UART的别名,如UART_HandleTypeDef huart1; 别名就是huart1;查看系统定义的句柄结构体,我们的上述代码中就是huart1串口uint8_t *pData:读到的数据uint16_t Size:数据的大小

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

if(huart -> Instance == USART1 )

{

if( g_uart1_bytes < sizeof(g_uart1_rxbuf) )

{

g_uart1_rxbuf[g_uart1_bytes++] = s_uart1_rxch;

}

HAL_UART_Receive_IT(&huart1, &s_uart1_rxch, 1);

}

}

(3)JSON_Validate()

JSON_VALIDATE()函数用于判断value的值是否是有效的JSON数据。

如果返回值是JSONPartial:说明数据还没有收完,只有一部分。如果返回值是JSONSuccess:说明数据接收完毕,是有效的JSON数据。

result = JSON_Validate(json_string, bytes);

if(JSONPartial == result)

{

printf("WARN: JSON document is valid so far but incomplete!\r\n");

return 0;

}

if(JSONSuccess != result )

{

printf("ERROR: JSON doument is not valid JSON!\r\n");

return -1;

}

(4)JSON_Search()

通过JSON_Search()函数去解析json数据并且去寻找匹配。匹配是根据leds[LedMax]循环匹配查找的。

gpio_t leds[LedMax] =

{

{"SysLed", SysLed_GPIO_Port, SysLed_Pin},

{"BlueLed", BlueLed_GPIO_Port, BlueLed_Pin},

{"RedLed", RedLed_GPIO_Port, RedLed_Pin},

{"GreenLed", GreenLed_GPIO_Port, GreenLed_Pin},

};

for(i=0; i

{

result = JSON_Search( json_string, bytes, leds[i].name, strlen(leds[i].name), &value, &valen);

...

}

假设发送的json格式的数据:{“RedLed”:“on”,“GreenLed”:“off”,“BlueLed”:“on”}

第一次循环:leds[0].name是Sysled,无匹配的,进入下一次循环。第二次循环:leds[1].name是BlueLed,匹配到了。就将value赋值为on,然后将valen赋值为2,然后进行接下来的操作(打开灯或者关灯)。第三次循环:leds[2].name是RedLed,匹配到了。就将value赋值为off,然后将valen赋值为3

(5)strncasecmp()

头文件:#include

定义函数:int strncasecmp(const char *s1, const char *s2, size_t n);

函数说明:strncasecmp()用来比较参数s1 和s2 字符串前n个字符,比较时会自动忽略大小写的差异。

返回值:若参数s1 和s2 字符串相同则返回0。s1 若大于s2 则返回大于0 的值,s1 若小于s2 则返回小于0 的值。

if( !strncasecmp(value, "on", 2))

{

printf("DBUG: turn %s on\r\n", leds[i].name);

turn_led(i, ON);

}

else if(!strncasecmp(value, "off", 3))

{

printf("DBUG: turn %s off\r\n", leds[i].name);

turn_led(i, OFF);

}

好文链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: