当前位置: 首页 > news >正文

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

一、前期配置

参考:
https://blog.csdn.net/weixin_44386927/article/details/155891583
的配置。

二、代码部分

1、定义部分
1、串口的初始化参考之前的配置。#defineAP_SSID"ESP01S_AP"// AP模式的WiFi名称#defineAP_PWD"12345678"// AP模式的WiFi密码(至少8位)#defineAP_CHANNEL6// AP信道(1-13)#defineAP_ENCRYPT3// 加密方式:3=WPA2_PSK(推荐)#defineTCP_SERVER_PORT8080typedefstruct{uint8_tconn_id;// 数据发送方的conn_iduint16_tdata_len;// 原始数据长度chardata_content[UART_RX_BUF_SIZE];// 原始数据内容uint8_tparse_ok;// 解析成功标记}IPD_Data_Proc_t;externuint8_tESP01_Send_To_Client(uint8_tconn_id,constchar*proc_data);externvoidESP01_Parse_IPD_Data(constchar*ipd_str,IPD_Data_Proc_t*ipd_proc);
2、函数部分
/** * @brief 去除字符串首尾空白符(\r\n/空格/制表符) */voidtrim_whitespace(char*str){if(str==NULL||*str=='\0')return;// 去除开头空白符char*start=str;while(*start!='\0'&&isspace((unsignedchar)*start))start++;// 去除结尾空白符char*end=str+strlen(str)-1;while(end>start&&isspace((unsignedchar)*end))end--;*(end+1)='\0';// 移动到原字符串开头memmove(str,start,strlen(start)+1);}/** * @brief 解析ESP01S的+IPD数据(兼容首尾\r\n,提取conn_id和内容) */voidESP01_Parse_IPD_Data(constchar*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)chartemp_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后的第一个数字)constchar*p=temp_buf+5;charid_str[4]={0};inti=0;while(*p!=','&&*p!='\0')id_str[i++]=*p++;ipd_proc->conn_id=atoi(id_str);p++;// 跳过逗号// 解析数据长度charlen_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_tESP01_Send_To_Client(uint8_tconn_id,constchar*proc_data){if(proc_data==NULL||strlen(proc_data)==0){printf("❌ 回传数据为空\r\n");return0;}uint16_tproc_len=strlen(proc_data);// 步骤1:发送AT+CIPSEND指令(指定ID和长度)charsend_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);return0;}// 步骤2:发送处理后的数据(纯数据,无\r\n)HAL_UART_Transmit(&huart2,(uint8_t*)proc_data,proc_len,100);osDelay(20);// 确保数据发送完成return1;}
3、任务部分
voidStartTask02(void*argument){ESP01_UART_Data_t rx_data={0};charcmd_buf[USART1_DMA_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+AT - 配置ESP01并开启\r\n");while(1){.....前面省略,参考之前的。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,"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,3snprintf(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));}}voidStartTask03(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端即客户端,要重新连接。

效果如下:

http://www.rkmt.cn/news/94751.html

相关文章:

  • 鸿蒙不是 Electron!深度解析 HarmonyOS 应用开发与跨端技术选型
  • 12bit 100MHz pipelined SAR ADC模数转换器 设计 65nm工艺,电...
  • LangChain从入门到进阶(7):学会让AI调用MCP「喂饭教程」
  • C++ 后端面试必刷大厂算法题(附代码实现)第一期
  • qt为什么转向用cmake放弃qmake
  • color
  • Qwen3-Embedding-4B:重新定义多语言文本检索的边界
  • 深度探究Span:.NET内存布局与零拷贝原理及实践
  • NNG 开源项目教程
  • helm 部署 elasticsearch 栈
  • 14、深入解析 Oracle Enterprise Manager 安装与配置
  • 手把手拆解10/100M以太网PHY设计:从PLL到均衡器的实战代码分析
  • 原神,启动!
  • 终极指南:Qwen3-30B-A3B多GPU分布式推理完整解决方案
  • 快速排序(Quick Sort)的“死穴”
  • 云屋音视频 SDK 凭何成为信创技术困局的 “破局者”?
  • 25、技术探索:数据查询、服务器管理与Python包管理
  • Day 38 - Dataset 和 DataLoader
  • Ansoft ANSYS Maxwell 有限元仿真:无线电能传输WPT、磁耦合谐振、多相多绕...
  • 【Spring框架】SpringMVC基本原理与配置
  • 地理信息与地图行业的新机会:从地图到空间智能
  • JavaScript 在 WebAssembly 时代的角色转变:作为 Wasm 模块编排层与高性能计算逻辑的共存模式研究
  • JavaScript 语言特性的未来演进:探讨可插拔语法扩展(Macros)对前端工具链(Babel/SWC)的底层重构潜力
  • 《智能世界2035》——华为预测十年以后智能世界的模样
  • 卷积神经网络中的自适应池化
  • RS-fMRI统计分析及作图入门
  • C++学习之旅【C++类和对象(下)】
  • 基于定子磁场矢量控制的异步电机磁链观测模型研究与应用
  • 告别CRUD Boy!Java缓存精要,是你突破技术天花板的“第一课”! - 详解
  • Petrel一体化软件平台压裂模块Kinetix与地应力模块Visage培训视频3套及模型文件