一、前期配置
参考:
https://blog.csdn.net/weixin_44386927/article/details/155891583
的配置。
二、代码部分
1、定义部分
c
1、串口的初始化参考之前的配置。
#define AP_SSID "ESP01S_AP" // AP模式的WiFi名称
#define AP_PWD "12345678" // AP模式的WiFi密码(至少8位)
#define AP_CHANNEL 6 // AP信道(1-13)
#define AP_ENCRYPT 3 // 加密方式:3=WPA2_PSK(推荐)
#define TCP_SERVER_PORT 8080
typedef struct {
uint8_t conn_id; // 数据发送方的conn_id
uint16_t data_len; // 原始数据长度
char data_content[UART_RX_BUF_SIZE];// 原始数据内容
uint8_t parse_ok; // 解析成功标记
} IPD_Data_Proc_t;
extern uint8_t ESP01_Send_To_Client(uint8_t conn_id, const char *proc_data) ;
extern void ESP01_Parse_IPD_Data(const char *ipd_str, IPD_Data_Proc_t *ipd_proc) ;
2、函数部分
c
/**
* @brief 去除字符串首尾空白符(\r\n/空格/制表符)
*/
void trim_whitespace(char *str) {
if (str == NULL || *str == '\0') return;
// 去除开头空白符
char *start = str;
while (*start != '\0' && isspace((unsigned char)*start)) start++;
// 去除结尾空白符
char *end = str + strlen(str) - 1;
while (end > start && isspace((unsigned char)*end)) end--;
*(end + 1) = '\0';
// 移动到原字符串开头
memmove(str, start, strlen(start) + 1);
}
/**
* @brief 解析ESP01S的+IPD数据(兼容首尾\r\n,提取conn_id和内容)
*/
void ESP01_Parse_IPD_Data(const char *ipd_str, IPD_Data_Proc_t *ipd_proc) {
memset(ipd_proc, 0, sizeof(IPD_Data_Proc_t));
ipd_proc->parse_ok = 0;
// 空数据校验
if (ipd_str == NULL || strlen(ipd_str) == 0) return;
// 去除首尾空白符(处理\r\n+IPD...\r\n)
char temp_buf[128] = {0};
strncpy(temp_buf, ipd_str, sizeof(temp_buf)-1);
trim_whitespace(temp_buf);
// 校验是否为IPD格式
if (strncmp(temp_buf, "+IPD,", 5) != 0) return;
// 解析conn_id(IPD后的第一个数字)
const char *p = temp_buf + 5;
char id_str[4] = {0};
int i = 0;
while (*p != ',' && *p != '\0') id_str[i++] = *p++;
ipd_proc->conn_id = atoi(id_str);
p++; // 跳过逗号
// 解析数据长度
char len_str[8] = {0};
i = 0;
while (*p != ':' && *p != '\0') len_str[i++] = *p++;
ipd_proc->data_len = atoi(len_str);
p++; // 跳过冒号
// 解析原始数据内容
if (ipd_proc->data_len > 0 && ipd_proc->data_len < 64) {
strncpy(ipd_proc->data_content, p, ipd_proc->data_len);
ipd_proc->data_content[ipd_proc->data_len] = '\0';
ipd_proc->parse_ok = 1;
}
}
/**
* @brief 向指定conn_id的客户端回传处理后的数据
*/
uint8_t ESP01_Send_To_Client(uint8_t conn_id, const char *proc_data) {
if (proc_data == NULL || strlen(proc_data) == 0) {
printf("❌ 回传数据为空\r\n");
return 0;
}
uint16_t proc_len = strlen(proc_data);
// 步骤1:发送AT+CIPSEND指令(指定ID和长度)
char send_cmd[64] = {0};
snprintf(send_cmd, sizeof(send_cmd), "AT+CIPSEND=%d,%d\r\n", conn_id, proc_len);
if (!ESP01_SendATCmd(send_cmd, ">", "ERROR", 1000)) {
printf("❌ ID%d:AT+CIPSEND指令失败\r\n", conn_id);
return 0;
}
// 步骤2:发送处理后的数据(纯数据,无\r\n)
HAL_UART_Transmit(&huart2, (uint8_t*)proc_data, proc_len, 100);
osDelay(20); // 确保数据发送完成
return 1;
}
3、任务部分
c
void StartTask02 (void *argument)
{
ESP01_UART_Data_t rx_data =
{ 0 };
char cmd_buf[USART1_DMA_BUF_SIZE] =
{ 0 };
char at_cmd[128] =
{ 0 };
printf ("串口1调试指令接收任务已启动,支持指令:\r\n");
printf ("1. LED_ON - 点亮LED\r\n");
printf ("2. LED_OFF - 关闭LED\r\n");
printf ("3. ESP_AT+AT - 配置ESP01并开启\r\n");
while(1)
{
.....前面省略,参考之前的。
else if (strncmp (cmd_buf, "ESP_AT+", 7) == 0)
{
// 提取AT指令(去掉前�?ESP_AT+,得到真正的AT指令�?
strncpy (at_cmd, cmd_buf + 7, sizeof(at_cmd) - 1);
printf ("手动发AT指令给ESP01:%s\r\n", at_cmd);
if (strcmp (at_cmd, "AP") == 0)
{
HAL_UART_Transmit (&huart2, (uint8_t*) "+++", 3, 100);
osDelay (1000);
if (!ESP01_SendATCmd ("AT", "OK", "ERROR", AT_CMD_TIMEOUT))
{
printf ("AT失败\r\n");
}
// 2. 切换到AP模式(CWMODE=2:仅AP;3:AP+STA)
if (!ESP01_SendATCmd ("AT+CWMODE=2", "OK", "ERROR",
AT_CMD_TIMEOUT))
{
printf ("AT+CWMODE=2失败\r\n");
}
ESP01_SendATCmd ("AT+RST", "READY", "ERROR", 2000);
osDelay (1500); // 等待重启完成(至少1秒)
if (!ESP01_SendATCmd ("AT", "OK", "ERROR", AT_CMD_TIMEOUT))
{
printf ("重启后AT测试失败\r\n");
}
if (!ESP01_SendATCmd ("AT+CIPMUX=1", "OK", "ERROR", AT_CMD_TIMEOUT))
{
printf ("开启多路连接失败\r\n");
}
else
{
printf ("多路连接模式已开启\r\n");
}
//配置AP参数(SSID、密码、信道、加密方式)
//AT+CWSAP="ESP01S_AP","12345678",11,3
snprintf (at_cmd, sizeof(at_cmd),
"AT+CWSAP=\"%s\",\"%s\",%d,%d", AP_SSID, AP_PWD,
AP_CHANNEL, AP_ENCRYPT);
if (!ESP01_SendATCmd (at_cmd, "OK", "ERROR", AT_CMD_TIMEOUT))
{
printf ("AT+CWSAP(配置AP参数)失败\r\n");
}
//AT+CIPMUX=1 # 1=多连接模式,0=单连接(默认)
//AT+CIPSERVER=1,8080 # 1=开启服务器,8080=监听端口
//AT+CIPSERVER? # 验证服务器状态,返回+CIPSERVER:1,8080即生效
snprintf (at_cmd, sizeof(at_cmd), "AT+CIPSERVER=1,%d",
TCP_SERVER_PORT);
if (!ESP01_SendATCmd (at_cmd, "OK", "ERROR", AT_CMD_TIMEOUT))
{
printf ("AT+CIPSERVER(启动TCP服务器)失败\r\n");
}
else
{
printf ("AP模式TCP服务器已启动:%d\r\n", TCP_SERVER_PORT);
// 可选:定时查询客户端连接状态
flag_ap_on=1;
osThreadFlagsSet (myTask03Handle, 0x01); // 通知myTask04开始检测连接状态
}
}
}
memset (&rx_data, 0, sizeof(rx_data));
}
}
void StartTask03(void *argument)
{
ESP01_UART_Data_t rx_data = {0};
IPD_Data_Proc_t ipd_proc;
while(1)
{
if (osMessageQueueGet (myQueue02Handle, (void*) &rx_data, NULL, 5000)
== osOK)
{
if (flag_ap_on == 1)
{
// 1. 解析IPD数据(提取conn_id和原始内容)
memset (&ipd_proc, 0, sizeof(ipd_proc));
ESP01_Parse_IPD_Data ((char*) rx_data.data, &ipd_proc);
if (ipd_proc.parse_ok == 0)
{
memset (&rx_data, 0, sizeof(rx_data));
continue;
}
if(strcmp(ipd_proc.data_content,"+++")== 0)
{
printf("look\n");
HAL_UART_Transmit(&huart2, (uint8_t*)ipd_proc.data_content, ipd_proc.data_len, 100);
osDelay(20); // 确保数据发送完成
}
ESP01_Send_To_Client(ipd_proc.conn_id, ipd_proc.data_content);
}
memset (&rx_data, 0, sizeof(rx_data));
osDelay(100);
}
osDelay(100);
}
}
注意:1、初始化配置完后,pc端即客户端,要重新连接。
效果如下:

源码:https://download.csdn.net/download/weixin_44386927/92458532?spm=1001.2014.3001.5501