西门子杯工业嵌入式-5-串口实现数据收发
- 一、通信基础
- 1.1 什么是通信
- 1.2 嵌入式系统中的通信
- 二、串行通信原理
- 2.1 串行通信简介
- 2.2 通信参数约定
- 三、GD32F470 串口资源与性能
- 3.1 串口硬件资源
- 四、串口通信的实现
- 4.1 串口初始化流程
- 4.2 串口发送函数编写
- 4.3 使用 printf 实现串口输出
- 五、串口接收中断机制
- 5.1 接收中断原理
- 5.2 接收中断配置
- 六、总结与注意事项
- 6.1 串口通信优势
- 6.2 编程注意事项
- 接线图
链接: B站视频
一、通信基础
1.1 什么是通信
信息从一个设备传输到另一个设备的过程
生活中的通信例子(通话、短信、上网)
1.2 嵌入式系统中的通信
微控制器与外设信息交互的关键方式
分类方式:
按传输介质:有线通信 vs 无线通信
按传输方式:串行通信 vs 并行通信
按同步方式:同步通信 vs 异步通信
二、串行通信原理
2.1 串行通信简介
基本方式
特点:一条数据线、按位传输、硬件简单
2.2 通信参数约定
关键参数:波特率、数据位、停止位、奇偶校验
参数不一致导致通信失败的例子(摩斯电码类比)
三、GD32F470 串口资源与性能
3.1 串口硬件资源
支持8个 USART/UART 接口
支持全双工通信
可配置波特率,最高10.5Mbps
内置16位波特率发生器
支持DMA和多种中断
四、串口通信的实现
4.1 串口初始化流程
启用 GPIO 和 USART 时钟
配置 GPIO 引脚复用功能(AF7, PA9, PA10)
设置 GPIO 模式为复用输出
串口复位并配置通信参数(波特率、校验、字长、停止位)
启用串口发送与接收功能
关闭流控 RTS/CTS
配置并启用 USART 中断
void USART0_Config(void)
{
rcu_periph_clock_enable(RCU_GPIOA); // 使能GPIO时钟
rcu_periph_clock_enable(RCU_USART0); // 使能串口时钟
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9 | GPIO_PIN_10); //配置端口复用
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9); //端口类型配置为复用
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_10); //端口类型配置为复用
gpio_output_options_set(GPIOA, GPIO_MODE_ANALOG, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
usart_deinit(USART0); // 串口复位
usart_word_length_set(USART0, USART_WL_8BIT); // 字长为8位
usart_stop_bit_set(USART0, USART_STB_1BIT); // 停止位1位
usart_parity_config(USART0, USART_PM_NONE); // 无校验
usart_baudrate_set(USART0, 115200U); // 波特率115200
usart_receive_config(USART0, USART_RECEIVE_ENABLE); // 接收使能
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); // 发送使能
usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
usart_enable(USART0); // 串口使能
}
4.2 串口发送函数编写
定义发送函数:传入数据指针和长度
轮询发送:等待发送完成标志
使用 usart_data_transmit() 实现字符逐个发送
```css
void USART0_SendData(uint16_t *buf,uint16_t len)
{
uint16_t t;
for(t=0;t<len;t++)
{
while(usart_flag_get(USART0, USART_FLAG_TC) == RESET);
usart_data_transmit(USART0,buf[t]);
}
while(usart_flag_get(USART0, USART_FLAG_TC) == RESET);
}
4.3 使用 printf 实现串口输出
重定向 fputc()
使能 MicroLib,配置标准输出到串口
printf 实质上也是通过 usart_data_transmit() 实现的
int fputc(int ch, FILE *f)
{
usart_data_transmit(USART0, (uint8_t)ch);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
return ch;
}
五、串口接收中断机制
5.1 接收中断原理
接收缓冲区非空时触发中断
避免轮询方式,提高实时性
应用场景:传感器数据采集、远程控制、通信协议实现等
5.2 接收中断配置
启用 USART 接收功能
启用接收缓冲区非空中断
编写中断服务函数
判断中断类型
读取数据并存储
清除中断标志,避免死循环
void USART0_Config(void)
{
rcu_periph_clock_enable(RCU_GPIOA); // 使能GPIO时钟
rcu_periph_clock_enable(RCU_USART0); // 使能串口时钟
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9 | GPIO_PIN_10); //配置端口复用
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9); //端口类型配置为复用
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_10); //端口类型配置为复用
gpio_output_options_set(GPIOA, GPIO_MODE_ANALOG, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
usart_deinit(USART0); // 串口复位
usart_word_length_set(USART0, USART_WL_8BIT); // 字长为8位
usart_stop_bit_set(USART0, USART_STB_1BIT); // 停止位1位
usart_parity_config(USART0, USART_PM_NONE); // 无校验
usart_baudrate_set(USART0, 115200U); // 波特率115200
usart_receive_config(USART0, USART_RECEIVE_ENABLE); // 接收使能
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); // 发送使能
usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
nvic_irq_enable(USART0_IRQn, 0, 0);
usart_interrupt_enable(USART0, USART_INT_RBNE);
usart_enable(USART0); // 串口使能
}
/************************************************************
* Function : USART0_IRQHandler
* Comment : 串口中断服务函数,用来接收串口数据
* Parameter: null
* Return : null
* Author : Lingyu Meng
* Date : 2025-03-14 V0.2 original
************************************************************/
void USART0_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE))
{
data_recv = usart_data_receive(USART0); // 接收串口数据
usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE); //清除接收中断标志位
process_data(data_recv); //处理数据
}
}
/************************************************************
* Function : process_data
* Comment : 数据为 ‘a’的时候点亮LED2
数据为'b'的时候关断LED2
其他数据则直接串口打印出来
* Parameter: char型的数据,只支持单字符
* Return : null
* Author : Lingyu Meng
* Date : 2025-03-14 V0.2 original
************************************************************/
void process_data(uint8_t data)
{
if (data == 'a')
{
LED2_ON();
}
else if(data == 'b')
{
LED2_OFF();
}
else
{
usart_data_transmit(USART0, data_recv); // 发送数据
}
}
六、总结与注意事项
6.1 串口通信优势
实现简单
应用广泛
配合中断机制高效可靠
6.2 编程注意事项
初始化要完整、参数一致
中断处理后必须清除中断标志
使用串口调试助手验证数据发送
接线图
注意TX与RX相接