wordpress mysqlli平臺關(guān)鍵詞排名優(yōu)化
- 項目描述:該系列記錄了STM32G0+EMW3080實現(xiàn)單片機智能聯(lián)網(wǎng)功能項目的從零開始一步步的實現(xiàn)過程;
- 硬件環(huán)境:單片機為STM32G030C8T6;物聯(lián)網(wǎng)模塊為EMW3080V2-P;網(wǎng)聯(lián)網(wǎng)模塊的開發(fā)板為MXKit開發(fā)套件,具體型號為XCHIP
MXKit-Base V2.2;- 軟件環(huán)境:STM32需要的軟件有STM32CubeMX和STM32CubeIDE;開發(fā)IDE為eclipse;MXKit的串口調(diào)試工具使用的是putty.exe;
- 串口指令:串口指令使用的是AT指令; 通信方式使用的是UART
- 項目過程:本項目采用模塊化的形式一步步的實現(xiàn)STM32G0+EMW3080+阿里云實現(xiàn)單片機智能聯(lián)網(wǎng)功能;第一步先使用MXKit開發(fā)板和PC進行通信;第二步是配置阿里云飛燕平臺;第三步是MXKit開發(fā)板實現(xiàn)配網(wǎng)功能,MXKit和阿里云之間成功通訊;第四步是STM32G0單片機實現(xiàn)和EMW3080的串口通訊;第五步是測試整體的功能;
本節(jié)為該項目的第四節(jié),主要任務是實現(xiàn)STM32G030C8T6控制EMW3080實現(xiàn)IoT功能,即STM32G030C8T6控制EMW3080實現(xiàn)配網(wǎng)、斷網(wǎng)重連、以及數(shù)據(jù)的下發(fā)、app控制設備等;最終的結(jié)果是,單片機上電后,向EMW3080發(fā)送配網(wǎng)指令,配網(wǎng)成功后,在云智能app端下發(fā)指令能夠控制單片機上的LED等開和關(guān);當然也支持wifi斷開重連等功能;
經(jīng)過上一篇文章,STM32G0+EMW3080+阿里云飛燕平臺實現(xiàn)單片機WiFi智能聯(lián)網(wǎng)功能(三)EMW3080完成配網(wǎng),EMW3080連接到阿里云飛平臺,通過串口調(diào)試EMW3080已經(jīng)能成功的進行配網(wǎng)了,所以我們現(xiàn)在要做的就是,讓STM32G030C8T6來發(fā)送配網(wǎng)指令,完成EMW3080的配網(wǎng)過程,并且在完成配網(wǎng)后,可以向STM32G030C8T6發(fā)送和接收數(shù)據(jù)用于控制設備;
文章目錄
- 一、硬件連接
- 二、代碼實現(xiàn)
- 筆記
一、硬件連接
STM32G030C8T6和EMW3080的連接原理圖如下圖所示:
其中,使用STM32G030C8T6的UART1串口,接到EMW3080的UART串口上,接線如上圖所示;然后STM32G030C8T6通過STLINK或JLINK連接到電腦上,便于調(diào)試和燒寫程序;EMW3080開發(fā)板通過自帶電源線也連接到電腦的USB端口上用于供電;這樣接線部分就接好了;
需要注意的是,STM32G030C8T6我是用的是USART1;EMW3080開發(fā)板上有“UART”和“DEBUG”兩個區(qū)域都由RX和TX,
我們需要使用UART區(qū)域中的RX和TX,而不是DEBUG中的,如果不小心使用了DEBUG中的RX和TX,指令雖然也能發(fā)送到EMW3080,但是無法識別;
接線完成后,實物圖如下所示:
二、代碼實現(xiàn)
接下來就是在STM32G030C8T6中編寫代碼實現(xiàn)向EMW3080發(fā)送AT指令進行配網(wǎng),并根據(jù)返回的信息判斷是否配網(wǎng)成功;待配網(wǎng)成功后,STM32G030C8T6接收云端發(fā)下來的指令,并進行響應的控制;本代碼示例中通過下發(fā)LED等開和關(guān)的指令,控制STM32上的燈亮和滅;
整個工程的代碼可以從以下鏈接中下載(https://download.csdn.net/download/AnChenliang_1002/88511568)
下載后的資源可以直接用STM32CubeIDE運行;
下面大致講解一下代碼結(jié)構(gòu):
主要的源文件如上圖所示,其中我們IoT的功能主要在wilo_wifiMoudule.c中實現(xiàn);
附上wilo_wifiMoudule.c的完整代碼:
#include "wilo_wifiModule.h"#include "wilo_uart.h"#define DISCONNECT_TRUE 1
#define DISCONNECT_FALSE 0extern UART_HandleTypeDef huart1;
extern uint8_t rxBuffer[128];
extern __IO uint8_t receivedIndex;//跟蹤接收到的字符的索引
extern uint8_t stringMatched ;//是否接收到完整的字符串
extern uint8_t receivedData[128]; // 全局數(shù)組用于存儲完整接收到的內(nèi)容
extern __IO uint8_t receivedLength; // 當前接收到的數(shù)據(jù)長度,為0時表示未收到數(shù)據(jù),大于0時表示收到了數(shù)據(jù)
extern uint8_t preReceivedLength;//前一次接收到的數(shù)據(jù)長度
extern const char* atCommands[] ;// 聲明一個設備參數(shù)變量
DeviceParameters deviceParams;void reset_receive()
{// 重置接收索引,準備接收下一段內(nèi)容receivedIndex = 0;stringMatched = 0;receivedLength = 0;preReceivedLength = 0;memset(receivedData,0,sizeof(receivedData));
}// 發(fā)送指令并等待回復函數(shù)
HAL_StatusTypeDef sendCommandAndWait(const char* command, const char* expectedReply)
{// 發(fā)送指令HAL_UART_Transmit_IT(&huart1, (uint8_t*)command, strlen(command));// 接收回復HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1); while((0 == receivedLength))//如果還未接收到數(shù)據(jù),一直等待;直到收到數(shù)據(jù){OLED_ShowString(0,4,"wait response");}//HAL_UART_Transmit_IT(&huart1, (uint8_t*)"wait!!!!\r\n", 10);//OLED_Clear();//OLED清零while(0 == stringMatched )//如果還沒有接收完所有數(shù)據(jù),一直等待,直到接收完所有數(shù)據(jù){ReceivedAll();//判斷是否接收完所有字符串了}//HAL_UART_Transmit_IT(&huart1, (uint8_t*)"111\r\n", 5);//HAL_Delay(1000);//HAL_UART_Transmit_IT(&huart1, (uint8_t*)"received\r\n", 10);OLED_Clear();//OLED清零OLED_ShowString(0,4,"received:");OLED_ShowString(80,4,(u8 *)receivedData);// 延時3秒//HAL_Delay(3000);//replyBuffer = receivedData;if (strstr((const char *)receivedData, expectedReply) != NULL){// 重置接收,準備接收下一段內(nèi)容reset_receive();// 收到期望的回復return HAL_OK;}// 重置接收,準備接收下一段內(nèi)容reset_receive(); return HAL_ERROR;
}
#if 0
//等待wifi配網(wǎng)成功
HAL_StatusTypeDef WaitConnected()
{//uint32_t startTime = HAL_GetTick();//uint32_t elapsedTime = 0;int Connected = 0;//是否配網(wǎng)完成// 持續(xù)等待回復,直到收到配網(wǎng)成功的回復;當TimeOut_flag為2時說明超時了while ( 1 != Connected){HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1);if(0 == stringMatched)//還未接收到數(shù)據(jù),一直等待{OLED_Clear();//OLED清零OLED_ShowString(0,4,"000 wait Connect");// 延時3秒//HAL_Delay(3000);while( stringMatched == 0){ReceivedAll();//判斷是否接收完所有字符串了}}if(1 == stringMatched){OLED_Clear();//OLED清零OLED_ShowString(0,0,"received:");OLED_ShowString(80,0,(u8 *)receivedData);// 延時3秒HAL_Delay(3000);if (strstr(receivedData, "ILOPEVENT:ILOP,CONNECTED") != NULL){OLED_Clear();//OLED清零OLED_ShowString(0,4,"Connect OK");// 延時3秒//HAL_Delay(3000);// 重置接收,準備接收下一段內(nèi)容reset_receive();Connected = 1;return HAL_OK;//配網(wǎng)成功}// 重置接收,準備接收下一段內(nèi)容reset_receive();}// 更新經(jīng)過的時間//elapsedTime = HAL_GetTick() - startTime;}return HAL_TIMEOUT;
}
#endif//等待wifi配網(wǎng)成功
HAL_StatusTypeDef WaitConnected()
{//uint32_t startTime = HAL_GetTick();//uint32_t elapsedTime = 0;OLED_Clear();//OLED清零OLED_ShowString(0,4," waiting Connect");int Connected = 0;//是否配網(wǎng)完成// 持續(xù)等待回復,直到收到配網(wǎng)成功的回復;當TimeOut_flag為2時說明超時了while ( 1 != Connected){HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1);if(0 != receivedLength)//收到數(shù)據(jù)了{//OLED_Clear();//OLED清零//OLED_ShowString(0,4,"000 wait Connect");// 延時3秒//HAL_Delay(3000);while( stringMatched == 0)//判斷是否接收完數(shù)據(jù),如果未接收完,則一直循環(huán),直到接收完{ReceivedAll();//判斷是否接收完所有字符串了}OLED_Clear();//OLED清零OLED_ShowString(0,0,"received:");OLED_ShowString(80,0,(u8 *)receivedData);// 延時3秒//HAL_Delay(3000);if (strstr((const char *)receivedData, "ILOPEVENT:ILOP,CONNECTED") != NULL){OLED_Clear();//OLED清零OLED_ShowString(0,4,"Connect OK");// 延時3秒//HAL_Delay(3000);// 重置接收,準備接收下一段內(nèi)容reset_receive();Connected = 1;return HAL_OK;//配網(wǎng)成功}// 重置接收,準備接收下一段內(nèi)容reset_receive();}}return HAL_TIMEOUT;
}// 進入WiFi配網(wǎng)過程的函數(shù)
HAL_StatusTypeDef WiFiConfigInit()
{HAL_StatusTypeDef status;// 發(fā)送指令 "AT",直到收到的回復是OKstatus = sendCommandAndWait(atCommands[0], "OK");while (status != HAL_OK){OLED_Clear();//OLED清零OLED_ShowString(0,4,"AT Not OK");status = sendCommandAndWait("AT\r\n", "OK");}OLED_Clear();//OLED清零OLED_ShowString(0,4,"AT OK");// 延時10秒//HAL_Delay(10000);// 發(fā)送指令 "AT+ILOPAWSAP\r\n"status = sendCommandAndWait("AT+ILOPAWSAP\r\n", "OK");while (status != HAL_OK){OLED_Clear();//OLED清零OLED_ShowString(0,4,"SWAP Not OK");status = sendCommandAndWait("AT+ILOPAWSAP\r\n", "OK");}OLED_Clear();//OLED清零OLED_ShowString(0,4,"SWAP OK");// 延時10秒//HAL_Delay(10000);if(HAL_OK == WaitConnected()){OLED_Clear();//OLED清零OLED_ShowString(0,4,"Connect OK");}else{OLED_Clear();//OLED清零OLED_ShowString(0,4,"Connect TimeOut");return HAL_TIMEOUT;}// 配網(wǎng)成功return HAL_OK;
}void DeviceInit()
{deviceParams.powerState = 0;
}
/*判斷wifi是否斷開,返回DISCONNECT 表示wifi斷開;返回CONNECT表示wifi處于連接狀態(tài)*/
uint8_t wifi_isDisconnected()
{uint8_t disConnected = DISCONNECT_FALSE;//默認沒有斷開if (strstr((const char *)receivedData, "ILOPEVENT:ILOP,CONNECTING") != NULL){OLED_Clear();//OLED清零OLED_ShowString(0,4,"wifi disconnect ");// 延時3秒//HAL_Delay(3000);// 重置接收,準備接收下一段內(nèi)容reset_receive();disConnected = DISCONNECT_TRUE;//wifi斷開} return disConnected;
}void wifi_task()
{HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1);//if(0 == stringMatched)//還未接收到數(shù)據(jù),一直等待if(0 != receivedIndex)//說明接收到消息了{//OLED_ShowString(0,4,"Recive date begin");// 延時3秒//HAL_Delay(3000);while( 0 == stringMatched){ReceivedAll();//判斷是否接收完所有字符串了}OLED_Clear();//OLED清零OLED_ShowString(0,0,"received:");OLED_ShowString(80,0,(u8 *)receivedData);// 延時3秒//HAL_Delay(3000);if(DISCONNECT_TRUE == wifi_isDisconnected())//如果wifi斷開了{OLED_Clear();//OLED清零OLED_ShowString(0,4,"wifi DisConnect ");// 延時3秒//HAL_Delay(3000); //while(HAL_OK != WaitConnected());WaitConnected();//等待wifi重連成功OLED_Clear();//OLED清零OLED_ShowString(0,4,"wifi recover ");// 延時3秒//HAL_Delay(3000); }else{OLED_Clear();//OLED清零OLED_ShowString(0,4,"wifi parse Task ");//HAL_Delay(3000);parseWiFiCommand((char *)receivedData);deviceControl();reset_receive(); }}{OLED_Clear();//OLED清零OLED_ShowString(0,4,"wifi connect "); } }void parseWiFiCommand(const char* command)
{const char* keyword = "+ILOPEVENT:SETJSON,property,";const char* powerstateKeyword = "\"powerstate\":";const char* powerstateValue = NULL;// 檢查指令是否以關(guān)鍵字開頭if (strncmp(command, keyword, strlen(keyword)) != 0) {while(1){OLED_Clear();//OLED清零OLED_ShowString(0,4,"error 1");}//return;}// 定位到powerstate關(guān)鍵字的位置powerstateValue = strstr(command, powerstateKeyword);if (powerstateValue == NULL) {while(1){OLED_Clear();//OLED清零OLED_ShowString(0,4,"error 2");}//return;}// 解析powerstate的值powerstateValue += strlen(powerstateKeyword);int powerstate = *powerstateValue - '0';//將powerstateValue指針所指向的字符轉(zhuǎn)換為整數(shù),并將結(jié)果存儲在powerstate變量中。*powerstateValue表示取指針所指向的字符,然后通過減去字符'0'的ASCII值,實現(xiàn)將字符轉(zhuǎn)換為對應的整數(shù)值。// 根據(jù)powerstate設置state的值if (powerstate == 0) {deviceParams.powerState = 0;} else if (powerstate == 1) {deviceParams.powerState = 1;} else {while(1){OLED_Clear();//OLED清零OLED_ShowString(0,4,"error 3");}}
}void deviceControl()
{if(0 == deviceParams.powerState)HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);//燈滅elseHAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);//燈亮
}// 發(fā)送數(shù)據(jù)
void sendWiFiData(const char* paramName, const char* paramValue) {// 構(gòu)建發(fā)送數(shù)據(jù)的格式//sprintf(txBuffer, "+ILOPEVENT:SETJSON,%s,%d,{\"%s\":%s}\r\n", paramName, strlen(paramValue), paramName, paramValue);// 在這里實現(xiàn)串口發(fā)送功能,將txBuffer中的數(shù)據(jù)發(fā)送出去// 例如:HAL_UART_Transmit(&huart1, (uint8_t*)txBuffer, strlen(txBuffer), HAL_MAX_DELAY);
}
筆記
記錄幾個開發(fā)中的細節(jié):
1、單片機向wifi模塊發(fā)送指令 AT+ILOPAWSAP\r\n
進行配網(wǎng)
2、當單片機收到wifi模塊返回的信息中,包含ILOPEVENT:ILOP,CONNECTED
時,說明配網(wǎng)成功
3、當單片機收到wifi模塊返回的信息中,包含ILOPEVENT:ILOP,CONNECTING
時,說明wifi已經(jīng)斷開,正在重連
4、云端向EMW3080發(fā)送的控制指令,也就是單片機需要解析的指令,格式如下(以參數(shù)“開關(guān)狀態(tài)”為例):
+ILOPEVENT:SETJSON,property,16,{"powerstate":0}
+ILOPEVENT:SETJSON,property,16,{"powerstate":1}