ESP8266与STM32串口数据交互

   日期:2021-01-12     浏览:676    评论:0    
核心提示:ESP8266与STM32串口数据交互(通过JSON)ESP8266部分JSON解析库的安装功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入在这篇文章中我会通过介绍ESP8266和STM32两部分的代码来实现两块MCU串口数据的交

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.s33的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

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服