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_CALLBACK
    USART0_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>
#endif

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);

#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); // 数据位:默认8bit
  usart_parity_config(USART0, USART_PM_NONE);   // 校验位:默认无校验
  usart_stop_bit_set(USART0, USART_STB_1BIT);   // 停止位:默认1bit
  usart_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);
  
  // 启用USART
  usart_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.长度不为0
  while(data && len--){
    USART0_send_byte(*data);
    data++;
  }
}

// 发送字符串 (结尾标记\0)
void USART0_send_string(char *data){
  // 满足:1.data指针不为空 2. 数据不能是\0
  while(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打印函数以及处理串口中断的相关操作。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python 多进程

单例模式 面试中&#xff0c;就被问到了这个问题&#xff0c;你知道用python怎么创建一个单例模式吗&#xff1f; 单例模式是什么&#xff1f; 就是这个对象只能被创建一次。 每次实例化&#xff0c;都是同一个对象。 单例模式是一种常用的软件设计模式。在它的核心结构中只包…

UE5.2打包安卓

目录 简介: 一. 根据官网配置 二. 手动定位SDK路径 三: 设置Android基本信息 四: 设置KeyStore 五: 开始打包 六:其他 七. 总结 简介: UE5.2 打包安卓是指将使用 Unreal Engine 5.2 开发的项目编译为可在安卓设备上运行的安装包。 以下是一般的打包步骤&#xff1a; 安装…

交易中的群体行为特征和决策模型

本文基于人的行为和心理特征&#xff0c;归纳出交易中群体的行为决策模型&#xff0c;并基于这个模型&#xff0c;分析股价波浪运行背后的逻辑&#xff0c;以及投机情绪的周期变化规律&#xff0c;以此指导交易&#xff0c;分析潜在的风险和机会&#xff0c;寻找并等待高性价比…

Java:九九乘法表,打印三角形

文章目录 九九乘法表打印三角形改进:控制行数的三角形有空格的三角形 九九乘法表 package com.zhang; /* 打印九九乘法表*/ public class Test8 {public static void main(String[] args) {//i是竖着的 j是横着的for (int i 1; i < 9; i) {for(int j 1; j < 9; j) {i…

流批一体计算引擎-10-[Flink]中的常用算子和DataStream转换

pyflink 处理 kafka数据 1 DataStream API 示例代码 从非空集合中读取数据&#xff0c;并将结果写入本地文件系统。 from pyflink.common.serialization import Encoder from pyflink.common.typeinfo import Types from pyflink.datastream import StreamExecutionEnviron…

【Vue】图形验证码功能

说明&#xff1a; 图形验证码&#xff0c;本质就是一个请求回来的图片用户将来输入图形验证码&#xff0c;用于强制人机交互&#xff0c;可以抵御机器自动化攻击 (例如&#xff1a;避免批量请求获取短信) 需求&#xff1a; 动态将请求回来的 base64 图片&#xff0c;解析渲染…

【面试干货】聚集索引和非聚集索引区别?

【面试干货】聚集索引和非聚集索引区别? 1、聚集索引&#xff08;Clustered Index&#xff09;1.1 特点1.2 例子 2、非聚集索引&#xff08;Nonclustered Index&#xff09;2.1 特点2.2 例子 3、根本区别 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&…

秋招突击——6/10——复习{(树形DP)树的最长路径、}——新作{电话号码的字母组合}

文章目录 引言复习树形DP——树的最长路径思路分析参考思路求图的最长的直径的通用方法证明 树形DP分析方法问题 参考代码使用一维数组模拟邻接表存储树形结构或者稀疏图 新作电话号码的组合思路分析参考实现 总结 引言 中间面试了两天&#xff0c;去上海呆了一天&#xff0c;…

小熊家务帮day19-day21 订单模块2(取消订单,退款功能等)

目录 1 订单退款功能1.1 需求分析1.2 接口分析1.3 退款流程分析1.4 表结构设计1.5 取消未支付订单实现1.5.1 接口开发Controller层开发Service层开发 1.5.2 接口测试 1.5 取消已支付订单实现 1 订单退款功能 1.1 需求分析 用户下单成功可以取消订单&#xff0c;在订单的不同状…

机器视觉系统-同轴光源大小选择技巧

同轴光源多用于检测光滑平面产品上的缺陷&#xff0c;同样利用上述的方法计算得出光源尺寸。 实际上&#xff0c;同轴光源可理解为没有孔的开孔面光&#xff0c;因此可等效为发光面相等的面光源&#xff0c;如下图&#xff1a; 如图所示&#xff0c;同轴光源的效果与开孔面光的…

【Labview】通过串口通信从上位机读取和写入数据

最近博主需要通过Labview的上位机控制一个温控仪表&#xff0c;主要实现在上位机读取实时温度和设定的目标温度&#xff0c;以及通过上位机设定目标温度。这里将其中遇到的问题和心得分享给大家&#xff0c;博主自己也做一个记录。 由于温控仪表采用的485通讯&#xff0c;modb…

王学岗鸿蒙开发(北向)——————(十)子组件修改父组件的内容与 动画

子组件修改父组件的内容 使用类似Android的回调&#xff0c;父组件传递给子组件一个函数 import { MyComment } from ./component/MyComment import { MyContent } from ./component/MyComtent import { MyTitleComponent } from ./component/MyTitleComponentEntry Componen…

现代x86汇编-环境安装

今天端午节&#xff0c;独自在家&#xff0c;翻阅了张银奎老师编写的《现代x86汇编语言程序设计》一书&#xff0c;前言部分说明书中示例代码都是用微软visual C工具编写并使用微软宏汇编&#xff08;著名的MASM&#xff09;编译的&#xff0c;好久没有用微软vc了&#xff0c;假…

18.2 HTTP服务器-处理函数、响应404错误

1. 处理函数 处理来自客户端的请求&#xff0c;并回之以特定的响应&#xff0c;这是处理函数的主要任务。在处理函数中&#xff0c;我们通常会完成如下工作&#xff1a; 验证请求路径 http.Request.URL.Pathhttp.NotFound(...) 当请求没有对应的处理函数时&#xff0c;返回4…

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《计及电-气园区综合能源系统多重不确定性的变置信区间优化调度 》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

物联网概念

物联网 物联网简介物联网体系结构物联网体系结构定义物联网体系结构设计原则物联网体系结构四层物联网体系结构感知控制层数据传输层数据处理层应用决策层 物联网关键技术感知标识技术网络与通信技术云计算技术安全技术 已有物联网相关应用架构无线传感器网络的体系结构EPC/UID…

【讲解下Chrome DevTools,什么是Chrome DevTools?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

精神建设:为什么要学C语言以及如何学习C语言

一&#xff0c;为什么要学习C语言 学习C语言有以下几个重要原因&#xff1a; 基础性&#xff1a;C语言是一种非常基础的编程语言&#xff0c;它接近计算机硬件层面&#xff0c;让你能够更深入地理解计算机系统如何工作&#xff0c;包括内存管理、指针操作等。这对于构建坚实的…

2024年6月最新开源电视影视TVAPP原生源码和后台管理平台源码及完整教程

本套源码为本人维护更新完善半年左右的还在使用开发的源码&#xff0c;与市面上倒卖的残次品不一样&#xff0c;没有可比性&#xff0c;向下兼容安卓4.0&#xff0c;向上兼容安卓13以上TV电视系统&#xff0c; 完全无闪退&#xff0c;弹窗报错&#xff0c;卡死、异常死循环残次…

[FreeRTOS 基础知识] 任务调度 与 链表

文章目录 任务并行的概念RTOS如何实现多任务调度&#xff1f; 任务并行的概念 在生活中&#xff0c;经常出现一心多用的情况。比如你需要一边吃饭一边手机回复信息&#xff0c;这里面就存在两个任务&#xff1a;任务一、吃饭。任务二、手机回复信息。 假如你无法一心多用&…