STM32与MQTT(一)STM32+ESP8266连接TCP服务器
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中加入需要用到的变量
#define USART1_MAX_SENDLEN 1024
#define USART1_MAX_RECVLEN 1024
#define USART2_MAX_SENDLEN 1024
#define USART2_MAX_RECVLEN 1024
void MX_USART1_UART_Init(void);
void MX_USART2_UART_Init(void);
extern uint8_t USART1_TxBUF[USART1_MAX_SENDLEN];
extern uint8_t USART1_RxBUF[USART1_MAX_RECVLEN];
extern uint8_t USART2_TxBUF[USART2_MAX_SENDLEN];
extern uint8_t USART2_RxBUF[USART2_MAX_RECVLEN];
extern volatile uint8_t USART2_RxLen;
extern volatile uint8_t USART2_RecvEndFlag;
void u1_printf(char *fmt, ...);
void u2_transmit(char *fmt, ...);
2.1.4 修改 “usart.c”
在 MX_USART2_UART_Init(void) 函数中添加以下代码,开启IDLE中断,并使能DMA接收 在最后添加第2步中声明的两个函数的函数体
void MX_USART2_UART_Init(void) {
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart2, USART2_RxBUF, USART2_MAX_RECVLEN);
}
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);
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;
}
2.1.5 修改 “stm32f1xx_it.c”
在中断部分加入代码,完成不定长数据接收,引入所需的头文件后,需要对 USART2_IRQHandler() 作如下修改,引入DMA中断,当DMA接收完成后将USART2_RxLen设置为接收数据的长度,USART2_RecvEndFlag标志置1
void USART2_IRQHandler(void)
{
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;
}
HAL_UART_IRQHandler(&huart2);
}
2.1.6 设置监听
完成上述步骤后,如果需要获取USART2接收到的数据只需要在需要获取数据的位置监听 USART2_RecvEndFlag 的值,当其为1时,读取USART2_RxBUF的内容即可,示例:
while (timeout--) {
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_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指令并检查指令闭环
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);
else
u2_transmit("%s\r\n", cmd);
u1_printf("(DBG:) Waiting reply\r\n");
while (timeout--) {
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;
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;
}
- 测试使用STM32驱动ESP8266连接电脑TCP服务器
在github仓库中找到 “esp8266.c” 和 “net_conf.h” 两个文件,对 “net_conf.h” 中的网络相关属性做配置,或使用其他的方法使函数可以获取TCP服务器的地址和端口,下面是 “net_conf.h” 的内容
#ifndef __NET_CONF_H
#define __NET_CONF_H
#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);
else
u2_transmit("%s\r\n", cmd);
u1_printf("(DBG:) Waiting reply\r\n");
while (timeout--) {
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;
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);
retry_count = 0;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
return _SUCCEED;
}
3. 结束
参考代码,完成上述过程后,STM32可以成功驱动ESP8266连接TCP服务器,连接不同的TCP服务器只需要修改配置中的服务器地址和服务器端口即可。
祝各位身体健康
|