不封装AT指令和MQTT协议,单片机还想实现物联网?开源

Posted kasami_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不封装AT指令和MQTT协议,单片机还想实现物联网?开源相关的知识,希望对你有一定的参考价值。

《物联网中你需要了解的ESP8266最基本的知识!》《每谈及物联网都难以离开的MQTT协议!》中,我们使用了模拟的方式让ESP8266通过AT指令加入云服务器和MQTT接入云服务器。但是我们实际使用时中却不能模拟的,不可能每一步都得自己调,这样的话毫无疑问会非常的麻烦。那么我们必须把这些指令和操作写在程序中,让其自动、智能地运行。

以下是我们将AT指令和MQTT协议在单片机封装的C语言程序的过程。当我们需要实现某个功能的时候,引用函数即可。

STM32源码下载地址:https://github.com/Liangyz2019/IoT-LED-STM32-

本例程采用了USART2与ESP8266相连,并使用了HAL库编写。

AT指令封装



//usart2发送和接收数组
uint8_t usart2_txbuf[256];
uint8_t usart2_rxbuf[512];
uint8_t usart2_rxone[1];
uint8_t usart2_rxcounter;


//串口2发送一个字节
static void USART2_SendOneByte(uint8_t val)
{
	((UART_HandleTypeDef *)&huart2)->Instance->DR = ((uint16_t)val & (uint16_t)0x01FF);
	while((((UART_HandleTypeDef *)&huart2)->Instance->SR&0X40)==0);//等待发送完成
}


//向ESP8266发送定长数据
void ESP8266_ATSendBuf(uint8_t* buf,uint16_t len)
{
	memset(usart2_rxbuf,0, 256);
	
	//每次发送前将接收串口接收总数置0,为了接收
	usart2_rxcounter = 0;	
	
	//定长发送
	HAL_UART_Transmit(&huart2,(uint8_t *)buf,len,0xFFFF);
}

//向ESP8266发送字符串
void ESP8266_ATSendString(char* str)
{
  memset(usart2_rxbuf,0, 256);
	
	//每次发送前将接收串口接收总数置0,为了接收
	usart2_rxcounter = 0;	
	
	//发送方法1
	while(*str)		USART2_SendOneByte(*str++);
	
	//发送法法2
//	HAL_UART_Transmit(&huart2,(uint8_t *)str,strlen(str),0xFFFF);
}

//退出透传
void ESP8266_ExitUnvarnishedTrans(void)
{
	ESP8266_ATSendString("+++");HAL_Delay(50);
	ESP8266_ATSendString("+++");HAL_Delay(50);	
}

//查找字符串中是否包含另一个字符串
uint8_t FindStr(char* dest,char* src,uint16_t retry_nms)
{
	retry_nms/=10;                   //超时时间

	while(strstr(dest,src)==0 && --retry_nms)//等待串口接收完毕或超时退出
	{		
		HAL_Delay(10);
	}

	if(retry_nms) return 1;                       

	return 0; 
}


uint8_t ESP8266_Check(void)
{
	uint8_t check_cnt=5;
	while(check_cnt--)
	{
		memset(usart2_rxbuf,0,sizeof(usart2_rxbuf)); 	 //清空接收缓冲
		ESP8266_ATSendString("AT\\r\\n");     		 			//发送AT握手指令	
		if(FindStr((char*)usart2_rxbuf,"OK",200) != 0)
		{
			return 1;
		}
	}
	return 0;
}




void ESP8266_Restore(void)
{
	ESP8266_ExitUnvarnishedTrans();          	//退出透传
  HAL_Delay(500);
	ESP8266_ATSendString("AT+RESTORE\\r\\n");		//恢复出厂 	
}



//开启透传模式
static uint8_t ESP8266_OpenTransmission(void)
{
	//设置透传模式
	uint8_t cnt=2;
	while(cnt--)
	{
		memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));    
		ESP8266_ATSendString("AT+CIPMODE=1\\r\\n");  
		if(FindStr((char*)usart2_rxbuf,"OK",200)!=0)
		{	
			return 1;
		}
	}
	return 0;
}




uint8_t DisconnectServer(void)
{
	uint8_t cnt;
	
	ESP8266_ExitUnvarnishedTrans();	//退出透传
	HAL_Delay(500);
	
	while(cnt--)
	{
		memset(usart2_rxbuf,0,sizeof(usart2_rxbuf)); //清空接收缓冲   
		ESP8266_ATSendString("AT+CIPCLOSE\\r\\n");//关闭链接

		if(FindStr((char*)usart2_rxbuf,"CLOSED",200)!=0)//操作成功,和服务器成功断开
		{
			break;
		}
	}
	if(cnt) return 1;
	return 0;
}

ESP8266初始化


uint8_t ESP8266_Init(void)
{
	//清空发送和接收数组
	memset(usart2_txbuf,0,sizeof(usart2_txbuf));
	memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));
	
	ESP8266_ExitUnvarnishedTrans();		//退出透传
	HAL_Delay(500);
	ESP8266_ATSendString("AT+RST\\r\\n");
	HAL_Delay(800);
	if(ESP8266_Check()==0)              //使用AT指令检查ESP8266是否存在
	{
		return 0;
	}
	
	memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));    //清空接收缓冲
	ESP8266_ATSendString("ATE0\\r\\n");     	//关闭回显 
	if(FindStr((char*)usart2_rxbuf,"OK",500)==0)  //设置不成功
	{
			return 0;      
	}
	return 1;                         //设置成功
}

ESP8266连接热点


uint8_t ESP8266_ConnectAP(char* ssid,char* pswd)
{
	uint8_t cnt=5;
	while(cnt--)
	{
		memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));     
		ESP8266_ATSendString("AT+CWMODE=1\\r\\n");              //设置为STATION模式	
		if(FindStr((char*)usart2_rxbuf,"OK",200) != 0)
		{
			break;
		}             		
	}
	if(cnt == 0)
		return 0;

	cnt=2;
	while(cnt--)
	{                    
		memset(usart2_txbuf,0,sizeof(usart2_txbuf));//清空发送缓冲
		memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));//清空接收缓冲
		sprintf((char*)usart2_txbuf,"AT+CWJAP=\\"%s\\",\\"%s\\"\\r\\n",ssid,pswd);//连接目标AP
		ESP8266_ATSendString((char*)usart2_txbuf);	
		if(FindStr((char*)usart2_rxbuf,"OK",8000)!=0)                      //连接成功且分配到IP
		{
			return 1;
		}
	}
	return 0;
}

ESP8266连接阿里云服务器


uint8_t ESP8266_ConnectServer(char* mode,char* ip,uint16_t port)
{
	uint8_t cnt;
   
	ESP8266_ExitUnvarnishedTrans();                   //多次连接需退出透传
	HAL_Delay(500);

	//连接服务器
	cnt=2;
	while(cnt--)
	{
		memset(usart2_txbuf,0,sizeof(usart2_txbuf));//清空发送缓冲
		memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));//清空接收缓冲   
		sprintf((char*)usart2_txbuf,"AT+CIPSTART=\\"%s\\",\\"%s\\",%d\\r\\n",mode,ip,port);
		ESP8266_ATSendString((char*)usart2_txbuf);
		if(FindStr((char*)usart2_rxbuf,"CONNECT",8000) !=0 )
		{
			break;
		}
	}
	if(cnt == 0) 
		return 0;
	
	//设置透传模式
	if(ESP8266_OpenTransmission()==0) return 0;
	
	//开启发送状态
	cnt=2;
	while(cnt--)
	{
		memset(usart2_rxbuf,0,sizeof(usart2_rxbuf)); //清空接收缓冲   
		ESP8266_ATSendString("AT+CIPSEND\\r\\n");//开始处于透传发送状态
		if(FindStr((char*)usart2_rxbuf,">",200)!=0)
		{
			return 1;
		}
	}
	return 0;
}

MQTT协议的封装

#include "esp8266_mqtt.h"
#include "esp8266_at.h"
//连接成功服务器回应 20 02 00 00
//客户端主动断开连接 e0 00
const uint8_t parket_connetAck[] = {0x20,0x02,0x00,0x00};
const uint8_t parket_disconnet[] = {0xe0,0x00};
const uint8_t parket_heart[] = {0xc0,0x00};
const uint8_t parket_heart_reply[] = {0xc0,0x00};
const uint8_t parket_subAck[] = {0x90,0x03};

volatile uint16_t MQTT_TxLen;

extern uint8_t usart2_txbuf[256];
extern uint8_t usart2_rxbuf[512];
extern uint8_t usart2_rxone[1];
extern uint8_t usart2_rxcounter;


//MQTT发送数据
void MQTT_SendBuf(uint8_t *buf,uint16_t len)
{
	ESP8266_ATSendBuf(buf,len);
}	

//发送心跳包
void MQTT_SentHeart(void)
{
	MQTT_SendBuf((uint8_t *)parket_heart,sizeof(parket_heart));
}

//MQTT无条件断开
void MQTT_Disconnect()
{
	MQTT_SendBuf((uint8_t *)parket_disconnet,sizeof(parket_disconnet));
}

//MQTT初始化
void MQTT_Init(uint8_t *prx,uint16_t rxlen,uint8_t *ptx,uint16_t txlen)
{
	memset(usart2_txbuf,0,sizeof(usart2_txbuf)); //清空发送缓冲
	memset(usart2_rxbuf,0,sizeof(usart2_rxbuf)); //清空接收缓冲
	
	//无条件先主动断开
	MQTT_Disconnect();HAL_Delay(100);
	MQTT_Disconnect();HAL_Delay(100);
}






ESP8266阿里云MQTT登陆

//MQTT连接服务器的打包函数
uint8_t MQTT_Connect(char *ClientID,char *Username,char *Password)
{
	int ClientIDLen = strlen(ClientID);
	int UsernameLen = strlen(Username);
	int PasswordLen = strlen(Password);
	int DataLen;
	MQTT_TxLen=0;
	//可变报头+Payload  每个字段包含两个字节的长度标识
  DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);
	
	//固定报头
	//控制报文类型
  usart2_txbuf[MQTT_TxLen++] = 0x10;		//MQTT Message Type CONNECT
	//剩余长度(不包括固定头部)
	do
	{
		uint8_t encodedByte = DataLen % 128;
		DataLen = DataLen / 128;
		// if there are more data to encode, set the top bit of this byte
		if ( DataLen > 0 )
			encodedByte = encodedByte | 128;
		usart2_txbuf[MQTT_TxLen++] = encodedByte;
	}while ( DataLen > 0 );
    	
	//可变报头
	//协议名
	usart2_txbuf[MQTT_TxLen++] = 0;        		// Protocol Name Length MSB    
	usart2_txbuf[MQTT_TxLen++] = 4;        		// Protocol Name Length LSB    
	usart2_txbuf[MQTT_TxLen++] = 'M';        	// ASCII Code for M    
	usart2_txbuf[MQTT_TxLen++] = 'Q';        	// ASCII Code for Q    
	usart2_txbuf[MQTT_TxLen++] = 'T';        	// ASCII Code for T    
	usart2_txbuf[MQTT_TxLen++] = 'T';        	// ASCII Code for T    
	//协议级别
	usart2_txbuf[MQTT_TxLen++] = 4;        		// MQTT Protocol version = 4    
	//连接标志
	usart2_txbuf[MQTT_TxLen++] = 0xc2;        	// conn flags 
	usart2_txbuf[MQTT_TxLen++] = 0;        		// Keep-alive Time Length MSB    
	usart2_txbuf[MQTT_TxLen++] = 60;        	// Keep-alive Time Length LSB  60S心跳包  

	usart2_txbuf[MQTT_TxLen++] = BYTE1(ClientIDLen);// Client ID length MSB    
	usart2_txbuf[MQTT_TxLen++] = BYTE0(ClientIDLen);// Client ID length LSB  	
	memcpy(&usart2_txbuf[MQTT_TxLen],ClientID,ClientIDLen);
	MQTT_TxLen += ClientIDLen;
	
	if(UsernameLen > 0)
	{   
		usart2_txbuf[MQTT_TxLen++] = BYTE1(UsernameLen);		//username length MSB    
		usart2_txbuf[MQTT_TxLen++] = BYTE0(UsernameLen);    	//username length LSB    
		memcpy(&usart2_txbuf[MQTT_TxLen],Username,UsernameLen);
		MQTT_TxLen += UsernameLen;
	}
	
	if(PasswordLen > 0)
	{    
		usart2_txbuf[MQTT_TxLen++] = BYTE1(PasswordLen);		//password length MSB    
		usart2_txbuf[MQTT_TxLen++] = BYTE0(PasswordLen);    	//password length LSB  
		memcpy(&usart2_txbuf[MQTT_TxLen],Password,PasswordLen);
		MQTT_TxLen += PasswordLen; 
	}    
	
	uint8_t cnt=2;
	uint8_t wait;
	while(cnt--)
	{
		memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));
		MQTT_SendBuf(usart2_txbuf,MQTT_TxLen);
		wait=30;//等待3s时间
		while(wait--)
		{
			//CONNECT
			if(usart2_rxbuf[0]==parket_connetAck[0] && usart2_rxbuf[1]==parket_connetAck[1]) //连接成功			   
			{
				return 1;//连接成功
			}
			HAL_Delay(100);			
		}
	}
	return 0;
}

ESP8266阿里云MQTT订阅主题

//MQTT订阅/取消订阅数据打包函数
//topic       主题 
//qos         消息等级 
//whether     订阅/取消订阅请求包
uint8_t MQTT_SubscribeTopic(char *topic,uint8_t qos,uint8_t whether)
{    
	MQTT_TxLen=0;
	int topiclen = strlen(topic);
	
	int DataLen = 2 + (topiclen+2) + 8-STM32物联网开发WIFI+GPRS基础篇(STM32+GPRS(AT指令)实现MQTT远程通信控制)

7-STM32物联网开发WIFI+GPRS基础篇(STM32+Wi-Fi(AT指令)实现MQTT远程通信控制)

ESA2GJK1DH1K基础篇: 阿里云物联网平台: 云平台显示单片机采集的温湿度数据,控制设备继电器(基于ESP8266,AT指令TCP_MQTT通信)(V1.0)

安信可NB-IoT模组EC系列AT指令应用笔记②MQTT接入阿里云

阿里云物联网平台配置ESP8266真实设备AT串口连接,支持MQTT协议通信

阿里云物联网平台配置ESP8266真实设备AT串口连接,支持MQTT协议通信