stm32连接EMQX上云之ESP01s

stm32连接EMQX上云之ESP01s

1、下载MQTT固件烧录到esp8266

下载链接:https://pan.baidu.com/s/1cpC7kKuWKyll242xaOq96A?pwd=gs2w

2、用到的库以及一些定义

  • 将宏定义需要替换的WIFI命名和密码替换

  • 配置设备的ID,用户名和密码

  • 服务器的IP和端口

  • 包头和包尾

#include "stm32f10x.h"                 // Device header
#include "ESP8266.h" 
#include "Usart.h"
#include "Delay.h"
#include "OLED.h"
#include <string.h>
#include <stdio.h>
#include "LED.h"

#define ESP8266_WIFI_INFO				"AT+CWJAP=\"WIFI名\",\"WIFI密码\"\r\n"
#define ESP8266_MQTT_USERINFO   "AT+MQTTUSERCFG=0,1,\"用户ID\",\"用户名\",\"用户密码\",0,0,\"\"\r\n"
#define ESP8266_MQTT_INFO  			"AT+MQTTCONN=0,\"服务器IP\",1883,0\r\n"

#define HEAD "<HEAD>"
#define TAIL "<TAIL>"

uint8_t ESP8266_Buf[100];
uint16_t ESP8266_Cnt,ESP8266_CntPre;

3、ESP8266初始化

这一部分就是通过AT指令连接WIFI,连接到自己服务器搭建的EMQX.

*ESP866的初始化*/
void ESP8266_Init(void)
{
	ESP8266_Clear();
	UsartPrintf(USART_DEBUG, " 1.AT+RST\r\n");
	OLED_Clear();
	OLED_ShowString(1,1,"1.AT+RST...");
	while(ESP8266_SendCmd("AT+RST\r\n","OK"))
		Delay_ms(1000);
	
	UsartPrintf(USART_DEBUG, "2. CWMODE\r\n");
	OLED_ShowString(2,1,"2.CWMODE...");
	while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
		Delay_ms(1000);
	
	UsartPrintf(USART_DEBUG, "3. AT+CWDHCP\r\n");
	OLED_ShowString(3,1,"3.AT+CWDHCP...");
	while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
		Delay_ms(200);
	
	UsartPrintf(USART_DEBUG, "4. CWJAP\r\n");
	OLED_ShowString(4,1,"4.CWJAP...");
	while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
		Delay_ms(200);
	
	UsartPrintf(USART_DEBUG, "Try Config MQTT\r\n");
	OLED_Clear();
	OLED_ShowString(1,1,"Try Config MQTT");
	while(ESP8266_SendCmd(ESP8266_MQTT_USERINFO, "OK"))
		Delay_ms(300);
	
	UsartPrintf(USART_DEBUG, "Try Connect MQTT\r\n");
	OLED_ShowString(2,2,"Try Connect MQTT...");
	while(ESP8266_SendCmd(ESP8266_MQTT_INFO, "OK"))
		Delay_ms(300);
	
	UsartPrintf(USART_DEBUG, "ESP8266 Init OK\r\n");
	OLED_Clear(); 
	OLED_ShowString(1,1,"ESP8266 Init OK"); 
	Delay_ms(200);
}

在这个函数中有一个频繁用到的函数,主要是用来判断发送AT指令后返回的值是否正确,如果返回值不是所期望的那样就会重新发送

/*向ESP8266发送指令校验*/
_Bool ESP8266_SendCmd(char *cmd,char *res)
{
	uint8_t timeout = 200;
	
	Usart_SendString(USART2,(uint8_t *)cmd,strlen((const char *)cmd));
//	UsartPrintf(USART_DEBUG,"send success");
	while(timeout--)
	{//在这循环200次等待数据收发完毕
		if(ESP8266_WaitReceive() == REV_OK)
		{
			if(strstr((const char *)ESP8266_Buf,res) != NULL)//用于检查收到的回应是否正确
			{
//				UsartPrintf(USART_DEBUG, "REV_OK\r\n");
				ESP8266_Clear();
				return 0;
			}
		}
		Delay_ms(10);
//		UsartPrintf(USART_DEBUG, "REV_Wait\r\n");
	}
	return 1;
}

清除缓冲区以及判断数据是否收发完毕的函数也给上

/*清空ESP8266缓冲区*/
void ESP8266_Clear(void)
{
	memset(ESP8266_Buf, 0, sizeof(ESP8266_Buf));//将ESP8266Buf区的所有字节均设置为0
	ESP8266_Cnt = 0;
	ESP8266_CntPre = 0;
}
/*判断数据是否收发完毕*/
_Bool ESP8266_WaitReceive(void)
{
	if(ESP8266_Cnt == 0)
		return REV_WAIT;
	if(ESP8266_Cnt == ESP8266_CntPre)
		return REV_OK;
	ESP8266_CntPre = ESP8266_Cnt;//每次调用此函数都会把Cnt的值赋给CntPre,一旦相等说明数据收发完毕
	return REV_WAIT;
}

3、ESP8266订阅主题

通过简单的AT指令即可实现订阅主题,函数传参为订阅名称和通话质量

/*ESP8266通过mqtt订阅Topic*/
void ESP8266_Subscribe(char *topic,uint8_t Qos)
{
	char Sub_Buf[30]; 
	sprintf(Sub_Buf,"AT+MQTTSUB=0,\"%s\",%u\r\n",topic,Qos);
	while(ESP8266_SendCmd(Sub_Buf,"OK"))
		Delay_ms(100);
	UsartPrintf(USART_DEBUG,"%s SUB OK\n",topic);
}

4、ESP8266发布消息

ESP8266通过AT指令发布消息,总共4个参数,第一个是要发送的主题名,另外三个是我需要用到的数据。(注:其实也可以将需要的数据存放到一个数组中,这样的话就只用定义一个指针就可以了)

/*ESP8266通过MQTT发布消息*/
void ESP8266_SendData(char *topic,uint8_t temp,uint8_t humi,uint8_t led)//
{
	char Send_Buf[100];
	sprintf(Send_Buf,"AT+MQTTPUB=0,\"%s\",\"Temp:%u  humi:%u  Led: %s\",0,0\r\n",topic,temp,humi,led==1?"ON ":"OFF");
	while(ESP8266_SendCmd(Send_Buf, "OK"))
		Delay_ms(300);
	UsartPrintf(USART2,"AT+MQTTPUB=0,\"ESP8266\",\"1234\",0,0\r\n");
	
}

5、ESP8266接收订阅消息

ESP8266通过上方的订阅函数订阅了主题后,就会收到来自那个主题的消息。我采用的方法是我会将串口ESP8266接收到所有消息放到一个Buf区中,然后解析这个Buf区就可以得到我所需要的数据。解析的函数如下,我截取了包头包尾之间的我需要的数据,包头包尾,在前方直接宏定义了

/*ESP8266接受订阅消息*/
void ESP8266_RecData(char *Buf,int Size)
{
	int HeadFound = 0;
	int HeadIndex = -1;
	int TailIndex = -1;
	
	for(int i = 0;i < Size;i++)
	{
		if(strncmp(&Buf[i],HEAD,strlen(HEAD)) == 0)
		{
			HeadFound = 1;
			HeadIndex = i;
			i += strlen(HEAD) - 1;//跳过包头再遍历包尾
		}
		
		if(HeadFound && strncmp(&Buf[i],TAIL,strlen(TAIL)) == 0)
		{
			TailIndex = i;
			break;//跳出for循环
		}
	}
	if(HeadFound && TailIndex != -1)
	{
		int packetsize = TailIndex - HeadIndex - strlen(HEAD);
		char packet[packetsize + 1];
		strncpy(packet,&Buf[HeadIndex + strlen(HEAD)],packetsize);
		packet[packetsize] = '\0';
//		UsartPrintf(USART_DEBUG,packet);
		ESP8266_Clear();
		if(strstr(packet,"LED ON") != NULL)
		{
			LED_Control(LED_ON);
		}
		else if(strstr(packet,"LED OFF") != NULL)
		{
			LED_Control(LED_OFF);
		}
	}
	else
	{
//		UsartPrintf(USART_DEBUG,"未找到完整字符串\n");
	}
}

在这一部分用到了较多的String库中的函数,有兴趣可以了解一下。

6、串口中断函数

/*串口2的中断函数*/
void USART2_IRQHandler(void)
{
	if(USART_GetITStatus(USART2,USART_IT_RXNE) == SET)
	{
		if(ESP8266_Cnt >= sizeof(ESP8266_Buf))
			ESP8266_Cnt = 0;
		ESP8266_Buf[ESP8266_Cnt++] = USART_ReceiveData(USART2);
		USART_ClearFlag(USART2,USART_FLAG_RXNE);
	}
}

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值