stm32之使用中断控制led灯
#include "stm32f10x.h"void delay_ms(uint32_t ms)
{for (uint32_t i = 0; i < ms * 8000; i++){ // 8 MHz HSI}
}void GPIO_Inits(void)
{// 1. 启用 GPIO 时钟、AFIO时钟使能RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN;GPIOA->CRL |= GPIO_CRL_CNF0_1;GPIOA->CRL &= ~GPIO_CRL_CNF0_0;GPIOA->CRL &= ~GPIO_CRL_MODE0;GPIOA->ODR &= ~GPIO_ODR_ODR0;// 配置 PA1 为推挽输出(2 MHz)GPIOC->CRH &= ~(GPIO_CRH_CNF13 | GPIO_CRH_MODE13);GPIOC->CRH |= GPIO_CRH_MODE13_1; // 2 MHz 输出 (10)GPIOC->ODR &= ~GPIO_ODR_ODR13;// 2. 选择 EXTI0 的PA0AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI0_PA;// 3.配置EXTI// 上升沿触发EXTI->RTSR |= EXTI_RTSR_TR0;// 开启中断频闭寄存器EXTI->IMR |= EXTI_IMR_MR0;NVIC_SetPriorityGrouping(3);NVIC_SetPriority(EXTI0_IRQn, 1); // 设置优先级// 启用中断NVIC_EnableIRQ(EXTI0_IRQn); // 启用 TIM1 更新中断
}void EXTI0_IRQHandler(void)
{EXTI->PR |= EXTI_PR_PR0; // 清除中断标志位delay_ms(10);if ((GPIOA->IDR & GPIO_IDR_IDR0) != 0){GPIOC->ODR ^= GPIO_ODR_ODR13; // 翻转PA0}
}int main(void)
{GPIO_Inits();while (1){}
}
代码总体功能
该代码为STM32F10x微控制器设计,通过外部中断(EXTI)实现PA0引脚(输入,通常连接按钮)检测上升沿信号,触发中断后翻转PC13引脚(输出,通常连接LED)的状态,实现类似按键控制LED亮灭的功能。代码包括延时函数、GPIO和EXTI初始化、中断处理及主循环。
详细总结
1. 延时函数 (delay_ms
)
- 功能:提供毫秒级别的延时,用于中断消抖。
- 实现细节:
- 函数参数为
uint32_t ms
,表示延时毫秒数。 - 使用忙等待循环:
for (uint32_t i = 0; i < ms * 8000; i++)
。 - 假设系统使用8 MHz HSI内部时钟,
ms * 8000
循环大致对应1毫秒(每循环耗时约1/8微秒,8000次循环约1ms)。
- 函数参数为
- 注意点:
- 延时精度依赖于系统时钟频率(HSI 8 MHz,未明确配置)。
- 忙等待方式占用CPU资源,适合简单应用但效率较低。
2. GPIO初始化 (GPIO_Inits
)
- 功能:配置GPIOA、GPIOC引脚及EXTI0中断,启用相关时钟。
- 实现细节:
- 时钟使能:
- 通过
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN
使能GPIOA、GPIOC和AFIO外设时钟。 - 确保相关外设可用。
- 通过
- PA0配置(输入):
GPIOA->CRL |= GPIO_CRL_CNF0_1; GPIOA->CRL &= ~GPIO_CRL_CNF0_0;
:配置PA0为浮空输入(CNF0 = 10)。GPIOA->CRL &= ~GPIO_CRL_MODE0;
:模式设为输入(MODE0 = 00)。GPIOA->ODR &= ~GPIO_ODR_ODR0;
:清除输出数据寄存器,可能用于初始化PA0为低电平(若后续启用下拉)。- 注意:代码未明确启用上拉/下拉电阻,可能依赖外部电路(如按钮外接上拉/下拉电阻)。
- PC13配置(输出):
GPIOC->CRH &= ~(GPIO_CRH_CNF13 | GPIO_CRH_MODE13);
:清除PC13的配置和模式。GPIOC->CRH |= GPIO_CRH_MODE13_1;
:配置PC13为2 MHz推挽输出(MODE13 = 10,CNF13 = 00)。GPIOC->ODR &= ~GPIO_ODR_ODR13;
:初始化PC13输出为低电平(LED初始熄灭,假设低电平关闭LED)。
- EXTI0配置:
AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI0_PA;
:选择PA0作为EXTI0的输入源。EXTI->RTSR |= EXTI_RTSR_TR0;
:配置EXTI0为上升沿触发。EXTI->IMR |= EXTI_IMR_MR0;
:使能EXTI0中断。
- NVIC配置:
NVIC_SetPriorityGrouping(3);
:设置中断优先级分组为3(2位抢占优先级,2位子优先级)。NVIC_SetPriority(EXTI0_IRQn, 1);
:设置EXTI0中断的优先级为1(较高优先级)。NVIC_EnableIRQ(EXTI0_IRQn);
:使能EXTI0中断。
- 时钟使能:
- 注意点:
- PA0未明确配置上拉/下拉,可能需外部电路支持。
- PC13常用于STM32开发板上的板载LED。
- NVIC优先级分组和优先级设置适合简单应用,但复杂系统中需考虑优先级冲突。
3. 中断处理函数 (EXTI0_IRQHandler
)
- 功能:处理EXTI0中断,检测PA0状态并翻转PC13输出。
- 实现细节:
EXTI->PR |= EXTI_PR_PR0;
:清除EXTI0中断标志位,防止重复触发。delay_ms(10);
:调用10ms延时,防止按键抖动导致多次触发。if ((GPIOA->IDR & GPIO_IDR_IDR0) != 0)
:检查PA0输入状态是否为高电平。- 如果PA0为高,执行
GPIOC->ODR ^= GPIO_ODR_ODR13;
翻转PC13输出状态(LED亮灭切换)。
- 如果PA0为高,执行
- 注意点:
- 10ms延时用于消抖,但忙等待可能影响中断响应实时性。
- 仅在PA0仍为高电平时翻转PC13,确保有效按键动作(进一步消抖)。
- 中断处理较为简单,未考虑复杂按键模式(如长按、双击)。
4. 主函数 (main
)
- 功能:初始化系统并保持运行,等待中断触发。
- 实现细节:
- 调用
GPIO_Inits
完成GPIO和中断初始化。 - 进入
while (1) {}
无限循环,系统仅靠中断驱动。
- 调用
- 注意点:
- 主循环为空,CPU空闲,适合低功耗场景但未优化(如进入低功耗模式)。
整体功能与应用场景
- 功能:实现按键(PA0)控制LED(PC13)的亮灭切换,检测按键的上升沿触发中断,翻转LED状态。
- 应用场景:
- 适用于STM32F10x开发板的入门实验(如按键控制板载LED)。
- 典型用于学习GPIO配置、EXTI中断和NVIC中断管理的教学案例。
- 硬件假设:
- PA0连接按钮,外部电路提供上拉/下拉电阻(代码未启用内部上下拉)。
- PC13连接LED(常见于STM32F103开发板,如蓝板或最小系统板)。
- 系统时钟为8 MHz HSI(延时函数依赖此频率)。
总结
该代码实现了一个基础的按键控制LED功能,通过PA0的外部中断(EXTI0)检测上升沿,触发后翻转PC13输出状态。代码结构清晰,适合初学者学习STM32的GPIO、EXTI和NVIC配置。主要包括延时函数、GPIO和中断初始化、中断处理及空主循环。存在改进空间,如优化消抖、增加时钟配置和功耗管理,适合嵌入式开发初级实验。