不封装AT指令和MQTT协议,单片机还想实现物联网?开源
Posted mini梁翊洲MAX
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) + (whether?1:08-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接入阿里云