STM32與MQTT(一)STM32+ESP8266連接TCP服務器
- 0. 前言
- 1. 開發前準備
- 1.1 準備作業
- 1.2 說明
- 2. 開發程序
- 2.1 USART1與USART2串口使用
- 2.1.1 兩個串口使用上的區別
- 2.1.2 工程配置
- 2.1.3 修改 "usart.h"
- 2.1.4 修改 "usart.c"
- 2.1.5 修改 "stm32f1xx_it.c"
- 2.1.6 設定監聽
- 2.1.7 測驗代碼
- 2.2 連接STM32與ESP8266
- 2.2.1 熟悉AT指令
- 2.2.2 串口驅動ESP8266連接電腦TCP服務器
- 2.2.3 STM32驅動ESP8266連接電腦TCP服務器
- 3. 結束
0. 前言
本系列不講MQTT協議具體的原理,只說怎么使用STM32+ESP8266在裸機狀態下使用HAL庫連接華為云MQTT服務器
1. 開發前準備
1.1 準備作業
- STM32F103C8T6核心板
- 正點原子ATK-ESP-01模塊(也可以使用其他ESP8266模塊)
- 開發環境:STM32CubeIDE
- 串口除錯助手
- 參考作者 張競豪 的文章,寫的真的很好
1.2 說明
- 使用資源說明
| 使用資源 | 功能 |
|---|---|
| USART1 | DBG資訊列印 |
| USART2 | 連接ESP8266模塊進行配置與網路通信 |
| DMA1_Channel6 | USART2_Rx的DMA用作與接收資料 |
| PB15 | ESP8266模塊復位引腳 |
| PC13 | 板載LED燈 |
- 正點原子ATK-ESP-01模塊使用請下載資料,就算使用其他的ESP8266模塊也可使用正點原子的資料,主要參考資料中對于ESP8266的AT指令集的說明,
- 使用STM32CubeIDE開發,集成環境,個人覺得在STM32開發上比MDK環境好用
- 使用野火的fireTool,網路除錯,串口除錯一應俱全
- 雖然我沒有私信聯系這位作者,但是我很感謝他,基本上是跟著他文章做下來的
2. 開發程序
2.1 USART1與USART2串口使用
2.1.1 兩個串口使用上的區別
請耐心看完以下內容
使用USART1時,考慮到在設計中只用作DBG資訊列印,因此對其接收沒有要求,甚至不需要接收,在這里我沒有用到USART1的接收功能
使用USART2時,首先要搞清楚,USART2是如何通過ESP8266連接網路,并進行通信的,類比HC-05等的藍牙模塊,這類模塊通過串口線連接到串口上,配置并連接完成后,對下層透明,下層不需要關心協議如何實作,只對其連接的串口發送資訊,而將資訊加上頭部、解包或無線傳輸等功能完全由該芯片(模塊)實作,所以類比HC-05等藍牙模塊,我們對ESP8266模塊要做的事情非常簡單:正確配置,連接網路,使能發送,
由于USART2需要發送與接收資料,顯然,發送資料的長度是本地可控的,簡單使用HAL庫函式即可完成,但是接收資料的長度是不可控的,其完全由配置程序中ESP8266回傳的資料和配置完成后ESP8266接收到的資料長度指定,即接收到的資料是不定長的,為了實作不定長實時資料接收,在這里我們使用DMA+中斷的方法(參考文章找不到了,但是能搜到的方法大致相同,我也會貼出我用到的方法),
2.1.2 工程配置
使用資源一覽,時鐘樹使用外部晶振,直接拉滿就可以

DMA1_Channel6 配置直接使用默認的就可以

讓STM32CubeIDE內置的CubeMX在生成代碼時按照庫的方式來生成

擴大堆疊堆

2.1.3 修改 “usart.h”
打開生成后的工程中usart.h
在usart.h中加入需要用到的變數
/* 對照注釋提示插入代碼,不在注釋包括出來的
* 區域內的代碼在重新生成代碼時會被清除
*/
/* USER CODE BEGIN Private defines */
// 用戶代碼開始
#define USART1_MAX_SENDLEN 1024
#define USART1_MAX_RECVLEN 1024
#define USART2_MAX_SENDLEN 1024
#define USART2_MAX_RECVLEN 1024
// 用戶代碼結束
/* USER CODE END Private defines */
void MX_USART1_UART_Init(void); // CubeMX生成的代碼
void MX_USART2_UART_Init(void); // CubeMX生成的代碼
/* USER CODE BEGIN Prototypes */
// 用戶代碼開始
extern uint8_t USART1_TxBUF[USART1_MAX_SENDLEN];// usart1 發送資料快取區
extern uint8_t USART1_RxBUF[USART1_MAX_RECVLEN];// usart1 接收資料快取區
extern uint8_t USART2_TxBUF[USART2_MAX_SENDLEN];// usart2 發送資料快取區
extern uint8_t USART2_RxBUF[USART2_MAX_RECVLEN];// usart2 接收資料快取區
extern volatile uint8_t USART2_RxLen;// usart2 接收資料長度
extern volatile uint8_t USART2_RecvEndFlag;// usart2 接收資料完成標志位
// 對usart1發送資料
void u1_printf(char *fmt, ...);
// 我不喜歡將對usart2發送資料也命名為printf,因為實際上并沒有對我print
void u2_transmit(char *fmt, ...);
// 用戶代碼結束
/* USER CODE END Prototypes */
2.1.4 修改 “usart.c”
在 MX_USART2_UART_Init(void) 函式中添加以下代碼,開啟IDLE中斷,并使能DMA接收
在最后添加第2步中宣告的兩個函式的函式體
void MX_USART2_UART_Init(void) {
//......
/* USER CODE BEGIN USART2_Init 2 */
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart2, USART2_RxBUF, USART2_MAX_RECVLEN);
/* USER CODE END USART2_Init 2 */
//......
}
/**********************分割線**********************/
/* USER CODE BEGIN 1 */
// 用戶代碼開始
void u1_printf(char *fmt, ...) {
uint16_t i;
va_list ap;
va_start(ap, fmt);
vsprintf((char*) USART1_TxBUF, fmt, ap);
va_end(ap);
i = strlen((const char*) USART1_TxBUF);
HAL_UART_Transmit(&huart1, USART1_TxBUF, i, 100);
memset(USART1_TxBUF, 0, USART1_MAX_SENDLEN);
}
void u2_transmit(char *fmt, ...) {
uint16_t i, j;
va_list ap;
va_start(ap, fmt);
vsprintf((char*) USART2_TxBUF, fmt, ap);
va_end(ap);
// 排除掉發送資訊中所有的'\00'使有效資訊可以發送
// 但是仍要考慮到,MQTT報文等內容中可能含有'\00'
// 這個時候就需要直接使用HAL_UART_Transmit()函式發送
// 而放棄使用u2_transmit()
for (i = 0; i < USART2_MAX_SENDLEN; i++) {
j = i + 1;
if (USART2_TxBUF[i] == '\00') {
for (; j < USART2_MAX_SENDLEN; j++) {
USART2_TxBUF[j - 1] = USART2_TxBUF[j];
}
}
}
i = strlen((const char*) USART2_TxBUF);
HAL_UART_Transmit(&huart2, USART2_TxBUF, i, 100);
memset(USART2_TxBUF, 0, USART2_MAX_SENDLEN);
memset(USART2_RxBUF, 0, USART2_MAX_RECVLEN);
USART2_RecvEndFlag = 0;
}
// 用戶代碼結束
/* USER CODE END 1 */
2.1.5 修改 “stm32f1xx_it.c”
在中斷部分加入代碼,完成不定長資料接收,引入所需的頭檔案后,需要對 USART2_IRQHandler() 作如下修改,引入DMA中斷,當DMA接收完成后將USART2_RxLen設定為接收資料的長度,USART2_RecvEndFlag標志置1
/**
* @brief This function handles USART2 global interrupt.
*/
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
uint32_t tmp_flag = 0;
uint32_t temp;
tmp_flag = __HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE);
if ((tmp_flag != RESET)) {
__HAL_UART_CLEAR_IDLEFLAG(&huart2);
temp = huart2.Instance->SR;
temp = huart2.Instance->DR;
HAL_UART_DMAStop(&huart2);
temp = hdma_usart2_rx.Instance->CNDTR;
USART2_RxLen = USART2_MAX_RECVLEN - temp;
USART2_RecvEndFlag = 1;
}
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
/* USER CODE END USART2_IRQn 1 */
}
2.1.6 設定監聽
完成上述步驟后,如果需要獲取USART2接收到的資料只需要在需要獲取資料的位置監聽 USART2_RecvEndFlag 的值,當其為1時,讀取USART2_RxBUF的內容即可,示例:
/* 在timeout時間內進行監聽,
* 如果監聽到USART2_RecvEndFlag為1則對資料進行處理
*/
while (timeout--) {
// u1_printf("%d ", timeout);
// finish dma receive
if (USART2_RecvEndFlag == 1) {
check = esp8266_CheckRespond(ack);
if (check == _MATCHOK) {
u1_printf("(DBG:) Command closed loop completed\r\n");
}
USART2_RxLen = 0;
USART2_RecvEndFlag = 0;
HAL_UART_Receive_DMA(&huart2, USART2_RxBUF, USART2_MAX_RECVLEN);
break;
}
HAL_Delay(1);
}
2.1.7 測驗代碼
不做展開,請自己測驗一下,如果不成功,請搜索相關內容再次嘗試,只要usart2能夠實作不定長資料接收,就可開始下一步
2.2 連接STM32與ESP8266
2.2.1 熟悉AT指令
請耐心看完以下內容
如果你已經下載了正點原子的資料,那么可以打開6,ESP8266相關資料檔案夾,查閱ESP8266_AT指令集V2.1.0了解ESP8266的AT指令集,在實際連接前,可以先使用CH340x、CP2102等串口模塊通過串口除錯助手將ESP8266模塊連接到網路,熟悉這個程序后,只需要使用STM32的USART2向ESP8266模塊發送在串口助手中發送過的指令,就可以使用STM32驅動ESP8266連接網路
那么先來了解一下本次需要用到的AT指令,均來自ESP8266_AT指令集V2.1.0
| AT指令 | 作用 |
|---|---|
| +++ | 請參照說明檔案 |
| AT\r\n | AT測驗指令,回傳OK |
| ATEx\r\n | x:0—關倍訓顯,1—打開回顯 |
| AT+CWMODE_CUR=x\r\n | 設定模塊作業模式,不保存到Flash,x:0—AP,1—STA,2—AP+STA |
| AT+CWAUTOCONN=x\r\n | 設定自動連接,x:0—關閉,1—開啟 |
| AT+CWJAP_CUR=“ssid”,“pswd”\r\n | 連接AP網路,不保存到Flash,ssid—網路名稱,pswd—密碼 |
| AT+CWJAP_CUR?\r\n | 查詢網路資訊,需要連接到網路 |
| AT+CIPSTA_CUR?\r\n | 查詢IP資訊,需要連接到網路 |
| AT+CWDHCP_CUR=x,y\r\n | 請參照說明檔案 |
| AT+CIPMUX=x\r\n | 多連接模式設定,x:0—關閉,1—開啟 |
| AT+CIPMODE=x\r\n | 傳輸模式設定,x:0—普通模式,1—透傳模式 |
| AT+CIPSTART=“mode”,“IpServer”,ServerPort\r\n | 連接到服務器,具體請參照說明檔案,mode指示服務器型別,IpServer指示服務器地址,ServerPort指示服務器埠 |
| AT+CIPSEND\r\n | 發送資料 |
其他AT指令請查閱檔案,將以上步驟按照設定引數并需要執行一次后,向ESP8266發送資料,TCP服務端即可收到資料,
2.2.2 串口驅動ESP8266連接電腦TCP服務器
接收資料測驗,以連接WIFI上網的Windows電腦為例:
- 在命令列中使用ipconfig查找到本機的ip地址

- 在串口除錯助手中設定

埠使用默認埠即可,注意這兩個對應上述指令中的AT+CIPSTART=“mode”,“IpServer”,“ServerPort”,將mode設定為TCP,因為連接的是TCP服務器 - 在串口中發送下圖所示指令,得到回傳結果,注意在發送服務器資訊時,埠號不加引號,最后進行發送資訊測驗

- 發送測驗資訊

2.2.3 STM32驅動ESP8266連接電腦TCP服務器
- 創建 “esp8266.h” 和 “esp8266.c” 檔案
- 檢查AT指令回傳的資料
使用函式strstr(str1, str2) 具體原理不贅述,該函式如果查找成功則回傳值不為NULL,使用此方法可以檢查發送AT指令后得到的回傳結果是否為預期,由此來判斷AT指令是否成功發送以及是否起作用
// WIFI_StateTypeDef 是我自己定義的一個表示ESP8266狀態的enum型別
// str 為期望的回傳,如期望回傳 "OK",則str應設定為 "OK"
WIFI_StateTypeDef esp8266_CheckRespond(uint8_t *str) {
u1_printf("(DBG:) usart2 recv:\r\n%s\r\n", USART2_RxBUF);
if (strstr((const char*) USART2_RxBUF, (const char*) str) != NULL) {
u1_printf("(DBG:) Match succeed\r\n");
memset(USART2_RxBUF, 0, USART2_MAX_RECVLEN);
return _MATCHOK;
}
memset(USART2_RxBUF, 0, USART2_MAX_RECVLEN);
return _MATCHERROR;
}
- 發送AT指令并檢查指令倍訓
/**
* @param cmd: cmd to be send
* @param ack: correct ack to be checked
* @param waitms: wait time ms
* @param newline: transmit a new line or not
*/
WIFI_StateTypeDef esp8266_TransmitCmd(uint8_t *cmd, uint8_t *ack,
uint32_t waitms, uint8_t newline) {
int timeout = waitms;
uint8_t check = 0;
memset(USART2_RxBUF, 0, USART2_MAX_RECVLEN);
u1_printf("\r\n(DBG:) Try to send cmd: %s\r\n", cmd);
if (newline == 0)
u2_transmit("%s", cmd); // transmit cmd to usart2
else
u2_transmit("%s\r\n", cmd); // transmit cmd to usart2
u1_printf("(DBG:) Waiting reply\r\n");
while (timeout--) {
// u1_printf("%d ", timeout);
// finish dma receive
if (USART2_RecvEndFlag == 1) {
check = esp8266_CheckRespond(ack);
if (check == _MATCHOK) {
u1_printf("(DBG:) Command closed loop completed\r\n");
}
USART2_RxLen = 0;
USART2_RecvEndFlag = 0;
HAL_UART_Receive_DMA(&huart2, USART2_RxBUF, USART2_MAX_RECVLEN);
break;
}
HAL_Delay(1);
}
if (check == _MATCHERROR) {
u1_printf("\r\n(DBG:) Cmd match failed\r\n");
return check;
}
if (timeout <= 0) {
u1_printf("(DBG:) Finish waiting\r\n");
u1_printf("\r\n(DBG:) Timeout\r\n");
return _TIMEOUT;
}
u1_printf("(DBG:) Succeed\r\n");
return _SUCCEED;
}
- 完善 "esp8266.c"
通過之前用串口助手控制ESP8266連接TCP服務器的程序,以上述兩個函式為基礎構建連接程序,以關倍訓顯的命令倍訓為例,發送命令后根據 **esp8266_Transmit()的回傳值決定下一步操作,當不成功時記錄重試次數,重試次數超過最大值后,放棄重試,回傳該命令發送失敗,具體代碼請查閱 Github倉庫 中 \Core\Inc\esp8266.h 和\Core\Src\esp8266.c
WIFI_StateTypeDef esp8266_SetUpTCPConnection() {
uint8_t retry_count = 0;
/* Other steps */
/**************************分割線**************************/
/* Close echo */
u1_printf("(DBG:) Trying to close echo\r\n");
wifi_config_step++;
while (esp8266_TransmitCmd((uint8_t*) "ATE0", OK_ACK, 500, WITH_NEWLINE) != _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Close echo failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
HAL_Delay(100);
retry_count = 0; // reset retry count
/**************************分割線**************************/
/* Other steps */
}
- 測驗使用STM32驅動ESP8266連接電腦TCP服務器
在github倉庫中找到 “esp8266.c” 和 “net_conf.h” 兩個檔案,對 “net_conf.h” 中的網路相關屬性做配置,或使用其他的方法使函式可以獲取TCP服務器的地址和埠,下面是 “net_conf.h” 的內容
#ifndef __NET_CONF_H
#define __NET_CONF_H
// Please modify those macro definitions to meet needs
#define WIFI_TAR 1
#if WIFI_TAR == 0
#define AP_SSID (const char*)"YOUR OWN WIFI SSID"
#define AP_PSWD (const char*)"YOUR OWN WIFI PSWD"
#elif WIFI_TAR == 1
#define AP_SSID (const char*)"YOUR OWN PC AP SSID"
#define AP_PSWD (const char*)"YOUR OWN PC AP PSWD"
#endif
#define CONNECT_MODE 0
#if CONNECT_MODE == 0
#define IpServer "YOUR OWN MQTT SERVER ADDRESS"
#define ServerPort "YOUR OWN MQTT SERVER PORT"
#elif CONNECT_MODE == 1
#define IpServer "YOUR OWN PC TCP SERVER ADDRESS"
#define ServerPort "YOUR OWN PC TCP SERVER PORT"
#endif
#define MQTT_DEVICE_ID (uint8_t*)"YOUR OWN MQTT DEVICE ID"
#define MQTT_SECRET (uint8_t*)"YOUR OWN MQTT DEVICE SECRET CODE"
#define MQTT_CLIENTID "YOUR OWN MQTT DEVICE CLIENTID"
#define MQTT_USERNAME "YOUR OWN MQTT DEVICE USERNAME"
#define MQTT_PASSWORD "YOUR OWN MQTT DEVICE PASSWORD"
#endif
- 上面所說的工程中只需要esp8266相關檔案即可使STM32驅動ESP8266連接TCP服務器,請務必讀多讀幾遍代碼,esp8266.c 代碼如下,實際上就是使用之前說的兩個函式復現使用串口助手發送AT指令的程序,并加入確認部分,請先運行以下代碼通過將測驗資訊發送給電腦TCP服務器成功后,再進行后續內容
#include "esp8266.h"
static WIFI_StateTypeDef wifi_state = _OFFLINE;
static WIFI_StateTypeDef trans_state = _UNKNOWN_STATE;
static uint8_t wifi_config_step = 0;
WIFI_StateTypeDef esp8266_CheckRespond(uint8_t *str) {
u1_printf("(DBG:) usart2 recv:\r\n%s\r\n", USART2_RxBUF);
if (strstr((const char*) USART2_RxBUF, (const char*) str) != NULL) {
u1_printf("(DBG:) Match succeed\r\n");
memset(USART2_RxBUF, 0, USART2_MAX_RECVLEN);
return _MATCHOK;
}
memset(USART2_RxBUF, 0, USART2_MAX_RECVLEN);
return _MATCHERROR;
}
WIFI_StateTypeDef esp8266_TransmitCmd(uint8_t *cmd, uint8_t *ack,
uint32_t waitms, uint8_t newline) {
int timeout = waitms;
uint8_t check = 0;
memset(USART2_RxBUF, 0, USART2_MAX_RECVLEN);
u1_printf("\r\n(DBG:) Try to send cmd: %s\r\n", cmd);
if (newline == 0)
u2_transmit("%s", cmd); // transmit cmd to usart2
else
u2_transmit("%s\r\n", cmd); // transmit cmd to usart2
u1_printf("(DBG:) Waiting reply\r\n");
while (timeout--) {
// u1_printf("%d ", timeout);
// finish dma receive
if (USART2_RecvEndFlag == 1) {
check = esp8266_CheckRespond(ack);
if (check == _MATCHOK) {
u1_printf("(DBG:) Command closed loop completed\r\n");
}
USART2_RxLen = 0;
USART2_RecvEndFlag = 0;
HAL_UART_Receive_DMA(&huart2, USART2_RxBUF, USART2_MAX_RECVLEN);
break;
}
HAL_Delay(1);
}
if (check == _MATCHERROR) {
u1_printf("\r\n(DBG:) Cmd match failed\r\n");
return check;
}
if (timeout <= 0) {
u1_printf("(DBG:) Finish waiting\r\n");
u1_printf("\r\n(DBG:) Timeout\r\n");
return _TIMEOUT;
}
u1_printf("(DBG:) Succeed\r\n");
return _SUCCEED;
}
WIFI_StateTypeDef esp8266_HardwareReset(uint32_t waitms) {
int timeout = waitms;
WIFI_RST_Enable();
HAL_Delay(500);
WIFI_RST_Disable();
while (timeout--) {
if (USART2_RecvEndFlag == 1) {
u1_printf("(DBG:) Hardware Reset OK!\r\n");
HAL_Delay(100);
USART2_RxLen = 0;
USART2_RecvEndFlag = 0;
HAL_UART_Receive_DMA(&huart2, USART2_RxBUF, USART2_MAX_RECVLEN);
return _SUCCEED;
}
HAL_Delay(1);
}
if (timeout <= 0) {
u1_printf("(DBG:) Finish waiting\r\n");
u1_printf("\r\n(DBG:) Timeout\r\n");
return _TIMEOUT;
}
return _UNKNOWN_ERROR;
}
WIFI_StateTypeDef esp8266_ConnectAP() {
uint16_t cmd_len = strlen(AP_SSID) + strlen(AP_PSWD) + 30;
uint8_t *cmd = (uint8_t*) malloc(cmd_len * sizeof(uint8_t));
memset(cmd, 0, cmd_len);
sprintf((char*) cmd, "AT+CWJAP_CUR=\"%s\",\"%s\"", AP_SSID, AP_PSWD);
if (esp8266_TransmitCmd(cmd, (uint8_t*) "WIFI CONNECTED",
3 * ESP8266_MAX_TIMEOUT, WITH_NEWLINE) == _SUCCEED)
wifi_state = _ONLINE;
else
wifi_state = _OFFLINE;
return wifi_state;
}
WIFI_StateTypeDef esp8266_ConnectServer() {
uint16_t cmd_len = strlen(IpServer) + strlen(ServerPort) + 30;
uint8_t *cmd = (uint8_t*) malloc(cmd_len * sizeof(uint8_t));
memset(cmd, 0, cmd_len);
sprintf((char*) cmd, "AT+CIPSTART=\"TCP\",\"%s\",%s", IpServer, ServerPort);
if (esp8266_TransmitCmd(cmd, (uint8_t*) "CONNECT", 3 * ESP8266_MAX_TIMEOUT,
WITH_NEWLINE) == _SUCCEED)
wifi_state = _CONNECTED;
else
wifi_state = _DISCONNECTED;
return wifi_state;
}
WIFI_StateTypeDef esp8266_SetUpTCPConnection() {
uint8_t retry_count = 0;
/* Reset esp8266 */
u1_printf("(DBG:) Trying to reset esp8266\r\n");
wifi_config_step++;
while (esp8266_HardwareReset(500) != _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Reset failed\r\n");
retry_count = 0;
trans_state = _UNKNOWN_STATE;
wifi_config_step--;
return _FAILED;
}
}
HAL_Delay(2000); // wait 2 seconds
retry_count = 0; // reset retry count
/* Disable transparent transmission */
u1_printf("(DBG:) Trying to close transparent transmission\r\n");
wifi_config_step++;
while (esp8266_TransmitCmd(TRANS_QUIT_CMD, TRANS_QUIT_CMD,
ESP8266_MAX_TIMEOUT,
WITHOUT_NEWLINE) != _SUCCEED) {
retry_count++;
HAL_Delay(1500);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Close transparent transmission failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
trans_state = _TRANS_DISABLE;
HAL_Delay(1500);
retry_count = 0; // reset retry count
/* Close echo */
u1_printf("(DBG:) Trying to close echo\r\n");
wifi_config_step++;
while (esp8266_TransmitCmd((uint8_t*) "ATE0", OK_ACK, 500, WITH_NEWLINE)
!= _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Close echo failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
HAL_Delay(100);
retry_count = 0; // reset retry count
/* Set wifi mode 0:AP 1:STA 2:AP+STA */
u1_printf("(DBG:) Trying to set Wifi mode\r\n");
wifi_config_step++;
while (esp8266_TransmitCmd((uint8_t*) "AT+CWMODE_CUR=1", OK_ACK, 500,
WITH_NEWLINE) != _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Set Wifi mode failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
HAL_Delay(100);
retry_count = 0; // reset retry count
/* Disable auto connect */
u1_printf("(DBG:) Trying to close auto connect\r\n");
wifi_config_step++;
while (esp8266_TransmitCmd((uint8_t*) "AT+CWAUTOCONN=0", OK_ACK, 500,
WITH_NEWLINE) != _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Close auto connect failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
HAL_Delay(100);
retry_count = 0; // reset retry count
/* Connect to AP(Wifi) */
u1_printf("(DBG:) Trying to connect to AP\r\n");
wifi_config_step++;
while (esp8266_ConnectAP() != _ONLINE) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Connect to AP failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
HAL_Delay(1000);
retry_count = 0; // reset retry count
/* Try to get AP info */
if (wifi_state == _ONLINE) {
while (esp8266_TransmitCmd((uint8_t*) "AT+CWJAP_CUR?", OK_ACK,
ESP8266_MAX_TIMEOUT, WITH_NEWLINE) != _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME / 2) {
u1_printf("(DBG:) Get AP msg failed\r\n");
u1_printf(
"(DBG:) Connect server process will not be terminated");
retry_count = 0;
wifi_config_step--;
break;
}
}
}
HAL_Delay(1000);
retry_count = 0; // reset retry count
/* Try to get IP info */
if (wifi_state == _ONLINE) {
while (esp8266_TransmitCmd((uint8_t*) " AT+CIPSTA_CUR?", OK_ACK,
ESP8266_MAX_TIMEOUT, WITH_NEWLINE) != _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME / 2) {
u1_printf("(DBG:) Get IP info failed\r\n");
u1_printf(
"(DBG:) Connect server process will not be terminated");
retry_count = 0;
wifi_config_step--;
break;
}
}
}
HAL_Delay(1000);
retry_count = 0; // reset retry count
/* Set DHCP */
u1_printf("(DBG:) Trying to set DHCP mode\r\n");
wifi_config_step++;
while (esp8266_TransmitCmd((uint8_t*) "AT+CWDHCP_CUR=1,1", OK_ACK, 1000,
WITH_NEWLINE) != _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Set DHCP model failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
HAL_Delay(1000);
retry_count = 0;
/* Set single connection */
u1_printf("(DBG:) Trying to set single connection\r\n");
wifi_config_step++;
while (esp8266_TransmitCmd((uint8_t*) "AT+CIPMUX=0", OK_ACK, 1000,
WITH_NEWLINE) != _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Set single connection model failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
HAL_Delay(1000);
retry_count = 0;
/* Set transparent transmission */
u1_printf("(DBG:) Trying to set transparent transmission mode\r\n");
wifi_config_step++;
while (esp8266_TransmitCmd((uint8_t*) "AT+CIPMODE=1", OK_ACK, 1000,
WITH_NEWLINE) != _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Set transparent transmission mode failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
HAL_Delay(1000);
retry_count = 0;
/* Connect to TCP server */
u1_printf("(DBG:) Trying to connect TCP server\r\n");
wifi_config_step++;
while (esp8266_ConnectServer() != _CONNECTED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Connect TCP server failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
HAL_Delay(1000);
retry_count = 0;
/* enable data send(transparent transmission) */
u1_printf("(DBG:) Trying to enable data send\r\n");
wifi_config_step++;
while (esp8266_TransmitCmd((uint8_t*) "AT+CIPSEND", OK_ACK, 1000,
WITH_NEWLINE) != _SUCCEED) {
retry_count++;
HAL_Delay(1000);
if (retry_count > ESP8266_MAX_RETRY_TIME) {
u1_printf("(DBG:) Set transparent transmission mode failed\r\n");
retry_count = 0;
wifi_config_step--;
return _FAILED;
}
}
trans_state = _TRANS_ENBALE;
HAL_Delay(1000);
retry_count = 0;
/* send test msg */
// u1_printf("Test msg is sending to TCP Server\r\n");
// u2_transmit("This msg means TCP connection has been set up\r\n");
// u1_printf("Test msg has been send to TCP Server\r\n");
return _SUCCEED;
}
3. 結束
參考代碼,完成上述程序后,STM32可以成功驅動ESP8266連接TCP服務器,連接不同的TCP服務器只需要修改配置中的服務器地址和服務器埠即可,
祝各位身體健康
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/290740.html
標籤:其他
