JSON格式介绍以及STM32串口通信JSON格式远程控制LED灯

这篇具有很好参考价值的文章主要介绍了JSON格式介绍以及STM32串口通信JSON格式远程控制LED灯。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


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的中断,使用中断来接收串口上收到的数据。
JSON格式介绍以及STM32串口通信JSON格式远程控制LED灯

(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 <stdio.h>
#include <string.h>

/* 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<LedMax; 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”}会看见三个灯都亮了。

JSON格式介绍以及STM32串口通信JSON格式远程控制LED灯


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<LedMax; 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 <string.h>

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

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

返回值:若参数s1 和s2 字符串相同则返回0。s1 若大于s2 则返回大于0 的值,s1 若小于s2 则返回小于0 的值。文章来源地址https://www.toymoban.com/news/detail-434601.html

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);
	}

到了这里,关于JSON格式介绍以及STM32串口通信JSON格式远程控制LED灯的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 多串口通信(stm32)

    在做项目的过程中我们会同时使用多个串口,如:Esp8266wifl模块,HC-05蓝牙模块,还有串口下载,这些都需要多个串口通信。 串口作为 MCU 的重要外部接口,同时也是软件开发重要的调试手段,其重要性不言而喻。 现在基本上所有的 MCU 都会带有串口, STM32 自然也不例外。

    2024年04月29日
    浏览(35)
  • STM32—串口通信

    目录 通信基础知识 通信的本质 时钟信号划分 同步通信 异步通信 通信方式划分 串行通信 串行通信 串行传输 优点 缺点  并行通信 并行通信 并行传输 优点 缺点  通信方向划分 单工 半双工 全双工  总线协议(电气协议) USART  串口通信协议  数据帧格式 USART功能框图  流

    2024年02月04日
    浏览(36)
  • 【STM32串口通信】

    每天更新STM32学习笔记 串口通信的数据按 位 顺序传输,其数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口,故串口通信至少需要两根线(GND和一根信号线)来实现单工通信。若要实现全双工通信,则要三根线(GND和两根信号线)。 串口通信的数据包由起始位、数

    2024年02月04日
    浏览(38)
  • STM32-串口通信(串口的接收和发送)

    本文在于记录自己的学习过程中遇到的问题和总结,各种情况下串口通信在STM32的实际使用方面占有很大的比重,本文主要对 串口通信 做一个简要的总结。 在STM32里,串口通信是USART,STM32可以通过串口和其他设备进行传输 并行数据 ,是 全双工 , 异步时钟控制 ,设备之间是

    2024年02月03日
    浏览(59)
  • ESP32 与 STM32 串口通信

    ESP32 一共有三个 UART 通讯接口,设备号从 0~2,即 UART0,UART1,UART2。 每个UART控制器都是独立配置的,参数包括波特率、数据比特长度、位序、停止位数、奇偶校验位等。 本文章中使用ESP-WROOM-32开发板下载调试串口UART0和UART2(与STM32进行通信)实现。 STM32部分代码参照 正点原

    2024年02月11日
    浏览(34)
  • STM32——串口通信应用篇

            STM32微控制器是一款功能强大的嵌入式系统芯片,广泛应用于各种领域。其中,串口通信是其重要功能之一,可用于与外部设备进行数据交换和控制。本文将介绍STM32串口通信的基本原理、应用场景以及实现方法。         STM32的串口通信是基于UART(通用异步收

    2024年02月04日
    浏览(25)
  • 【STM32】学习笔记(串口通信)

    串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信 单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力。 电平标准

    2024年02月10日
    浏览(30)
  • STM32速成笔记—串口通信

    🎀 文章作者:二土电子 🌸 关注文末公众号获取其他资料和工程文件! 🐸 期待大家一起学习交流! 串口通信是指外部设备与主控芯片之间,通过数据信号线、地线等,按位进行数据传输的一种通信方式,属于串行通信方式。串行通信是指使用一条数据线依次逐位传输数据

    2024年02月09日
    浏览(45)
  • STM32串口通信—串口的接收和发送详解

    目录 前言: STM32串口通信基础知识: 1,STM32里的串口通信 2,串口的发送和接收 串口发送: 串口接收: 串口在STM32中的配置: 1. RCC开启USART、串口TX/RX所对应的GPIO口 2. 初始化GPIO口 3. 串口初始化 4. 串口使能 5. 串口发送数据 串口接收的两种实现方式: 1,轮询方式: 2,中断

    2024年04月08日
    浏览(95)
  • STM32使用中断及串口通信

    采用中断模式编程,当开关接高电平时,LED亮灯;接低电平时,LED灭灯。单片机除了基本的连线外,我们另外只接一只LED灯。 使用外部中断的基本步骤如下: 1.设置对应时钟 2.设置中断 3.初始化IO 4. 把特定IO口设置为中断线路进行初始化 5. 在中断通道的响应函数中中断函数

    2024年02月04日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包