2. LED闪烁

任务说明

本案例以LED闪烁为载体,完成定时器的首次实践。目标不是“让LED亮灭”本身,而是通过LED的闪烁周期,直观验证定时器的定时计算、初始化流程与中断服务函数的正确性。你需要完成:配置定时器产生1ms中断,在中断中累加计数,每500ms翻转一次LED状态,最终实现LED以1Hz频率闪烁(亮500ms,灭500ms)。

硬件连接与原理

以STM32F103系列为例,LED接在PC13(板上常见位置),低电平点亮。定时器选用TIM2,其时钟源为APB1定时器时钟(通常为72MHz)。定时器初值计算公式为:

定时周期 = (ARR + 1) × (PSC + 1) / 定时器时钟频率

若需要1ms中断,72MHz时钟下可取PSC=71(分频后1MHz),ARR=999(计数1000次),则周期为1000×1µs = 1ms。

代码实现


#include "stm32f1xx_hal.h"

/* 中断计数变量 */
volatile uint16_t tick_count = 0;
volatile uint8_t  led_state  = 0;

/* TIM2初始化:1ms中断 */
void TIM2_Init(void)
{
    TIM_HandleTypeDef htim2;
    htim2.Instance               = TIM2;
    htim2.Init.Prescaler         = 71;      /* 72MHz/72 = 1MHz */
    htim2.Init.CounterMode       = TIM_COUNTERMODE_UP;
    htim2.Init.Period            = 999;     /* 1MHz/1000 = 1kHz → 1ms */
    htim2.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    HAL_TIM_Base_Init(&htim2);

    HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);

    HAL_TIM_Base_Start_IT(&htim2);   /* 使能更新中断并启动定时器 */
}

/* TIM2中断服务函数 */
void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&htim2);      /* 调用HAL库公共处理,内部会清更新标志 */
}

/* 定时器更新回调(HAL库在更新中断中自动调用) */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM2) {
        tick_count++;
        if (tick_count >= 500) {     /* 500ms */
            tick_count = 0;
            led_state = !led_state;
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13,
                              led_state ? GPIO_PIN_RESET : GPIO_PIN_SET);
        }
    }
}

/* 简单主函数示意 */
int main(void)
{
    HAL_Init();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_TIM2_CLK_ENABLE();

    GPIO_InitTypeDef gpio;
    gpio.Pin   = GPIO_PIN_13;
    gpio.Mode  = GPIO_MODE_OUTPUT_PP;
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOC, &gpio);

    TIM2_Init();

    while (1) {
        /* 主循环无需额外处理,LED翻转由中断驱动 */
    }
}

关键点说明

  • 中断服务函数中必须调用HAL_TIM_IRQHandler(),由它负责清除更新中断标志并触发回调,否则会反复进入中断。
  • 回调函数HAL_TIM_PeriodElapsedCallback是弱函数,你在用户代码中重写即可,无需修改HAL库。
  • LED翻转逻辑:led_state为1时输出低电平点亮LED,为0时输出高电平熄灭,实现500ms亮、500ms灭。

验证方法

将代码编译后下载至开发板,连接PC13引脚至LED(若为板上LED则直接观察)。上电后观察LED是否以约1Hz频率闪烁(每周期约1秒)。若闪烁频率明显偏差,优先检查以下两点:

  1. 确认SystemCoreClock是否为72000000(即72MHz),若芯片实际运行在8MHz内部时钟,则需调整PSC与ARR数值。
  2. 用示波器或逻辑分析仪测量PC13引脚波形,高电平持续时间应为500ms±10ms,低电平持续时间同理。若波形周期正确但占空比异常,检查翻转逻辑。

判定标准:LED以稳定周期闪烁,肉眼观察无明显快慢变化;用示波器测得翻转周期为1s±20ms,即认为定时器配置正确,案例通过。

TIM2定时中断驱动LED闪烁时序 72MHz时钟 PSC=71 ÷72 → 1MHz ARR=999 计数1000次 溢出中断 每1ms一次 TIM2_IRQHandler tick_count++ tick≥500? 是 翻转LED tick清零 否 → 继续累加 LED输出:500ms低电平(亮) ↔ 500ms高电平(灭)

常见问题排查

  • LED不闪烁:检查TIM2时钟是否使能(__HAL_RCC_TIM2_CLK_ENABLE()),以及NVIC中断是否开启。
  • 闪烁频率异常快:确认PSC与ARR是否按72MHz计算;若芯片时钟不是72MHz,需按实际时钟重新计算。
  • 编译报错:确认已包含stm32f1xx_hal.h,且工程中已添加HAL库的定时器模块源文件。