基于ZigBee的智能家居设计与实现—WiFi模块开发

本文详细介绍了ESP8266 ESP_01模块的引脚功能、AT指令使用,以及MQTT协议的报文格式。ESP8266初始化涉及关闭透传模式、检查存在性和关闭回显。连接WiFi热点和MQTT服务器的步骤包括设置工作模式、连接到指定热点和登录MQTT服务器。在MQTT协议实现中,重点讲解了订阅和发布消息的过程,包括构建连接请求、订阅和发布报文。通过STM32与ESP8266的交互,实现了数据传输。
摘要由CSDN通过智能技术生成

ESP8266简介

ESP_01引脚图

img

ESP_01引脚介绍

引脚功能工作时接线
3V33.3V供电,不要使用5V3.3V
RX串口接收端MCU:TX
RST外部复位引脚NC
IO0I/O口0,状态:悬空:Flash下载模式或工作模式;下拉:串口下载模式NC
EN使能端口:高电平工作,低电平不工作3.3V
IO2I/O口2,开机上电是禁止下拉,默认高电平NC
TX串口发送端MCU:RX
GND电源地线GND

ESP_01 AT指令简介

功能AT指令
工作模式设置AT+CWMODE=2 # 1-Station 模式,2-AP 模式,3-AP & Station 模式
重启AT+RST
查询周围热点AT+CWLAP
连接到热点AT+CWJAP=“HOTPOINT”,“1234”
查询已连接的热点AT+CWJAP?
查询自身IPAT+CIFSR
连接到TCP服务器AT+CIPSTART=“TCP”,“192.168.1.100”,8080
发送数据AT+CIPSEND=4 \n数据
开启透传模式AT+CIPMODE=1
开始透传AT+CIPSEND
退出透传+++

MQTT简介

MQTT协议部分报文格式

请求连接报文

请求连接报文格式

报文头
遗嘱主题
遗嘱消息
用户名
密码

连接请求报文头格式

BitsData说明
byte10x16固定报头
byte2剩余长度
byte1~byte5协议类型
byte70x04协议级别
byte8连接标志
byte9~byte10保持链接

协议类型格式

Bits76543210
MSB00000000
LSB00000100
M01001101
Q01010001
T01010100
T01010100

连接标志格式

byteUser Name FlagPassword FlagWill RetainWill QosWill QosWill FlagClaen SessionReserved

保持链接标志:两个字节的数据,代表的是连接心跳的时间。

链接标志格式

保持链接 Keep Alive MSB
保持链接 Keep Alive LSB

确认链接报文

确认链接报文格式

Bits76543210说明
byte100100000固定报头
byte200000010剩余长度
byte30000000Session Present连接确认标志
byte4xxxxxxxx连接返回码

订阅消息报文

订阅消息报文格式

Bits76543210说明
byte110000010固定报头
byte2剩余长度(最多4字节)
byte3-byte4报文标识符
bytex有效载荷

报文标识符格式

描述
报文标识符
byte1MSB(0)0x00
byte2LSB(0) 0x01

有效载荷格式

描述
主题过滤器
byte1长度MSB
byte2长度LSB
byte3~N主题过滤器 Topic Filter
服务质量要求
byteN+10 0 0 0 0 0 X X

订阅确认报文

订阅确认报文格式

Bits76543210说明
byte110010000固定报头
byte2剩余长度
byte3~byte4报文标识符
byteN有效载荷

返回码格式

描述76543210
返回码x00000xx

返回码取值说明:

  • 0x00:最大QoS 0
  • 0x01:成功—最大QoS 1
  • 0x02:成功—最大QoS 2
  • ox80:Failure失败

发表消息报文

发表消息报文格式

结构
固定报头
剩余最大长度
可变报头
发布消息的内容(有效载荷=剩余长度-可变报头长度)

固定报头格式

Bits76543210
byte10011DUPQoS-HQoS-Retain

可变报头

Bits说明
byte1主题名
byte2报文标识符(只有Qos等级为1/2时才有)

主题名格式

描述76543210
主题名
byte1length MSB00000000
byte2length LSB00000011
byte3a(0x61)
byte4/(0x2F)
byte5b(0x62)
报文标识符
byte6MSB(0)
byte7LSB(0)

发布确认

Bits76543210说明
byte101000000固定报头
byte200000010剩余长度
byte3~byte4可变报头

模块构成

ESP01与STM32的USART1相连,组成WiFi模块。STM32的USART2与ZigBee网络的协调器相连,实现网络之间数据传输。

MQTT协议实现

ESP—01实现 MQTT协议的步骤

  • 初始化ESP—01
  • 连接到WiFi热点
  • 连接到MQTT服务器
  • 登录MQTT
  • 订阅一个主题
  • 发布一条消息
  • 接收订阅的主题更新的消息

初始化ESP—01

  1. 退出透传模式
  2. 检查ESP—01是否存在
  3. 关闭uart回显
uint8_t ESP8266_Init(void)
{
	ESP8266_ExitUnvarnishedTrans();		//退出透传
	HAL_Delay(500);
	ESP8266_ATSendString("AT+RST\r\n");
	HAL_Delay(800);
	if(ESP8266_Check()==0)              //使用AT指令检查ESP8266是否存在
	{
		return 0;
	}
	ESP8266_ATSendString("ATE0\r\n");     	//关闭回显 
	if(FindStr((char*)usart1_rxbuf,"OK",500)==0)  //设置不成功
	{
		return 0;      
	}
	return 1;                         //设置成功
}

连接到WiFi热点

使用AT指令连接到既定的热点

连接到MQTT服务器

调用连接到TCP服务器的指令连接到MQTT服务器,端口号为1883

登录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);
	
	//固定报头
	//控制报文类型
  usart1_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;
		usart1_txbuf[MQTT_TxLen++] = encodedByte;
	}while ( DataLen > 0 );
    	
	//可变报头
	//协议名
	usart1_txbuf[MQTT_TxLen++] = 0;        		// Protocol Name Length MSB    
	usart1_txbuf[MQTT_TxLen++] = 4;        		// Protocol Name Length LSB    
	usart1_txbuf[MQTT_TxLen++] = 'M';        	// ASCII Code for M    
	usart1_txbuf[MQTT_TxLen++] = 'Q';        	// ASCII Code for Q    
	usart1_txbuf[MQTT_TxLen++] = 'T';        	// ASCII Code for T    
	usart1_txbuf[MQTT_TxLen++] = 'T';        	// ASCII Code for T    
	//协议级别
	usart1_txbuf[MQTT_TxLen++] = 4;        		// MQTT Protocol version = 4    
	//连接标志
	usart1_txbuf[MQTT_TxLen++] = 0xc2;        	// conn flags 
	usart1_txbuf[MQTT_TxLen++] = 0;        		// Keep-alive Time Length MSB    
	usart1_txbuf[MQTT_TxLen++] = 60;        	// Keep-alive Time Length LSB  60S心跳包  

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

订阅一个主题

报文格式同上节所示,有限等待后得到确认报文后就证明登录成功。

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:0);//可变报头的长度(2字节)加上有效载荷的长度
	//固定报头
	//控制报文类型
	if(whether) usart1_txbuf[MQTT_TxLen++] = 0x82; //消息类型和标志订阅
	else	usart1_txbuf[MQTT_TxLen++] = 0xA2;    //取消订阅

	//剩余长度
	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;
		usart1_txbuf[MQTT_TxLen++] = encodedByte;
	}while ( DataLen > 0 );	
	
	//可变报头
	usart1_txbuf[MQTT_TxLen++] = 0;				//消息标识符 MSB
	usart1_txbuf[MQTT_TxLen++] = 0x01;           //消息标识符 LSB
	//有效载荷
	usart1_txbuf[MQTT_TxLen++] = BYTE1(topiclen);//主题长度 MSB
	usart1_txbuf[MQTT_TxLen++] = BYTE0(topiclen);//主题长度 LSB   
	memcpy(&usart1_txbuf[MQTT_TxLen],topic,topiclen);
	MQTT_TxLen += topiclen;

	if(whether)
	{
		usart1_txbuf[MQTT_TxLen++] = qos;//QoS级别
	}
	
	uint8_t cnt=2;
	uint8_t wait;
	while(cnt--)
	{
		memset(usart1_rxbuf,0,sizeof(usart1_rxbuf));
		MQTT_SendBuf(usart1_txbuf,MQTT_TxLen);
		wait=30;//等待3s时间
		while(wait--)
		{
			if(usart1_rxbuf[0]==parket_subAck[0] && usart1_rxbuf[1]==parket_subAck[1]) //订阅成功			   
			{
				return 1;//订阅成功
			}
			HAL_Delay(100);			
		}
	}
	if(cnt) return 1;	//订阅成功
	return 0;
}

发送一条消息

报文格式同上节所示。

uint8_t MQTT_PublishData(char *topic, char *message, uint8_t qos)
{  
	int topicLength = strlen(topic);    
	int messageLength = strlen(message);     
	static uint16_t id=0;
	int DataLen;
	MQTT_TxLen=0;
	//有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度
	//QOS为0时没有标识符
	//数据长度             主题名   报文标识符   有效载荷
	if(qos)	DataLen = (2+topicLength) + 2 + messageLength;       
	else	DataLen = (2+topicLength) + messageLength;   

    //固定报头
	//控制报文类型
	usart1_txbuf[MQTT_TxLen++] = 0x30;    // MQTT Message Type PUBLISH  

	//剩余长度
	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;
		usart1_txbuf[MQTT_TxLen++] = encodedByte;
	}while ( DataLen > 0 );	
	
	usart1_txbuf[MQTT_TxLen++] = BYTE1(topicLength);//主题长度MSB
	usart1_txbuf[MQTT_TxLen++] = BYTE0(topicLength);//主题长度LSB 
	memcpy(&usart1_txbuf[MQTT_TxLen],topic,topicLength);//拷贝主题
	MQTT_TxLen += topicLength;
        
	//报文标识符
	if(qos)
	{
			usart1_txbuf[MQTT_TxLen++] = BYTE1(id);
			usart1_txbuf[MQTT_TxLen++] = BYTE0(id);
			id++;
	}
	memcpy(&usart1_txbuf[MQTT_TxLen],message,messageLength);
  MQTT_TxLen += messageLength;
        
	MQTT_SendBuf(usart1_txbuf,MQTT_TxLen);
  return MQTT_TxLen;
}

接收订阅的主题更新的消息

ESP—01收到数据后会通过串口发送到STM32,根据协议对数据进行拆包,将需要的数据进行转发。

结束语

以上介绍了ESP-01模块,使用到的ESP8266 的部分AT指令,MQTT协议的报文格式以及实际使用方法。关于MQTT协议的具体内容,我也是刚开始学习,如果有同学对于这里有问题或者有兴趣的话欢迎讨论学习。最后欢迎大神批评指导。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值