物联网学习之旅:微信小程序控制STM32(二)--ESP8266连接mqtt服务端
ESP8266連接mqtt服務(wù)端
微信小程序控制STM32的第二步,就是要編寫ESP8266固件,來連接已經(jīng)搭建好的物聯(lián)網(wǎng)服務(wù)器。也有別的方式,只要你足夠了解mqtt協(xié)議,可以通過使用ESP8266原生的AT指令來連接,因?yàn)镋SP8266連接mqtt服務(wù)端中mqtt協(xié)議也是通過建立TCP連接,發(fā)送相應(yīng)的協(xié)議報(bào)文來連接服務(wù)端。但是樂鑫官方提供的SDK中含有連接mqtt服務(wù)端的實(shí)例代碼,要做的就是根據(jù)自己的功能要求去修改代碼。
我修改的固件是ESP8266與STM32之間進(jìn)行串口通信,以透?jìng)鞯姆绞交ハ鄠鬟f數(shù)據(jù),然后ESP8266作為中轉(zhuǎn)把數(shù)據(jù)發(fā)到相應(yīng)的目的地。
我用的是ESP8266-01這款模塊
ESP8266有UART 下載模式和Flash 運(yùn)行模式 ,接線不一樣的地方就是在下載模式時(shí)GPIO0要接低電平,運(yùn)行模式時(shí)懸空即可,每次運(yùn)行模式和下載模式切換都需要重啟一下模塊,才能第二次燒寫或者運(yùn)行。
我是采用這樣的連接方式來燒寫固件,運(yùn)行程序時(shí)把GPIO0拔掉,然后拔掉esp8266的vcc線,然后又插上,重啟一下就可以了。燒寫的時(shí)候把GPIO0接共地端,然后拔掉esp8266的vcc線,然后又插上,重啟一下,就可以燒寫程序了。至于我為什么要用這么復(fù)雜的接線方式來燒寫程序,那是因?yàn)橘I這個(gè)esp8266調(diào)試器的時(shí)候,不懂,圖便宜(根本也是因?yàn)槲姨F了,哈哈哈),然而這個(gè)用來運(yùn)行調(diào)試是最合適的,直接插上去即可。不過這樣也能燒寫固件。也可以用TTL轉(zhuǎn)串口來燒寫,都是可以的,原理都一樣。
進(jìn)入安信可ESP8266 系列模組專題,按照開發(fā)環(huán)境搭建的步驟搭建開發(fā)環(huán)境。
點(diǎn)擊藍(lán)色文字下載ESP8266_NONOS_SDK-v3.0.0,也可以選擇在樂鑫官網(wǎng)上下載最新版本的SDK,根據(jù)需要下載開發(fā)文檔,我用到了這兩個(gè)文檔。
值得注意的是,本項(xiàng)目用到的是esp_mqtt_proj這個(gè)例程,所以在構(gòu)建工程文件時(shí),需要將examples/esp_mqtt_proj目錄工程目錄的頂層文件中,其它的按照安信可提供的步驟搭建即可,編譯沒有錯(cuò)誤之后,其實(shí)example文件夾就可以刪除掉了,這個(gè)項(xiàng)目只用到mqtt部分,其它例程刪掉后編譯仍然是成功的。
打開編譯通過的工程,需要修改的有這幾個(gè)地方
1)user_main.c中修改
2)uart.c中修改
通過user_main.c文件中的uart_init()定位到uart.c文件,然后對(duì)這里面進(jìn)行修改。首先需要引入user_main.c定義的“MQTT_Client* mqttclient;”,這樣下面在串口處理函數(shù)中,當(dāng)從串口接收完數(shù)據(jù)之后,通過引入的mqtt客戶端指針,將數(shù)據(jù)發(fā)到特定的主題,然后別忘了引入“mqtt.h”,因?yàn)檫@里要用到這里面的函數(shù),將數(shù)據(jù)發(fā)送出去。
最后修改串口中斷處理函數(shù)。
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)) { //檢測(cè)到是超時(shí)中斷fifo_len=(READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT; //獲取數(shù)據(jù)長(zhǎng)度buf_idx=0;for(buf_idx=0;buf_idx<fifo_len;buf_idx++){RcvChar[buf_idx]=READ_PERI_REG(UART_FIFO(UART0))&0xFF; //將數(shù)據(jù)儲(chǔ)存起來}if(RcvChar[0]=='A'){ //接收到詢問是否初始化完成的消息if(mqttState==1){ //初始化完成了os_printf("1111\r\n"); //串口發(fā)送初始化完成,如果發(fā)送字母就會(huì)亂碼}else{os_printf("2222\r\n");}}if(RcvChar[0]=='{'){MQTT_Publish(mqttclient, "Topic1", RcvChar, fifo_len, 0, 0); //把接收到的數(shù)據(jù)發(fā)送到mqtt服務(wù)端}if(RcvChar[0]=='T'){os_printf("\r\ntime:%s\r\n", time);}os_memset(RcvChar,0,256); //清除數(shù)據(jù)WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR); //清除超時(shí)中斷狀態(tài)} 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技術(shù)參考手冊(cè),串口中斷狀態(tài)分為:接收 full 中斷、接收溢出中斷、接收超時(shí)中斷 tout、發(fā)送 fifo 空中斷、流量量控制狀態(tài)中斷。我只對(duì)接收超時(shí)中斷進(jìn)行了配置,因?yàn)檫@個(gè)足夠滿足需求,若考慮全面,可以適當(dāng)增加。手冊(cè)中也有一個(gè)中斷處理函數(shù)的例程,參照這個(gè)修改。
上面代碼的注釋也寫的很清楚了。
3)修改mqtt_config.h
記得要修改CFG_HOLDER,隨便更改某一個(gè)十六進(jìn)制數(shù)就行,否則出現(xiàn)修改的參數(shù)不生效的后果,我也是一步一步采坑過來的。
不過還有一個(gè)坑,我現(xiàn)在才說,目的就是為了經(jīng)歷遇到問題,解決問題的過程。遇到問題之后自己解決,這樣可以學(xué)到更多的東西。修改完中斷處理函數(shù)之后,調(diào)試時(shí),似乎根本就不會(huì)進(jìn)入修改好的中斷處理函數(shù),找了各種原因:是不是沒有配置好串口的相關(guān)寄存器啊,是不是mqttclient不能傳遞到另一個(gè)文件中使用啊,等等等。最后找到答案,ESP8266 NONOS_SDK-3.0 開發(fā)中官方例程 UART0串口進(jìn)入不了中斷問題。因?yàn)楣こ虡?gòu)建得有問題,esp_mqtt_proj目錄中雖然有uart.h頭文件,但是根本不含有uart.c文件,我們所修改的不過是沒有引入到項(xiàng)目中的uart.c文件。所以我的解決方式是:
1)將driver_lib下的driver復(fù)制到esp_mqtt_proj項(xiàng)目文件夾內(nèi)
2)在Makefile文件中加入相應(yīng)的庫文件目錄。
把對(duì)應(yīng)的二進(jìn)制文件燒錄進(jìn)esp8266
4. 調(diào)試效果
1)連接好ESP8266和串口調(diào)試器,插到電腦USB口上。
2)打開串口調(diào)試助手(安信可官網(wǎng)開發(fā)工具清單中下載)。
這樣表示mqtt服務(wù)端連接成功。
3)模擬一下微信小程序與ESP8266之間進(jìn)行通信,首先在MQTTBox上添加mqtt客戶端用以模擬微信小程序端,配置如下:
在MQTTBox上發(fā)布消息
可以看到esp8266串口中打印出來了消息,如果esp8266接在STM32上,STM32只需要讀取串口數(shù)據(jù)就可以獲取到微信小程序發(fā)來的數(shù)據(jù)了、
esp8266轉(zhuǎn)發(fā)串口數(shù)據(jù)(AT+RST)
可以看到微信小程序訂閱的Topic1主題,接收到了消息。
這樣這個(gè)環(huán)節(jié)就OK了。
更新內(nèi)容
問題:在最開始做這個(gè)項(xiàng)目的時(shí)候,有一個(gè)問題沒注意,后來調(diào)試之后,突然發(fā)現(xiàn)一個(gè)問題,當(dāng)Esp8266和STM32同時(shí)上電之后,不會(huì)發(fā)送上線消息,然后微信小程序就不會(huì)檢測(cè)到STM32是否上線,進(jìn)而無法控制STM32。這是因?yàn)樵谏想姾?#xff0c;stm32和esp8266各自執(zhí)行自己的代碼,沒有聯(lián)系,所以STM32初始化過程中發(fā)送在線信息時(shí),ESP8266還沒有連接上服務(wù)器,然后向串口發(fā)送在線信息時(shí),ESP8266不會(huì)轉(zhuǎn)發(fā)到主題上去。
解決方法:更改STM32程序,在STM32初始化時(shí),向ESP8266串口發(fā)送詢問數(shù)據(jù),詢問ESP8266是否連接上服務(wù)器。更新ESP8266固件,當(dāng)串口接收到詢問數(shù)據(jù)后,在串口返回初始化完畢的狀態(tài)。
更改后的代碼貼在下面。
user_main.c
在mqtt.c里面mqtt_tcpclient_recv函數(shù),當(dāng)訂閱成功之后表示連接服務(wù)器成功,表示可以接收詢問數(shù)據(jù)了
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;個(gè)人能力有限,有錯(cuò)誤的地方歡迎指正,有問題也可以提,可以一起探討一下
總結(jié)
以上是生活随笔為你收集整理的物联网学习之旅:微信小程序控制STM32(二)--ESP8266连接mqtt服务端的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 滚动到页面底部自动加载内容
- 下一篇: [转]你每天90%的注意力被浪费了