当前位置: 首页 > 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】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...