二、在freertos中对应esp01s模块的ap模式下的通信测试。

一、前期配置

参考:

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

相关推荐
CFZPL6 小时前
esp32,stm32编译的不同
单片机·esp32
硅农深芯6 小时前
MCU的启动流程你了解么?
单片机·嵌入式硬件·硬件工程
xiaohai@Linux7 小时前
ESP32 IDF v5.3.1 驱动 CST816T 触摸芯片(I2C 协议)
单片机·嵌入式硬件·触摸·i2c·cst816t
zd8451015007 小时前
16bit ADC+DAC模拟量控制板第二方案设计
单片机·嵌入式硬件
星一工作室8 小时前
STM32项目分享:基于stm32的自动升降棋系统
stm32·单片机·嵌入式硬件
up向上up8 小时前
基于STM32温湿度采集Proteus仿真设计
stm32·单片机·proteus
d111111111d10 小时前
江协科技-PID基本原理-(学习笔记)-主页有所有STM32外设的笔记基本都是万字起步。
笔记·科技·stm32·单片机·嵌入式硬件·学习
wotaifuzao10 小时前
Nordic-nRF54L 系列架构全景:从蓝牙 6.0 到超低功耗设计详解
单片机·物联网·硬件架构·蓝牙·nordic
1+2单片机电子设计12 小时前
基于 STM32 的太阳能 MPPT 充电控制器设计
stm32·单片机·嵌入式硬件