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…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...