單片機-STM32部分:18、WiFi模組

飛書文檔https://x509p6c8to.feishu.cn/wiki/WFmqwImDViDUezkF7ercZuNDnve

一、WiFi模組應用

當設備需要連接網絡,實現遠程控制,狀態監控時,就需要添加通信模組,常見的通信模組WiFi模組、2G模組、4G模組等:

我們的板卡上沒有直接用現成的模組,而是直接把WiFi芯片設計到板卡上:

所以,我們就可以基于這個芯片嘗試做聯網的應用。

因為我們用的是原廠芯片的方案,所以WiFi芯片內是沒有程序的,我們需要先到官方下載WiFi的固件進行燒錄,燒錄成功后,才能用串口驅動WiFi芯片。

二、WiFi模組固件燒錄

AT指令是什么?

ESP-AT 是樂鑫開發的可直接用于量產的物聯網應用固件,旨在降低客戶開發成本,快速形成產品。通過 ESP-AT 指令,您可以快速加入無線網絡、連接云平臺、實現數據通信以及遠程控制等功能,真正的通過無線通訊實現萬物互聯。

固件下載

官方AT固件下載(ESP8266是樂鑫的方案)

https://docs.espressif.com/projects/esp-at/en/release-v2.2.0.0_esp8266/AT_Binary_Lists/ESP8266_AT_binaries.html

安信可固件下載(安信可是ESP8266模組廠商)

https://docs.ai-thinker.com/%E5%9B%BA%E4%BB%B6%E6%B1%87%E6%80%BB

建議直接下載下方固件即可:參考飛書文檔

燒錄接線

下載AT指令固件到本地后,我們需要先按下方接好線,DC電源頭供電,核心板不接,然后只接TX RX GND

部分小伙伴出現電腦USB供電不足導致燒錄失敗或亂碼、無應答問題,可以嘗試獨立供電,如下圖:

  1. 1、拆除STM32核心板,因為STM32的TX RX和WiFi的共用,避免有數據干擾。
  2. 2、USB轉TTL模塊只需要接TXD、RXD、GND到板卡,注意3V3不需要接
  3. 3、接上電源適配器,按復位按鍵即可進入燒錄(注意燒錄模式短接MODE的插針,運行模式斷開)

注意,如果使用外部DC頭供電,下方的3.3V紅色線就不需要接了。

如果接線正常,我們可以在電腦的設備管理器中,可以看到新出現的COM口,每臺電腦不一樣,可以查看下自己電腦的COM口,下方燒錄需要用到。

燒錄軟件使用

需要使用樂鑫提供的flash_download_tool工具進行固件燒錄,下載鏈接如下。

https://www.espressif.com.cn/zh-hans/support/download/other-tools

[flash_download_tool_3.9.2_0.zip]

下載后直接解壓即用,運行燒錄工具中的.exe文件,選擇型號,選擇ESP8266

打開燒錄軟件,

從"…“選擇要燒錄的bin文件: xxxESP8266-AT_MQTT-xM.bin,上面下載的固件。
填寫燒錄地址"0x0”,然后勾選固件前面的√,很重要;
SPI MODE選擇 “DOUT”;
"DoNotChgBin"不變;
“COM” 選擇你電腦的COM口;
波特率默認即可。

上述配置完成后, 點擊下方START開始燒錄,若一直停在等待上電同步,可以點擊板卡的RES按鈕,就可以開始下載了,下載一般20s左右,如果1S內完成的,一般是上面沒勾選,如果長時間沒下載完,一般是線有問題,可以換杜邦線重新接穩。

下載完成后,拔掉J10的IO0的杜邦線,從下載模式切換到運行模式,打開串口助手,設置波特率115200 8 N 1,按RES按鈕,就可以看到設備啟動數據,注意

需要接上電源&打開開關,能看到如下打印

到這里,模組燒錄就已經完成啦

注意:

部分小伙伴出現電腦USB供電不足導致燒錄失敗或亂碼問題,可以嘗試獨立供電,如下圖:

  1. 1、拆除STM32核心板,因為STM32的TX RX和WiFi的共用,避免有數據干擾。
  2. 2、USB轉TTL模塊只需要接TXD、RXD、GND到板卡,注意3V3不需要接
  3. 3、接上電源適配器,按復位按鍵即可進入燒錄(注意燒錄模式短接MODE的插針,運行模式斷開)

三、阿里云物聯網云平臺

我們WiFi準備好后,

還需要有個路由器,方便WiFi模組連接外網,也可以開手機熱點。

最后,還需要有個云服務器做遠程控制,或者上報設備狀態。

云服務器廠家有很多

阿里云物聯網

騰訊物聯網

中移動物聯網

機智云等等

注意:

由于近期阿里云暫停個人賬號開通物聯網平臺,為了方便大家做實驗,這里開放幾個測試賬號給大家使用

阿里云物聯網共享賬號 目前只提供購買板卡小伙伴學習使用,可以從旺旺給你發送的資料鏈接中獲取密碼。

共享賬號已經創建了產品,大家可以拷貝創建好的設備的MQTT連接參數直接使用,然后直接查看第四章。

課程使用阿里云物聯網平臺,需要我們注冊登錄下,下方是步驟

https://www.aliyun.com/

點擊管理控制臺

如果提示未開通,點擊開通即可,測試使用是免費的。

選擇公共實例,然后鼠標點擊“公共實例”進入。

如果尚未開通,需要先進行開通,開通時間一般5min內

創建一個新的產品。

填寫產品名稱所屬品類等必要信息,并完成產品創建步驟。

這里我們選擇創建一個溫濕度檢測產品,產品將會影響到后續的通信協議字段。

在創建完成的產品頁面上,點擊添加設備。

輸入設備名稱并確認。

至此,阿里云物聯網平臺創建設備完成。進入設備詳情頁,查看MQTT連接參數,并進行保存。

至此,平臺部分配置完成,

這些參數將用于在ESP-01S / ESP8266上配置AT指令,實現設備與物聯網平臺之間的通信。

{"clientId":"k0rqhbzuJeE.device1|securemode=2,signmethod=hmacsha256,timestamp=1705652029669|","username":"device1&k0rqhbzuJeE","mqttHostUrl":"iot-06z00dcx1hvlwd3.mqtt.iothub.aliyuncs.com","passwd":"f3c17488453a737afd24edefdd4ec6862848a0ca2f8866b7015f5787b90e68a2","port":1883}

四、配置WiFi模組連接云平臺

連接阿里云服務器

阿里云使用MQTT協議

MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸協議),是一種基于發布/訂閱(publish/subscribe)模式的“輕量級”通訊協議,該協議構建于TCP/IP協議上,由IBM在1999年發布。
MQTT最大優點在于,用極少的代碼和有限的帶寬,為連接遠程設備提供實時可靠的消息服務。
作為一種低開銷、低帶寬占用的即時通訊協議,使其在物聯網、小型設備、移動應用等方面有較廣泛的應用。MQTT 與 HTTP 一樣,MQTT 運行在傳輸控制協議/互聯網協議 (TCP/IP) 堆棧之上。

wifi連接服務器用哪種協議?
TCP:比較原始,需要自己擴展的功能較多,開發效率低
HTTP:比較重,網頁端的協議,占用的帶寬較大。
MQTT:適用于物聯網設備和傳感器等低帶寬、不穩定網絡環境下的通信。MQTT的特性
-協議心跳包僅兩個字節
-協議支持QoS(服務質量)設置,可以確保消息傳輸的可靠性。
QoS 0:最多一次傳輸。消息發布者只發送一次消息,不考慮它是否被接收。這種傳輸方式是最快的,但也是最不可靠的,因為消息可能會丟失。
QoS 1:至少一次傳輸。消息發布者會發送消息并等待確認,如果確認未收到,則會重發消息。這種傳輸方式可以保證消息最少被傳輸一次,但可能會重復傳輸。
QoS 2:恰好一次傳輸。消息發布者會發送消息并等待確認,如果確認未收到,則會重發消息。接收者會對消息進行去重和重復檢查,以確保消息只被傳輸一次。這種傳輸方式是最可靠的,但也是最慢的。
-協議支持發布/訂閱模式,可以根據應用場景選擇不同的模式。
-可擴展設備影子模式

我們模組固件是支持MQTT的,我們可以使用串口AT配置模組連接云平臺

這里用安信可官方提供的串口助手,調試更加便捷:參考飛書文檔

AT指令如下:

連接阿里云AT指令介紹
AT+CWMODE=3 設置ESP模塊為Station+SoftAP模式;
AT+CWJAP="SSID","PWD" 設置ESP模塊連接無線網絡 *注意雙引號為英文;
AT+MQTTUSERCFG=0,1,"NULL","username","password",0,0,"" MQTT用戶屬性,username和passwd與下圖對應
AT+MQTTCLIENTID=0,"clientId" 設置MQTT 的clientId參數;clientId也與下圖對應
AT+MQTTCONN=0,"host",1883,1 連接 MQTT Broker;host與下圖mqttHostUrl對應。
AT+MQTTCLEAN 斷開MQTT連接。
AT+RST 復位ESP-01S / ESP8266模塊;
需要注意AT+MQTTCLIENTID指令中的clientId中的逗號前需要加\符號進行轉義,
假設clientId為"xxx|securemode=2,signmethod=hmacsha256,timestamp=xxx|",
那么AT指令應為AT+MQTTCLIENTID=0,"xxx|securemode=2\,signmethod=hmacsha256\,timestamp=xxx|"下方是我賬號的設備信息,可以參考下,替換為自己平臺的信息:
AT+CWMODE=3
AT+CWJAP="leo","123456789"
AT+MQTTUSERCFG=0,1,"NULL","device1&kxxxxxxJeE","f3c17488453a7xxxxxxx015f5787b90e68a2",0,0,""
AT+MQTTCLIENTID=0,"k0rqhxxxxeE.device1|securemode=2\,signmethod=hmacsha256\,timestamp=1705652029669|"
AT+MQTTCONN=0,"iot-06z0xxxxxxlwd3.mqtt.iothub.aliyuncs.com",1883,1更多AT指令可以參考官方文檔
https://docs.espressif.com/projects/esp-at/en/release-v2.2.0.0_esp8266/Get_Started/index.html

發送完以上指令后,在阿里云物聯網平臺中刷新設備網頁,你將會看到設備已成功上線的信息。

狀態上報-發布

回到平臺的產品界面,點擊Topic類列表,點擊物模型通信,可以看到你自己的狀態上報Topic

/sys/xxxx/${deviceName}/thing/event/property/post

然后看下我們這個產品的功能定義中,有哪些需要上報的字段

這里,我們使用當前溫度為例,記錄標識符CurrentTemperature,當然,我們也可以點擊“編輯”添加、刪除、修改功能模塊。

拿到標識符后,我們就可以通過下方MQTT指令上報狀態

AT+MQTTPUB=0,"topic字段","data字段",1,0 通過 topic 發布 MQTT消息特別注意,空格,英文符號
注意,topic中的deviceName改為你創建的設備名稱:
AT+MQTTPUB=0,"/sys/k0rqhbzuJeE/device1/thing/event/property/post","{\"params\":{\"CurrentTemperature\":33}}",1,0

然后,我們就可以在設備界面看到上報的溫度數據啦:

控制接收-訂閱

回到平臺的產品界面,點擊Topic類列表,點擊物模型通信,可以看到你自己的設備設置的Topic

/sys/k0rqhbzuJeE/${deviceName}/thing/service/property/set

然后通過串口調試助手訂閱主題

AT+MQTTSUB=0,"topic字段",1? 訂閱指定 MQTT topic特別注意,空格,英文符號
AT+MQTTSUB=0,"/sys/k0rqhbzuJeE/device1/thing/service/property/set",1

然后我們可以增加一個開關控制字段

我們隨便添加一個支持讀寫的屬性,也可以自己自定義

記得點擊發布上線

發布成功后,我們可以模擬手機端操作這個字段,發送控制指令給模組。

修改對應屬性,點擊設置

然后我們就可以在串口調試助手看到接收的指令

五、STM32驅動WiFi模組

前面我們都是使用串口助手發送指令驅動WiFi模組的,那接下來,我們就可以用STM32替換串口助手驅動WiFi模組啦。

開始這個章節時,可以把下方USB轉串口部分拔掉。

這部分的原理圖是這樣的,因為模組使用串口通信,所以我們只需要關注PC10和PC11的USART3。

創建工程,打開UART4

同時,開啟串口中斷

配置DMA

調整DMA初始化順序(重要)

為了更直觀看到設備運行狀態,打開USART1作為日志口。

生成工程,然后參考串口章節,添加日志打印重定向

main.c
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes *//* USER CODE BEGIN 2 */printf("app init\n");/* USER CODE END 2 *//* USER CODE BEGIN 4 */
int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);return ch;
}

添加最簡單的AT指令發送和接收判斷,通過串口中斷+DMA不定長接收


main.c
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
/* USER CODE END Includes *//* USER CODE BEGIN 0 */
#define AT "AT\r\n"
#define ACK_OK "OK"
#define BUFFER_SIZE 256uint8_t rx_buf[BUFFER_SIZE];? //應用處理buffer
bool rx_status = false;
extern DMA_HandleTypeDef hdma_uart4_rx;
uint8_t dma_rxbuf[BUFFER_SIZE];?????????????????????????????????????? //DMA接收bufferstatic void init(void);
/* USER CODE END 0 *//* USER CODE BEGIN 2 */printf("app init\n");__HAL_UART_ENABLE_IT(&huart4,UART_IT_IDLE);HAL_UART_Receive_DMA(&huart4,dma_rxbuf,sizeof(dma_rxbuf));init();/* USER CODE END 2 *//* USER CODE BEGIN 4 */
void copy_to_rx_buf(uint8_t *ack,uint8_t len){if(rx_status)return;if(len > sizeof(rx_buf))return;memcpy(rx_buf,ack,len);rx_status = true;
}bool send_cmd(uint8_t *cmd,uint8_t *ack){int time_out = 500;memset(rx_buf,0,sizeof(rx_buf));printf("send ----> %s\n",cmd);HAL_UART_Transmit_DMA(&huart4 , (uint8_t *)cmd, strlen((const char *)cmd));while (time_out --){if(rx_status){printf("read ----> %s\n",rx_buf);if(strstr((const char*)rx_buf,(const char*) ack) != NULL){printf("ack ok\n");rx_status = false;return true;}memset(rx_buf,0,sizeof(rx_buf));rx_status = false;}HAL_Delay(10);}printf("ack fail\n");return false;
}void init(){send_cmd((uint8_t *)AT,(uint8_t *)ACK_OK);HAL_Delay(500);
}void UART_IDLEHandler(){if(__HAL_UART_GET_FLAG(&huart4, UART_FLAG_IDLE) == SET) //如果串口處于空閑狀態{__HAL_UART_CLEAR_FLAG(&huart4, UART_FLAG_IDLE);//清空空閑狀態標志HAL_UART_DMAStop(&huart4); //關閉DMA傳輸//計算接收到的數據長度 ,已接收長度=需要接收總長度-剩余待接收長度uint8_t rlen = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_uart4_rx);//進行數據處理????copy_to_rx_buf(dma_rxbuf,rlen);//重新打開DMA接收HAL_UART_Receive_DMA(&huart4,dma_rxbuf,sizeof(dma_rxbuf));???????????????}
}int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);return ch;
}
/* USER CODE END 4 */mian.h
/* USER CODE BEGIN EFP */
void UART_IDLEHandler(void);
/* USER CODE END EFP */stm32f1xx_it.c
void UART4_IRQHandler(void)
{/* USER CODE BEGIN UART4_IRQn 0 *//* USER CODE END UART4_IRQn 0 */HAL_UART_IRQHandler(&huart4);/* USER CODE BEGIN UART4_IRQn 1 */UART_IDLEHandler();/* USER CODE END UART4_IRQn 1 */
}

燒錄運行:

工程參考飛書文檔

然后我們可以所有初始化AT指令全部加上,并且發布和訂閱對應消息,最終實現溫度上報和控制指令接收的功能。

最終版本的main.c如下


/* USER CODE BEGIN Header */
/********************************************************************************* @file?????????? : main.c* @brief????????? : Main program body******************************************************************************* @attention** Copyright (c) 2024 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#define AT "AT\r\n"
#define AT_WIFI_MODE "AT+CWMODE=3\r\n"
#define AT_SET_PSW "AT+CWJAP=\"Kang\",\"555883200\"\r\n"
#define AT_SET_MQTT_CFG "AT+MQTTUSERCFG=0,1,\"NULL\",\"device1&k0rqhbzuJeE\",\"f3c17488453a737afd24edefdd4ec6862848a0ca2f8866b7015f5787b90e68a2\",0,0,\"\"\r\n"
#define AT_SET_MQTT_CLENTID "AT+MQTTCLIENTID=0,\"k0rqhbzuJeE.device1|securemode=2\\,signmethod=hmacsha256\\,timestamp=1705652029669|\"\r\n"
#define AT_SET_MQTT_CONN "AT+MQTTCONN=0,\"iot-06z00dcx1hvlwd3.mqtt.iothub.aliyuncs.com\",1883,1\r\n"
#define AT_MQTT_SUB "AT+MQTTSUB=0,\"/sys/k0rqhbzuJeE/device1/thing/service/property/set\",1\r\n"
#define AT_MQTT_PUB "AT+MQTTPUB=0,\"/sys/k0rqhbzuJeE/device1/thing/event/property/post\",\"{\\\"params\\\":{\\\"CurrentTemperature\\\":%d}}\",1,0\r\n"
#define ACK_OK "OK"#define BUFFER_SIZE 256uint8_t rx_buf[BUFFER_SIZE];? //應用處理buffer
uint8_t tx_buf[BUFFER_SIZE];? //發送buffer
bool rx_status = false;extern DMA_HandleTypeDef hdma_uart4_rx;
uint8_t dma_rxbuf[BUFFER_SIZE];?????????????????????????????????????? //DMA接收bufferstatic void init(void);
static bool send_cmd(uint8_t *cmd,uint8_t *ack);
static void read_cmd(void);
/* USER CODE END 0 *//*** @brief? The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();MX_UART4_Init();/* USER CODE BEGIN 2 */printf("app init\n");__HAL_UART_ENABLE_IT(&huart4,UART_IT_IDLE);HAL_UART_Receive_DMA(&huart4,dma_rxbuf,sizeof(dma_rxbuf));init();printf("wifi init finish\n");uint8_t temperature = 20;uint8_t send_count = 0;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */send_count ++;if(send_count >= 10){//10s上報一條send_count = 0;sprintf((char *)tx_buf,"AT+MQTTPUB=0,\"/sys/k0rqhbzuJeE/device1/thing/event/property/post\",\"{\\\"params\\\":{\\\"CurrentTemperature\\\":%d}}\",1,0\r\n", temperature);send_cmd(tx_buf,(uint8_t *)ACK_OK);temperature ++;if(temperature > 100)temperature = 20;}read_cmd();HAL_Delay(1000);}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 */void copy_to_rx_buf(uint8_t *ack,uint8_t len){if(rx_status)return;if(len > sizeof(rx_buf))return;memcpy(rx_buf,ack,len);rx_status = true;
}bool send_cmd(uint8_t *cmd,uint8_t *ack){int time_out = 500;memset(rx_buf,0,sizeof(rx_buf));printf("send ----> %s\n",cmd);HAL_UART_Transmit_DMA(&huart4 , (uint8_t *)cmd, strlen((const char *)cmd));while (time_out --){if(rx_status){printf("read ----> %s\n",rx_buf);if(strstr((const char*)rx_buf,(const char*) ack) != NULL){printf("ack ok\n");rx_status = false;return true;}memset(rx_buf,0,sizeof(rx_buf));rx_status = false;}HAL_Delay(10);}printf("ack fail\n");return false;
}void read_cmd(){if(rx_status){printf("read ----> %s\n",rx_buf);rx_status = false;}
}void init(){send_cmd((uint8_t *)AT,(uint8_t *)ACK_OK);HAL_Delay(500);send_cmd((uint8_t *)AT_WIFI_MODE,(uint8_t *)ACK_OK);HAL_Delay(500);send_cmd((uint8_t *)AT_SET_PSW,(uint8_t *)ACK_OK);HAL_Delay(500);send_cmd((uint8_t *)AT_SET_MQTT_CFG,(uint8_t *)ACK_OK);HAL_Delay(500);send_cmd((uint8_t *)AT_SET_MQTT_CLENTID,(uint8_t *)ACK_OK);HAL_Delay(500);send_cmd((uint8_t *)AT_SET_MQTT_CONN,(uint8_t *)ACK_OK);HAL_Delay(500);send_cmd((uint8_t *)AT_MQTT_SUB,(uint8_t *)ACK_OK);HAL_Delay(500);
}void UART_IDLEHandler(){if(__HAL_UART_GET_FLAG(&huart4, UART_FLAG_IDLE) == SET) //如果串口處于空閑狀態{__HAL_UART_CLEAR_FLAG(&huart4, UART_FLAG_IDLE);//清空空閑狀態標志HAL_UART_DMAStop(&huart4); //關閉DMA傳輸//計算接收到的數據長度 ,已接收長度=需要接收總長度-剩余待接收長度uint8_t rlen = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_uart4_rx);//進行數據處理????copy_to_rx_buf(dma_rxbuf,rlen);//重新打開DMA接收HAL_UART_Receive_DMA(&huart4,dma_rxbuf,sizeof(dma_rxbuf));???????????????}
}int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);return ch;
}/* USER CODE END 4 *//*** @brief? This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef? USE_FULL_ASSERT
/*** @brief? Reports the name of the source file and the source line number*???????? where the assert_param error has occurred.* @param? file: pointer to the source file name* @param? line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

設備連接平臺成功后,每間隔10s上報一次溫度數據

在云平臺設置燈開關,設備也會收到消息

工程參考:飛書文檔

上面的工程僅僅使用數據復制的方式進行拷貝處理,當交互頻繁時,可能會出現丟失指令的情況,下方的工程使用環形緩沖區,可以避免指令丟失情況。

參考飛書文檔

手機APP開發參考

采用MQTT協議實現Android APP與阿里云平臺的連接_android連接mqtt 阿里云

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/81033.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/81033.shtml
英文地址,請注明出處:http://en.pswp.cn/web/81033.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

探索Qwen2ForCausalLM 架構上進行微調

簡述 試驗參考了mini_qwen 的開源實現 GitHub - qiufengqijun/mini_qwen: 這是一個從頭訓練大語言模型的項目&#xff0c;包括預訓練、微調和直接偏好優化&#xff0c;模型擁有1B參數&#xff0c;支持中英文。這是一個從頭訓練大語言模型的項目&#xff0c;包括預訓練、微調和…

hysAnalyser特色的TS流編輯、剪輯和轉存MP4功能說明

摘要 hysAnalyser 是一款特色的 MPEG-TS 數據分析工具&#xff0c;融合了常規TS文件的剪輯&#xff0c;轉存功能&#xff0c;可用于平常的視頻開發和測試。 本文詳細闡述了對MPEG-TS 流的節目ID&#xff0c;名稱&#xff0c;PID&#xff0c;時間戳&#xff0c;流類型&#xff…

前端[插件化]設計思想_Vue、React、Webpack、Vite、Element Plus、Ant Design

前端插件化設計思想旨在提升應用的可擴展性、可維護性和模塊化程度。這種思想不僅體現在框架&#xff08;如 Vue、React&#xff09;中&#xff0c;也廣泛應用于構建工具&#xff08;如 Webpack、Vite&#xff09;以及 UI 庫&#xff08;如 Element Plus、Ant Design&#xff0…

2025年高防IP與游戲盾深度對比:如何選擇最佳防護方案?

2025年&#xff0c;隨著DDoS攻擊規模的指數級增長和混合攻擊的常態化&#xff0c;高防IP與游戲盾成為企業網絡安全的核心選擇。然而&#xff0c;兩者在功能定位、技術實現及適用場景上存在顯著差異。本文結合最新行業實踐與技術趨勢&#xff0c;全面解析兩者的優劣&#xff0c;…

日志根因分析:Elastic Observability 的異常檢測與日志分類功能

作者&#xff1a;來自 Elastic Bahubali Shetti Elastic Observability 不僅提供日志聚合、指標分析、APM 和分布式追蹤&#xff0c;Elastic 的機器學習能力還能幫助分析問題的根因&#xff0c;讓你將時間專注于最重要的任務。 隨著越來越多的應用程序遷移到云端&#xff0c;收…

Linux火墻管理及優化

網絡環境配置 使用3個新的虛擬機【配置好軟件倉庫和網絡的】 F1 192.168.150.133 NAT F2 192.168.150.134 192.168.10.20 NAT HOST-ONLY 網絡適配僅主機 F3 192.168.10.30 HOST-ONLY 網絡適配僅主機 1 ~]# hostnamectl hostname double1.timinglee.org 【更…

java配置webSocket、前端使用uniapp連接

一、這個管理系統是基于若依框架&#xff0c;配置webSocKet的maven依賴 <!--websocket--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency> 二、配…

基于Yolov8+PyQT的老人摔倒識別系統源碼

概述 ??基于Yolov8PyQT的老人摔倒識別系統??&#xff0c;該系統通過深度學習算法實時檢測人體姿態&#xff0c;精準識別站立、摔倒中等3種狀態&#xff0c;為家庭或養老機構提供及時預警功能。 主要內容 ??完整可運行代碼?? 項目采用Yolov8目標檢測框架結合PyQT5開發…

Oracle 創建外部表

找別人要一下數據&#xff0c;但是他發來一個 xxx.csv 文件&#xff0c;怎么辦&#xff1f; 1、使用視圖化工具導入 使用導入工具導入&#xff0c;如 DBeaver&#xff0c;右擊要導入的表&#xff0c;選擇導入數據。 選擇對應的 csv 文件&#xff0c;下一步就行了&#xff08;如…

【華為OD- B卷 01 - 傳遞悄悄話 100分(python、java、c、c++、js)】

【華為OD- B卷 01 - 傳遞悄悄話 100分(python、java、c、c++、js)】 題目 給定一個二叉樹,每個節點上站一個人,節點數字表示父節點到該節點傳遞悄悄話需要花費的時間。 初始時,根節點所在位置的人有一個悄悄話想要傳遞給其他人,求二叉樹所有節點上的人都接收到悄悄話花…

房貸利率計算前端小程序

利率計算前端小程序 視圖效果展示如下&#xff1a; 在這里插入代碼片 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0&qu…

自制操作系統day8 (鼠標數據取得、通往32位模式之路、A20GATE、切換到保護模式、控制寄存器cr0-cr4以及cr8、ALIGNB)

day8 鼠標數據取得方法 fifo8_init(&mousefifo, 128, mousebuf); for (;;) { io_cli(); if (fifo8_status(&keyfifo) fifo8_status(&mousefifo) 0) { io_stihlt(); } else { if (fifo8_status(&keyfifo) ! 0) { i fifo8_get(&keyfifo); io_sti(); spr…

IP大科普:住宅IP、機房IP、原生IP、雙ISP

不同類型的IP在跨境電商、廣告營銷、網絡技術、數據收集等領域都有廣泛應用&#xff0c;比如常見的住宅IP、機房IP、原生IP、雙ISP等&#xff0c;這些IP分別都有什么特點&#xff0c;發揮什么作用&#xff0c;適合哪些業務場景&#xff1f; 一、IP類型及其作用 1.住宅IP 住宅…

Elasticsearch面試題帶答案

Elasticsearch面試題帶答案 Elasticsearch面試題及答案【最新版】Elasticsearch高級面試題大全(2025版),發現網上很多Elasticsearch面試題及答案整理都沒有答案,所以花了很長時間搜集,本套Elasticsearch面試題大全,Elasticsearch面試題大匯總,有大量經典的Elasticsearch面…

Eigen與OpenCV矩陣操作全面對比:最大值、最小值、平均值

功能對比總表 功能Eigen 方法OpenCV 方法主要區別最大值mat.maxCoeff(&row, &col)cv::minMaxLoc(mat, NULL, &maxVal, NULL, &maxLoc)Eigen需要分開調用&#xff0c;OpenCV一次獲取最小值mat.minCoeff(&row, &col)cv::minMaxLoc(mat, &minVal, NU…

echarts之雙折線漸變圖

vue3echarts實現雙折線漸變圖 echarts中文官網&#xff1a;https://echarts.apache.org/examples/zh/index.html 效果圖展示&#xff1a; 整體代碼如下&#xff1a; <template><div id"lineChart" style"width:100%;height:400px;"></di…

MD編輯器推薦【Obsidian】含下載安裝和實用教程

為什么推薦 Obsidian &#xff1f; 免費 &#xff08;Typora 開始收費了&#xff09;Typora 實現的功能&#xff0c;它都有&#xff01;代碼塊可一鍵復制 文件目錄支持文件夾 大綱支持折疊、搜索 特色功能 – 白板 特色功能 – 關系圖譜 下載 https://pan.baidu.com/s/1I1fSly…

vue 鼠標經過時顯示/隱藏其他元素

方式一&#xff1a; 使用純css方式 , :hover是可以控制其他元素 1、 當兩個元素是父子關系 <div class"all_" ><div> <i class"iconfont icon-sun sun"></i></div> </div> .all_{} .sun {display: none; /* 默認…

靜態網站部署:如何通過GitHub免費部署一個靜態網站

GitHub提供的免費靜態網站托管服務可以無需擔心昂貴的服務器費用和復雜的設置步驟&#xff0c;本篇文章中將一步步解如何通過GitHub免費部署一個靜態網站&#xff0c;幫助大家將創意和作品快速展現給世界。 目錄 了解基礎情況 創建基礎站點 在線調試站點 前端項目部署 部署…

Pytorch里面多任務Loss是加起來還是分別backward? | Pytorch | 深度學習

當你在深度學習中進入“多任務學習(Multi-task Learning)”的領域,第一道關卡可能不是設計網絡結構,也不是準備數據集,而是:多個Loss到底是加起來一起backward,還是分別backward? 這個問題看似簡單,卻涉及PyTorch計算圖的構建邏輯、自動求導機制、內存管理、任務耦合…