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

Clion开发STM32之ESP8266系列(四)

前言

上一篇: Clion开发STM32之ESP8266系列(三)

本篇主要内容

  1. 实现esp8266需要实现的函数
  2. 串口3中断函数的自定义(这里没有使用HAL提供的)
  3. 封装esp8266服务端的代码和测试

正文

主要修改部分

核心配置头文件(添加一些宏定义)

  1. 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");}}

代码测试

  1. 本次设置esp8266模块的IP为192.168.199.12,端口号为8000

主入口函数调整

在这里插入图片描述### 下载程序

观察日志记录

在这里插入图片描述

用客户端去连接192.168.199.12:8000

在这里插入图片描述

客户端

在这里插入图片描述

查看串口

  1. 接收数据正常

在这里插入图片描述
在这里插入图片描述

结尾

  1. ESP8266系列的章节也就更新完成,目前基础功能模板工程已经完。
  2. 目前可以根据此工程执行对应的指令控制的逻辑了。
  3. 后续在此基础之上设计一个指令集动态加载服务器接收处理和响应的框架。
  4. 完整的项目已上传到gitee,有需要自行查看开头结尾的git地址.

下个系列的目标

  1. 整合Freertos
  2. 整合Modbus协议和自定义协议框架

相关文章:

Clion开发STM32之ESP8266系列(四)

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

降本增效,StarRocks 在同程旅行的实践

作者&#xff1a;周涛 同程旅行数据中心大数据研发工程师 同程旅行是中国在线旅游行业的创新者和市场领导者。作为一家一站式平台&#xff0c;同程旅行致力于满足用户旅游需求&#xff0c;秉持 "让旅行更简单、更快乐" 的使命&#xff0c;主要通过包括微信小程序、AP…...

INTP型人格适合选择哪些专业?

INTP人格内倾理性人格、具有强烈的好奇心、创造性和独立性的特点。他们善于独立思考和寻找问题的本质&#xff0c;并对抽象的想法和理论感兴趣。 INTP人格的人具有很强的逻辑思维和分析能力&#xff0c;他们的思维方式非常系统&#xff0c;追求完美和准确。因此他们适合选择需…...

【LeetCode热题100】打卡第16天:组合总和

文章目录 组合总和⛅前言&#x1f512;题目&#x1f511;题解 组合总和 ⛅前言 大家好&#xff0c;我是知识汲取者&#xff0c;欢迎来到我的LeetCode热题100刷题专栏&#xff01; 精选 100 道力扣&#xff08;LeetCode&#xff09;上最热门的题目&#xff0c;适合初识算法与数…...

tinkerCAD案例:1.戒子环

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

RPC接口测试技术-Tcp 协议的接口测试

【摘要】 首先明确 Tcp 的概念&#xff0c;针对 Tcp 协议进行接口测试&#xff0c;是指基于 Tcp 协议的上层协议比如 Http &#xff0c;串口&#xff0c;网口&#xff0c; Socket 等。这些协议与 Http 测试方法类似&#xff08;具体查看接口自动化测试章节&#xff09;&#xf…...

MyBatis Plus基本用法-SpringBoot框架

依赖 使用 Mybatis Plus 框架时&#xff0c;需要添加以下依赖&#xff1a; <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>latest-version</version> </dependency…...

指针--指针变量的定义和初始化

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

Web基本概念

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

Niagara—— Texture Sample 与 Particle Subuv 区别

目录 一&#xff0c;Texture Sample 二&#xff0c;Particle Subuv 一&#xff0c;Texture Sample 此节点是最基本的采样节点&#xff0c;依据UV坐标来采样Texture&#xff1b; MipValueMode&#xff0c;设置采样的Mipmap Level&#xff1b; None&#xff0c;根据当前Texture…...

如何在食品行业运用IPD?

食品是我国重要的民生产业之一&#xff0c;是保障和满足人民群众不断增长消费需求的重要支撑。食品指各种供人食用或者饮用的成品和原料以及按照传统既是食品又是药品的物品&#xff0c;包括加工食品&#xff0c;半成品和未加工食品&#xff0c;不包括烟草或只作药品用的物质。…...

如何用pandas进行条件分组计算?

Pandas提供了强大的分组聚合功能&#xff0c;可以轻松进行条件分组计算和统计。本文通过一个例子&#xff0c;展示如何使用Pandas的.groupby()和.agg()方法进行条件分组计算。 准备数据 假设有这样一个字典数据: dict { 姓名: [张三&#xff0c;李四&#xff0c;王五&#x…...

tomcat如何调优,涉及哪些参数?

Tomcat是一个流行的开源Java Servlet容器&#xff0c;用于部署和管理Java Web应用程序。调优Tomcat可以提高性能、并发处理能力和稳定性。以下是一些常见的Tomcat调优参数和技巧&#xff1a; 1.调整内存参数&#xff1a; -Xms&#xff1a;指定Tomcat启动时的初始堆内存大小。 -…...

java培训机构学校教学教务选课管理平台springboot+vue

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

半导体(TSS)放电管的两大选购注意事项及选型小策略

固体放电管&#xff0c;是以半导体工艺制作而成的&#xff0c;因此我们也称为半导体&#xff08;TSS&#xff09;放电管&#xff0c;它常在电路中并联使用&#xff0c;具备伏安特性。 TSS放电管在电路中类似开关&#xff0c;在正常工作时不动作&#xff0c;但一般被保护电路受到…...

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

增加了多进程的方式执行测试代码&#xff0c;对代码改动比较大 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单片机的内外时钟切换问题

绪论 本文主要讲解单片机的时钟系统的相关知识&#xff0c;并进行超频测试&#xff0c;同时介绍如何在STM32F0单片机上进行内外时钟的切换&#xff0c;在不使用外部晶振或者外部晶振不启动时自动切换内部时钟的方法。 一、杂谈 问题来源于群里的一次问答&#xff1a; 诚然&…...

centos6.10环境下安装php7.4(基于WLNMP包)

centos6系统已经被官网停止维护&#xff0c;要安装软件必须用第三方的RPM包&#xff0c;下面使用yum安装php7.4正式版&#xff0c;当前基于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…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

高考志愿填报管理系统---开发介绍

高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发&#xff0c;采用现代化的Web技术&#xff0c;为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## &#x1f4cb; 系统概述 ### &#x1f3af; 系统定…...

Linux安全加固:从攻防视角构建系统免疫

Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...

React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?

系列回顾&#xff1a; 在上一篇《React核心概念&#xff1a;State是什么&#xff1f;》中&#xff0c;我们学习了如何使用useState让一个组件拥有自己的内部数据&#xff08;State&#xff09;&#xff0c;并通过一个计数器案例&#xff0c;实现了组件的自我更新。这很棒&#…...

初探用uniapp写微信小程序遇到的问题及解决(vue3+ts)

零、关于开发思路 (一)拿到工作任务,先理清楚需求 1.逻辑部分 不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问 2.页面部分(含国际化) 整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用 (时间充分的前提下,不…...