基于STM32F103RCT6的USART串口通信完整代码实现(配合STM32CubeMX)
一、CubeMX配置步骤
-
引脚分配
- USART1
- PA9: USART1_TX
- PA10: USART1_RX
- LED指示(可选)
- PC13: GPIO_Output(用于通信状态指示)
- USART1
-
USART1参数配置
- Mode: Asynchronous
- Baud Rate: 115200
- Word Length: 8 Bits
- Parity: None
- Stop Bits: 1
- 启用中断:
- NVIC Settings → 勾选
USART1 global interrupt
- NVIC Settings → 勾选
-
生成代码
- 选择IDE(Keil/IAR/STM32CubeIDE)
- 确保生成代码包含USART初始化及中断配置。
二、完整代码(main.c
)
#include "main.h"
#include "string.h" // 用于字符串处理
UART_HandleTypeDef huart1;
// 自定义变量
#define RX_BUFFER_SIZE 64 // 接收缓冲区大小
uint8_t rx_buffer[RX_BUFFER_SIZE]; // 接收缓冲区
uint8_t rx_byte; // 单字节接收缓存
uint16_t rx_index = 0; // 缓冲区索引
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
// 启动首次接收(中断模式)
HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
while (1) {
// 主循环可添加其他任务(如LED闪烁指示)
}
}
// USART接收完成中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
// 将接收到的字节存入缓冲区
if (rx_index < RX_BUFFER_SIZE - 1) {
rx_buffer[rx_index++] = rx_byte;
}
// 回显接收到的字节到电脑
HAL_UART_Transmit(&huart1, &rx_byte, 1, 100);
// 检测换行符(可根据需求自定义协议)
if (rx_byte == '\n' || rx_byte == '\r') {
// 处理完整一帧数据(示例:点亮LED)
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
rx_index = 0; // 清空缓冲区
}
// 重新启动接收中断
HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
}
}
// USART1初始化函数(由CubeMX生成)
static void MX_USART1_UART_Init(void) {
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);
}
// GPIO初始化(由CubeMX生成)
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
// PC13配置为LED输出
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // 初始状态:LED灭
// USART1引脚配置(PA9-TX, PA10-RX)
GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 系统时钟配置(由CubeMX自动生成)
void SystemClock_Config(void) {
// ...(无需修改自动生成的代码)
}
三、关键代码说明
-
中断接收流程
- 启动接收中断:
HAL_UART_Receive_IT(&huart1, &rx_byte, 1)
- 每次接收1字节后触发
HAL_UART_RxCpltCallback
- 在回调函数中回显数据并重新启动接收中断
- 启动接收中断:
-
数据回显(Echo)
- 通过
HAL_UART_Transmit
将接收到的字节原样发送回电脑 - 可使用串口助手(如XCOM、Putty)测试收发
- 通过
-
协议扩展
- 示例中检测换行符
\n
或回车符\r
作为一帧结束标志 - 实际应用可解析
rx_buffer
中的自定义协议(如AT指令)
- 示例中检测换行符
四、硬件连接与测试
-
硬件接线
- STM32F103RCT6 → USB转TTL模块
- PA9 (USART1_TX) → RXD
- PA10 (USART1_RX) → TXD
- GND → GND
- STM32F103RCT6 → USB转TTL模块
-
测试步骤
- 烧录程序后,打开串口助手(波特率115200)
- 发送任意字符,观察是否回显相同字符
- 发送回车符(
\r
或\n
),观察PC13 LED状态翻转
五、常见问题处理
-
无数据收发
- 检查串口线连接是否正确(交叉连接TX/RX)
- 确认CubeMX中USART时钟已使能(APB2时钟树)
-
数据错乱或丢失
- 检查波特率是否匹配(双方均为115200)
- 增加接收缓冲区大小(修改
RX_BUFFER_SIZE
)
-
中断优先级冲突
- 若使用其他中断,需在CubeMX中调整USART中断优先级(NVIC设置)
六、扩展功能建议
- 添加命令解析:在回调函数中解析特定指令(如
LED_ON
/LED_OFF
) - 使用DMA传输:通过CubeMX配置USART DMA,提升大数据量传输效率
- 集成printf重定向:通过重写
_write
函数支持printf
调试输出
通过上述代码和配置,可实现基本的USART双向通信。建议基于CubeMX生成的工程框架直接集成代码,确保编译环境正确。