学习目标
- 掌握封装抽取流程
-
学习内容
开发流程
在文件系统中,创建中间件功能文件目录
- 在keil工程中,创建分组管理中间件
- 编写中间件逻辑
-
文件目录创建
在工程根目录,创建
Middleware目录,在这个目录中,创建具体的功能目录,当前是做串口功能,我们新建usart。
分组创建
创建
Middleware分组。右键进入Manage Project Items

- 创建头文件和c文件
接口定义
发送功能定义
void Usart0_init();void Usart0_send_data(uint8_t data);void Usart0_send_string(char *data);
接收回调定义
#define USART0_RECV_CALLBACK 1#if USART0_RECV_CALLBACKextern void Usart0_recv(uint8_t *data, uint32_t len);#endif
...// TODO: g_recv_buff为接收的数据,g_recv_length为接收的长度#if USART0_RECV_CALLBACKUsart0_recv(g_recv_buff, g_recv_length);#endif...
- 通过宏定义做开关
系统printf打印定义
#define USART0_PRINTF 1#if USART0_PRINTF#include <stdio.h>#endif
#if USART0_PRINTF//重写fputc方法 调用printf,会自动调用这个方法实现打印int fputc(int ch, FILE *f) {Usart0_send_data((uint8_t)ch);return ch;}#endif
完整代码
#ifndef __USART0_H__#define __USART0_H__#include "gd32f4xx.h"#include "systick.h"#define USART0_RECV_CALLBACK 1#define USART0_PRINTF 1#if USART0_PRINTF#include <stdio.h>#endifvoid Usart0_init();void Usart0_send_data(uint8_t data);void Usart0_send_string(char *data);#if USART0_RECV_CALLBACKextern void Usart0_recv(uint8_t *data, uint32_t len);#endif#endif
#include "Usart0.h"#define USART0_RECEIVE_LENGTH 1024//串口接收缓冲区大小static uint8_t g_recv_buff[USART0_RECEIVE_LENGTH]; // 接收缓冲区//接收到字符存放的位置static int g_recv_length = 0;void Usart0_init() {uint32_t usartx_tx_rcu = RCU_GPIOA;uint32_t usartx_tx_port = GPIOA;uint32_t usartx_tx_pin = GPIO_PIN_9;uint32_t usartx_tx_af = GPIO_AF_7;uint32_t usartx_rx_rcu = RCU_GPIOA;uint32_t usartx_rx_port = GPIOA;uint32_t usartx_rx_pin = GPIO_PIN_10;uint32_t usartx_rx_af = GPIO_AF_7;uint32_t usartx = USART0;uint32_t usartx_rcu = RCU_USART0;uint32_t usartx_irqn = USART0_IRQn;uint32_t usartx_p_baudrate = 115200;uint32_t usartx_p_parity = USART_PM_NONE;uint32_t usartx_p_wl = USART_WL_8BIT;uint32_t usartx_p_stop_bit = USART_STB_1BIT;uint32_t usartx_p_data_first = USART_MSBF_LSB;/************** gpio config **************/// txrcu_periph_clock_enable(usartx_tx_rcu); // 配置时钟gpio_mode_set(usartx_tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_tx_pin);gpio_af_set(usartx_tx_port, usartx_tx_af, usartx_tx_pin);gpio_output_options_set(usartx_tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_tx_pin);// rxrcu_periph_clock_enable(usartx_rx_rcu); // 配置时钟gpio_mode_set(usartx_rx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_rx_pin);gpio_af_set(usartx_rx_port, usartx_rx_af, usartx_rx_pin);//gpio_output_options_set(usartx_rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_rx_pin);/************** usart config **************/// 串口时钟rcu_periph_clock_enable(RCU_USART0);// USART复位usart_deinit(usartx);usart_baudrate_set(usartx, usartx_p_baudrate); // 波特率usart_parity_config(usartx, usartx_p_parity); // 校验位usart_word_length_set(usartx, usartx_p_wl); // 数据位数usart_stop_bit_set(usartx, usartx_p_stop_bit); // 停止位usart_data_first_config(usartx, usartx_p_data_first); // 先发送高位还是低位// 发送功能配置usart_transmit_config(usartx, USART_TRANSMIT_ENABLE);// 接收功能配置usart_receive_config(usartx, USART_RECEIVE_ENABLE);// 接收中断配置nvic_irq_enable(usartx_irqn, 2, 2);// usart int rbneusart_interrupt_enable(usartx, USART_INT_RBNE);usart_interrupt_enable(usartx, USART_INT_IDLE);// 使能串口usart_enable(usartx);}void Usart0_send_data(uint8_t data) {//通过USART发送usart_data_transmit(USART0, data);//判断缓冲区是否已经空了//FlagStatus state = usart_flag_get(USART_NUM,USART_FLAG_TBE);while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));}void Usart0_send_string(char *data) {//满足: 1.data指针不为空 2.发送的数据不是\0结束标记while(data && *data) {Usart0_send_data((uint8_t)(*data));data++;}}#if USART0_PRINTF//重写fputc方法 调用printf,会自动调用这个方法实现打印int fputc(int ch, FILE *f) {Usart0_send_data((uint8_t)ch);return ch;}#endifvoid USART0_IRQHandler(void) {if ((usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) == SET) {uint16_t value = usart_data_receive(USART0);g_recv_buff[g_recv_length] = value;g_recv_length++;}if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) == SET) {//读取缓冲区,清空缓冲区usart_data_receive(USART0);g_recv_buff[g_recv_length] = '\0';// TODO: g_recv_buff为接收的数据,g_recv_length为接收的长度#if USART0_RECV_CALLBACKUsart0_recv(g_recv_buff, g_recv_length);#endifg_recv_length = 0;}}
练习题
- 实现串口驱动定义



