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打印函数以及处理串口中断的相关操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/26133.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

这可能是最清晰易懂的 G1 GC 资料

滑动验证页面 概述 G1 (Garbage-First) 于JDK 6u14版本发布&#xff0c;JDK 7u4版本发行时被正式推出&#xff0c;在JDK9时已经成了默认的垃圾回收器&#xff0c;算是CMS回收器的替代 方案&#xff08;CMS在JDK9以后已经废弃&#xff09; G1是一款分代的 (generational)&a…

@并行计算和分布式计算解决方案

并行计算和分布式计算解决方案 文章目录 为什么需要并行计算为什么需要分布式计算常见的解决方案有哪些 为什么需要并行计算 需要最大化利用计算机资源&#xff0c;加速计算。 为什么需要分布式计算 单机资源不足或者单机加速不达标&#xff0c;需要联合多台计算机&#xff…

如何使用C++ STL标准模板库中的算法函数(附源码)

目录 1、概述 2、调用sort函数对列表元素进行排序 3、调用count_if查找满足条件的元素个数 4、调用find_if函数找到目标元素的信息 5、调用remove_copy_if函数搜索满足条件的多个元素 6、总结 VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.…

LeetCode刷题之HOT100之子集

2024/6/11 周二&#xff0c;闷热&#xff0c;很热。两天没有做题了&#xff0c;前天去附近一景点《十八重溪》游玩&#xff0c;去了才知道暂停开放&#xff0c;只能在附近转转了&#xff0c;瀑布是看不到了。昨天在宿舍呆了一天&#xff0c;今天早上起来就来了实验室。补三张图…

端午节,来看看这本应景的“龙舟书”吧!

大家端午安康呀图片~~ 端午节&#xff0c;不仅要吃粽子&#xff0c;还要看龙舟&#xff01;图片 所以&#xff0c;今天就和大家分享一本“龙舟书”——《精进ChatGPT&#xff1a;高效应用实战88例》&#xff01; 不仅和今天的端午节应景&#xff0c;还和当今的AI时代很配图片…

AI Agent 热门的10篇论文

人工智能代理领域广阔,涵盖广泛的主题,包括多代理系统、强化学习、上下文感知系统以及将大型语言模型 (LLMs) 集成到基于代理的系统中。以下是 arXiv 的一些顶级论文,涵盖了人工智能代理的各个方面: A Framework For Intelligent Multi Agent System Based Neural Network …

Python 基础语法详解(四)

Python 基础语法详解&#xff08;四&#xff09; Python 条件语句最简单的 if 语句基本的 if 语句实战&#xff1a; 复杂 if 语句实战&#xff1a; 看一看 elif 的好处题目&#xff1a;代码实现&#xff1a; 三元表达式格式为&#xff1a;实操&#xff1a; Python 条件语句 在…

Windows 托盘图标实现类封装及使用(附源码)

在系统桌面右下角的托盘区域,创建一个托盘图标,已经是很多软件的标配了,特别是IM即时通讯软件,要在托盘图标上显示来消息时的闪动头像。 其实托盘图标创建很简单,使用起来也比较方便,主要是调用Shell_NotifyIcon API函数,传入不同参数表示对应的操作: 1)NIM_AD…

synchronized 的底层实现

用户态与内核态 JDK 早期&#xff0c;synchronized 叫做重量级锁&#xff0c; 因为申请锁资源必须通过 kernel&#xff08;指大多数操作系统的核心部分&#xff09;&#xff0c;系统调用。 ;hello.asm ;write(int fd, const void *buffer, size_t nbytes)section datamsg db …

数据结构(用 JS 实现栈和队列【三种方式】)

栈 先进后出 JS 实现栈 栈 : 用数组实现入栈 push ---- 时间复杂度 O(1)出栈 pop ---- 时间复杂度 O(1) let stack [];// 入栈 stack.push("a"); stack.push("b");console.log(stack);// 出栈 -- 先进后出 -- b 出栈 stack.pop();console.log(stack);队…

安装golang

官网:All releases - The Go Programming Language (google.cn) 下载对应的版本安装即可

【Python】 如何使用Pandas DataFrame的‘in‘和‘not in‘进行筛选,就像在SQL中一样

基本原理 在Python的Pandas库中&#xff0c;DataFrame是一个强大的数据结构&#xff0c;用于处理表格数据。Pandas提供了多种方法来筛选DataFrame中的数据&#xff0c;其中使用in和not in是模仿SQL查询中IN和NOT IN操作的一种方式。在SQL中&#xff0c;IN用于筛选出在某个列表…

线性代数|机器学习-P9向量和矩阵范数

文章目录 1. 向量范数2. 对称矩阵S的v范数3. 最小二乘法4. 矩阵范数 1. 向量范数 范数存在的意义是为了实现比较距离&#xff0c;比如&#xff0c;在一维实数集合中&#xff0c;我们随便取两个点4和9&#xff0c;我们知道9比4大&#xff0c;但是到了二维实数空间中&#xff0c…

C# Maui 报错:程序“[15748] MauiApp1.exe”已退出,返回值为 2147942405 (0x80070005)

“MauiApp1.exe”(CoreCLR: DefaultDomain): 已加载“C:\Program Files\dotnet\shared\ Microsoft.NETCore.App\8.0.6\System.Private.CoreLib.dll”。 “MauiApp1.exe”(CoreCLR: clrhost): 已加载“E:\cDemo\MauiApp1\MauiApp1\bin\Debug\net8.0-windows10.0.19041.0\win10-x…

碳酸钠去除铁离子杂志树脂T-IRR

"高级"铁去除离子交换树脂介质 Tulsion T- IRR 是一款高级的离子交换树脂介质。设计了更好的多空性架构和卓越的催化性以去除溶解在地下水中的铁离子。 Tulsion T- IRR 具有氧化性能&#xff0c;可以把铁转化为3价铁离子。形成的不溶铁离子会被床体有效的拦截过滤&a…

LCD屏的价格和显示区的尺寸有关

LCD屏的价格和显示区的尺寸有关&#xff0c;和外尺寸无关。 下面通过12864点阵屏&#xff0c;对不同尺寸的屏&#xff0c;进行价格比较&#xff0c;就可以发现&#xff1a;LCD屏的价格和显示区的尺寸有关&#xff1b; 同点阵的屏&#xff0c;显示区域太小&#xff0c;显示12*1…

Python基础速成

文件操作 文件读取 with open语法 文件写入 注意事项 文件追加 异常、模块与包 捕获异常 捕获方法 捕获传递 模块的导入与自定义 定义 导入方式 自定义 测试模块 注意事项 python包 定义 操作 第三方包 定义 pip指令安装包

FlashSequence: SORA视频生成长序列任务训练解决方案

作者&#xff1a;黄奕桐、沈雯婷、艾宝乐、王昂、九丰 摘要 我们提出了长序列训练方案 FlashSequence 并集成在 PAI-TorchAcc &#xff08;阿里云机器学习平台开发的Pytorch上的大模型训练加速框架&#xff09;中&#xff0c;该方案能够支持SORA类超长序列模型的高效训练。在…

如何在小程序中实现页面之间的跳转

在小程序中实现页面之间的跳转&#xff0c;你可以使用上面提到的几个API。以下是具体的步骤和示例&#xff1a; 1. 使用 wx.navigateTo 跳转 wx.navigateTo 是小程序中常用的页面跳转API&#xff0c;用于保留当前页面&#xff0c;并跳转到应用内的某个页面。 示例&#xff1…

CAS Server Restful接口实现后台认证

背景 对于一些比较复杂定制化登录页的情况下&#xff0c;之前提到过可以自定义修改使用CAS Server提供的登录页这种操作已经明显跟不上复杂定制场景了&#xff0c;所以CAS Server也提供了支持Restful接口&#xff0c;支持服务端后台登陆&#xff0c;对于复杂登陆场景时&#x…