<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      STM32F103+ESP-01S+MQTT協(xié)議連接華為云端(附踩坑記錄)

      STM32F103+ESP-01S+MQTT協(xié)議連接華為云端(附踩坑記錄)

      一、物料準(zhǔn)備

      硬件:

      1. STM32F103C8T6最小核心板
      2. ESP01S WIFI模塊

      軟件:

      1. Keil
      2. esp32固件燒寫軟件
      3. 華為云服務(wù)器(個人免費使用,每天消息上限)

      二、調(diào)試過程

      調(diào)試總體思路:

      1. 燒寫官方的MQTT固件(這樣可以省去協(xié)議的手動組裝,直接調(diào)用AT指令+傳參就行了);

      2. 單片機的硬線連接,做好usart配置;

      3. wifi連接熱點;

      4. MQTT連接云服務(wù)器

      5. ESP01S固件燒寫

        ESP01S的芯片其實也是8266

        參考博文:http://www.rzrgm.cn/xilimiss510/p/17592856.html

        官網(wǎng)固件庫:https://docs.ai-thinker.com/固件匯總

      6. 硬線+usart配置

      首先是硬件接線+USART配置,我用的是STM32F103的USART2,USART的配置基本都是通用的,注意單片機的串口引腳和所在時鐘就行了。如果要接入FreeRTOS的話,注意NVIC的配置的優(yōu)先級分組和整體保持一致就行了(一般是第4組)NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 4位搶占優(yōu)先級,0位子優(yōu)先級,代碼如下:

      // USART2_TX:PA2,USART2_RX:PA3,
      void USART2_Config(int baud)
      {
      	USART_InitTypeDef USART_InitStructure;
      	NVIC_InitTypeDef NVIC_InitStructure;
      	GPIO_InitTypeDef GPIO_InitStructure;
      	/********* RCC配置 ******************/
      	// 打開USART2時鐘
      	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
      
      	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
      	/********* NVIC配置 **********************************/
          NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 12;  // 搶占優(yōu)先級12(>11)
          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;          // 子優(yōu)先級無效(分組4)
          NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
          NVIC_Init(&NVIC_InitStructure);
      
      	/********* 引腳配置 **********************************/
      	
      	// 映射引腳和復(fù)用功能
      	//RX端口
      	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
      	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      	GPIO_Init(GPIOA, &GPIO_InitStructure);
      	
      	//TX端口
      	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
      	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
      	GPIO_Init(GPIOA, &GPIO_InitStructure);
      
      	/********* 串口配置 ************************************/
      	USART_InitStructure.USART_BaudRate = baud;
      	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      	USART_InitStructure.USART_StopBits = USART_StopBits_1;
      	USART_InitStructure.USART_Parity = USART_Parity_No;
      	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
      	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
      	USART_Init(USART2, &USART_InitStructure);
      
      	// 配置中斷
      	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
      	
      	// 打開usart
      	USART_Cmd(USART2, ENABLE);
      }
      
      /***************************************** usart中斷服務(wù) ********************************/
      
      uint8_t esp8266_buf[ESP8266_BUF_SIZE];
      uint16_t esp8266_cnt = 0;
      
      //前臺程序就是中斷服務(wù)程序,該程序是不需要手動調(diào)用的,當(dāng)中斷觸發(fā)之后CPU會自動跳轉(zhuǎn)過來執(zhí)行該函數(shù)
      void USART2_IRQHandler(void)
      {
      	//uint8_t data;
      	//判斷中斷是否發(fā)生
      	if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
      	{   
      		//從USART2中接收一個字節(jié) 
      		esp8266_buf[esp8266_cnt++] = USART_ReceiveData(USART2);  //一次只能接收一個字節(jié)   
      		//data = USART_ReceiveData(USART2);
      		//把接收到的數(shù)據(jù)轉(zhuǎn)發(fā)出去
      		//USART_SendData(USART1,data);
      	}
      }
      
      
      1. wifi入網(wǎng)

      esp-01s的波特率設(shè)置為115200,所以為了調(diào)試方便,USART1的波特率也調(diào)整為115200,同時xcom的波特率也調(diào)整為115200,然后按照以下示例即可發(fā)送成功測試

      官方指令集參考:

      https://docs.espressif.com/projects/esp-at/zh_CN/latest/esp32/AT_Command_Set/index.html

      #define ESP8266_WIFI_INFO 		"AT+CWJAP=\"wifiusername\",\"wifipassword\"\r\n"
      
      /**
        * @brief  向ESP8266發(fā)送AT指令并檢查響應(yīng)
        * @param  cmd: 要發(fā)送的AT指令字符串
        * @param  resp: 期望的響應(yīng)字符串
        * @retval 0: 成功(接收到期望響應(yīng)); 1: 失敗
        */
      uint8_t ESP8266_SendCmd(char *cmd, char *resp)
      {
          uint16_t timeout = 0;
          
          // 清空接收緩沖區(qū)
          ESP8266_Clear();
          
          // 發(fā)送AT指令到ESP8266(通過USART2)
          USART2_Send_Str(cmd);
          
          // 等待響應(yīng),超時時間為5秒(500*10ms)
          while(timeout++ < 500)
          {
              delay_ms(10);  // 等待10ms
              
              // 檢查是否接收到期望的響應(yīng)
              if(strstr((char *)esp8266_buf, resp) != NULL)
              {
      			USART1_Send_Str((char *)esp8266_buf);
                  return 0;  // 成功
              }
          }
          return 1;
      }
      
      //連接wifi
      void ESP_Config(void)
      {
      	ESP8266_Clear();
      	
      //	while(ESP8266_SendCmd("AT\r\n", "OK"))
      //		delay_ms(50);
      
      	//1、復(fù)位
      	while(ESP8266_SendCmd("AT+RST\r\n", "OK"))
      		delay_ms(50);
      		
      	//2、設(shè)置工作站STA模式
      	while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
      		delay_ms(50);
      	
      	//3、連接wifi
      	while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
      		delay_ms(50);
      }
      

      注意末尾都要加"\r\n",字符串該轉(zhuǎn)義的轉(zhuǎn)義

      這里連接上了可以試著測試個天氣應(yīng)用的api

      1. MQTT連接

      官方MQTT指令集(中文)非常詳細(xì):MQTT AT 命令集 - ESP32 - — ESP-AT 用戶指南 latest 文檔

      完整的連接發(fā)布訂閱代碼:

      
      void ESP8266_Clear(void)
      {
          memset(esp8266_buf, 0, sizeof(esp8266_buf));
          esp8266_cnt = 0;
      }
      
      bool ESP8266_recv(char *substr)
      {
      	// 檢查是否接收到期望的響應(yīng)
      	if(strstr((char *)esp8266_buf, substr) != NULL)
      	{
      		USART1_Send_Str("收到風(fēng)扇控制命令");
      		USART1_Send_Str((char *)esp8266_buf);
      		ESP8266_Clear();
      		return true;
      	}
      	return false;
      }
      
      /**
        * @brief  向ESP8266發(fā)送AT指令并檢查響應(yīng)
        * @param  cmd: 要發(fā)送的AT指令字符串
        * @param  resp: 期望的響應(yīng)字符串
        * @retval 0: 成功(接收到期望響應(yīng)); 1: 失敗
        */
      uint8_t ESP8266_SendCmd(char *cmd, char *resp)
      {
          uint16_t timeout = 0;
          
          // 清空接收緩沖區(qū)
          ESP8266_Clear();
          
          // 發(fā)送AT指令到ESP8266(通過USART2)
          USART2_Send_Str(cmd);
          
          // 等待響應(yīng),超時時間為5秒(500*10ms)
          while(timeout++ < 500)
          {
              delay_ms(10);  // 等待10ms
              
              // 檢查是否接收到期望的響應(yīng)
              if(strstr((char *)esp8266_buf, resp) != NULL)
              {
      			USART1_Send_Str((char *)esp8266_buf);
                  return 0;  // 成功
              }
          }
          return 1;
      }
      
      void ESP_PUB(char *cmd)
      {	
      	ESP8266_SendCmd(cmd, "OK");	//判斷OK是否是cmd的子串
      }
      
      //連接wifi、連接云端服務(wù)器
      void ESP_Config(void)
      {
      	ESP8266_Clear();
      	
      //	while(ESP8266_SendCmd("AT\r\n", "OK"))
      //		delay_ms(50);
      
      	//1、復(fù)位
      	while(ESP8266_SendCmd("AT+RST\r\n", "OK"))
      		delay_ms(50);
      		
      	//2、設(shè)置工作站STA模式
      	while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
      		delay_ms(50);
      	
      	//3、連接wifi
      	while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
      		delay_ms(50);
      	
      	//4、配置用戶參數(shù)
      	while(ESP8266_SendCmd("AT+MQTTUSERCFG=0,1,\"monitor_123\",\"monitor\",\"XXXXXXXXXXXXXXXXXX\",0,0,\"\"\r\n", "OK"))
      		delay_ms(50);
      	
      	//5、連接云服務(wù)器
      	while(ESP8266_SendCmd("AT+MQTTCONN=0,\"XXXXXXXXXXXXXX",1883,0\r\n", "OK"))
      		delay_ms(50);
      
      	//6、訂閱app控制風(fēng)扇的主題
      	while(ESP8266_SendCmd("AT+MQTTSUB=0,\"control_fan\",1\r\n", "OK"))
      		delay_ms(50);
      }
      
      // 修改云端屬性(暫未啟用,只通過/mesasge/up進行分發(fā))
      void ESP_PUB_Properties(float temper, float humidity, bool isAlarming)
      {
      	sprintf(
      	ts,
      	"AT+MQTTPUB=0,\"$oc/devices/monitor/sys/properties/report\",\"{\\\"services\\\":[{\\\"service_id\\\":\\\"Monitor\\\"\\,\\\"properties\\\":{\\\"temper\\\":10\\,\\\"humidity\\\":30\\,\\\"isAlarming\\\":true}}]}\",1,0\r\n"
      	);
      	ESP_PUB(ts);
      }
      
      // 發(fā)布消息
      void ESP_PUB_Message(float temper, float humidity, bool isAlarming,bool isFanNormallyOpen)
      {
      	memset(ts,0,300);
      	sprintf(
      	ts,
      	"AT+MQTTPUB=0,\"$oc/devices/monitor1/sys/messages/up\",\"{\\\"temper\\\":%.1f\\,\\\"humidity\\\":%.1f\\,\\\"isAlarming\\\":%s\\,\\\"isFanNormallyOpen\\\":%s}\",1,0\r\n",
      	temper,
      	humidity,
      	isAlarming?"true":"false",
      	isFanNormallyOpen?"true":"false"
      	);
      	ESP_PUB(ts);
      }
      
      

      注意這里組裝消息的時候有個大坑,卡了我非常之久:

      
      // 修改云端屬性(暫未啟用,只通過/mesasge/up進行分發(fā))
      void ESP_PUB_Properties(float temper, float humidity, bool isAlarming)
      {
      	sprintf(
      	ts,
      	"AT+MQTTPUB=0,\"$oc/devices/monitor/sys/properties/report\",\"{\\\"services\\\":[{\\\"service_id\\\":\\\"Monitor\\\"\\,\\\"properties\\\":{\\\"temper\\\":10\\,\\\"humidity\\\":30\\,\\\"isAlarming\\\":true}}]}\",1,0\r\n"
      	);
      	ESP_PUB(ts);
      }
      

      假設(shè)要發(fā)布的JSON對象:

      // 華為云屬性更新的固定格式
      {
          "services":[
              {
                  "service_id":"Monitor",
                  "properties":{
                      "temper":10,
                      "humidity":30
                  }
              }
          ]
      }
      
      // 去除format
      {"services":[{"service_id":"Monitor","properties":{"temper":10,"humidity":30}}]}
      

      那跟據(jù)MQTT文檔需要發(fā)送的指令則是

      // 官方示例
      AT+CWMODE=1
      AT+CWJAP="ssid","password"
      AT+MQTTUSERCFG=0,1,"ESP32","espressif","1234567890",0,0,""
      AT+MQTTCONN=0,"192.168.10.234",1883,0
      AT+MQTTPUB=0,"topic","\"{\"timestamp\":\"20201121085253\"}\"",0,0  // 發(fā)送此命令時,請注意特殊字符是否需要轉(zhuǎn)義。
      
      // 我們的指令進行第一次轉(zhuǎn)義,仔細(xì)看,這里我們將","也進行了轉(zhuǎn)義!!!
      AT+MQTTPUB=0,"$oc/devices/monitor/sys/properties/report","{\"services\":[{\"service_id\":\"Monitor\"\,\"properties\":{\"temper\":10\,\"humidity\":30}}]}"
      

      注意,這里我們不僅將數(shù)據(jù)中引號進行了轉(zhuǎn)義,同時對","也進行了轉(zhuǎn)義,這里轉(zhuǎn)義","的原因是因為需要告訴ESP的固件程序,這個逗號是我數(shù)據(jù)中的逗號,而不是指令中的逗號!!!

      指令有了,我們現(xiàn)在要通過sprintf進行數(shù)據(jù)的組裝,所以要進行第二次轉(zhuǎn)義,而這次的轉(zhuǎn)義,是要將所有的"\"和引號進行轉(zhuǎn)義,不用轉(zhuǎn)義逗號,所以最終就變成了

      "AT+MQTTPUB=0,\"$oc/devices/monitor/sys/properties/report\",\"{\\\"services\\\":[{\\\"service_id\\\":\\\"Monitor\\\"\\,\\\"properties\\\":{\\\"temper\\\":10\\,\\\"humidity\\\":30}}]}\""
      

      這就是為什么要發(fā)布的數(shù)據(jù)中的逗號前有兩個反斜杠

      posted @ 2025-08-08 19:44  小鎮(zhèn)青年達師傅  閱讀(315)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 蜜臀久久综合一本av| 国产亚洲999精品AA片在线爽| 亚洲国产精品无码久久久| 亚洲中文字幕无码日韩精品| 最新偷拍一区二区三区| 亚洲av日韩av综合在线观看| 婷婷综合缴情亚洲| 99久热在线精品视频| 国产精品自拍自在线播放| 国产av一区二区不卡| 中文字幕在线精品国产| 蜜臀av在线一区二区三区| 久久丫精品国产| 国产一区二区三区亚洲精品| 妖精视频yjsp毛片永久| 色综合视频一区二区三区| 天堂亚洲免费视频| 邹城市| 亚洲综合伊人久久大杳蕉| 狠狠色综合久久狠狠色综合| 国产欧美日韩视频一区二区三区| 强奷漂亮少妇高潮麻豆| 高清免费毛片| 国产资源精品中文字幕| 人妻少妇精品视频专区| 亚洲av色综合久久综合| 精品亚洲国产成人av| 国产免费午夜福利蜜芽无码| 中文亚洲成A人片在线观看| 久久精品夜夜夜夜夜久久| 日韩中文字幕国产精品| 亚洲国模精品一区二区| 中文字幕日韩有码第一页| 日喀则市| 九色国产精品一区二区久久| 国产无遮挡又黄又爽在线视频| 人妻av中文字幕无码专区| 精品国产一区二区三区四区| 少妇午夜福利一区二区三区 | 精品久久久久久无码人妻蜜桃| 18禁黄无遮挡网站免费|