STM32F103C8T6+ESP-01S+MQTT服务器实现数据上传和接收(二)

2023-10-31


文章目录
STM32F103C8T6+ESP-01S+MQTT服务器实现数据上传和接收(一)

前言

因程序需要接收并识别JSON数据,需要引入cJSON库。
cJSON的使用需要占用堆内存空间,STM32F103C8T6默认设置的堆空间为0x00000200,不足以达到cJSON的使用要求。
因此需要修改startup_stm32f10x_md.s文件中第44行。将堆内存改为0x00001000

修改完成后如下所示:

修改堆内存大小

串口配置

初始化

常规的串口初始化代码,最后需要注意开启接收中断和总线空闲中断

这里简单接收一下两种中断
串口每次接收到一个字符就会进入一下接收中断。
串口接收到一个完整的字符串会进入一次总线空闲中断。
例如:设备向单片机发送了一个字符串"lcheng"。
就会进入接收中断6次,当字符串最后一个’g’接收完毕后,就会进入总线空闲中断1次

void usart_init(uint32_t bound)				//115200
{
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
        //USART1_TX   PA.9
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);   
        
        USART_InitStructure.USART_BaudRate = bound;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        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);			//开启接收中断
		USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);			//开启空闲中断
				
        USART_Cmd(USART1, ENABLE);                   
}

printf输出重定向

如果需要重定向到USART2,请替换下面所有的USART1为USART2

#include <stdio.h>							//重定向需要引入该头文件
int fputc(int ch,FILE *f)					
{  
	USART_ClearFlag(USART1, USART_FLAG_TC);
    USART_SendData(USART1,(unsigned char)ch); 
    while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);  
    return ch;  
}

串口中断函数

在串口接收中断中,将接收到的每一个字符配合Rec_i存入全局变量USART_ReceiveString中。

uint16_t Rec_i;
void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   
    {
			USART_ReceiveString[Rec_i++]=USART_ReceiveData(USART1);				//将接收到的字符存入USART_ReceiveString中
    }
		if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET){					//表示接收到了一个完整的字符串
			uint16_t clear;
			USART_ReceiveString[Rec_i]='\0';
			if(USART_ReceiveString[0]!='\0'){
				baseACK(USART_ReceiveString);				//处理AT指令基本回复  OK  ERROR FALT
				msg_handle(USART_ReceiveString);			//真正的数据处理
				clear_ReceiveString();						//清除串口的接收数据。
			}
			clear = USART1->SR;								//清除寄存器
			clear = USART1->DR;
		}
}
void clear_ReceiveString(){	
	USART_ReceiveString[0]='\0';
	Rec_i=0;
}

对串口接收到的数据进行处理

baseAck()

该函数用于对8266的基本应答做出修改程序中对应的应答标志位的处理。

void baseACK(char USART_ReceiveString[]){
	if(checkOK(USART_ReceiveString,OK)){
		back_flag=SUCC;
	}else if(checkOK(USART_ReceiveString,ERROR)||checkOK(USART_ReceiveString,FAIL)){
		back_flag=FAULT;
	}else{
		clearBackFlag();
	}
	if (checkOK(USART_ReceiveString,WIFI_GOT_IP)||checkOK(USART_ReceiveString,WIFI_CONNECTED)){
			ATBack_KeyWords=WIFI_GOT;
		}
}

获取MQTT主题内容get_mqttval()

该函数用于获取MQTT订阅的主题的内容,需要配合info_type()使用

void get_mqttval(char USART_ReceiveString[],char *val){
	unsigned short int i,j,count=0;  //count为逗号数量
	for(i=0;USART_ReceiveString[i]!='\0';i++){
		if(USART_ReceiveString[i]==','&&count!=3){
			if(count<3){
				j=0;
				count+=1;
			}
		}else{
			if(count==3){
				val[j++]=USART_ReceiveString[i];
				if(USART_ReceiveString[i+1]=='\r'){
					val[j++]='\0';
				}
			}
		}
	}
}

msg_handle()

根据串口接收到的数据进行相应的处理

void msg_handle(char *USART_ReceiveString){

	if(info_type(USART_ReceiveString)){	//是mqtt订阅的话题题消息,就根据mqtt协议得到最终数据进行处理
		char val[300],*type,*msg;
		cJSON* val_json=NULL;
		get_mqttval(USART_ReceiveString,val);		//去掉MQTT协议壳得到原始数据(json字符串)
		val_json=cJSON_Parse(val);					//将json字符串转化成cJSON结构体数据
		if(val_json!=NULL){
			type=cJSON_GetObjectItem(val_json,"type")->valuestring;		//得到json中键为type的值
			msg=cJSON_GetObjectItem(val_json,"msg")->valuestring;       //得到json中键为msg的值
			if(!strcmp(type,"dj")){				//对键值进行判断
				if(!strcmp(msg,"ON")|| !strcmp(msg,"on")){  
					//如果匹配进行相应处理
				}else{
					//其他处理........
				}
			}
			cJSON_Delete(val_json);				//JSON结构体使用完毕需要释放掉,不然会造成堆内存溢出导致程序卡死
		}
	}else{		//非MQTT话题消息
		/*非MQTT话题消息处理
		例如baseACK()函数可以放在此处性能会更好,
		但是为了代码可读性更好,选择放在了与msg_handle()同级的地方。*/
	}
}

总结

发送MQTT消息时没有选择使用cJSON是因为MQTT发送的json数据中的’,‘需要转义,cJSON构建的字符串中’,'并没有转义,这个地方不太和谐,另外使用cJSON构建json字符串比起解析json字符串来说需要占用更大的堆内存,因此没有使用cJSON,后续可继续改进这个地方。另外由于引入了cJSON会导致生成的hex文件偏大一点,如果没有使用JSON的需求可以选择不引入cJSON,会节省一些flash容量,

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32F103C8T6+ESP-01S+MQTT服务器实现数据上传和接收(二) 的相关文章

  • L-shape 方法

    L shape 方法是求解两阶段随机规划的一种常用方法 基本思想是利用切平面将第二阶段的反馈函数线性化 在构造切平面条件时有点类似 bender s 方法 注 这个图形中黑实线 Q x mathcal Q x Q x 就是下面模型中的
  • 【已解决】ModuleNotFoundError: No module named ‘distutils.util‘

    系统从Ubuntu18 04升级到20 04 内核也变动了很多次 之前运行在python3 6正常的代码突然报错 ModuleNotFoundError No module named distutils util 网上的解决方法 sudo

随机推荐

  • 字节跳动技术团队年度 TOP10 技术干货,陪你度过不平凡的 2020

    2020 注定是不平凡的一年 在这特殊的一年里 字节跳动技术团队依旧在技术人身边 分享字节跳动的技术实践 本年度字节跳动技术团队共发布了50篇技术干货 其中许多都受到读者的喜爱 值此元旦佳节 我们精选出了其中最受大家欢迎的10 篇文章 供大
  • r语言向量代码如何创建函数c,如何使用R中的rep函数生成的向量创建矩阵?

    仅当我们传递偶数个元素时 才能生成矩阵 如果要使用由rep函数生成的向量创建矩阵 则该向量的长度必须可除以2 例如 如果我们有一个由rep函数创建的向量x 其长度为20 则矩阵说M可以使用matrix x ncol 2 构造使用该向量的10
  • 实验9 I/O流(P293)

    实验目的和要求 1 掌握格式化的输入输出方法 2 熟悉系统提供的输入操作函数 3 掌握磁盘文件的输入输出方法 实验内容 1 程序sy9 1 cpp用以打印表中的数据 但程序中存在逻辑错误 上机调试后写出正确的代码 原程序如下 sy9 1 c
  • 使用javascript写一个CRC16(CCITT)校验

    CRC16 CCITT 校验是一种用于数据传输的常用校验方法 在 JavaScript 中 我们可以使用以下代码实现这种校验 function crc16 data var crc 0xFFFF var polynomial 0x1021
  • 如何分析AWR报告

    AWR 存储位置 SYSAUX表空间 详细信息视图dba hist snapshot 存储策略 60分钟一个 存七天 用途 AWR并不像其他V 视图或者表一样诊断实时问题 只是用来诊断历史性能问题 比如数据库响应慢 大量等待事件 慢SQL
  • 永洪BI助力华海药业数字化转型,挖掘药企发展新优势

    医药制造业是我国国民经济的重要组成部分 在整个消费市场中有着举足轻重的地位 对于生物医药企业来讲 只有合规运营 降本增效 才能保持长期可持续发展 这种情况下 数字化转型将成为生物医药企业的必然选择 也是我国药企向创新型技术型转型升级 提升自
  • Unity3d

    环境配置及Vuforia的使用 vuforia官网 https developer vuforia com 环境配置 vuforia内的SDK支持的Unity版本现为2018 4 所以需要下载Unity2018 4版本 笔者下载的是2018
  • Matlab如何从dat或者txt文件读入数据

    Matlab中可以使用命令 load data dat 或者 load data txt 或者 data in textread data txt data in textread data dat 以上两个命令 只适用于纯数据 且只有一列
  • layui的自定义page

    一 前端页面使用laypage div align center style margin top 20px div let totalCount 0 getPageData 1 6 function getPageData page li
  • DAY34:贪心算法(一)贪心算法理论基础

    文章目录 什么是贪心算法 贪心算法的两个极端 真正需要数学推导的情况 类似环形链表 贪心的套路 课程链接 贪心算法理论基础 哔哩哔哩 bilibili 什么是贪心算法 贪心算法的本质就是找到每个阶段的局部最优 从而去推导全局最优 例如一堆不
  • 常用adb命令整理

    一 adb介绍 adb Android Debug Bridge Android 调试桥的缩写 adb 是一个 C S 架构的命令行工具 主要由 3 部分组成 运行在 PC 端的 Client 可以通过它对 Android 应用进行安装 卸
  • Spring Boot项目中的静态资源位置详解

    一 默认提供的静态资源位置 在使用IntelliJ IDEA中的Spring Boot初始化工具创建的Spring Boot项目中 默认存在resources static目录用于存放静态资源 而在Spring Boot项目中 默认一共有5
  • 如何使用Java进行集成测试?

    在Java中进行集成测试有很多种方法 以下介绍一种比较常见的基于JUnit框架的集成测试方法 确定需要测试的代码 首先需要确定需要进行集成测试的代码 可以是整个应用程序 也可以是特定的模块或者方法 配置测试环境 在测试环境中创建测试数据库
  • CSS实现全局的自适应

    放置全屏地图时遇到的问题 解决方案如下 方法一 css view plain copy map height 100 width 100 position absolute top 0px bottom 0px background 00F
  • war包发布tomcat出错

    tomcat 错误 严重 Error listenerStart 网上说有很多种可能的原因 我的是因为缺少了spring core jar 但我的pom xml里确实是有的 而且在eclipse里是可以跑的程序 打成war后这个包就没了 原
  • Ethereum学习之路 —— 状态树

    状态树 要设计一种什么数据结构呢 要完成账户地址到账户状态的映射 以太坊的账户地址是160位的 也就是20个字节 一般表示成40个16进制的数 状态时指外部账户和合约账户的balance nonce等 MPT 了解MPT之前 先了解下tri
  • 如何从About:Config中列出,过滤,添加,删除更改Firefox设置

    Firefox provides settings and configuration windows in a user friendly way But as a browser it provides a lot of configu
  • Github怎么上传到代码到仓库

    Github是一个非常受欢迎的代码托管平台 使用Git作为版本控制系统 它允许开发者将自己的代码存储在远程仓库中 以便于团队协作 项目管理和版本控制 本教程将详细介绍如何将代码上传到Github仓库 准备工作 注册并登录Github账户 访
  • 双目立体视觉-特征检测与特征匹配总结

    特征检测 opencv可以检测图像的主要特征 然后提取这些特征 使其成为图像描述符 特征 特征就是有意义的图像区域 该区域具有独特性或易于识别性 角点与高密度区域是一个很好的特征 边缘可以将图像分为两个区域 因此可以看作很好的特征 斑点 与
  • STM32F103C8T6+ESP-01S+MQTT服务器实现数据上传和接收(二)

    MQTT自定义库函数的实际应用 前言 串口配置 初始化 printf输出重定向 串口中断函数 对串口接收到的数据进行处理 baseAck 获取MQTT主题内容get mqttval msg handle 总结 文章目录 STM32F103C