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

ARM32开发--串口库封装(初级)

知不足而奋进·望远山而前行


目录

文章目录

前言

目标

内容

开发流程

文件目录创建

分组创建

接口定义

完整代码

总结


前言

在嵌入式软件开发中,封装抽取流程和抽取封装策略是非常重要的技术,能够提高代码的复用性和可维护性。本文将介绍如何在文件系统中创建库目录,并通过keil工程中创建分组管理库的方式,实现串口功能的封装和抽取。通过具体的步骤和代码示例,帮助读者掌握封装抽取流程和策略。


目标

  1. 掌握封装抽取流程
  2. 掌握抽取封装策略

内容

开发流程

  1. 在文件系统中,创建库目录Library
  2. 在keil工程中,创建分组管理库Library
  3. 编写中间件逻辑
  4. 使用中间件
文件目录创建

在工程根目录,创建Library目录,在这个目录中,创建具体的功能目录,当前是做串口功能,我们新建usart

分组创建
  1. 创建Library分组。右键进入Manage Project Items

  1. 右键创建头文件和c文件

添加include引入

接口定义

初始化及发送功能定义

void USART0_init(void);// 发送1个byte数据
void USART0_send_byte(uint8_t byte);// 发送多个byte数据
void USART0_send_data(uint8_t* data, uint32_t len);// 发送字符串 (结尾标记\0)
void USART0_send_string(char *data);

接收回调定义

// 功能开关配置
#define USART0_RECV_CALLBACK    1#if USART0_RECV_CALLBACK
// 收到串口0数据,回调函数
extern void USART0_on_recv(uint8_t* data, uint32_t len);
#endif
...
#if USART0_RECV_CALLBACKUSART0_on_recv(g_rx_buffer, g_rx_cnt);
#endif
...
  • 通过宏定义做开关

系统printf打印定义

#define USART0_PRINTF				 1#if	USART0_PRINTF
#include <stdio.h>
#endif
#if USART0_PRINTF
// 配置printf打印函数
int fputc(int ch, FILE *f) {USART0_send_byte(ch);return ch;
}
#endif

完整代码

#ifndef __USART0_H__
#define __USART0_H__#include "gd32f4xx.h"// 功能开关配置
#define USART0_RECV_CALLBACK    1
#define USART0_PRINTF           1#if	USART0_PRINTF
#include <stdio.h>
#endifvoid USART0_init(void);// 发送1个byte数据
void USART0_send_byte(uint8_t byte);// 发送多个byte数据
void USART0_send_data(uint8_t* data, uint32_t len);// 发送字符串 (结尾标记\0)
void USART0_send_string(char *data);#if USART0_RECV_CALLBACK
// 收到串口0数据,回调函数
extern void USART0_on_recv(uint8_t* data, uint32_t len);
#endif#endif
#include "USART0.h"
#include <stdio.h>void USART0_init(void) {// GPIO 初始化 ----------------------------------------------------// 启用GPIO时钟rcu_periph_clock_enable(RCU_GPIOA);/* 配置TX PA9和RX PA10引脚 */gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);/* configure the USART0 TX pin and USART0 RX pin */gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9);gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);// 串口 初始化 ----------------------------------------------------// 启用USART0时钟rcu_periph_clock_enable(RCU_USART0);// 重置(可选)usart_deinit(USART0);// 配置串口参数:波特率*, 数据位,校验位,停止位, 大小端模式usart_baudrate_set(USART0, 115200UL);         // 波特率:必填usart_word_length_set(USART0, USART_WL_8BIT); // 数据位:默认8bitusart_parity_config(USART0, USART_PM_NONE);   // 校验位:默认无校验usart_stop_bit_set(USART0, USART_STB_1BIT);   // 停止位:默认1bitusart_data_first_config(USART0, USART_MSBF_LSB);// 大小端模式:默认小端// 启用发送功能usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);// 启用接收功能usart_receive_config(USART0, USART_RECEIVE_ENABLE);// 开启接收中断nvic_irq_enable(USART0_IRQn, 2, 2);// 启用RBNE中断,读数据缓冲区不为空中断usart_interrupt_enable(USART0, USART_INT_RBNE);// 启用IDLE中断,空闲中断usart_interrupt_enable(USART0, USART_INT_IDLE);// 启用USARTusart_enable(USART0);
}// 发送1个byte数据
void USART0_send_byte(uint8_t byte){// 从USART0的TX发送一个字节出去usart_data_transmit(USART0, (uint8_t)byte);// 等待发送完成 (轮询等待发送数据缓冲区为空)while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
}// 发送多个byte数据
void USART0_send_data(uint8_t* data, uint32_t len){// 满足:1.data指针不为空 2.长度不为0while(data && len--){USART0_send_byte(*data);data++;}
}// 发送字符串 (结尾标记\0)
void USART0_send_string(char *data){// 满足:1.data指针不为空 2. 数据不能是\0while(data && *data){USART0_send_byte((uint8_t)*data);data++;}
}#if USART0_PRINTF
// 配置printf打印函数
int fputc(int ch, FILE *f) {USART0_send_byte(ch);return ch;
}
#endif/************************************
中断函数:收到标记信号,马上执行
1. 触发中断函数的原因(标记)有很多
2. 需要区分是哪个标记触发的中断
RBNE: read data buffer not empty中断函数名不能随便写,要根据中断向量表复制
*************************************/#define   RX_BUFFER_LEN   1024
uint8_t   g_rx_buffer[RX_BUFFER_LEN];
uint32_t  g_rx_cnt = 0;void USART0_IRQHandler(void){if(SET == usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)){// 收到数据
//    printf(">RBNE<\n");// 清理标记(避免多次触发中断)usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);// 获取寄存器里的数据uint8_t data = usart_data_receive(USART0);// 缓存到buffer中g_rx_buffer[g_rx_cnt++] = data;// 避免缓冲区溢出 (可选)if(g_rx_cnt >= RX_BUFFER_LEN) g_rx_cnt = 0;// 原样返回 send_byte(data);}if(SET == usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)){
//    printf(">IDLE<\n"); // 空闲// 清理标记(无效) usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);// 只能使用以下方式清理IDLE标记usart_data_receive(USART0); // 必须读取一次USART0,读到的结果没有用// 添加字符串结束标记,避免打印出错g_rx_buffer[g_rx_cnt] = '\0';#if USART0_RECV_CALLBACK
//    printf("%s", g_rx_buffer);USART0_on_recv(g_rx_buffer, g_rx_cnt);
#endif// 把缓冲区[0, g_rx_cnt)设置为0x00 (可选)
//    memset(g_rx_buffer, 0x00, g_rx_cnt);// 重置缓冲区数据个数g_rx_cnt = 0;}
}


总结

通过本文的学习,我们深入探讨了如何使用文件系统中的库目录和keil工程中的分组管理库来实现串口功能的封装和抽取。通过编写中间件逻辑和定义相关接口,我们实现了串口初始化、发送数据以及接收数据的功能,并通过宏定义的开关配置来实现功能的灵活控制。同时,我们也介绍了如何配置printf打印函数以及处理串口中断的相关操作。

相关文章:

ARM32开发--串口库封装(初级)

知不足而奋进望远山而前行 目录 文章目录 前言 目标 内容 开发流程 文件目录创建 分组创建 接口定义 完整代码 总结 前言 在嵌入式软件开发中&#xff0c;封装抽取流程和抽取封装策略是非常重要的技术&#xff0c;能够提高代码的复用性和可维护性。本文将介绍如何在文…...

统一管理:Vue公共组件/公共样式/全局自定义指令

main.js 引入存放公共文件的文件路径 import "./plugins";src/plugins文件夹下的index.js 在处理公共文件中分别引入 /* 公共引入,勿随意修改,修改时需经过确认 */ import Vue from "vue";import "/icons"; // 图标 import ByuiQueryForm fr…...

Linux之旅: 基础知识点的终极指南

文章目录 1、Linux的目录结构2、ls命令3、管理文件和目录4、linux命令使用细节和技巧5、权限管理基本命令6、搜索命令7、管道符与重定向8、压缩和解压命令9、用户及vim编辑器10、用户和用户组管理一、Linux系统用户账号的基本管理二、Linux系统用户组的管理 1、Linux的目录结构…...

C#部分方法有什么用处?和传统方法有什么区别?什么时候用合适?

在C#中&#xff0c;部分类&#xff08;partial class&#xff09;和部分方法&#xff08;partial method&#xff09;是两个不同的概念&#xff0c;但它们经常一起使用&#xff0c;特别是在代码生成和框架设计中。下面我将分别解释这两个概念&#xff0c;并讨论它们的用处、与传…...

elasticsearch hanlp插件远程词典配置

elasticsearch hanlp插件远程词典配置 背景远程词典配置新增远程词典文件修改hanlp-remote.xml自动加载词典 远程词典测试 背景 在使用elasticsearch的过程中&#xff0c;总会遇到与分词相关的需求&#xff0c;这里将针对常用的elasticsearch hanlp&#xff08;后面统称为 es …...

力扣每日一题 6/18 字符串/模拟

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 2288.价格减免 【中等】 题目&#xff1a; 句子 是由若干个单词组成的字符…...

架构设计 - Nginx Proxy Cache 缓存配置

摘要&#xff1a; web 应用业务缓存通常3级&#xff1a; 一级缓存&#xff1a;JVM 本地缓存 二级缓存&#xff1a;Redis集中式缓存 三级缓存&#xff1a;Nginx Proxy Cache 缓存 或 Nginx Lua 缓存 四级缓存&#xff1a;静态资源CDN缓存 本文主要分享 Nginx Proxy Cache 缓…...

【前端】HTML5基础

目录 0 参考1 网页1.1 什么是网页1.2 什么是HTML1.3 网页的形成 2 浏览器2.1 常用的浏览器2.2 浏览器内核 3 Web标准3.1 为什么需要Web标准3.2 Web标准的构成 4 HTML 标签4.1 HTML语法规范4.1.1 基本语法概述4.1.2 标签关系4.1.2.1 包含关系4.1.2.2 并列关系 4.2 HTML基本结构标…...

9个最佳性能测试工具(2024)

1、前言 性能测试检查软件程序在预期工作负载下的速度、响应时间、可靠性、资源使用情况和可扩展性。性能测试的目的不是发现功能缺陷&#xff0c;而是消除软件或设备中的性能瓶颈。 性能测试为利益相关者提供有关其应用程序的速度、稳定性和可扩展性的信息。更重要的是&…...

RTthread+STM32F407ZGTx+烟雾报警检测+蜂鸣器报警+LED闪烁||使用RTthread Studio

目录 实验背景 1.安装环境 2.配置环境 3.先编译下载实例程序2&#xff0c;观察DS0是否闪烁 4.实验方法 5.实例代码 6.硬件连接 7.实验效果 8.关于这次开发遇到的问题 1.反应慢&#xff0c;都熄灭1分钟多了&#xff0c;才报的问题&#xff1f; 2.关于rt_pin_mode(KEY…...

k8s资源的基本操作

文章目录 一、Namespace1、概述2、预定义的k8s命名空间2.1、default2.2、kube-public2.3、kube-system2.4、kube-node-lease 3、命名空间基本操作3.1、查看3.1.1、查看所有的命名空间3.1.2、查看指定的命名空间3.1.3、指定输出格式3.1.4、查看ns详情 3.2、创建3.2.1、命令行创建…...

19.面包屑导航制作

面包屑导航制作 官网&#xff1a;组件 | Element 1. 在layout下新建BreadCrumb.vue BreadCrumb.vue <template><div class"bread-text"><el-breadcrumb class"bred"separator"/"><el-breadcrumb-item v-for"item in…...

做动画?Animatediff 和 ComfyUI 更配哦!

如果从工作流和内存利用率的角度来说&#xff0c;Animatediff 和 ComfyUI 可能更配一些&#xff0c;毕竟制作动画是一个很吃内存的操作。 首先&#xff0c;我们需要在管理器中下载 Animatediff 插件&#xff0c;当然也可以直接导入听雨的工作流&#xff0c;然后在管理器的安装…...

笔记-python里面的xlrd模块详解

那我就一下面积个问题对xlrd模块进行学习一下&#xff1a; 1.什么是xlrd模块&#xff1f; 2.为什么使用xlrd模块&#xff1f; 3.怎样使用xlrd模块&#xff1f; 1.什么是xlrd模块&#xff1f; ♦python操作excel主要用到xlrd和xlwt这两个库&#xff0c;即xlrd是读excel&…...

oracle将字符串中的字符和数字拆分开等功能

将字符串中的字符和数字拆分开 create or replace procedure F_GetNumber1( inString IN VARCHAR2,n_return1 out varchar2, n_return2 out varchar2) ISDCHAR VARCHAR2(1024); OUTCHAR VARCHAR2(1024); j number default 0; ulen number; BEGINOUTCHAR:;DCHAR:TRIM(inStr…...

汇编基础之使用vscode写hello world

汇编语言&#xff08;Assembly Language&#xff09; 概述 汇编语言&#xff08;Assembly Language&#xff09;是一种低级编程语言&#xff0c;它直接对应于计算机的机器代码&#xff08;machine code&#xff09;&#xff0c;但使用了更易读的文本符号。每台个人计算机都有…...

APS计划排程系统如何打破装备使用约束

APS计划排程系统是离散制造型企业在计划控制方向的重要支撑&#xff0c;它提供的是交期预测、订单排产计划、物料采购计划、人力分配计划等等。近些几年来&#xff0c;多品种、小批量、多订单的生产模式&#xff0c;让企业的计划员应接不暇、疲累不堪&#xff0c;传统的人工经验…...

gigachad - suid

gigachadeasyftp利用、google反图搜索、 suid提权、s-nail 提权 主机发现 ┌──(kali㉿kali)-[~/桌面/OSCP] └─$ sudo netdiscover -i eth0 -r 192.168.44.138/24服务探测 ┌──(kali㉿kali)-[~/桌面/OSCP] └─$ sudo nmap -sV -A -T 4 -p- 192.168.44.138 |_/kingchad…...

QtScript模块

在Qt中&#xff0c;可以使用Qt Script模块来将C类和方法绑定到Qt脚本引擎中&#xff0c;从而使得可以在Qt脚本中调用这些C类和方法。以下是一个简单的示例&#xff0c;演示了如何在Qt中将C类暴露给Qt Script引擎&#xff1a; 假设有一个名为 MyClass 的C类&#xff0c;其头文件…...

qt中for循环不要使用循环中会更改的变量

检查代码&#xff0c;发现始终会少了一位&#xff0c;最后发现我在使用for循环时&#xff0c;懒省事&#xff0c;判断条件中使用的变量是涉及到循环体中更改的变量&#xff0c;代码如下&#xff0c;更直观 for (int i 0; i < m_images.size(); i) {packageToDBList[0].imag…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...

Tauri2学习笔记

教程地址&#xff1a;https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引&#xff1a;https://tauri.app/zh-cn/start/ 目前Tauri2的教程视频不多&#xff0c;我按照Tauri1的教程来学习&…...

Qt的学习(二)

1. 创建Hello Word 两种方式&#xff0c;实现helloworld&#xff1a; 1.通过图形化的方式&#xff0c;在界面上创建出一个控件&#xff0c;显示helloworld 2.通过纯代码的方式&#xff0c;通过编写代码&#xff0c;在界面上创建控件&#xff0c; 显示hello world&#xff1b; …...

【Java】Ajax 技术详解

文章目录 1. Filter 过滤器1.1 Filter 概述1.2 Filter 快速入门开发步骤:1.3 Filter 执行流程1.4 Filter 拦截路径配置1.5 过滤器链2. Listener 监听器2.1 Listener 概述2.2 ServletContextListener3. Ajax 技术3.1 Ajax 概述3.2 Ajax 快速入门服务端实现:客户端实现:4. Axi…...

开疆智能Ethernet/IP转Modbus网关连接鸣志步进电机驱动器配置案例

在工业自动化控制系统中&#xff0c;常常会遇到不同品牌和通信协议的设备需要协同工作的情况。本案例中&#xff0c;客户现场采用了 罗克韦尔PLC&#xff0c;但需要控制的变频器仅支持 ModbusRTU 协议。为了实现PLC 对变频器的有效控制与监控&#xff0c;引入了开疆智能Etherne…...

[C++错误经验]case语句跳过变量初始化

标题&#xff1a;[C错误经验]case语句跳过变量初始化 水墨不写bug 文章目录 一、错误信息复现二、错误分析三、解决方法 一、错误信息复现 write.cc:80:14: error: jump to case label80 | case 2:| ^ write.cc:76:20: note: crosses initialization…...