---
title: "W5500 Aliyun MQTT Porting based on STM32F103"
url: "https://maker.wiznet.io/chen/projects/W5500-Aliyun-MQTT-Porting-based-on-STM32F103/"
markdown_url: "https://maker.wiznet.io/chen/projects/W5500-Aliyun-MQTT-Porting-based-on-STM32F103/md"
type: "UCC: User Created Content"
author: "chen"
author_url: "https://maker.wiznet.io/chen/"
original_author: "chen"
original_url: "https://blog.csdn.net/wicevi/article/details/108044141?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.highlightwordscore&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.highlightwordscore"
published: "2022-07-04"
language: "en"
hardware: ["WIZnet W5500", "stm32f103"]
likes: 0
views: 375
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# W5500 Aliyun MQTT Porting based on STM32F103

> W5500 Aliyun MQTT Porting based on STM32F103

Original author: chen (source: https://blog.csdn.net/wicevi/article/details/108044141?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.highlightwordscore&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.highlightwordscore)

## Components

- **WIZnet W5500** x 1 ([docs](https://docs.wiznet.io/Product/Chip/Ethernet/W5500))
- **stm32f103** x 1
- Software: **aliyun**
- Software: **MQTT**

WIZnet parts: W5500 ([Datasheet](https://docs.wiznet.io/Product/Chip/Ethernet/W5500/datasheet?utm_source=maker&utm_medium=project&utm_campaign=w5500), [product hub](https://maker.wiznet.io/products/w5500/))

## Documents and links

- [demo code](https://download.csdn.net/download/wicevi/12719521) (code)

## Article

一、MQTT?? MQTT是一?基于客?端-服?器的消息?布/??????。MQTT??是?量、??、?放和易于??的，?些特点使?适用范?非常?泛。在?多情?下，包括受限的?境中，如：机器?机器（M2M）通信和物??（IoT）。其在，通??星?路通信?感器、偶???的????、智能家居、及一些小型化??中已?泛使用。 ??MQTT??需要客?端和服?器端通?完成，在通??程中，MQTT??中有三?身?：?布者（Publish）、代理（Broker）（服?器）、??者（Subscribe）。其中，消息的?布者和??者都是客?端，消息代理是服?器，消息?布者可以同?是??者。 在?里我???使用STM32F103+W5500作?客?端，????布和??消息。 二、???境 硬件??：stm32f103c8t6+w5500 ???件：Keil MDK 525 云平台：阿里云 相??接：STM32芯片?料 w5500芯片?料 阿里云 三、云端准? 以aliyun??直接?入IoT控制台，如果??有?通阿里云物??套件服?，?申??通 ?通完后，?建一?自定??品? 之后再添加一????? 名?默??空就好 添加好之后点?去?看??，?取???的????（ProductKey、DeviceName、DeviceSecret），后面?用到 之后再去?品那??看自定?Topic列表，默?有一??布和一???的Topic，?${deviceName}替?成上一?步??取的DeviceName然后保存，后面?用到，到?里??所需的云端就准?好了 四、移植和?? 先去W5500官?下???的例程下?，我?只需要提取其MQTT的?文件，至于?那?MQTT_CON_ALI函???就不要了，封?可?性太差了，感??例程就是?出?了的(￣o￣) ?以上?文件添加到工程之后，就可以?始?行封?了 ?建一?新的文件 mqtt_api.c ?MQTT?文件和W5500?文件?明?入 #include "mqtt_api.h" #include "MQTTPacket.h" #include "w5500api.h" #include &lt;stdlib.h> #include &lt;stdint.h> #include &lt;string.h> 新建一?函? ?判???的?据包?型，?入接收到的?据 返回?据包?型 /**解析收到的ACK?文*/ int mqtt_decode_msg(unsigned char*buf) { int rc = -1; MQTTHeader header = {0}; header.byte = buf[0]; rc = header.bits.type; return rc; } MQTT包?型?明在MQTTPacket.h 文件里 enum msgTypes { CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, PINGREQ, PINGRESP, DISCONNECT }; 然后??Connect函?，W5500有8?SOCKET，函?可以根据需求?入不同的SOCKET建立多??接（?SOCKET必??于SOCK_ESTABLISHED??） ?函?主要是?接?接?文，MQTTPacket_connectData???置好之后通?MQTTSerialize_connect函??接 然后通?socket?送?服?器，??要注意的是 不同云平台??的字段和方法不同，需根据具?情?更改，??只介?阿里云平台的方法： > data.clientID.cstring="$clientId|securemode=3,signmethod=hmacsha1,timestamp=789|";//$clientId?是客?端自表示id,建?mac或sn,64字符? 其?三???分?是安全模式【可??有2(TLS直?模式)、3(TCP直?模式)】、?名算法?型、??截 > data.keepAliveInterval =180;//保活?? 阿里云?定必?大于60 ?位：秒 > data.cleansession=1;//??志置1服?器必???之前保持的客?端的信息 > data.username.cstring="$deviceName&$productKey";//$deviceName和$productKey?????里的 > data.password.cstring=hmacsha1($deviceSecret,$content);//$deviceSecret??????里的 $content?productKey，deviceName,timestamp,clientId按照手母?序排序，然后????依次?接例如： > clientId192.168.207.115deviceNameMQTT1productKeyTKKMt4nMF8Utimestamp789 //?接MQTT服?器函? uint8 connectMqtt(SOCKET Socket){ int len,rc,wait_ack_time=0; MQTTPacket_connectData data = MQTTPacket_connectData_initializer;//配置部分可??部的? data.clientID.cstring = mqttClientId; //客?端??，用于?分每?客?端 data.keepAliveInterval = keepalive; //保活??器，定?了服?器收到客?端消息的最大???隔 data.cleansession = cleansession; //??志置1服?器必???之前保持的客?端的信息，???接??“不存在” data.username.cstring = mqttUsername; data.password.cstring = password; memset(buf,0,buflen); len = MQTTSerialize_connect(buf, buflen, &data); /*1 ?造?接?文*/ rc = send(Socket,buf,len); //?送?接?求 if(rc != len) { printf("Send Connect Error: rc=%d len=%dnr",rc,len); return 1; } //循??取Connect Ack do{ delay_ms(10); len=getSn_RX_RSR(Socket); wait_ack_time++; if(wait_ack_time>MAX_OVERTIME) { printf("Wait CONNACK Overtimenr"); return 2; } }while(len&lt;=0); recv(Socket,buf,len);//接收?据 判?是否?Connect Ack if(mqtt_decode_msg(buf)!=CONNACK){ printf("Error CONNACK:%snr",buf); return 3; } printf("Connect Is Ok:%srn",buf); return 0; } 接上之后 在keepAliveInterval???，我??需要和服?器之?至少得有一次?据??，不然??一到，服?器??客服端??。但是此?又?有消息需要?布或者主?需要???，??候就需要用到Ping了，由客?端向服?器?送一?空的Ping包 服?器回?PINGRESP，?相互通信一次，服?端的keepAliveInterval??也就更新了 //PING服?器 保持存活 uint8 pingMqtt(SOCKET Socket){ int len,rc,wait_ack_time=0; memset(buf,0,buflen); len=MQTTSerialize_pingreq(buf,buflen); rc=send(Socket,buf, len); if(len!=rc) { printf("Send Ping Error: rc=%d len=%dnr",rc,len); return 1; } do{ delay_ms(10); len=getSn_RX_RSR(Socket); wait_ack_time++; if(wait_ack_time>MAX_OVERTIME) { printf("Wait PINGRESP Overtimenr"); return 2; } }while(len&lt;=0); recv(Socket,buf,len); if(mqtt_decode_msg(buf) != PINGRESP){ printf("Error PINGRESP:%snr",buf); return 3; } printf("PING Successfully:%snr",buf); // if(len>2){ // if(mqtt_decode_msg(buf+2) == PUBLISH){ // dealMqtt(Socket,buf+2,buflen-2); // } // } return 0; } 然后是?布和??函? //MQTT?布消息函? uint8 publishMqtt(SOCKET Socket,char *pTopic,char *pMessage) { int len,rc,wait_ack_time=0; MQTTString topicString = MQTTString_initializer; int msglen = strlen(pMessage);//?算?布消息的?度 memset(buf,0,buflen); topicString.cstring = pTopic; len = MQTTSerialize_publish(buf, buflen, 0, 1, 0, 0, topicString, (unsigned char*)pMessage, msglen); /*2 ?造?布消息的?文*/ rc = send(Socket,buf,len); //?送消息 if (rc != len) { printf("Send Publish Error: rc=%d len=%dnr",rc,len); return 1; } do{ delay_ms(10); len=getSn_RX_RSR(Socket); wait_ack_time++; if(wait_ack_time>MAX_OVERTIME) { printf("Wait PUBACK Overtimenr"); return 2; } }while(len&lt;=0); recv(Socket,buf,len); if(mqtt_decode_msg(buf) != PUBACK){ printf("error PUBACK:%snr",buf); return 3; } printf("Publish Successfully:%snr",buf); return 0; } //MQTT??函? uint8 subscribMqtt(SOCKET Socket,char *pTopic) { int len,rc,wait_ack_time=0; MQTTString topicString = MQTTString_initializer; int msgid = 1; //???消息??符 int req_qos = 1; memset(buf,0,buflen); topicString.cstring = pTopic; len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos);//?造??主??文 rc = send(Socket,buf,len); //?送消息 if (rc != len) { printf("Send Subscrib Error: rc=%d len=%dnr",rc,len); return 1; } do{ delay_ms(10); len=getSn_RX_RSR(Socket); wait_ack_time++; if(wait_ack_time>MAX_OVERTIME) { printf("Wait SUBACK Overtimenr"); return 2; } }while(len&lt;=0); recv(Socket,buf,len); if(mqtt_decode_msg(buf) != SUBACK){ printf("Error SUBACK:%snr",buf); return 3; } SUB_FLAG=1; printf("Subscrib Successfully:%snr",buf); return 0; } 注意：???布包?建函?（MQTTSerialize_publish）的????需要注意一下，函?的原型是在MQTTSerializePublish.c 里面 /** * Serializes the supplied publish data into the supplied buffer, ready for sending * @param buf the buffer into which the packet will be serialized * @param buflen the length in bytes of the supplied buffer * @param dup integer - the MQTT dup flag * @param qos integer - the MQTT QoS value * @param retained integer - the MQTT retained flag * @param packetid integer - the MQTT packet identifier * @param topicName MQTTString - the MQTT topic in the publish * @param payload byte buffer - the MQTT publish payload * @param payloadlen integer - the length of the MQTT payload * @return the length of the serialized data. &lt;= 0 indicates error */ int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,MQTTString topicName, unsigned char* payload, int payloadlen); dup:其是用?在保?消息??可?的，如果?置?1，?在下面的???部里多加MessageId,?需要回???，保?消息??完成，但不能用于??消息重??送。 qos:主要用于PUBLISH（?布?）消息的，保?消息??的次?。0：至多一次 1：至少一次，如果?置?0，?服?器收到之后不?返回PUBACK retained：主要用于PUBLISH(?布?)的消息，表示服?器要保留?次推送的信息，如果有新的??者出?，就把?消息推送??。如果不?那?推送至?前??的就?放了。 packetid：也就是MessageId ?送的函?基本都封?完了，接下?就是接收??消息的函?了，??是在Socket有消息?的?候?消息?型?行判?，如果是PUBLISH?据包，?用??消息解析?理 //MQTT?理??消息函? void dealPublish(SOCKET Socket,uint8 *msgbuf,uint16 msglen){ //?取??消息??// unsigned char dup; int qos; unsigned char retained; unsigned short mssageid; int payloadlen_in; unsigned char* payload_in; MQTTString receivedTopic; / int len,rc; MQTTDeserialize_publish(&dup, &qos, &retained, &mssageid, &receivedTopic, &payload_in, &payloadlen_in, msgbuf, msglen); printf("message id: %dnr",mssageid); printf("message qos: %dnr",qos); printf("message receivedTopic: %snr",receivedTopic.lenstring.data); printf("message arrived[%d]: %snr", payloadlen_in, payload_in); if(qos>0){//需要回? len = MQTTSerialize_puback(buf, buflen, mssageid);//?造ack?文 rc = send(Socket,buf,len); //?送消息 if(len!=rc)printf("Send PUBACK Error: rc=%d len=%dnr",rc,len); } } //?行函? 需循??用 uint8 do_mqtt(SOCKET Socket,uint8 *sip,uint16 sport,uint16 lport){ static uint8 CONNECT_FLAG = 0; uint16 rlen; switch(getSn_SR(Socket)){ case SOCK_INIT: connect(Socket,sip,sport); break; case SOCK_ESTABLISHED: if(getSn_IR(Socket)&Sn_IR_CON)setSn_IR(Socket,Sn_IR_CON); if(!CONNECT_FLAG)if(!connectMqtt(Socket))CONNECT_FLAG=1; rlen=getSn_RX_RSR(Socket); if(rlen>0){ recv(Socket,buf,rlen); switch(mqtt_decode_msg(buf)){ case PUBLISH: dealPublish(Socket,buf,rlen); break; default: printf("recv:%s",buf); break; } } break; case SOCK_CLOSE_WAIT: disconnect(Socket); close(Socket); break; case SOCK_CLOSED: CONNECT_FLAG=0; socket(Socket,Sn_MR_TCP,lport,Sn_MR_ND); break; } return CONNECT_FLAG; } 到此就封?全封?好了，可以同?八?socket都??或者?布不同的主?，只需要改?一下???可，注意：阿里云平台的? 端口是1883 域名每?地?不同 具?官??看 while(1){ cnt_flag=do_mqtt(MQTT_SOCK,NET_CONFIG.rip,1883,5500); if(cnt_flag==0){sub_flag=0;sup_flag=0;time=0;} if(cnt_flag&&sub_flag==0)sub_flag=!subscribMqtt(MQTT_SOCK,subTopic); if(cnt_flag&&sub_flag&&sup_flag==0)sup_flag=!publishMqtt(MQTT_SOCK,pubTopic,"?接上的一????布消息"); if(cnt_flag)time++; if(time==5000){ time=0; pingMqtt(MQTT_SOCK); } delay_ms(10); } ?始?? 在???出中可以看到???接???和?布成功了，看看阿里云平台 成功上???布了一?消息和一?主?，接下?往??的主?推送消息 成功送?！！ ?格???不算是移植最多就是封??接口，官方例程那?是在太?了，所以????整理了一下，也?便理一理代?和通信流程，收??是?多的的(??? )，Dome后面整理完?出。 Dome:https://download.csdn.net/download/wicevi/12719521

---

Source: https://maker.wiznet.io/chen/projects/W5500-Aliyun-MQTT-Porting-based-on-STM32F103/
