一、项目概述
本文将实现一个基于STM32的中断驱动串口通信系统,主要功能包括:
- 计算机通过串口助手发送数据给STM32
- STM32使用USART中断接收数据
- 接收到的数据立即通过串口回传给计算机
- LED灯周期性闪烁指示系统运行状态
硬件需求:
- STM32开发板(本文以STM32F103C8T6为例)
- USB转TTL模块(CH340/CP2102等)
- LED灯(开发板自带或外接)
- 杜邦线若干
开发环境:
- Keil MDK-ARM
- STM32标准外设库
- 串口调试助手(推荐XCOM或SSCOM)
二、硬件连接
STM32引脚 | 连接目标 |
---|---|
PA9 (TX) | USB-TTL的RX |
PA10 (RX) | USB-TTL的TX |
PC13 | LED阳极 |
3.3V | USB-TTL的3.3V |
GND | USB-TTL的GND |

三、代码实现
1. 初始化配置(main.c)
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
// 定义LED引脚
#define LED_PIN GPIO_Pin_13
#define LED_PORT GPIOC
// 环形缓冲区配置
#define BUF_SIZE 128
uint8_t rx_buf[BUF_SIZE];
volatile uint16_t rx_head = 0; // 接收头指针
volatile uint16_t rx_tail = 0; // 接收尾指针
void GPIO_Config(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
RCC_APB2Periph_GPIOC |
RCC_APB2Periph_AFIO, ENABLE);
// LED配置(PC13)
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = LED_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_PORT, &GPIO_InitStruct);
// USART1引脚配置(PA9-TX, PA10-RX)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void USART1_Config(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = 115200;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStruct);
// 使能接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// 中断优先级配置
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
USART_Cmd(USART1, ENABLE); // 使能串口
}
2. 环形缓冲区实现
// 环形缓冲区写入(中断中使用)
void buf_write(uint8_t data) {
uint16_t next_head = (rx_head + 1) % BUF_SIZE;
if (next_head != rx_tail) { // 缓冲区未满
rx_buf[rx_head] = data;
rx_head = next_head;
}
}
// 主循环中读取缓冲区数据
uint8_t buf_read(uint8_t *data) {
if (rx_head == rx_tail)
return 0; // 缓冲区空
*data = rx_buf[rx_tail];
rx_tail = (rx_tail + 1) % BUF_SIZE;
return 1;
}
3. 中断服务函数
void USART1_IRQHandler(void) {
// 检查接收中断标志
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
uint8_t ch = USART_ReceiveData(USART1); // 读取接收数据
buf_write(ch); // 写入缓冲区
// 立即回发数据(回显)
USART_SendData(USART1, ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); // 等待发送完成
}
}
4. 主循环处理
int main(void) {
SystemInit(); // 系统时钟初始化
GPIO_Config();
USART1_Config();
while(1) {
// LED闪烁(500ms周期)
GPIO_SetBits(LED_PORT, LED_PIN);
Delay(250);
GPIO_ResetBits(LED_PORT, LED_PIN);
Delay(250);
// 处理缓冲区数据
uint8_t data;
while (buf_read(&data)) {
// 此处可扩展数据处理逻辑
// 例如: 协议解析, 控制其他外设等
}
}
}
// 简单延时函数(实际项目建议用SysTick)
void Delay(uint32_t nCount) {
for(; nCount != 0; nCount--);
}
四、关键代码解析
1. 中断处理流程
graph TD
A[串口接收到数据] --> B[触发USART_IT_RXNE中断]
B --> C[进入USART1_IRQHandler]
C --> D[读取USART1->DR寄存器]
D --> E[数据存入环形缓冲区]
E --> F[立即回发相同数据]
F --> G[清除中断标志]
2. 环形缓冲区优势
- 数据安全:隔离中断与主循环
- 防数据丢失:当主循环处理不及时时缓冲数据
- 高效处理:避免在中断中执行耗时操作
3. LED指示设计
- 闪烁周期:500ms(250ms亮 + 250ms灭)
- 作用:直观显示系统运行状态
- 扩展:可通过改变闪烁频率指示不同状态
五、测试与验证
测试步骤:
- 使用Keil编译并烧录程序
- 连接硬件(注意TX/RX交叉)
- 打开串口助手(波特率115200)
- 发送测试数据:"Hello STM32!"
预期结果:
- PC端串口助手收到相同的回传数据
- 开发板上的LED灯稳定闪烁
- 无数据丢失现象(可连续发送大量数据测试)
六、常见问题解决
-
无数据回传
- 检查TX/RX接线是否反接
- 确认波特率设置一致(115200)
- 检查串口助手是否打开正确COM口
-
数据乱码
- 检查系统时钟配置
- 验证USART时钟源是否使能
- 降低波特率测试(如改为9600)
-
LED不闪烁
- 确认LED引脚定义是否正确
- 检查LED限流电阻是否合适
- 测试GPIO输出是否正常
七、项目扩展方向
- 协议解析:在
buf_read
处理中添加自定义协议解析 - 多串口支持:扩展USART2/3实现多通道通信
- DMA传输:结合DMA实现高速数据传输
- 状态指示:不同LED闪烁模式表示不同状态
- 数据存储:添加SD卡存储接收到的数据
八、总结
本文实现了基于STM32中断机制的串口通信系统,具有以下特点:
- 🚀 高效中断处理:及时响应串口数据
- 🔁 可靠数据缓冲:环形缓冲区防止数据丢失
- 💡 直观状态指示:LED闪烁显示系统运行
- ⚙️ 模块化设计:便于功能扩展