一、在freertos上使用esp01s模块并配置使用sta模式进行数据通信传输测试。

一、前期配置情况




二、代码部分展示

1、数据定义:

c 复制代码
#define USART1_DMA_BUF_SIZE 256
#define UART_RX_BUF_SIZE 256
#define USART2_DMA_BUF_SIZE 256
#define AT_CMD_TIMEOUT 3000
typedef struct {
    uint8_t data[UART_RX_BUF_SIZE];
    uint16_t len;
} ESP01_UART_Data_t;
 uint8_t ESP01_SendATCmd(const char *cmd, const char *resp_ok, const char *resp_err, uint32_t timeout);
#define TASK_LIST_BUF_SIZE 512
char task_list_buf[TASK_LIST_BUF_SIZE];
uint8_t FLG_CWLAP=0;

typedef struct wifiinfo
{
  char wifi_ssid[160];
  char wifi_pwd[160];
  char tcp_server_ip[11];
} uwifi_info;
uwifi_info use_wifi={0};

二、重要函数编写

c 复制代码
uint8_t usart1_dma_buf[USART1_DMA_BUF_SIZE] = {0};
uint8_t usart2_dma_buf[USART2_DMA_BUF_SIZE] = {0};

  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
     // 启动DMA循环接收(和串口2逻辑一致)
   HAL_UART_Receive_DMA(&huart1, usart1_dma_buf, USART1_DMA_BUF_SIZE);
   
//串口1和2的中断服务函数类似
   void USART1_IRQHandler(void)
{

    ESP01_UART_Data_t rx_data = {0};  

    if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)
    {
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);
        HAL_UART_DMAStop(&huart1);

        // 计算接收长度
        rx_data.len = USART1_DMA_BUF_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
        if (rx_data.len > 0 && rx_data.len <= USART1_DMA_BUF_SIZE)
        {
            memcpy(rx_data.data, usart1_dma_buf, rx_data.len);
            // 中断中发送数据到队列
            if(osMessageQueuePut (myQueue01Handle, (void *)&rx_data,0, 0)==osOK)
          	{

          	}
            osThreadYield();
        }

        // 重启DMA接收
        HAL_UART_Receive_DMA(&huart1, usart1_dma_buf, USART1_DMA_BUF_SIZE);
    }

    HAL_UART_IRQHandler(&huart1);
}

uint8_t ESP01_SendATCmd(const char *cmd, const char *resp_ok, const char *resp_err, uint32_t timeout)
{

    uint8_t retry = 0;
    ESP01_UART_Data_t rx_data = {0};
    TickType_t xStartTick = xTaskGetTickCount();
    char temp_buf[USART2_DMA_BUF_SIZE * 2] = {0};
    uint16_t temp_len = 0;
    while (retry <3)
    {
    	osMessageQueueReset (myQueue02Handle);
    	memset(temp_buf, 0, sizeof(temp_buf));
    	        temp_len = 0;
    	        xStartTick = xTaskGetTickCount();

        HAL_UART_Transmit(&huart2, (uint8_t*)cmd, strlen(cmd), 100);
        HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", 2, 100);
       // printf("AT指令(配置阶段)%s\r\n", cmd);
        while ((xTaskGetTickCount() - xStartTick) < pdMS_TO_TICKS(timeout))
        {

            if(osMessageQueueGet (myQueue02Handle,(void *)&rx_data,NULL,10)==osOK)
            {
            	if (temp_len + rx_data.len < sizeof(temp_buf))
            	 {
            		memcpy(temp_buf + temp_len, rx_data.data, rx_data.len);
            		temp_len += rx_data.len;
            	 }
            	  //printf("接收数据%s(原始字节:%d)\r\n", temp_buf, temp_len);
            	   if (strstr(temp_buf, resp_ok) != NULL)
            	   {
            	       // printf("匹配到成功响应:%s\r\n", resp_ok);
            	         return 1;
            	  }            	            	                                   // 5. 匹配失败响应
            	  if (strstr(temp_buf, resp_err) != NULL)
            	  {
            	       // printf("匹配到失败响应:%s\r\n", resp_err);
            	      break;
            	  }
            }

        }
        retry++;
        vTaskDelay(50);
    }
    return 0;
}

任务调用

c 复制代码
void StartTask02 (void *argument)
{

  ESP01_UART_Data_t rx_data =
    { 0 };
  char cmd_buf[UART_RX_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+CMD - 配置ESP01命令\r\n");

  for (;;)
    {
      if (osMessageQueueGet (myQueue01Handle, (void*) &rx_data, NULL, 5000)
	  == osOK)
	{
	  // 清空指令缓冲区,去除换行/空格等无效字�??
	  memset (cmd_buf, 0, sizeof(cmd_buf));
	  strncpy (cmd_buf, (char*) rx_data.data, rx_data.len);
	  // 去除字符串末尾的\r\n(串口助手输入的换行�??
	  cmd_buf[strcspn (cmd_buf, "\r\n")] = '\0';

	  printf ("串口1收到指令:%s\r\n", cmd_buf);

	  // ========== 1. LED控制指令解析 ==========
	  if (strcmp (cmd_buf, "LED_ON") == 0)
	    {
	      printf ("执行指令:点亮LED,当前状态:%s\r\n", "ON");
	      HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);

	    }
	  else if (strcmp (cmd_buf, "LED_OFF") == 0)
	    {
	      printf ("执行指令:关闭LED,当前状态:%s\r\n", "OFF");
	      HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
	    }
	   else if (strncmp (cmd_buf, "WIFI_SSID+", 10) == 0)
	    {

	      strncpy (at_cmd, cmd_buf + 10, sizeof(at_cmd) - 1);
	      printf ("CMD:%s\r\n", at_cmd);
	      strcpy (use_wifi.wifi_ssid, at_cmd);
	    }

	  else if (strncmp (cmd_buf, "WIFI_PWD+", 9) == 0)
	    {
	      strncpy (at_cmd, cmd_buf +9, sizeof(at_cmd) - 1);
	      printf ("CMD:%s\r\n", at_cmd);
	      strcpy (use_wifi.wifi_pwd, at_cmd);
	    }
	  else if (strncmp (cmd_buf, "TCP_SERVER_IP+", 14) == 0)
	    {
	      strncpy (at_cmd, cmd_buf + 14, sizeof(at_cmd) - 1);
	      printf ("CMD:%s\r\n", at_cmd);
	      strcpy (use_wifi.tcp_server_ip , at_cmd);
	    }
	  else if(strcmp (cmd_buf, "INFOS") == 0)
	    {
	      printf("use_wifi tcp_server_ip:%s\n",use_wifi.tcp_server_ip);
	      printf("use_wifi wifi_pwd:%s\n",use_wifi.wifi_pwd);
	      printf("use_wifi wifi_ssid:%s\n",use_wifi.wifi_ssid);
	    }
	    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, "STA") == 0)
		{
		  HAL_UART_Transmit (&huart2, (uint8_t*) "+++", 3, 100);
		  osDelay (1000);
		  if (!ESP01_SendATCmd ("AT", "OK", "ERROR", AT_CMD_TIMEOUT))
		    {
		      printf ("AT失败\r\n");
		    }
		  if (!ESP01_SendATCmd ("AT+CWMODE=1", "OK", "ERROR",
		  AT_CMD_TIMEOUT))
		    {
		      printf ("AT+CWMODE=1失败\r\n");

		    }

		  if (!ESP01_SendATCmd ("AT+CWQAP", "OK", "ERROR", AT_CMD_TIMEOUT))
		 {
		  printf ("AT+CWQAP失败\r\n");
		 }
		  osDelay (20);
		  //用之前定义的use_wifi,替换 tcp_server_ip,wifi_pwd,wifi_ssid
		  snprintf (at_cmd, sizeof(at_cmd), "AT+CWJAP=\"%s\",\"%s\"",
		  WIFI_SSID, WIFI_PWD);
		  if (!ESP01_SendATCmd (at_cmd, "WIFI CONNECTED", "ERROR",
		  AT_CMD_TIMEOUT))
		    {
		      printf ("AT+CWJAP=失败\r\n");
		    }
		  if (!ESP01_SendATCmd ("AT+CIPMUX=0", "OK", "ERROR",
		  AT_CMD_TIMEOUT))
		    {
		      printf ("TCP配置失败:关闭多路连接失败\r\n");
		    }
		  snprintf (at_cmd, sizeof(at_cmd),
			    "AT+CIPSTART=\"TCP\",\"%s\",%d", TCP_SERVER_IP,
			    TCP_SERVER_PORT);
		  if (!ESP01_SendATCmd (at_cmd, "CONNECT", "ERROR",
		  AT_CMD_TIMEOUT))
		    {
		      printf ("TCP配置失败:连接服务器%s:%d失败\r\n", TCP_SERVER_IP,
		      TCP_SERVER_PORT);

		    }
		  if (!ESP01_SendATCmd ("AT+CIPMODE=1", "OK", "ERROR",
		  AT_CMD_TIMEOUT))
		    {
		      printf ("TCP配置失败:传模式失败\r\n");
		    }

			  if (!ESP01_SendATCmd ("AT+CIPSEND", ">", "ERROR",AT_CMD_TIMEOUT))
			    {
			      printf ("TCP配置失败:AT+CIPSEND 透传失败\r\n");
			    }
		  		else
		   		 {
			      printf ("透传开启\r\n");
			      char state_str[32] =
					{ 0 };
			      snprintf (state_str, sizeof(state_str), "esp01s open status:%s\r\n",
					"ON");
			      HAL_UART_Transmit (&huart2, (uint8_t*) state_str,
						 strlen (state_str), 100);
			      FLG_CWLAP=1;
			      osThreadSuspend (myTask02Handle);
		    	}
			}
	    }
	  }
	  osDelay (10);
	}
 }

  void StartTask03 (void *argument)
  {
    ESP01_UART_Data_t rx_data = {0};
    char state_str[256] = {0};
    for (;;)
      {
      if (osMessageQueueGet (myQueue02Handle, (void*) &rx_data, NULL, 5000)== osOK)
	 	{
		    if(FLG_CWLAP==1)
		    {
			// 打印ESP01响应
		      snprintf(state_str, sizeof(state_str), ":%s\r\n",rx_data.data);
			// 通过ESP01的TCP透传发到服务器:用于检查
		      HAL_UART_Transmit (&huart2, (uint8_t*) state_str,strlen (state_str), 100);
		    	if (strstr (state_str, ":LED_ON") != NULL)
				{
					  printf ("执行指令:点亮LED,当前状态:%s\r\n", "ON");
					  HAL_GPIO_WritePin (GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
				}
				//添加任务恢复和通信退出即可。
	   		 }
	   	 osDelay (2);
		}
        osDelay (10);
    }
  }
void StartDefaultTask(void *argument)
 {

	for (;;) 
	{
		printf("\r\n===== FreeRTOS Task Status ====\r\n");
		memset(task_list_buf, 0, TASK_LIST_BUF_SIZE);
		vTaskList(task_list_buf);
		printf("%s", task_list_buf);
		printf("===============================\r\n");
		osDelay(2000);  // 2秒打印一次,释放CPU
	}

}

三、细节说明:

1、关于队列初始化

需要修改大小。否则可能疏忽后,在哪里调试串口。

c 复制代码
myQueue01Handle = osMessageQueueNew(5, sizeof(ESP01_UART_Data_t),
			&myQueue01_attributes);
2、关于任务大小

根据任务的实际分配大小以及内部变量大小出适当改变。若不够可能造成运行异常的问题。

3、关于测试模块

供电上需要独立或稳定的供电条件。若条件不够可能配置总是失败。

4、关于任务优先级

上需要做出调整,优先进行模块的初始化配置,配置完成挂起,当退出模块通信后就恢复挂起的任务。

5、关于模块测试时

每次初始化配置完成后,客户端上需要重新打开服务器的监听进行刷新客户端的状态,否则可能客户端仅能监听无法进行传输通信。
效果图

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

相关推荐
星期天27 小时前
1.1江科大之LED闪烁&LED流水灯&蜂鸣器
stm32·单片机·嵌入式硬件
梓德原7 小时前
【经验】MSP430编译器使用经验-IAR编辑框分框
单片机·嵌入式硬件·物联网
电子工程师-C517 小时前
基于51单片机的自动乒乓球发球机
单片机·嵌入式硬件·51单片机
玩转单片机与嵌入式7 小时前
在STM32F103单片机上跑通AI模型:为什么选正弦波作为Hello World?
人工智能·stm32·单片机
星期天28 小时前
1.2STM32江科大GPIO的输入(电路硬件连接)
单片机·嵌入式硬件·stm32江科大·gpio的输入·硬件电路的链接
Darken039 小时前
标准外设库与HAL库有什么区别?都怎样去使用?如何区分?
单片机·嵌入式硬件·hal库与基本外设库
czhaii10 小时前
8051U深度入门到32位51大型实战
单片机
boneStudent11 小时前
Day28:I2C 配置与使用
stm32·单片机·嵌入式硬件
法号:行颠11 小时前
Chaos-nano协作式异步操作系统(六):`Chaos-nano` 在手持式 `VOC` 检测设备上的应用
c语言·单片机·嵌入式硬件·mcu·系统架构