ESP8266与STM32串口数据交互


在这篇文章中我会通过介绍ESP8266和STM32两部分的代码来实现两块MCU串口数据的交互,交互的数据格式采用的是JSON格式,ESP8266的开发环境使用的是arduino,STM32使用的是KEIL5。


ESP8266部分

ESP8266我会从以下三部分介绍:①ArduinoJson解析库的安装②串口接收的实现③ArduinoJson库实现数据解析④ArduinoJson库实现数据的打包发送

JSON解析库的安装

本篇博客中使用的JSON库为ArduinoJson,版本是V5版本,目前最新的是V6版本,大家可以选择V6版本安装,只需看下示例,修改下我分享的工程即可。
安装ArduinoJson

串口接收的实现

在ESP8266程序中需要将usartEvent();函数放到loop()函数中。

/*串口数据接收*/
void usartEvent(){
  comdata = "";
  while (Serial.available())//时刻读取硬件串口数据
  {
    comdata = Serial.readStringUntil('\n');//从串口缓存区读取字符到一个字符串型变量,直至读完或遇到某终止字符。
    UserData(comdata);//进行JOSN数据解析
  }
  while (Serial.read() >= 0){}//清除串口缓存
}

ArduinoJson库实现数据解析

/*数据解析{status:true}*/ 
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包,大家自动安装即可。
JSON解析库的安装

串口接收的实现

STM32的串口中断我才用的是串口空闲中断,空闲中断是接受数据后出现一个byte的高电平(空闲)状态,就会触发空闲中断。
代码实现如下:
需要定义的全局变量:u8 buf1_size = 0;//串口数据接收数量标记 bool data_change = 0;//串口接收完成/变化标志位

#include <stdarg.h>
#include <string.h>
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.s33的Stack_Size EQU 0x00000200修改为Stack_Size EQU 0x00000C00,这一步骤是将STM32的堆栈增加,防止在解析的时候出现堆栈不够用的情况。

#include <jansson.h>
bool led_status;
//开关灯JSON函数{"status":true}
//存在问题!!使用本函数解析后串口printf无法使用,建议使用USART1_printf函数实现发送
/** 
* @brief  Json解析函数
* @param none
* @return 
* - 0 转换成功
* - 1 转换失败
* @details   
*/ 
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;
}
/*
// string 类型的解析
name = (char *)json_string_value(json_object_get(root, "name"));
// int 类型的解析
age = json_integer_value(json_object_get(root, "age"));
// double 类型的解析
score = json_real_value(json_object_get(root, "score"));
// bool 类型的解析
status = json_object_get(root, "status");
if(json_is_true(status))
else if(json_is_false(status))
*/

JSON数据的打包发送

Jansson包提供了一个json数据打包的函数,但此函数在打包过程中会占用极大的片内空间,因此在这里仅介绍给大家,不推荐大家使用,推荐大家使用的方法还是使用printf函数进行格式化输出。

/** 
* @brief  将数据打包为Json格式
* @param [in] status 
* @return none
* @details   
*/ 
void jansson_pack(bool state)
{
	json_t *root;
	char *out;
	/* Build the JSON object */
	root = json_pack("{sb}","status",status);
	out = json_dumps(root, JSON_ENCODE_ANY);
	printf("%s",out);
	json_decref(root);//释放JSON空间
	free(out);//释放JSON空间
}
/*
s 代表string类型
b 代表bool类型
d 代表int类型
f 代表float、double类型
*/

使用printf格式化输出只需要:

printf("{\"status\":%d}",status);

需要注意的是在使用格式化输出函数输出JSON数据时需要自己进行JSON格式的校验和转义。
推荐大家使用JSON在线视图查看器.进行格式查验和转义。


程序分享

ESP8266
STM32

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值