STM32 ES8266上阿里云IOT MQTT实践

STM32 ES8266上阿里云IOT MQTT实践

DHT11与OLED配置就不多赘述了
程序结构
在这里插入图片描述

1.串口配置

1.1串口1的配置

串口1仅作为调试输出串口,设置波特率为9600,并不设置中断 。

在这里插入图片描述

1.2串口3的配置

  • 根据原理图配置CubeMX

在这里插入图片描述

在这里插入图片描述

  • 配置中断

在这里插入图片描述

2.添加驱动文件

2.1添加esp8266驱动文件

  • 将ESP8266放在Src文件夹

在这里插入图片描述

在这里插入图片描述

  • 在工程中导入文件

在这里插入图片描述

  • 在main.c中引入头文件
#include "esp8266_at.h"

在这里插入图片描述

2.2添加MQTT驱动文件

步骤与2.1相同,就不多赘述

3.快速连接阿里云

3.1数据准备

  • 准备好AliYun配置软件,生成阿里云连接属性

在这里插入图片描述

  • 在main.c中根据自己的情况进行配置。

在这里插入图片描述

3.2开发板初始化配置

以下函数皆在main.c添加

  • 开启USART3接收中断 接受订阅消息
HAL_UART_Receive_IT(&huart3,usart3_rxone,1);
  • 添加MQTT初始化函数
ES8266_MQTT_Init();
//MQTT初始化函数
void ES8266_MQTT_Init(void)
{
	uint8_t status=0;

	//初始化
	if(ESP8266_Init())
	{
		
		status++;
		printf("ESP8266初始化成功!status=%d\n",status);
	}
	else Enter_ErrorMode(0);

	//连接热点
	if(status==1)
	{
		if(ESP8266_ConnectAP(WIFI_NAME,WIFI_PASSWD))
		{
			
			status++;printf("ESP8266连接热点成功!status=%d\n",status);
		}
		else Enter_ErrorMode(1);
	}
	
	//阿里云MQTT配置
	if(status==2)
	{
		if(MQTT_PeiZhi(MQTT_CLIENTID, MQTT_USARNAME, MQTT_PASSWD) != 0)
		{
			
			status++;printf("ESP8266阿里云MQTT配置成功!status=%d\n",status );
		}
		else Enter_ErrorMode(2);
	}
	
	//登陆MQTT
	if(status==3)
	{
		if(ESP8266_ConnectServer(MQTT_BROKERADDRESS,1883)!=0)
		{
			
			status++;printf("ESP8266登录阿里云MQTT服务器成功!status=%d \n",status );
		}
		else Enter_ErrorMode(3);
		
		
	}

	//订阅主题
	if(status==4)
	{
		if(MQTT_SubscribeTopic(MQTT_SUBSCRIBE_TOPIC) != 0)
		{
			printf("ESP8266阿里云MQTT订阅主题成功!\r\n");
		}
		else Enter_ErrorMode(4);
	}
}
  • 添加串口3接收中断处理函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART3)	// 判断是由哪个串口触发的中断
	{
		//将接收到的数据放入接收usart3接收数组
		usart3_rxbuf[usart3_rxcounter] = usart3_rxone[0];
		usart3_rxcounter++;	//接收数量+1
		
		//重新使能串口3接收中断
		HAL_UART_Receive_IT(&huart3,usart3_rxone,1);		
	}
}

  • 添加错误模式处理函数
//进入错误模式等待手动重启
void Enter_ErrorMode(uint8_t mode)
{
	
	while(1)
	{
		switch(mode){
			case 0:printf("ESP8266初始化失败!\r\n");break;
			case 1:printf("ESP8266连接热点失败!\r\n");break;
			case 2:printf("ESP8266阿里云MQTT配置服务器失败!\r\n");break;
			case 3:printf("ESP8266阿里云MQTT登陆失败!\r\n");break;
			case 4:printf("ESP8266阿里云MQTT订阅主题失败!\r\n");break;
			default:printf("Nothing\r\n");break;
		}
		printf("请重启开发板");

		HAL_Delay(200);
	}
}

3.3单片机数据上传配置

  • 先复制本代码,然后根据阿里云物理模型进行配置
//单片机状态上报
void STM32DHT11_StatusReport(void)
{
	//获取温湿度信息
	uint8_t temperature;
	uint8_t humidity;

	char StrBuf[64]= {0};
	
	if( Read_DHT11(&DHT11_Data)==0)										 //“\”表示转向一下行
		{	
			printf("****读取DHT11成功!****\r\n湿度为%d.%d %RH ,温度为 %d.%d℃ \r\n",\
							DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);
		
			HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
			temperature = (int8_t)DHT11_Data.temp_int;    //温度,单位:℃
			humidity = (int8_t)DHT11_Data.humi_int;       //湿度,单位:%
		
			memset(StrBuf, '\0', 64);
			sprintf(StrBuf, " %d Degree",temperature);
			OLED_ShowString(0,4,(uint8_t *)StrBuf);//OLED显示当前温度
			memset(StrBuf, '\0', 64);
			sprintf(StrBuf, " %d %%",humidity);
			OLED_ShowString(0,6,(uint8_t *)StrBuf);//OLED显示当前相对湿度
	

		//jsion 格式
			sprintf(mqtt_message,
			"{\\\"method\\\":\\\"thing.event.property.post\\\"\\,\\\"params\\\":{\\\"CurrentTemperature\\\":%d\\,\\\"CurrentHumidity\\\":%d}}",
			(int)temperature,
			(int)humidity
			);

			MQTT_PublishData(MQTT_PUBLISH_TOPIC,mqtt_message);
		}
		else
		{
			printf("Read DHT11 ERROR!\r\n");//采集温湿度数据
			HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
		}
		
}

在这里插入图片描述

3.4 上云

下载程序,查看串口助手与阿里云物模型

在这里插入图片描述

4.源码分析

本项目多次用到的几个函数

4.1sprintf函数

属于C标准库<stdio.h>

描述:C 库函数 int sprintf(char *str, const char *format, …) 发送格式化输出到 str 所指向的字符串。

声明

int sprintf(char *str, const char *format, ...)
  • str – 这是指向一个字符数组的指针,该数组存储了 C 字符串。
  • format – 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:
specifier(说明符)输出
c字符
d 或 i有符号十进制整数
e使用 e 字符的科学科学记数法(尾数和指数)
E使用 E 字符的科学科学记数法(尾数和指数)
f十进制浮点数
g自动选择 %e 或 %f 中合适的表示法
G自动选择 %E 或 %f 中合适的表示法
o有符号八进制
s字符的字符串
u无符号十进制整数
x无符号十六进制整数
X无符号十六进制整数(大写字母)
p指针地址
n无输出
%字符
flags(标识)描述
-在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。
+强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。
(space)如果没有写入任何符号,则在该值前面插入一个空格。
#与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。 与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。 与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。
0在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。
width(宽度)描述
(number)要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断。
*宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
.precision(精度)描述
.number对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。 对于 e、E 和 f 说明符:要在小数点后输出的小数位数。 对于 g 和 G 说明符:要输出的最大有效位数。 对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。 对于 c 类型:没有任何影响。 当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。
.*精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
length(长度)描述
h参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。
l参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。
L参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。
  • 附加参数 – 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

返回值:

如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

实例:

在本项目中,多使用以下方法,将后面的字符串写入第一个参数

sprintf(name_pwd,"AT+MQTTUSERCFG=0,1,\"NULL\",\"%s\",\"%s\",0,0,\"\"\r\n",Username,Password);
//将后面的字符串写入到name_pwd 

4.2FindStr函数

**描述:**查找字符串中是否包含另一个字符串

声明uint8_t FindStr(char* dest,char* src,uint16_t retry_nms)

dest:是目标字符串

src:是原字符串

retry_nms:超时时间 ————>没用这个参数

定义:

uint8_t FindStr(char* dest,char* src,uint16_t retry_nms)
{
//	retry_nms/=10;                   //超时时间

//	while(strstr(dest,src)!=NULL )//等待串口接收完毕或超时退出
//	{		
		HAL_Delay(100);
//	}

	if(strstr(dest,src)!=NULL) return 0; 
		else 	return 1; 
}

在上述函数中使用了strstr()函数以下相关介绍

C 库函数 char *strstr(const char *haystack, const char *needle) 在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 ‘\0’。

声明

下面是 strstr() 函数的声明。

char *strstr(const char *haystack, const char *needle)

参数

  • haystack – 要被检索的 C 字符串。
  • needle – 在 haystack 字符串内要搜索的小字符串。

返回值

该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 null。

实例

下面的实例演示了 strstr() 函数的用法。

实例

#include <stdio.h>
#include <string.h>
 
 
int main()
{
   const char haystack[20] = "RUNOOB";
   const char needle[10] = "NOOB";
   char *ret;
 
   ret = strstr(haystack, needle);
 
   printf("子字符串是: %s\n", ret);
   
   return(0);
}

让我们编译并运行上面的程序,这将产生以下结果:

子字符串是: NOOB

4.3ESP8266_ATSendString()函数

描述:向ESP8266发送字符串

声明:

void ESP8266_ATSendString(char* str);

参数:

str:发送的字符串

定义:

void ESP8266_ATSendString(char* str)
{
  memset(usart3_rxbuf,0, 256);
	
	//每次发送前将接收串口接收总数置0,为了接收
	usart3_rxcounter = 0;	
	
	//发送方法1
//	while(*str)		USART1_SendOneByte(*str++);
	
	//发送法法2
	HAL_UART_Transmit(&huart3,(uint8_t *)str,strlen(str),0xFFFF);
}

### 4.3ESP8266_ATSendString()函数

**描述**:向ESP8266发送字符串

**声明:**

```c
void ESP8266_ATSendString(char* str);

参数:

str:发送的字符串

定义:

void ESP8266_ATSendString(char* str)
{
  memset(usart3_rxbuf,0, 256);
	
	//每次发送前将接收串口接收总数置0,为了接收
	usart3_rxcounter = 0;	
	
	//发送方法1
//	while(*str)		USART1_SendOneByte(*str++);
	
	//发送法法2
	HAL_UART_Transmit(&huart3,(uint8_t *)str,strlen(str),0xFFFF);
}

完整的项目我放在我的百度网盘了

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值