1. 串口通信基础从概念到硬件连接第一次接触GD32F303的串口功能时我完全被各种术语搞晕了。USART、UART、波特率、数据帧...这些名词听起来很专业其实理解起来并不难。让我用最直白的方式给你解释清楚。串口通信就像两个人用对讲机通话。对讲机需要约定好相同的频道波特率说话要有开始和结束的标记起始位和停止位还要确认对方是否听清楚了校验位。在GD32F303上USART0就是我们最常用的对讲机频道对应PA9(TX)和PA10(RX)两个引脚TX负责发送数据RX负责接收数据。硬件连接特别简单你只需要用USB转TTL模块连接开发板模块的TX接开发板的RX(PA10)模块的RX接开发板的TX(PA9)共地连接(GND接GND)我刚开始总把TX和RX接反导致数据传不出去。后来记住一个口诀发对收收对发就是开发板的TX接模块的RX开发板的RX接模块的TX。2. USART与UART的区别同步还是异步很多新手会困惑USART和UART的区别。简单来说UART只能异步通信而USART既支持异步也支持同步。就像手机的通话功能同步和短信功能异步的区别。在GD32F303上我们通常使用异步模式这时USART和UART的用法完全一样。同步模式一般用于特殊场景比如驱动SPI设备。异步通信的优势是不需要时钟线接线简单缺点是传输速率不能太高且需要双方约定好相同的波特率。我实测过GD32F303的USART0在115200波特率下非常稳定。高于这个速率时偶尔会出现数据丢失所以建议新手先用这个波特率。3. 串口初始化配置一步一步来配置串口就像设置对讲机需要把各个参数都调对。下面是我调试多次后总结的最佳配置方案void uart0_init(void) { // 1. 开启时钟 rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_USART0); // 2. 配置GPIO引脚 gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); // TX gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); // RX // 3. 复位USART usart_deinit(USART0); // 4. 设置波特率115200 usart_baudrate_set(USART0, 115200U); // 5. 使能接收和发送 usart_receive_config(USART0, USART_RECEIVE_ENABLE); usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); // 6. 使能USART usart_enable(USART0); }这里有几个容易出错的地方忘记开启GPIO时钟和USART时钟我就犯过这个错TX引脚要配置为复用推挽输出RX配置为浮空输入波特率设置要准确常用的有9600、115200等4. 数据发送三种常用方式实际项目中我们需要发送不同类型的数据。我整理了三种最常用的发送函数4.1 发送单个字节void uart0_send_byte(uint8_t ch) { usart_data_transmit(USART0, ch); while(RESET usart_flag_get(USART0, USART_FLAG_TBE)); }这个函数会等待发送完成才返回。TBE标志位表示发送缓冲区为空可以发送下一个字节。4.2 发送字符串void uart0_send_string(uint8_t *str) { while(*str) { uart0_send_byte(*str); } }使用时直接传入字符串指针比如uart0_send_string(Hello GD32F303!\r\n);4.3 发送任意数据数组void uart0_send_data(uint8_t *data, int len) { for(int i0; ilen; i) { uart0_send_byte(data[i]); } }这个函数特别适合发送传感器数据或自定义协议数据。5. 中断接收数据高效处理方案串口接收最可靠的方式是使用中断。下面是我在实际项目中验证过的稳定方案#define BUFFER_SIZE 100 uint8_t uart0_rx_buff[BUFFER_SIZE]; uint16_t uart0_rx_index 0; void USART0_IRQHandler(void) { if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) { uint8_t ch usart_data_receive(USART0); if(uart0_rx_index BUFFER_SIZE) { uart0_rx_buff[uart0_rx_index] ch; // 检测到回车换行认为一条命令结束 if(ch \n || ch \r) { process_command(uart0_rx_buff, uart0_rx_index); uart0_rx_index 0; } } else { // 缓冲区溢出处理 uart0_rx_index 0; } } }使用中断接收需要注意在主程序中开启USART中断在NVIC中配置USART0中断优先级缓冲区大小要合适太小容易溢出太大浪费内存6. 调试技巧串口助手的使用调试串口时一个好用的串口调试助手能事半功倍。我推荐使用以下功能自动添加回车换行发送时勾选加回车换行十六进制显示调试二进制数据时特别有用定时发送功能测试通信稳定性常见问题排查如果收不到数据检查接线是否正确波特率是否匹配收到乱码检查地线是否接好波特率是否准确数据不完整降低波特率试试或者检查缓冲区大小7. 实战案例温度传感器数据上报最后分享一个真实案例通过串口上报温度传感器数据。硬件连接DS18B20到GD32F303每1秒上报一次温度。while(1) { float temp read_temperature(); char buffer[50]; sprintf(buffer, Temperature: %.2fC\r\n, temp); uart0_send_string(buffer); delay_ms(1000); }这个简单的例子包含了串口初始化和数据发送的全部要素。你可以在此基础上扩展比如加入校验、协议头等。
GD32F303实战【4】串口通信从零到一:配置、收发与调试
1. 串口通信基础从概念到硬件连接第一次接触GD32F303的串口功能时我完全被各种术语搞晕了。USART、UART、波特率、数据帧...这些名词听起来很专业其实理解起来并不难。让我用最直白的方式给你解释清楚。串口通信就像两个人用对讲机通话。对讲机需要约定好相同的频道波特率说话要有开始和结束的标记起始位和停止位还要确认对方是否听清楚了校验位。在GD32F303上USART0就是我们最常用的对讲机频道对应PA9(TX)和PA10(RX)两个引脚TX负责发送数据RX负责接收数据。硬件连接特别简单你只需要用USB转TTL模块连接开发板模块的TX接开发板的RX(PA10)模块的RX接开发板的TX(PA9)共地连接(GND接GND)我刚开始总把TX和RX接反导致数据传不出去。后来记住一个口诀发对收收对发就是开发板的TX接模块的RX开发板的RX接模块的TX。2. USART与UART的区别同步还是异步很多新手会困惑USART和UART的区别。简单来说UART只能异步通信而USART既支持异步也支持同步。就像手机的通话功能同步和短信功能异步的区别。在GD32F303上我们通常使用异步模式这时USART和UART的用法完全一样。同步模式一般用于特殊场景比如驱动SPI设备。异步通信的优势是不需要时钟线接线简单缺点是传输速率不能太高且需要双方约定好相同的波特率。我实测过GD32F303的USART0在115200波特率下非常稳定。高于这个速率时偶尔会出现数据丢失所以建议新手先用这个波特率。3. 串口初始化配置一步一步来配置串口就像设置对讲机需要把各个参数都调对。下面是我调试多次后总结的最佳配置方案void uart0_init(void) { // 1. 开启时钟 rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_USART0); // 2. 配置GPIO引脚 gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); // TX gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); // RX // 3. 复位USART usart_deinit(USART0); // 4. 设置波特率115200 usart_baudrate_set(USART0, 115200U); // 5. 使能接收和发送 usart_receive_config(USART0, USART_RECEIVE_ENABLE); usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); // 6. 使能USART usart_enable(USART0); }这里有几个容易出错的地方忘记开启GPIO时钟和USART时钟我就犯过这个错TX引脚要配置为复用推挽输出RX配置为浮空输入波特率设置要准确常用的有9600、115200等4. 数据发送三种常用方式实际项目中我们需要发送不同类型的数据。我整理了三种最常用的发送函数4.1 发送单个字节void uart0_send_byte(uint8_t ch) { usart_data_transmit(USART0, ch); while(RESET usart_flag_get(USART0, USART_FLAG_TBE)); }这个函数会等待发送完成才返回。TBE标志位表示发送缓冲区为空可以发送下一个字节。4.2 发送字符串void uart0_send_string(uint8_t *str) { while(*str) { uart0_send_byte(*str); } }使用时直接传入字符串指针比如uart0_send_string(Hello GD32F303!\r\n);4.3 发送任意数据数组void uart0_send_data(uint8_t *data, int len) { for(int i0; ilen; i) { uart0_send_byte(data[i]); } }这个函数特别适合发送传感器数据或自定义协议数据。5. 中断接收数据高效处理方案串口接收最可靠的方式是使用中断。下面是我在实际项目中验证过的稳定方案#define BUFFER_SIZE 100 uint8_t uart0_rx_buff[BUFFER_SIZE]; uint16_t uart0_rx_index 0; void USART0_IRQHandler(void) { if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) { uint8_t ch usart_data_receive(USART0); if(uart0_rx_index BUFFER_SIZE) { uart0_rx_buff[uart0_rx_index] ch; // 检测到回车换行认为一条命令结束 if(ch \n || ch \r) { process_command(uart0_rx_buff, uart0_rx_index); uart0_rx_index 0; } } else { // 缓冲区溢出处理 uart0_rx_index 0; } } }使用中断接收需要注意在主程序中开启USART中断在NVIC中配置USART0中断优先级缓冲区大小要合适太小容易溢出太大浪费内存6. 调试技巧串口助手的使用调试串口时一个好用的串口调试助手能事半功倍。我推荐使用以下功能自动添加回车换行发送时勾选加回车换行十六进制显示调试二进制数据时特别有用定时发送功能测试通信稳定性常见问题排查如果收不到数据检查接线是否正确波特率是否匹配收到乱码检查地线是否接好波特率是否准确数据不完整降低波特率试试或者检查缓冲区大小7. 实战案例温度传感器数据上报最后分享一个真实案例通过串口上报温度传感器数据。硬件连接DS18B20到GD32F303每1秒上报一次温度。while(1) { float temp read_temperature(); char buffer[50]; sprintf(buffer, Temperature: %.2fC\r\n, temp); uart0_send_string(buffer); delay_ms(1000); }这个简单的例子包含了串口初始化和数据发送的全部要素。你可以在此基础上扩展比如加入校验、协议头等。