IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32与MQTT(一)STM32+ESP8266连接TCP服务器 -> 正文阅读

[嵌入式]STM32与MQTT(一)STM32+ESP8266连接TCP服务器


0. 前言

本系列不讲MQTT协议具体的原理,只说怎么使用STM32+ESP8266在裸机状态下使用HAL库连接华为云MQTT服务器

1. 开发前准备

1.1 准备工作

  1. STM32F103C8T6核心板
  2. 正点原子ATK-ESP-01模块(也可以使用其他ESP8266模块)
  3. 开发环境:STM32CubeIDE
  4. 串口调试助手
  5. 参考作者 张竞豪 的文章,写的真的很好

1.2 说明

  1. 使用资源说明
使用资源功能
USART1DBG信息打印
USART2连接ESP8266模块进行配置与网络通信
DMA1_Channel6USART2_Rx的DMA用作与接收数据
PB15ESP8266模块复位引脚
PC13板载LED灯
  1. 正点原子ATK-ESP-01模块使用请下载资料,就算使用其他的ESP8266模块也可使用正点原子的资料,主要参考资料中对于ESP8266的AT指令集的说明。
  2. 使用STM32CubeIDE开发,集成环境,个人觉得在STM32开发上比MDK环境好用
  3. 使用野火的fireTool,网络调试,串口调试一应俱全
  4. 虽然我没有私信联系这位作者,但是我很感谢他,基本上是跟着他文章做下来的

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 工程配置

使用资源一览,时钟树使用外部晶振,直接拉满就可以
配置图1
DMA1_Channel6 配置直接使用默认的就可以
配置图2
让STM32CubeIDE内置的CubeMX在生成代码时按照库的方式来生成
配置图3
扩大栈堆
配置图4

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\nAT测试指令,返回OK
ATEx\r\nx: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电脑为例:

  1. 在命令行中使用ipconfig查找到本机的ip地址
    在这里插入图片描述
  2. 在串口调试助手中设置
    在这里插入图片描述
    端口使用默认端口即可,注意这两个对应上述指令中的AT+CIPSTART=“mode”,“IpServer”,“ServerPort”,将mode设置为TCP,因为连接的是TCP服务器
  3. 在串口中发送下图所示指令,得到返回结果,注意在发送服务器信息时,端口号不加引号,最后进行发送信息测试
    发送指令并得到返回
  4. 发送测试信息
    接收到信息

2.2.3 STM32驱动ESP8266连接电脑TCP服务器

  1. 创建 “esp8266.h”“esp8266.c” 文件
  2. 检查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;
}
  1. 发送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;
}
  1. 完善 "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 */
}
  1. 测试使用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
  1. 上面所说的工程中只需要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服务器只需要修改配置中的服务器地址和服务器端口即可。


祝各位身体健康

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-28 13:27:32  更:2021-07-28 13:27:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 22:55:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码