WiFi通信——STM32通过ESP8266-01S上传DHT11温湿度和LED灯状态到阿里云物联网平台上(二)MQTT协议代码讲解

        上一篇博客讲了ESP8266-01S的MQTT固件包烧录过程,配置了阿里云物联网平台,并且利用MQTT.fx验证和阿里云通信的过程,链接如下:

https://blog.csdn.net/weixin_41011452/article/details/140645130

1 MQTT协议

        MQTT(Message Queuing Telemetry Transport, 消息队列遥测传输协议)是IBM在1999年发布的,基于TCP/IP提供网络连接,同时也有基于UDP的版本,称为MQTT-SN。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛,使其在物联网、小型设备、移动应用等方面有较广泛的应用。如果想了解大概原理,百度一大堆。我只讲解这个协议怎么用。

        MQTT协议是基于TCP/IP的,也就是网络分层里的应用层,它不能独立存在,必须附着于网络上,不像NB-IOT和4G可以自己创建网络,所以啊,MQTT就必须依赖于ESP8266-01S,通过wifi把数据收发。

        MQTT协议一共有两个版本,MQTT 3.1.1版本已经足够满足大多数物联网应用的需求,并且由于其广泛的兼容性和稳定性而被广泛使用。而MQTT 5.0版本则提供了更多的高级特性和改进,适用于需要更高性能和更复杂功能的场景。我们使用的是3.1.1版本。

MQTT 3.1.1协议英文原版的下载地址是:

https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/

英文不好的建议看中文,中文的协议的下载地址是:

https://mqtt.p2hp.com/mqtt311

        英文原版协议一共是80页的内容,不用从头看到尾,浪费时间还容易看了后面忘了前面,我读研的时候就这么干过。一般我们做嵌入式开发的,其实用到啥看啥就行了,用到的内容你去看协议里对应的部分就行,用不到的地方就别看了。

STM32通过ESP8266-01S连接阿里云其实用到MQTT的控制报文并不多,只有CONNECT、CONNACK、SUBSCRIBE、SUBACK、PINGRESP、PUBLISH、PINGREQ这七个控制报文。这七个报文在MQTT 3.1.1的控制协议说明书里有

1.1 CONNECT报文及其代码(其他报文和代码放在文末的视频链接讲解)

        MQTT协议的每一个报文都有固定的报头,就跟你看新闻热搜一样,热搜列出50条,那么每一条都要有标题,你只会根据标题是否感兴趣决定读不读这条热搜,MQTT也是一样,必须要有个固定的报头。

        固定报头都是两个字节的,第一个字节就是根据报文控制类型不同定义的,就是上面那个截图,比如CONNECT的第一个字节就是十进制1,换算成十六进制就是0x10;CONNACK的第一个字节就是十进制2,换算成十六进制就是0x2。

        第二个字节就是这条报文的剩余长度,从第三个字节才是可变报头或者有效载荷,报文并不都是有可变报头的,这个要看MQTT协议的每一个报文的具体说明,如果有可变报头那么第三个字节开始就是可变报头,如果没有可变报头,那么第三个字节就是有效载荷,载荷说白了就是你要传输的数据。

上面说了一堆我们要抽丝剥茧,刚刚也说了MQTT的每一个报文都有固定的两个字节报头,可变报头不一定每个报文都有,根据上面截图的CONNECT报文,可以看出它是有可变报头的,并且是有10个字节的可变报头,其中这10个字节的可变报头又分为:6个字节的协议名+1个字节的协议级别+1个字节的连接标志+2个字节的保持连接,所以CONNECT报文一共是12个字节,我们开始分析。

第一个字节(byte1):固定报头,固定为0001 0000,换算成十六进制就是0x10

第二个字节(byte2):固定报头,剩余长度,等于10个字节的可变报头加有效载荷

第三个字节(byte3):可变报头里的协议名的第一个字节,是协议名的长度高8位,固定为0000 0000,换算成十六进制就是0x00

第四个字节(byte4):可变报头里的协议名的第二个字节,是协议名的长度低8位,固定为0000 0100,换算成十六进制就是0x04

第五个字节(byte5):可变报头里的协议名的第三个字节,是协议名MQTT里的M,固定为0100 1101,换算成十六进制就是0x4D,其实就是字母M的ASCII码,请看下图

第六个字节(byte6):可变报头里的协议名的第四个字节,是协议名MQTT里的Q,固定为0101 0001,换算成十六进制就是0x51,其实就是字母Q的ASCII码

第七个字节(byte7):可变报头里的协议名的第五个字节,是协议名MQTT里的T,固定为0101 0100,换算成十六进制就是0x54,其实就是字母T的ASCII码

第八个字节(byte8):可变报头里的协议名的第六个字节,是协议名MQTT里的T,固定为0101 0100,换算成十六进制就是0x54,其实就是字母T的ASCII码

第九个字节(byte9):可变报头里的协议级别,如果是MQTT 3.1.1版本的协议,固定就是0x04,请看下图

第十个字节(byte10):可变报头里的连接标志,连接标志根据设置不同可以有不同的组合,我们的组合是使能用户名和密码校验,不使用遗嘱,不保留会话

第十一个字节(byte11):可变报头里的保持连接的高八位,我们的代码里设置的是0x00

第十二个字节(byte12):可变报头里的保持连接的低八位,我们的代码里设置的是0x64,换算成十进制就是100,也就是保持连接100秒

 在STM32中的代码如下所示,除此之外还有有效载荷,有效载荷就放在代码讲解放在文末的视频链接去讲解。

*----------------------------------------------------------*/
/*函数名:连接服务器报文                                    */
/*参  数:无                                                */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void MQTT_ConectPack(void)
{
    int temp,Remaining_len;

    Fixed_len = 1;                                                        //连接报文中,固定报头长度暂时先=1
    Variable_len = 10;                                                    //连接报文中,可变报头长度=10
    Payload_len = 2 + ClientID_len + 2 + Username_len + 2 + Passward_len; //连接报文中,负载长度
    Remaining_len = Variable_len + Payload_len;                           //剩余长度=可变报头长度+负载长度

    temp_buff[0]=0x10;                       //固定报头第1个字节 :固定0x10
    do {                                     //循环处理固定报头中的剩余长度字节,字节量根据剩余字节的真实长度变化
        temp = Remaining_len%128;            //剩余长度取余128
        Remaining_len = Remaining_len/128;   //剩余长度取整128
        if(Remaining_len>0)
            temp |= 0x80;                    //按协议要求位7置位
        temp_buff[Fixed_len] = temp;         //剩余长度字节记录一个数据
        Fixed_len++;	                     //固定报头总长度+1
    } while(Remaining_len>0);                 //如果Remaining_len>0的话,再次进入循环

    temp_buff[Fixed_len+0]=0x00;  //可变报头第1个字节 :固定0x00
    temp_buff[Fixed_len+1]=0x04;  //可变报头第2个字节 :固定0x04
    temp_buff[Fixed_len+2]=0x4D;	//可变报头第3个字节 :固定0x4D
    temp_buff[Fixed_len+3]=0x51;	//可变报头第4个字节 :固定0x51
    temp_buff[Fixed_len+4]=0x54;	//可变报头第5个字节 :固定0x54
    temp_buff[Fixed_len+5]=0x54;	//可变报头第6个字节 :固定0x54
    temp_buff[Fixed_len+6]=0x04;	//可变报头第7个字节 :固定0x04
    temp_buff[Fixed_len+7]=0xC2;	//可变报头第8个字节 :使能用户名和密码校验,不使用遗嘱,不保留会话
    temp_buff[Fixed_len+8]=0x00; 	//可变报头第9个字节 :保活时间高字节 0x00
    temp_buff[Fixed_len+9]=0x64;	//可变报头第10个字节:保活时间高字节 0x64   100s

    /*     CLIENT_ID      */
    temp_buff[Fixed_len+10] = ClientID_len/256;                			  			    //客户端ID长度高字节
    temp_buff[Fixed_len+11] = ClientID_len%256;               			  			    //客户端ID长度低字节
    memcpy(&temp_buff[Fixed_len+12],ClientID,ClientID_len);                 			//复制过来客户端ID字串
    /*     用户名        */
    temp_buff[Fixed_len+12+ClientID_len] = Username_len/256; 				  		    //用户名长度高字节
    temp_buff[Fixed_len+13+ClientID_len] = Username_len%256; 				 		    //用户名长度低字节
    memcpy(&temp_buff[Fixed_len+14+ClientID_len],Username,Username_len);                //复制过来用户名字串
    /*      密码        */
    temp_buff[Fixed_len+14+ClientID_len+Username_len] = Passward_len/256;			    //密码长度高字节
    temp_buff[Fixed_len+15+ClientID_len+Username_len] = Passward_len%256;			    //密码长度低字节
    memcpy(&temp_buff[Fixed_len+16+ClientID_len+Username_len],Passward,Passward_len);   //复制过来密码字串

    TxDataBuf_Deal(temp_buff, Fixed_len + Variable_len + Payload_len);                  //加入发送数据缓冲区
}

2 代码讲解

链接地址如下:STM32C8T6+DHT11+ESP8266-01S温湿度上传阿里云物联网平台代码讲解(一)_哔哩哔哩_bilibili

3 实现效果

因为我们的代码用串口1作为输出打印调试信息,所以把STM32的串口1连接到CH340上,然后插入电脑,打开串口助手,程序烧录成功上电后就可以接收数据了。可以看到连接路由器和连接服务器的记录,都是通过串口1打印出来的。

        连接成功后去 阿里云物联网平台查看数据是否上传成功,因为我用杜邦线接的线,STM32C8T6单片机模块5V的供电就一个,所以就没接DHT11,所以上传上来的数据始终是0,但是数据传输是没问题的,说明整个通信过程没问题。

4 资料获取

        我这个资料也是移植别人的,然后自己改的,网上好多的程序都是坑,移植完了如果自己不改根本没法用,所以需要辨别。想获取资料可以加我个人微信,有偿使用,白嫖的就算了。

  • 29
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以帮您完成这个项目。首先,您需要准备以下物品:Arduino UNO开发板、DHT11传感器和ESP8266-01S模块。然后,您可以按照以下步骤进行操作: 1. 将DHT11传感器连接到Arduino开发板上。具体连接方式如下: - 将DHT11中的VCC引脚连接到开发板上的5V电源引脚上。 - 将DHT11中的GND引脚连接到开发板上的GND引脚上。 - 将DHT11中的数据引脚连接到开发板上的数字引脚2上。 2. 编写Arduino代码,用于采集温湿度数据。可以使用Adafruit提供的DHT库进行操作。将以下代码拷贝到Arduino IDE中并上传到开发板: ``` #include <DHT.h> #define DHTPIN 2 // DHT11连接到数字引脚2上 #define DHTTYPE DHT11 // DHT类型为DHT11 DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(9600); dht.begin(); } void loop() { float h = dht.readHumidity(); // 读取湿度 float t = dht.readTemperature(); // 读取温度(摄氏度) if (isnan(h) || isnan(t)) { Serial.println("读取温湿度数据失败!"); return; } Serial.print("湿度: "); Serial.print(h); Serial.print(" %\t"); Serial.print("温度: "); Serial.print(t); Serial.println(" 度C"); delay(2000); // 2秒钟采集一次 } ``` 3. 配置ESP8266-01S模块,用于连接到阿里云。具体操作如下: - 下载并安装Arduino ESP8266开发环境(https://github.com/esp8266/Arduino)。 - 在Arduino IDE中,选择ESP8266开发板型号,并选择串口。 - 在Arduino IDE中,打开示例程序“ESP8266WiFi / WiFiClient”,并按照要求填写WiFi名称和密码。 - 在程序中添加以下代码,用于连接到阿里云上传数据: ``` #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <PubSubClient.h> // WiFi网络信息设置 const char* ssid = "your_SSID"; const char* password = "your_PASSWORD"; // 阿里云IoT平台信息设置 const char* mqtt_server = "your_mqtt_server"; const int mqtt_port = 1883; const char* mqtt_user = "your_mqtt_user"; const char* mqtt_password = "your_mqtt_password"; const char* mqtt_clientID = "your_mqtt_clientID"; // WiFi客户端 WiFiClient espClient; // MQTT客户端 PubSubClient client(espClient); // DHT11连接到数字引脚2上 #define DHTPIN 2 // DHT类型为DHT11 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); void setup() { // 初始化串口 Serial.begin(9600); // 初始化DHT11传感器 dht.begin(); // 连接WiFi网络 WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); // 连接MQTT服务器 client.setServer(mqtt_server, mqtt_port); while (!client.connected()) { if (client.connect(mqtt_clientID, mqtt_user, mqtt_password)) { Serial.println("MQTT connected"); } else { Serial.print("failed with state "); Serial.print(client.state()); delay(2000); } } } void loop() { float h = dht.readHumidity(); // 读取湿度 float t = dht.readTemperature(); // 读取温度(摄氏度) if (isnan(h) || isnan(t)) { Serial.println("读取温湿度数据失败!"); return; } Serial.print("湿度: "); Serial.print(h); Serial.print(" %\t"); Serial.print("温度: "); Serial.print(t); Serial.println(" 度C"); // 将温湿度数据上传阿里云 char message[50]; snprintf(message, 50, "{\"temperature\":\"%.1f\",\"humidity\":\"%.1f\"}", t, h); Serial.print("Publish message: "); Serial.println(message); client.publish("/your_topic", message); delay(2000); // 2秒钟采集一次 } ``` 4. 修改程序中的WiFi网络信息和阿里云IoT平台信息。 5. 将ESP8266-01S模块连接到Arduino开发板上,并上传程序到开发板。 以上是基于Arduino UNO开发板,使用DHT11采集温湿度数据,并通过ESP8266-01S模块将温湿度数据上传阿里云的一些基本操作,希望能够帮到您!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值