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

🎬 秋野酱:《个人主页》

🔥 个人专栏:《Java专栏》《Python专栏》

⛺️心若有所向往,何惧道阻且长

文章目录

开发流程

  1. 在文件系统中,创建库目录Library
  2. 在keil工程中,创建分组管理库Library
  3. 编写中间件逻辑
  4. 使用中间件
    文件目录创建
    在工程根目录,创建Library目录,在这个目录中,创建具体的功能目录,当前是做串口功能,我们新建usart。

分组创建

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

    右键创建头文件和c文件

    添加include引入

接口定义

初始化及发送功能定义

csharp 复制代码
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);

接收回调定义

csharp 复制代码
// 功能开关配置
#define USART0_RECV_CALLBACK    1

#if USART0_RECV_CALLBACK
// 收到串口0数据,回调函数
extern void USART0_on_recv(uint8_t* data, uint32_t len);
#endif
csharp 复制代码
...
#if USART0_RECV_CALLBACK
    USART0_on_recv(g_rx_buffer, g_rx_cnt);
#endif
...

● 通过宏定义做开关

系统printf打印定义

csharp 复制代码
#define USART0_PRINTF				 1

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

完整代码

csharp 复制代码
#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
csharp 复制代码
#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;
  }
}
相关推荐
智商偏低1 小时前
单片机之helloworld
单片机·嵌入式硬件
青牛科技-Allen3 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
沉在嵌入式的鱼3 小时前
使用nomachine远程连接ARM设备桌面
arm开发·rk3588·远程连接·nomachine
森焱森5 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白5 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D5 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术8 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt9 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘9 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang9 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c