news 2026/3/20 18:06:20

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一、在freertos上使用esp01s模块并配置使用sta模式进行数据通信传输测试。

一、前期配置情况




二、代码部分展示

1、数据定义:

#defineUSART1_DMA_BUF_SIZE256#defineUART_RX_BUF_SIZE256#defineUSART2_DMA_BUF_SIZE256#defineAT_CMD_TIMEOUT3000typedefstruct{uint8_tdata[UART_RX_BUF_SIZE];uint16_tlen;}ESP01_UART_Data_t;uint8_tESP01_SendATCmd(constchar*cmd,constchar*resp_ok,constchar*resp_err,uint32_ttimeout);#defineTASK_LIST_BUF_SIZE512chartask_list_buf[TASK_LIST_BUF_SIZE];uint8_tFLG_CWLAP=0;typedefstructwifiinfo{charwifi_ssid[160];charwifi_pwd[160];chartcp_server_ip[11];}uwifi_info;uwifi_info use_wifi={0};

二、重要函数编写

uint8_tusart1_dma_buf[USART1_DMA_BUF_SIZE]={0};uint8_tusart2_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的中断服务函数类似voidUSART1_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_tESP01_SendATCmd(constchar*cmd,constchar*resp_ok,constchar*resp_err,uint32_ttimeout){uint8_tretry=0;ESP01_UART_Data_t rx_data={0};TickType_t xStartTick=xTaskGetTickCount();chartemp_buf[USART2_DMA_BUF_SIZE*2]={0};uint16_ttemp_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);return1;}// 5. 匹配失败响应if(strstr(temp_buf,resp_err)!=NULL){// printf("匹配到失败响应:%s\r\n", resp_err);break;}}}retry++;vTaskDelay(50);}return0;}

任务调用

voidStartTask02(void*argument){ESP01_UART_Data_t rx_data={0};charcmd_buf[UART_RX_BUF_SIZE]={0};charat_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);}elseif(strcmp(cmd_buf,"LED_OFF")==0){printf("执行指令:关闭LED,当前状态:%s\r\n","OFF");HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_SET);}elseif(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);}elseif(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);}elseif(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);}elseif(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);}elseif(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_ssidsnprintf(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");charstate_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);}}voidStartTask03(void*argument){ESP01_UART_Data_t rx_data={0};charstate_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);}}voidStartDefaultTask(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、关于队列初始化

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

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

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

3、关于测试模块

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

4、关于任务优先级

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

5、关于模块测试时

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/16 3:12:31

盛水最多的容器(滑动窗口 双指针)

这道题当然可以暴力求解&#xff0c;O(N^2),但是有时候并不会通过&#xff0c;因此要想一个时间复杂度为O&#xff08;N&#xff09;的方法。如果说用滑动窗口肯定会有人会有疑问&#xff0c;这怎么用&#xff1f;下面直接说解法&#xff1a;首先left与right分别指向数组的两边…

作者头像 李华
网站建设 2026/3/20 3:52:10

深度探究Span:.NET内存布局与零拷贝原理及实践

深度探究Span&#xff1a;.NET内存布局与零拷贝原理及实践 在.NET开发中&#xff0c;高效的内存管理至关重要&#xff0c;尤其在处理高性能、低延迟的应用场景时。Span<T> 类型应运而生&#xff0c;它为开发者提供了一种灵活且高效的内存操作方式&#xff0c;能够显著提升…

作者头像 李华
网站建设 2026/3/20 6:47:36

helm 部署 elasticsearch 栈

说明:本文使用的 chart 仓库名字为 elastic/cloud-on-k8s 地址为 elastic/cloud-on-k8s。 1、添加 repo 源 helm repo add elastic https://helm.elastic.co helm repo update2、安装 eck-operator ⚠️说明:ECK Operator(Elastic Cloud on Kubernetes)本身安装的东西其…

作者头像 李华
网站建设 2026/3/20 10:26:15

Qt定时器线程使用全解析

1.Qt定时器线程使用全解析在Qt框架中&#xff0c;定时器&#xff08;如QTimer&#xff09;的“使用线程”特指其所属线程&#xff08;即创建该定时器的线程&#xff09;必须是由QThread启动并管理、且运行了事件循环&#xff08;exec()&#xff09;的线程。这一规则涉及线程的创…

作者头像 李华
网站建设 2026/3/20 2:24:28

低代码开发的“真香”定律:从排斥到离不开

在数字化工具迭代的历史中&#xff0c;几乎所有颠覆性技术都曾经历过“从排斥到追捧”的转折——智能手机初现时&#xff0c;有人质疑“不如功能机耐用”&#xff1b;云计算普及前&#xff0c;企业担忧“数据放在云端不安全”&#xff1b;低代码开发如今的处境&#xff0c;亦复…

作者头像 李华
网站建设 2026/3/15 7:52:36

32、Django Web应用开发实战指南

Django Web应用开发实战指南 1. 网络应用概述 网络的规模极其庞大,上面充斥着人们日常依赖的各种应用程序。网络应用如此之多,主要有以下几个原因: - 普遍可访问性 :网络应用部署后,任何有权限访问的人只需在浏览器中输入URL即可使用。用户通常只需安装浏览器(他们可…

作者头像 李华