STM32串口中断控制LED闪烁速度:原理详解与代码实现指南
一、项目背景与目标
在嵌入式系统开发中,经常需要通过外部输入动态调整设备行为。本项目实现通过串口中断接收上位机指令,实时修改 LED 的闪烁间隔,从而控制闪烁速度。核心目标是理解 STM32 的串口中断机制、GPIO 输出控制以及中断优先级配置,掌握通过外部输入动态调整程序逻辑的方法。
二、硬件准备
1.硬件平台:
2.硬件连接:
| STM32 引脚 | 功能 | 连接对象 |
|---|---|---|
| PA9 | USART1_TX | 串口模块 TX |
| PA10 | USART1_RX | 串口模块 RX |
| PC13 | LED 控制引脚 | 板载 LED 阴极 |
| 3.3V/GND | 电源 | 串口模块电源 |
三、软件设计核心思路
-
核心逻辑:
- 通过串口(USART1)接收上位机发送的字符(如 '0'、'1'、'2')。
- 使用中断方式处理串口接收,避免占用 CPU 资源。
- 根据接收到的字符修改全局变量
BlinkTime,从而改变 LED 闪烁间隔。 -
关键技术点:
- GPIO 初始化:配置 PC13 为推挽输出,控制 LED 亮灭。
- USART 初始化:设置波特率、数据位、停止位等参数,使能接收中断。
- NVIC 中断配置:设置串口中断的优先级,确保中断正确响应。
- 中断处理函数:解析接收数据,更新闪烁间隔变量。
四、代码逐行解析
1. 头文件与全局变量
#include "stm32f10x.h" // STM32标准库头文件
#include "delay.h" // 延时函数头文件(需自行实现简单延时)
// #include "usart.h" // 若封装串口功能,可包含此文件
volatile uint32_t BlinkTime = 1000; // 闪烁间隔(单位:ms),volatile防止优化
volatile:确保编译器不优化该变量,允许中断函数直接修改。BlinkTime初始值为 1000ms,即 LED 每秒闪烁一次。2. GPIO 初始化(LED 控制)
void My_GPIO_Init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // 使能GPIOC时钟
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13; // PC13引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 最大输出速度50MHz
GPIO_Init(GPIOC, &GPIO_InitStruct); // 初始化GPIOC
}
3. USART1 初始化(串口配置)
void My_USART1_Init(void) {
// 初始化USART1的TX/RX引脚(PA9/PA10)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟
GPIO_InitTypeDef GPIO_InitStruct = {0};
// TX引脚(PA9)配置为复用推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用功能推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// RX引脚(PA10)配置为上拉输入
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 初始化USART1参数
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 使能USART1时钟
USART_InitTypeDef USART_InitStruct = {0};
USART_InitStruct.USART_BaudRate = 115200; // 波特率115200
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控制
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 使能接收和发送
USART_InitStruct.USART_Parity = USART_Parity_No; // 无校验位
USART_InitStruct.USART_StopBits = USART_StopBits_1; // 1个停止位
USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 8位数据位
USART_Init(USART1, &USART_InitStruct); // 初始化USART1
// 使能USART1及接收中断
USART_Cmd(USART1, ENABLE); // 使能USART1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 使能接收中断(RXNE标志)
// 配置NVIC中断优先级
NVIC_InitTypeDef NVIC_InitStruct = {0};
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // 选择USART1中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级1
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; // 子优先级1
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStruct); // 初始化NVIC
}
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2)设置优先级分组为 2(2 位抢占优先级,2 位子优先级),需在所有 NVIC 配置前调用(用户代码中已在main函数开头调用)。4. 主函数逻辑
int main(void) {
My_GPIO_Init(); // 初始化LED引脚
My_USART1_Init(); // 初始化串口
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置优先级分组(需在NVIC初始化前)
while (1) {
// 点亮LED并延时
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET); // PC13输出低电平(LED亮)
Delay(BlinkTime); // 延时BlinkTime ms
// 熄灭LED并延时
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET); // PC13输出高电平(LED灭)
Delay(BlinkTime); // 延时BlinkTime ms
}
}
GPIO_WriteBit控制 LED 亮灭,间隔由BlinkTime决定。5. 串口中断处理函数
void USART1_IRQHandler(void) {
if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) { // 检查接收中断标志
uint32_t dataRcvd = USART_ReceiveData(USART1); // 读取接收数据
// 根据接收到的字符修改闪烁间隔
if (dataRcvd == '0') {
BlinkTime = 80; // 快速闪烁(80ms)
} else if (dataRcvd == '1') {
BlinkTime = 300; // 中速闪烁(300ms)
} else if (dataRcvd == '2') {
BlinkTime = 500; // 低速闪烁(500ms)
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清除中断标志位
}
}
USART_ReceiveData获取 8 位数据(实际为uint16_t,低 8 位有效)。6. 依赖函数(需自行实现)
Delay函数:
示例实现(基于 SysTick,需包含delay.h):
void Delay(uint32_t ms) {
uint32_t i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 8400; j++); // 假设系统时钟72MHz,此延时非精确,仅作示例
}
七、总结
本项目通过 STM32 的串口中断实现了外部输入对 LED 闪烁速度的动态控制,核心在于:
- 中断机制:利用 USART 的接收中断(RXNE)异步处理数据,避免阻塞主程序。
- 优先级配置:通过 NVIC 合理设置中断优先级,确保关键事件及时响应。
- 全局变量共享:通过
volatile修饰的全局变量BlinkTime,在中断与主循环之间安全通信。
作者:Kryon__VVN