日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

物联网学习之旅:微信小程序控制STM32(二)--ESP8266连接mqtt服务端

發布時間:2023/12/20 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 物联网学习之旅:微信小程序控制STM32(二)--ESP8266连接mqtt服务端 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ESP8266連接mqtt服務端

微信小程序控制STM32的第二步,就是要編寫ESP8266固件,來連接已經搭建好的物聯網服務器。也有別的方式,只要你足夠了解mqtt協議,可以通過使用ESP8266原生的AT指令來連接,因為ESP8266連接mqtt服務端中mqtt協議也是通過建立TCP連接,發送相應的協議報文來連接服務端。但是樂鑫官方提供的SDK中含有連接mqtt服務端的實例代碼,要做的就是根據自己的功能要求去修改代碼。
我修改的固件是ESP8266與STM32之間進行串口通信,以透傳的方式互相傳遞數據,然后ESP8266作為中轉把數據發到相應的目的地。

  • 硬件準備
    我用的是ESP8266-01這款模塊

    ESP8266有UART 下載模式和Flash 運行模式 ,接線不一樣的地方就是在下載模式時GPIO0要接低電平,運行模式時懸空即可,每次運行模式和下載模式切換都需要重啟一下模塊,才能第二次燒寫或者運行。

    我是采用這樣的連接方式來燒寫固件,運行程序時把GPIO0拔掉,然后拔掉esp8266的vcc線,然后又插上,重啟一下就可以了。燒寫的時候把GPIO0接共地端,然后拔掉esp8266的vcc線,然后又插上,重啟一下,就可以燒寫程序了。至于我為什么要用這么復雜的接線方式來燒寫程序,那是因為買這個esp8266調試器的時候,不懂,圖便宜(根本也是因為我太窮了,哈哈哈),然而這個用來運行調試是最合適的,直接插上去即可。不過這樣也能燒寫固件。也可以用TTL轉串口來燒寫,都是可以的,原理都一樣。
  • 搭建ESP8266開發環境
    進入安信可ESP8266 系列模組專題,按照開發環境搭建的步驟搭建開發環境。


    點擊藍色文字下載ESP8266_NONOS_SDK-v3.0.0,也可以選擇在樂鑫官網上下載最新版本的SDK,根據需要下載開發文檔,我用到了這兩個文檔。

    值得注意的是,本項目用到的是esp_mqtt_proj這個例程,所以在構建工程文件時,需要將examples/esp_mqtt_proj目錄工程目錄的頂層文件中,其它的按照安信可提供的步驟搭建即可,編譯沒有錯誤之后,其實example文件夾就可以刪除掉了,這個項目只用到mqtt部分,其它例程刪掉后編譯仍然是成功的。
  • 編寫ESP8266固件
    打開編譯通過的工程,需要修改的有這幾個地方
    1)user_main.c中修改
  • void mqttConnectedCb(uint32_t *args) {MQTT_Client* client = (MQTT_Client*)args;mqttclient=client;INFO("MQTT: Connected\r\n");MQTT_Subscribe(client, "Topic0", 0); //訂閱Topic0主題,用于接收微信小程序的數據MQTT_Publish(client, "Topic1", "hello1", 6, 0, 0); //發布消息//Topic0用于下行通道,Topic1用于上行通道 } void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) { //接收到數據時執行char *topicBuf = (char*)os_zalloc(topic_len+1),*dataBuf = (char*)os_zalloc(data_len+1);MQTT_Client* client = (MQTT_Client*)args;os_memcpy(topicBuf, topic, topic_len);topicBuf[topic_len] = 0;os_memcpy(dataBuf, data, data_len);dataBuf[data_len] = 0;os_printf("%s\r\n",dataBuf); //串口打印接收到的消息os_free(topicBuf);os_free(dataBuf); } MQTT_Client* mqttclient; //此指針會用在uart.c中

    2)uart.c中修改
    通過user_main.c文件中的uart_init()定位到uart.c文件,然后對這里面進行修改。首先需要引入user_main.c定義的“MQTT_Client* mqttclient;”,這樣下面在串口處理函數中,當從串口接收完數據之后,通過引入的mqtt客戶端指針,將數據發到特定的主題,然后別忘了引入“mqtt.h”,因為這里要用到這里面的函數,將數據發送出去。

    extern MQTT_Client* mqttclient;

    最后修改串口中斷處理函數。

    LOCAL void uart0_rx_intr_handler(void *para) {/* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents* uart1 and uart0 respectively*/uint8_t RcvChar[256];uint8_t uart_no = UART0;//UartDev.buff_uart_no;uint8_t fifo_len = 0;uint8_t buf_idx = 0;uint8_t temp, cnt;if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) {DBG1("FRM_ERR\r\n");WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);} else if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) {DBG("f");uart_rx_intr_disable(UART0);WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);system_os_post(uart_recvTaskPrio, 0, 0);} else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) { //檢測到是超時中斷fifo_len=(READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT; //獲取數據長度buf_idx=0;for(buf_idx=0;buf_idx<fifo_len;buf_idx++){RcvChar[buf_idx]=READ_PERI_REG(UART_FIFO(UART0))&0xFF; //將數據儲存起來}if(RcvChar[0]=='A'){ //接收到詢問是否初始化完成的消息if(mqttState==1){ //初始化完成了os_printf("1111\r\n"); //串口發送初始化完成,如果發送字母就會亂碼}else{os_printf("2222\r\n");}}if(RcvChar[0]=='{'){MQTT_Publish(mqttclient, "Topic1", RcvChar, fifo_len, 0, 0); //把接收到的數據發送到mqtt服務端}if(RcvChar[0]=='T'){os_printf("\r\ntime:%s\r\n", time);}os_memset(RcvChar,0,256); //清除數據WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR); //清除超時中斷狀態} else if (UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST)) {DBG("e");CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA); #if UART_BUFF_ENtx_start_uart_buffer(UART0); #endif//system_os_post(uart_recvTaskPrio, 1, 0);WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);} else if (UART_RXFIFO_OVF_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_OVF_INT_ST)) {WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_OVF_INT_CLR);DBG1("RX OVF!!\r\n");}}

    問為什么要這樣改,官方文檔中做出了說明,參考esp8266技術參考手冊,串口中斷狀態分為:接收 full 中斷、接收溢出中斷、接收超時中斷 tout、發送 fifo 空中斷、流量量控制狀態中斷。我只對接收超時中斷進行了配置,因為這個足夠滿足需求,若考慮全面,可以適當增加。手冊中也有一個中斷處理函數的例程,參照這個修改。

    上面代碼的注釋也寫的很清楚了。
    3)修改mqtt_config.h

    /*只有在持有人標識和之前不同的情況下才會更新系統參數,這就是為什么在配置文件這里修改MQTThost等內容時,燒進去的程序沒有變化*/ #define CFG_HOLDER 0x00FF55A4 /* Change this value to load default configurations */#define MQTT_HOST "0.0.0.0" //改成自己服務器的公網IP #define MQTT_PORT 1883 // the listening port of your MQTT server or MQTT broker #define MQTT_CLIENT_ID "esp8266" // 自定義的clientID #define MQTT_USER "admin" // your MQTT login name, if MQTT server allow anonymous login,any string is OK, otherwise, please input valid login name which you had registered #define MQTT_PASS "public" // you MQTT login password, same as above #define STA_SSID "**********" //填自己的SSID #define STA_PASS "**********" // 你的AP/路由器的密碼

    記得要修改CFG_HOLDER,隨便更改某一個十六進制數就行,否則出現修改的參數不生效的后果,我也是一步一步采坑過來的。

    不過還有一個坑,我現在才說,目的就是為了經歷遇到問題,解決問題的過程。遇到問題之后自己解決,這樣可以學到更多的東西。修改完中斷處理函數之后,調試時,似乎根本就不會進入修改好的中斷處理函數,找了各種原因:是不是沒有配置好串口的相關寄存器啊,是不是mqttclient不能傳遞到另一個文件中使用啊,等等等。最后找到答案,ESP8266 NONOS_SDK-3.0 開發中官方例程 UART0串口進入不了中斷問題。因為工程構建得有問題,esp_mqtt_proj目錄中雖然有uart.h頭文件,但是根本不含有uart.c文件,我們所修改的不過是沒有引入到項目中的uart.c文件。所以我的解決方式是:
    1)將driver_lib下的driver復制到esp_mqtt_proj項目文件夾內

    2)在Makefile文件中加入相應的庫文件目錄。


    把對應的二進制文件燒錄進esp8266

    4. 調試效果
    1)連接好ESP8266和串口調試器,插到電腦USB口上。

    2)打開串口調試助手(安信可官網開發工具清單中下載)。

    這樣表示mqtt服務端連接成功。
    3)模擬一下微信小程序與ESP8266之間進行通信,首先在MQTTBox上添加mqtt客戶端用以模擬微信小程序端,配置如下:

    在MQTTBox上發布消息

    可以看到esp8266串口中打印出來了消息,如果esp8266接在STM32上,STM32只需要讀取串口數據就可以獲取到微信小程序發來的數據了、

    esp8266轉發串口數據(AT+RST)

    可以看到微信小程序訂閱的Topic1主題,接收到了消息。

    這樣這個環節就OK了。


    更新內容
    問題:在最開始做這個項目的時候,有一個問題沒注意,后來調試之后,突然發現一個問題,當Esp8266和STM32同時上電之后,不會發送上線消息,然后微信小程序就不會檢測到STM32是否上線,進而無法控制STM32。這是因為在上電后,stm32和esp8266各自執行自己的代碼,沒有聯系,所以STM32初始化過程中發送在線信息時,ESP8266還沒有連接上服務器,然后向串口發送在線信息時,ESP8266不會轉發到主題上去。
    解決方法:更改STM32程序,在STM32初始化時,向ESP8266串口發送詢問數據,詢問ESP8266是否連接上服務器。更新ESP8266固件,當串口接收到詢問數據后,在串口返回初始化完畢的狀態。
    更改后的代碼貼在下面。
    user_main.c

    void user_init(void) {uart_init(BIT_RATE_115200, BIT_RATE_115200);os_delay_us(60000);uart_rx_intr_disable(UART0); //先關閉串口中斷,待連接上服務器后再開啟,防止在連接服務器時,不斷收到詢問是否初始化完成的數據CFG_Load();os_printf("\r\nSDKversion:%s\r\n",system_get_sdk_version());MQTT_InitConnection(&mqttClient, sysCfg.mqtt_host, sysCfg.mqtt_port, sysCfg.security);MQTT_InitClient(&mqttClient, sysCfg.device_id, sysCfg.mqtt_user, sysCfg.mqtt_pass, sysCfg.mqtt_keepalive, 1);MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);MQTT_OnConnected(&mqttClient, mqttConnectedCb);MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);MQTT_OnPublished(&mqttClient, mqttPublishedCb);MQTT_OnData(&mqttClient, mqttDataCb);WIFI_Connect(sysCfg.sta_ssid, sysCfg.sta_pwd, wifiConnectCb);INFO("\r\nSystem started ...\r\n"); }

    在mqtt.c里面mqtt_tcpclient_recv函數,當訂閱成功之后表示連接服務器成功,表示可以接收詢問數據了

    case MQTT_MSG_TYPE_SUBACK:if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id){mqttState=1;os_delay_us(60000);uart_rx_intr_enable(UART0);}break;

    個人能力有限,有錯誤的地方歡迎指正,有問題也可以提,可以一起探討一下

    總結

    以上是生活随笔為你收集整理的物联网学习之旅:微信小程序控制STM32(二)--ESP8266连接mqtt服务端的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。