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;
  }
}
相关推荐
c10638915142 小时前
STM32外设之LTDC/DMA2D—液晶显示(野火)
stm32·单片机·嵌入式硬件
LongRunning2 小时前
【快速笔记】freeRTOS
单片机
唯创知音3 小时前
电子烟智能化创新体验:WTK6900P语音交互芯片方案,融合频谱计算、精准语音识别与流畅音频播报
人工智能·单片机·物联网·音视频·智能家居·语音识别
MGT_97964 小时前
基于51单片机的台灯控制(Proteus仿真)
嵌入式硬件·51单片机·proteus
夜间去看海4 小时前
基于51单片机的倒计时音乐播放系统设计
单片机·嵌入式硬件·51单片机
aqymnkstkw5 小时前
2024年【电气试验】考试题库及电气试验模拟试题
大数据·c语言·人工智能·嵌入式硬件·安全
xxpro6 小时前
S3C2440开发板点亮LED灯+PWM定时器
单片机·嵌入式硬件
百里与司空6 小时前
学习CubeIDE——定时器开发
stm32·单片机·嵌入式硬件·学习
天蓝蓝235287 小时前
嵌入式硬件基础知识
嵌入式硬件
代码总长两年半7 小时前
STM32+FATFS+SD卡+RTC(生成.CSV格式文件)
stm32·嵌入式硬件·实时音视频