Clion开发STM32之ESP8266系列(四)
前言
上一篇: Clion开发STM32之ESP8266系列(三)
本篇主要内容
- 实现esp8266需要实现的函数
- 串口3中断函数的自定义(这里没有使用HAL提供的)
- 封装esp8266服务端的代码和测试
正文
主要修改部分
核心配置头文件(添加一些宏定义)
- sys_core_conf.h文件中
实现esp8266需要实现的函数
源码
/******************************************************************************** @author scl* @email shchlu188@163.com* @brief 实现esp8266的驱动******************************************************************************/
#include "module_esp8266.h"
#include "bsp.h"extern data_frame_t esp_rx_frame;static void sys_delay(uint32_t ms) {HAL_Delay(ms);
}/*** @brief esp8266 驱动外设初始化*/
void esp8266_driver_init() {/*设置系esp8266延时回调*/esp8266_set_delay_call(sys_delay);/*配置 CH_PD 引脚*/gpio_init(GPIOB, GPIO_PIN_8, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH);/* 配置 RST 引脚*/gpio_init(GPIOB, GPIO_PIN_9, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH);/*串口配置*/com3_init(115200);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8 | GPIO_PIN_9, GPIO_PIN_SET);/*开启串口中断*/UART_ENABLE_IT(USART3, UART_IT_RXNE); /** 开启串口中断*/UART_ENABLE_IT(USART3, UART_IT_IDLE); /** 开启串口空闲中断*/
}/*** @brief esp8266 复位引脚* @param flag true: 置高; false: 置低*/
void esp8266_rst_pin(bool flag) {if (flag) {pin_high(GPIOB, GPIO_PIN_9);} else {pin_low(GPIOB, GPIO_PIN_8);}
}/*** @brief esp8266 使能引脚* @param flag true: 使能*/
void esp8266_ch_enable(bool flag) {if (flag) {pin_high(GPIOB, GPIO_PIN_8);} else {pin_low(GPIOB, GPIO_PIN_8);}
}/*** @brief esp8266 发送数据* @param data* @param len*/
void esp8266_send(void *data, uint16_t len) {HAL_UART_Transmit(com_handle_get(com3), data, len, 1000);
}/*** @brief 清空接收缓冲区*/
void esp8266_clear_buf(void) {esp_rx_frame.InfAll = 0;
}/*** @brief esp8266 接收数据* @return 接收数据*/
char *esp8266_rec() {if (esp_rx_frame.InfBit.frame_finished_flag != 0) {/*添加结束符*/esp_rx_frame.p_rx_buf[esp_rx_frame.InfBit.frame_len] = '\0';esp_rx_frame.InfAll = 0;// 清除一次标志位return esp_rx_frame.p_rx_buf;}return NULL;
}/*** @brief esp8266 构造指令的缓存区* @return*/
char *esp8266_get_cmd_buf() {static char esp8266_buf[200] = {0};return esp8266_buf;
}
对应的串口3中断函数的编写
extern data_frame_t esp_rx_frame;static inline void esp8266_tcp_server_IRQHandler() {uint8_t ucTemp;if (UART_GET_FLAG(USART3, UART_FLAG_RXNE)) {ucTemp = READ_REG(USART3->DR);// 读取数据if (esp_rx_frame.InfBit.frame_len < (esp_rx_frame.rx_buf_len - 1)) {esp_rx_frame.p_rx_buf[esp_rx_frame.InfBit.frame_len++] = ucTemp;}}//数据帧接收完毕if (UART_GET_FLAG(USART3, UART_FLAG_IDLE)) {esp_rx_frame.InfBit.frame_finished_flag = 1;// 添加结束符esp_rx_frame.p_rx_buf[esp_rx_frame.InfBit.frame_len] = '\0';//由软件序列清除中断标志位(先读USART_SR,然后读USART_DR)_UART_CLEAR_PEFLAG(USART3);}
}void USART3_IRQHandler(void) {/* HAL库中断处理函数*/// HAL_UART_IRQHandler(&com3_handle);/* 自定义中断处理函数*/esp8266_tcp_server_IRQHandler();
}
封装esp8266服务端的代码(针对驱动层再进行一个封装)
头文件
/******************************************************************************** @author scl* @email shchlu188@163.com******************************************************************************/#ifndef STM32F103VET6_ESP8266_ESP8266_SERVICE_H
#define STM32F103VET6_ESP8266_ESP8266_SERVICE_H#include "service_include.h"
/*wifi 账号*/
#define WIFI_SSID "账号"
/*wifi 密码*/
#define WIFI_PWD "密码"
/*尝试执行次数*/
#define TRY_CNT 3
/*本地IP配置*/
#define LOCAL_SERVER_IP "192.168.199.12"
/*本地端口配置*/
#define LOCAL_SERVER_PORT 8000
/*宏定义调试日志*/
#define esp_ps(fmt, ...) os_ps(fmt,##__VA_ARGS__)
/*************************************ESP 服务端 STA模式**********************************************/
/*** @brief esp8266 在sta模式下初始化 sever* @return*/
bool esp_sta_tcp_server_init(void);
/*** @brief esp8266 在sta模式下获取ip* @param dstIp 保存ip* @param len dstIp的长度* @return*/
bool esp_sta_tcp_server_get_ip(char *dstIp, uint8_t len);
/*** @brief esp8266 客户端请求处理* @param data 接收的数据* @param len 数据长度* @return*/
bool esp_sta_tcp_server_request_handle(char *data, uint16_t len);#endif //STM32F103VET6_ESP8266_ESP8266_SERVICE_H
源文件
/******************************************************************************** @author scl* @email shchlu188@163.com******************************************************************************/#include "esp8266_service.h"
#include "module_esp8266.h"
#include "bsp.h"/*** @brief 禁止接收数据(静态内联函数)*/
sys_force_static_inline void esp_disable_rec() {UART_DISABLE_IT(USART3, UART_IT_RXNE);
}sys_force_static_inline void esp_enable_rec() {UART_ENABLE_IT(USART3, UART_IT_RXNE);
}bool esp_sta_tcp_server_init(void) {esp_ps("--esp_sta_tcp_server_init start---\r\n");/*使能信号*/esp8266_ch_enable(true);/*测试AT指令*/try_cnt_run (esp8266_base_at_cmd_test(10, 500), 1);esp_ps("esp8266_base_at_cmd_test ok\r\n");/*动态分配IP地址*/try_cnt_run(esp8266_dhcp_cur_set(sta_mode, true, -1), TRY_CNT);/* 设置为STA模式 */try_cnt_run(esp8266_wifi_mode_cur_set(sta_mode, -1), TRY_CNT);esp_ps("esp8266_mode_cur_set ok\r\n");/* 设备本地设备ip*/try_cnt_run(esp8266_ip_sta_cur_set(LOCAL_SERVER_IP, NULL, NULL, -1), TRY_CNT);esp_ps("esp8266_ip_sta_cur_set ok\r\n");/*连接WiFi*/try_cnt_run (esp8266_wifi_join_cur_set(WIFI_SSID, WIFI_PWD, NULL, -1), TRY_CNT);esp_ps("esp8266_wifi_join_cur_set ok\r\n");/*允许多连接*/try_cnt_run (esp8266_mul_connect_set(true, -1), TRY_CNT);esp_ps("esp8266_mul_connect_set ok\r\n");/*开启服务器模式*/try_cnt_run (esp8266_server_tcp_start(true, LOCAL_SERVER_PORT, -1), TRY_CNT);esp_ps("esp8266_server_tcp_start ok\r\n");/*设置服务器链接超时时间*/try_cnt_run (esp8266_server_tcp_timeout_set(20, -1), TRY_CNT);esp_ps("esp8266_server_tcp_timeout_set ok\r\n");esp_ps("--esp_sta_tcp_server_init end---\r\n");return true;
}bool esp_sta_tcp_server_get_ip(char *dstIp, uint8_t len) {esp_ps("--esp_sta_tcp_server_get_ip start---\r\n");try_cnt_run (esp8266_ip_sta_inquire(dstIp, len, -1), TRY_CNT);esp_ps("--esp_sta_tcp_server_get_ip end---\r\n");return true;
}
/*** @brief 解析接收的数据* @param rec_data 接收的数据* @param no_id socket id* @param data_len 发送的数据长度* @return 实际数据的位置*/
sys_force_static_inline char *parse_rec_data(char *rec_data, uint8_t *no_id, uint16_t *data_len) {static char *pre_str = "+IPD,";char *p_data = strstr(rec_data, pre_str);// 数据解析错误 +IPD,0,2:12if (!p_data) return false;/*跳过前缀*/p_data += strlen(pre_str);/*解析socket id 号*/*no_id = strtol(p_data, &p_data, 10);if (!*p_data) return false;/*解析数据长度 */*data_len = strtol(p_data + 1, &p_data, 10);if (!*p_data) return false;/*获取数据*/p_data += 1;return p_data;
}bool esp_sta_tcp_server_request_handle(char *data, uint16_t len) {/* 禁止esp多个客户端同时发送数据 */uint16_t data_len = 0;/*实际客户端发送的数据长度*/uint8_t socket_id;/*实际客户端连接的端口号*/bool result_flag = true;/*禁止接收,保证同一时间只只处理一个请求 */esp_disable_rec();/*实际客户端发送的数据位置*/char *p_data = parse_rec_data(data, &socket_id, &data_len);if (p_data) {// todo 这里就是做业务逻辑控制的地方,目前只是回显esp_ps("parse_rec_data:%d %d %s\r\n", socket_id, data_len, p_data);if (esp8266_server_tcp_send_to(socket_id, p_data, data_len, -1)) {esp_ps("response ok\r\n");} else {esp_ps("response error\r\n");}} else {result_flag = false;}/*清除这次的请求数据,保证下次数据为最新的*/esp8266_clear_buf();/*开启请求,保证同一时间只只处理一个请求 */esp_enable_rec();return result_flag;
}
esp8266驱动配置文件的编写
/******************************************************************************** @author scl* @email shchlu188@163.com******************************************************************************/
#include "app_conf.h"
#include "module_esp8266.h"
#include "service.h"/*创建数据接收帧*/
static char rx_buf[1024] = {0};
data_frame_t esp_rx_frame = {.p_rx_buf=rx_buf, .rx_buf_len=1024};static void driver_init(void) {/*esp8266初始化*/esp8266_driver_init();
}/*这句话就是将驱动导出到段中*/
DRIVER_EXPORT(esp8266_driver, driver_init);/*** 测试阶段暂时使用此方法* */
void app_run() {if (esp_sta_tcp_server_init()) {os_ps("--esp_sta_tcp_server_init ok--\r\n");while (1) {if (esp_rx_frame.InfBit.frame_finished_flag) {esp_sta_tcp_server_request_handle(esp_rx_frame.p_rx_buf, esp_rx_frame.InfBit.frame_len);}}} else {os_ps("--esp_sta_tcp_server_init error--\r\n");}}
代码测试
- 本次设置esp8266模块的IP为192.168.199.12,端口号为8000
主入口函数调整
### 下载程序
观察日志记录
用客户端去连接192.168.199.12:8000
客户端
查看串口
- 接收数据正常
结尾
- ESP8266系列的章节也就更新完成,目前基础功能模板工程已经完。
- 目前可以根据此工程执行对应的指令控制的逻辑了。
- 后续在此基础之上设计一个指令集动态加载服务器接收处理和响应的框架。
- 完整的项目已上传到gitee,有需要自行查看开头结尾的git地址.
下个系列的目标
- 整合Freertos
- 整合Modbus协议和自定义协议框架
相关文章:

Clion开发STM32之ESP8266系列(四)
前言 上一篇: Clion开发STM32之ESP8266系列(三) 本篇主要内容 实现esp8266需要实现的函数串口3中断函数的自定义(这里没有使用HAL提供的)封装esp8266服务端的代码和测试 正文 主要修改部分 核心配置头文件(添加一些宏定义) sys_core_conf.h文件中…...

降本增效,StarRocks 在同程旅行的实践
作者:周涛 同程旅行数据中心大数据研发工程师 同程旅行是中国在线旅游行业的创新者和市场领导者。作为一家一站式平台,同程旅行致力于满足用户旅游需求,秉持 "让旅行更简单、更快乐" 的使命,主要通过包括微信小程序、AP…...
INTP型人格适合选择哪些专业?
INTP人格内倾理性人格、具有强烈的好奇心、创造性和独立性的特点。他们善于独立思考和寻找问题的本质,并对抽象的想法和理论感兴趣。 INTP人格的人具有很强的逻辑思维和分析能力,他们的思维方式非常系统,追求完美和准确。因此他们适合选择需…...

【LeetCode热题100】打卡第16天:组合总和
文章目录 组合总和⛅前言🔒题目🔑题解 组合总和 ⛅前言 大家好,我是知识汲取者,欢迎来到我的LeetCode热题100刷题专栏! 精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数…...

tinkerCAD案例:1.戒子环
基本戒指 在本课中,您将学习使用圆柱形状制作戒指。来吧! 说明 将圆柱体拖动到工作平面上并使其成为孔。 圆柱体应缩放以适合其制造手指。 在本例中,我们将使用 17mm 作为直径,但请根据您的需要随意调整尺寸。 将“圆柱”形状拖…...

RPC接口测试技术-Tcp 协议的接口测试
【摘要】 首先明确 Tcp 的概念,针对 Tcp 协议进行接口测试,是指基于 Tcp 协议的上层协议比如 Http ,串口,网口, Socket 等。这些协议与 Http 测试方法类似(具体查看接口自动化测试章节)…...
MyBatis Plus基本用法-SpringBoot框架
依赖 使用 Mybatis Plus 框架时,需要添加以下依赖: <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>latest-version</version> </dependency…...

指针--指针变量的定义和初始化
存放变量的地址需要一种特殊类型的变量,这种特殊的数据类型就是指针(Pointer)。 具有指针类型的变量,称为指针变量,它时专门用于存储变量的地址值和变量。 其定义形式如下: 类型关键字 * 指针变量名&#x…...

Web基本概念
一、前言 World Wide Web的简称,是一个由许多互相链接的超文本组成的系统,通过互联网访问 (为用户提供信息) 静态网页 仅适用于不能经常更改内容的网页; 动态网页 网络编程技术创建的页面;通过在传统的静态…...

Niagara—— Texture Sample 与 Particle Subuv 区别
目录 一,Texture Sample 二,Particle Subuv 一,Texture Sample 此节点是最基本的采样节点,依据UV坐标来采样Texture; MipValueMode,设置采样的Mipmap Level; None,根据当前Texture…...

如何在食品行业运用IPD?
食品是我国重要的民生产业之一,是保障和满足人民群众不断增长消费需求的重要支撑。食品指各种供人食用或者饮用的成品和原料以及按照传统既是食品又是药品的物品,包括加工食品,半成品和未加工食品,不包括烟草或只作药品用的物质。…...
如何用pandas进行条件分组计算?
Pandas提供了强大的分组聚合功能,可以轻松进行条件分组计算和统计。本文通过一个例子,展示如何使用Pandas的.groupby()和.agg()方法进行条件分组计算。 准备数据 假设有这样一个字典数据: dict { 姓名: [张三,李四,王五&#x…...
tomcat如何调优,涉及哪些参数?
Tomcat是一个流行的开源Java Servlet容器,用于部署和管理Java Web应用程序。调优Tomcat可以提高性能、并发处理能力和稳定性。以下是一些常见的Tomcat调优参数和技巧: 1.调整内存参数: -Xms:指定Tomcat启动时的初始堆内存大小。 -…...

java培训机构学校教学教务选课管理平台springboot+vue
近年来,随着培训机构机构规模的逐渐增大,人工书写的方式已经不能满足如此庞大的数据。为了更好的适应信息时代的高效性,一个利用计算机来实现培训机构教务管理工作的系统将必然诞生。基于这一点,设计了一个培训机构教务管理系统&a…...

半导体(TSS)放电管的两大选购注意事项及选型小策略
固体放电管,是以半导体工艺制作而成的,因此我们也称为半导体(TSS)放电管,它常在电路中并联使用,具备伏安特性。 TSS放电管在电路中类似开关,在正常工作时不动作,但一般被保护电路受到…...
05-使用Vue3 + Vue CLI 实现前端模块的搭建
1、环境准备 流程:安装node得到npm,使用npm安装vue cli(脚手架),使用vue cli创建项目。 Vue CLI版本和Node版本有关,用Node V12只能下载到Vue CLI V4.X,必须用Node V18才能下载到Vue CLI V5.X IDEA支持配置多个版本的Node,类似配置多个JDK。 node.js安装 1、官网下载…...

3.1 增加多进程执行playwright
增加了多进程的方式执行测试代码,对代码改动比较大 1、case case目录依然是自动生成 2、config dir_collection.py新增了配置 mkdir_collections [case,log,img, ] del_collections [results,report ] del_regex temp3、data/img/log/resource/video data/im…...

关于单片机的时钟浅谈及STM32F103/F030单片机的内外时钟切换问题
绪论 本文主要讲解单片机的时钟系统的相关知识,并进行超频测试,同时介绍如何在STM32F0单片机上进行内外时钟的切换,在不使用外部晶振或者外部晶振不启动时自动切换内部时钟的方法。 一、杂谈 问题来源于群里的一次问答: 诚然&…...
centos6.10环境下安装php7.4(基于WLNMP包)
centos6系统已经被官网停止维护,要安装软件必须用第三方的RPM包,下面使用yum安装php7.4正式版,当前基于WLNMP提供的一键安装包来安装 1、添加epel源 yum install epel-release yum install epel-release 2、添加WLNMP一键安装包源 rpm -iv…...

Qt使用第三方库openssl进行RSA加密解密操作详解
一、openssl库的编译,可以参考文档: https://blog.csdn.net/liang19890820/article/details/51658574/ 因为我这里使用的是windows操作系统,可以直接下载exe格式的安装文件,直接安装即可,就包含了我们需要的头文件和库文件,省去了编译操作。exe安装文件下载地址: htt…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...

毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...

Unity VR/MR开发-VR开发与传统3D开发的差异
视频讲解链接:【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...