【前言】
准备做个血氧采集的程序,他的接口为串口,因此找出开发板做一个串口接收的程序,现在用不长定接收来实现一下。
【串口选择】
由于使用日志打印占用了开发板上的USART0,开发板的接口为2.0接口,也没有焊接,查找原理图,发现可以使用摄像头接口的PC6、PC7来配置为USART5接口。其原理图如下:

再看看GD32F27的数据手册,找到复用表,将其复用为AF8即可:

【串口初始化】
串口初始化的步骤是开启GPIOC时钟->开启USART时钟->配置GPIO输出模式->复用IO->配置串口参数(如波特率数据位等)->配置中断级别->使能串口接与发送->开启接收中断(RBNE)与空闲中断(IDLE)。代码如下:
#define MKS_GPIO_PORT GPIOC
#define MKS_UART USART5
#define MKS_UART_AF GPIO_AF_8
#define MKS_UART_PIN_TX GPIO_PIN_6
#define MKS_UART_PIN_RX GPIO_PIN_7
void MKS_UART_Init(void)
{
/* enable GPIO clock */
rcu_periph_clock_enable(RCU_GPIOC);
/* enable USART clock */
rcu_periph_clock_enable(RCU_USART5);
/* enable NVIC interrupt */
nvic_irq_enable(USART5_IRQn, 10, 0);
/* connect port to USART5_Tx */
gpio_af_set(GPIOC, MKS_UART_AF, MKS_UART_PIN_TX);
/* connect port to USART5_Rx */
gpio_af_set(GPIOC, MKS_UART_AF, MKS_UART_PIN_RX);
/* configure USART Tx as alternate function push-pull */
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, MKS_UART_PIN_TX);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, MKS_UART_PIN_TX);
/* configure USART Rx as alternate function push-pull */
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, MKS_UART_PIN_RX);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, MKS_UART_PIN_RX);
/* USART configure */
usart_deinit(MKS_UART);
usart_baudrate_set(MKS_UART, 115200U);
usart_word_length_set(MKS_UART, USART_WL_8BIT); // 8位数据位
usart_stop_bit_set(MKS_UART, USART_STB_1BIT); // 1位停止位
usart_parity_config(MKS_UART, USART_PM_NONE); // 无奇偶校验
usart_hardware_flow_rts_config(MKS_UART, USART_RTS_DISABLE); // 禁用RTS
usart_hardware_flow_cts_config(MKS_UART, USART_CTS_DISABLE); // 禁用CTS
usart_receive_config(MKS_UART, USART_RECEIVE_ENABLE);
usart_transmit_config(MKS_UART, USART_TRANSMIT_ENABLE);
usart_enable(MKS_UART);
/* clear all relevant flags */
usart_flag_clear(MKS_UART, USART_FLAG_TC);
usart_flag_clear(MKS_UART, USART_FLAG_RBNE);
usart_flag_clear(MKS_UART, USART_FLAG_IDLE);
/* enable receive interrupt and IDLE interrupt */
usart_interrupt_enable(MKS_UART, USART_INT_RBNE);
usart_interrupt_enable(MKS_UART, USART_INT_IDLE);
}接下来添加中断回调函数,在中断回调函数中,首先判断是哪个中断,如果是接收中断则进行数据接收,并将数据添加到接收数据中,如果是空闲中断,则认为这一帧数据接收完整,对数据进行处理。
代码如下:
static uint8_t rx_buffer[MAX_BUFFSIZE]; // 接收数据缓冲区
static volatile uint16_t rx_counter = 0; // 接收字节计数器
/*!
\brief this function handles USART RBNE interrupt request and IDLE interrupt request
\param[in] none
\param[out] none
\retval none
*/
void USART5_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(MKS_UART, USART_INT_FLAG_RBNE))// 获取USART中断标志位状态
// USART_INT_FLAG_RBNE:读数据缓冲区非空中断标志
{
usart_interrupt_flag_clear(MKS_UART, USART_INT_FLAG_RBNE);// 清除USART中断标志位状态
uint8_t ch = (uint8_t)usart_data_receive(MKS_UART);// USART接收数据功能
rx_counter = (rx_counter + 1)% MAX_BUFFSIZE;
rx_buffer[rx_counter] = ch;
}
else if(RESET != usart_interrupt_flag_get(MKS_UART, USART_INT_FLAG_IDLE))// USART_INT_FLAG_IDLE:IDLE线检测中断标志
{
usart_interrupt_flag_clear(MKS_UART, USART_INT_FLAG_IDLE);
if(rx_counter > 0)
{
usart_interrupt_disable(MKS_UART, USART_INT_RBNE);// 失能USART中断
usart_interrupt_disable(MKS_UART, USART_INT_IDLE);
/* 测试部分,接收到的数据最好在main中处理掉 */
MKS_UART_SendData(rx_buffer,rx_counter);
usart_interrupt_enable(MKS_UART, USART_INT_RBNE);
usart_interrupt_enable(MKS_UART, USART_INT_IDLE);
}
}
}在中断处理中,在进入接收后,需要先清除中断标志位。在进入空闲中断时需要清除中断位,然后失能中断,处理数据后再开启。
【实现效果】
下载到开发板后,就可以看到发什么回给我们什么了。

我要赚赏金
