ESP8266与STM32串口数据交互(通过JSON)
- ESP8266部分
-
- JSON解析库的安装
- 串口接收的实现
- ArduinoJson库实现数据解析
- ArduinoJson库实现数据的打包发送
- STM32部分
-
- JSON解析库的安装
- 串口接收的实现
- JSON库实现数据解析
- JSON数据的打包发送
- 程序分享
在这篇文章中我会通过介绍ESP8266和STM32两部分的代码来实现两块MCU串口数据的交互,交互的数据格式采用的是JSON格式,ESP8266的开发环境使用的是arduino,STM32使用的是KEIL5。
ESP8266部分
ESP8266我会从以下三部分介绍:①ArduinoJson解析库的安装②串口接收的实现③ArduinoJson库实现数据解析④ArduinoJson库实现数据的打包发送
JSON解析库的安装
本篇博客中使用的JSON库为ArduinoJson
,版本是V5版本,目前最新的是V6版本,大家可以选择V6版本安装,只需看下示例,修改下我分享的工程即可。
串口接收的实现
在ESP8266程序中需要将usartEvent();
函数放到loop()
函数中。
void usartEvent(){
comdata = "";
while (Serial.available())//时刻读取硬件串口数据
{
comdata = Serial.readStringUntil('\n');//从串口缓存区读取字符到一个字符串型变量,直至读完或遇到某终止字符。
UserData(comdata);//进行JOSN数据解析
}
while (Serial.read() >= 0){ }//清除串口缓存
}
ArduinoJson库实现数据解析
void UserData(String content){
StaticJsonDocument<200> doc;//申请JSON解析空间
DeserializationError error = deserializeJson(doc,content);
if (error) { //解析错误
Serial.print(F("deserializeJson() failed: "));
return;
}
status= doc["status"];
}
ArduinoJson库实现数据的打包发送
参照ArduinoJson库的JsonGeneratorExample
工程即可得到以下代码,当然也可采用serial.println()
函数进行格式化输出。
StaticJsonDocument<200> doc;
doc["sensor"] = "gps";
doc["time"] = 1351824120;
serializeJsonPretty(doc, Serial);
STM32部分
STM32同ESP8266一样,我会从以下四部分介绍:①JSON解析库的安装②串口接收的实现③JSON库实现数据解析④JSON数据的打包发送
JSON解析库的安装
STM32上我采用的JSON解析库是Jansson
,我会给大家提供这个库的pack包,大家自动安装即可。
串口接收的实现
STM32的串口中断我才用的是串口空闲中断,空闲中断是接受数据后出现一个byte的高电平(空闲)状态,就会触发空闲中断。
代码实现如下:
需要定义的全局变量:u8 buf1_size = 0;//串口数据接收数量标记 bool data_change = 0;//串口接收完成/变化标志位
void USART1_printf (char *fmt, ...){
char buffer[USART1_REC_LEN+1]; // 数据长度
u8 i = 0;
va_list arg_ptr;
va_start(arg_ptr, fmt);
vsnprintf(buffer, USART1_REC_LEN+1, fmt, arg_ptr);
while ((i < USART1_REC_LEN) && (i < strlen(buffer))){
USART_SendData(USART1, (u8) buffer[i++]);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
va_end(arg_ptr);
}
void USART1_Init(u32 bound){ //串口1初始化
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启ENABLE/关闭DISABLE串口接收中断
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断
USART_Cmd(USART1, ENABLE); //使能串口
}
void USART1_IRQHandler(void){ //串口1中断服务程序(固定的函数名不能修改)
u8 clear = clear;
USART_ClearFlag(USART1,USART_FLAG_TC);
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=Bit_RESET)//串口中断发生
{
if(data_change == 0)//重新接收
{
memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));//清空整个接收数组
data_change = 1;//标志位拉高
}
USART1_RX_BUF[buf1_size++]=USART1->DR;
}
else if(USART_GetFlagStatus(USART1,USART_FLAG_IDLE)!=Bit_RESET)//空闲中断发生
{
buf1_size = 0;
data_change = 0;//标志位拉低,下次数据改变进入
data_sys = 1;//允许解析
clear = USART1->SR;//空闲中断要读这两个寄存器
clear = USART1->DR;
USART_ClearITPendingBit(USART1,USART_IT_IDLE);//清除空闲中断标志位
}
}
JSON库实现数据解析
JSON库解析需要调用头文件#include <jansson.h>
,bool类型变量使用需要#include "stdbool.h"
头文件。
并且非常重要的是,在对大量数据进行解析的时候,需要将startup_stm32f10x_md.s
33的Stack_Size EQU 0x00000200
修改为Stack_Size EQU 0x00000C00
,这一步骤是将STM32的堆栈增加,防止在解析的时候出现堆栈不够用的情况。
#include <jansson.h>
bool led_status;
//开关灯JSON函数{"status":true}
//存在问题!!使用本函数解析后串口printf无法使用,建议使用USART1_printf函数实现发送
uint8_t Jansson_Analysis(char *text)
{
json_error_t error;
json_t *root;
root = json_loads((const char*)text, 0, &error);
if(json_is_object(root))
{
status = json_object_get(root, "status");
if(json_is_true(status))
led_status = 1;
else if(json_is_false(status))
led_status = 0;
}
else
{
USART1_printf("root format error:%d-%s\r\n", error.line, error.text);
return 1;
}
json_decref(root);//释放JSON空间
return 0;
}
JSON数据的打包发送
Jansson
包提供了一个json数据打包的函数,但此函数在打包过程中会占用极大的片内空间,因此在这里仅介绍给大家,不推荐大家使用,推荐大家使用的方法还是使用printf
函数进行格式化输出。
void jansson_pack(bool state)
{
json_t *root;
char *out;
root = json_pack("{sb}","status",status);
out = json_dumps(root, JSON_ENCODE_ANY);
printf("%s",out);
json_decref(root);//释放JSON空间
free(out);//释放JSON空间
}
使用printf
格式化输出只需要:
printf("{\"status\":%d}",status);
需要注意的是在使用格式化输出函数输出JSON数据时需要自己进行JSON格式的校验和转义。
推荐大家使用JSON在线视图查看器.进行格式查验和转义。
程序分享
ESP8266
STM32