☰
用STM32f103c8t6手把手教你做呼吸灯!
2026/10/20 2:24:43 网站建设 项目流程

STM32F103 定时器与 PWM 呼吸灯实验(CubeMX + HAL 库)

文章目录

  • STM32F103 定时器与 PWM 呼吸灯实验(CubeMX + HAL 库)
    • 一、实验要求
    • 二、硬件接线
    • 三、CubeMX 配置
      • 1. 新建工程和选芯片
      • 2. RCC 和 SYS
      • 3. 时钟树
      • 4. 任务一的 TIM3 配置
      • 5. 生成工程
    • 四、任务一:定时器中断控制 LED
      • 1. 思路
      • 2. 主要代码
      • 3. 定时时间
      • 4. 现象
    • 五、任务二:PWM 呼吸灯
      • 1. 思路
      • 2. 主要代码
      • 3. PWM 频率和占空比
      • 4. 现象
    • 六、Keil 仿真和 Logic Analyzer
      • 1. 设置 Use Simulator
      • 2. 进入仿真
      • 3. 打开 Logic Analyzer
      • 4. 看 PWM 波形
      • 5. 看任务一的波形
    • 七、实验总结
    • 八、参考资料

一、实验要求

  1. 使用 TIM2~TIM5 中的一个定时器通道,连接 LED,用定时器计数方式控制 LED 以 2 s 的周期亮灭。
  2. 使用定时器 PWM 模式,让 LED 渐亮渐灭,呼吸周期 1~2 s,并调整占空比到比较舒服的效果。
  3. 使用 Keil 的 Logic Analyzer 观察 PWM 输出波形。

二、硬件接线

LED 采用高电平点亮接法:

PA6 ── LED 阳极 ── LED 阴极 ── GND

三、CubeMX 配置

1. 新建工程和选芯片

打开 STM32CubeMX,点File → New Project,在Part Number里输入STM32F103C8,选择STM32F103C8Tx,然后点Start Project。

2. RCC 和 SYS

在System Core → RCC里,把High Speed Clock (HSE)选成Crystal/Ceramic Resonator。板子上是 8 MHz 外部晶振。

在System Core → SYS里,把Debug选成Serial Wire,保留 SWD 下载口。

3. 时钟树

点上面的Clock Configuration,主要设置如下:

  • PLL Source 选 HSE
  • PLLMul 选 ×9
  • System Clock Mux 选 PLLCLK
  • AHB 不分频
  • APB1 选 /2
  • APB2 选 /1

这样 SYSCLK 就是 8 MHz × 9 = 72 MHz,HCLK 和 APB2 是 72 MHz,APB1 是 36 MHz。

4. 任务一的 TIM3 配置

任务一只需要 TIM3 定时,不需要它控制引脚,所以 PA6 还是普通 GPIO 输出。

在Timers → TIM3里这样设置:

  • Clock Source:Internal Clock

  • Prescaler:7199

  • Counter Mode:Up

  • Counter Period:9999

  • Auto-reload Preload:Enable

  • 打开TIM3 global interrupt

  • NVIC 里 TIM3 的优先级保持默认或者设成 2 都可以


然后回到引脚图,把 PA6 设成GPIO_Output,输出电平先设成 Low,速度 Low 就行。

5. 生成工程

在Project Manager里把工程名写成STM32F103C8T6_TIM3_PWM,Toolchain/IDE 选MDK-ARM V5,然后点GENERATE CODE。

四、任务一:定时器中断控制 LED

1. 思路

TIM3 每 1 s 产生一次更新中断,在中断回调里翻转 PA6。PA6 高电平 LED 亮,低电平 LED 灭,所以 LED 亮 1 s、灭 1 s,一个完整周期是 2 s。

2. 主要代码

任务一的初始化:

staticvoidMX_TIM3_TimeBase_Init(void){TIM_ClockConfigTypeDef sClockSourceConfig={0};TIM_MasterConfigTypeDef sMasterConfig={0};__HAL_RCC_TIM3_CLK_ENABLE();htim3.Instance=TIM3;htim3.Init.Prescaler=7199U;htim3.Init.CounterMode=TIM_COUNTERMODE_UP;htim3.Init.Period=9999U;htim3.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;htim3.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE;HAL_TIM_Base_Init(&htim3);sClockSourceConfig.ClockSource=TIM_CLOCKSOURCE_INTERNAL;HAL_TIM_ConfigClockSource(&htim3,&sClockSourceConfig);sMasterConfig.MasterOutputTrigger=TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE;HAL_TIMEx_MasterConfigSynchronization(&htim3,&sMasterConfig);HAL_NVIC_SetPriority(TIM3_IRQn,2U,0U);HAL_NVIC_EnableIRQ(TIM3_IRQn);}

主函数里启动更新中断:

if(HAL_TIM_Base_Start_IT(&htim3)!=HAL_OK){Error_Handler();}

中断服务函数在stm32f1xx_it.c里:

voidTIM3_IRQHandler(void){HAL_TIM_IRQHandler(&htim3);}

翻转 LED 的回调:

voidHAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim){if(htim->Instance==TIM3){HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_6);}}

3. 定时时间

TIM3 的时钟是 72 MHz,PSC=7199,所以计数频率是 10 kHz。ARR=9999,计数器从 0 计到 9999 是 10000 个数:

10 kHz 计 10000 个数 = 1 s

中断里每 1 s 翻转一次 PA6,所以 LED 亮 1 s、灭 1 s,完整周期 2 s。

4. 现象

烧进去以后,PA6 上的 LED 会稳定地亮 1 s、灭 1 s。这个时间由定时器决定,不受主循环里其他代码影响。

五、任务二:PWM 呼吸灯

1. 思路

PSC=71,ARR=999,PWM 频率就是 1 kHz。CCR1 从 0 增加到 1000,再减小回 0,LED 就会从灭逐渐变亮,再逐渐变灭。

每 10 ms 改一次 CCR1,上升 100 次、下降 100 次,共 200 次,呼吸周期大约是 2 s。

2. 主要代码

PWM 初始化:

staticvoidMX_TIM3_PWM_Init(void){TIM_ClockConfigTypeDef sClockSourceConfig={0};TIM_MasterConfigTypeDef sMasterConfig={0};TIM_OC_InitTypeDef sConfigOC={0};__HAL_RCC_TIM3_CLK_ENABLE();htim3.Instance=TIM3;htim3.Init.Prescaler=71U;htim3.Init.CounterMode=TIM_COUNTERMODE_UP;htim3.Init.Period=999U;htim3.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;htim3.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE;HAL_TIM_Base_Init(&htim3);sClockSourceConfig.ClockSource=TIM_CLOCKSOURCE_INTERNAL;HAL_TIM_ConfigClockSource(&htim3,&sClockSourceConfig);HAL_TIM_PWM_Init(&htim3);sMasterConfig.MasterOutputTrigger=TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE;HAL_TIMEx_MasterConfigSynchronization(&htim3,&sMasterConfig);sConfigOC.OCMode=TIM_OCMODE_PWM1;sConfigOC.Pulse=0U;sConfigOC.OCPolarity=TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode=TIM_OCFAST_DISABLE;HAL_TIM_PWM_ConfigChannel(&htim3,&sConfigOC,TIM_CHANNEL_1);}

启动 PWM:

__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,0U);HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);

呼吸灯循环:

#defineBREATH_STEP_MS10U#defineBREATH_STEPS100U#definePWM_FULL_SCALE1000Uuint32_tn;uint32_tphase;uint32_tduty;while(1){for(n=0U;n<(2U*BREATH_STEPS);n++){if(n<=BREATH_STEPS){phase=n;}else{phase=(2U*BREATH_STEPS)-n;}/* 平方映射,低亮度区停留更久,看起来更柔和 */duty=(phase*phase*PWM_FULL_SCALE)/(BREATH_STEPS*BREATH_STEPS);__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);HAL_Delay(BREATH_STEP_MS);}}

3. PWM 频率和占空比

计数频率:

72 MHz / (71 + 1) = 1 MHz

PWM 频率:

1 MHz / (999 + 1) = 1 kHz

占空比:

D = CCR1 / (ARR + 1) = CCR1 / 1000

所以 CCR1=0 是 0%,CCR1=500 是 50%,CCR1=1000 是 100%。PWM 周期是 1 ms。

4. 现象

LED 会慢慢变亮,再慢慢变暗,周期大约 2 s。因为 PWM 是 1 kHz,正常看的时候看不到灯在闪,只能看到平均亮度在变。

六、Keil 仿真和 Logic Analyzer

1. 设置 Use Simulator

打开 Keil 工程,点Options for Target,进Debug页:

  • 左边选Use Simulator
  • Dialog DLL填DARMSTM.DLL
  • Parameter填-pSTM32F103C8

2. 进入仿真

按Ctrl+F5进入调试。进入后,Keil 左下角会显示Simulation,左边能看到寄存器在变化。

3. 打开 Logic Analyzer

在仿真状态下点:

View → Analysis Windows → Logic Analyzer

4. 看 PWM 波形

按F5全速跑一会儿,再按Esc停下来。把时间轴缩到 0~3 ms 左右,就能看到 1 ms 一个周期的 PWM 波形。

测量的时候看两点:

  1. TIM3_CNT从 0 计到 999,一个锯齿波是 1 ms。
  2. PA6的高电平时间除以 1 ms,就是占空比。比如高电平 0.5 ms,就是 50%。



前两张图片放大看出PA6占空比一直在变化,后两张图可看出整体变化。

5. 看任务一的波形

把main.c里的DEMO_MODE改成1U,重新编译,再按Ctrl+F5进仿真。把 Logic Analyzer 的时间轴调到 3 s 左右,添加TIM3_CNT、TIM3_SR、GPIOA_ODR,就能看到 PA6 每 1 s 翻转一次。

从第二张图红色圆圈部分不难看出 PA6 每 1 s 翻转一次

七、实验总结

这次实验主要是把定时器的 PSC、ARR 和 CCR 弄明白。任务一里 TIM3 只负责定时,中断里翻转 PA6;任务二里 TIM3_CH1 直接输出 PWM,CCR1 决定高电平时间。

我一开始把 APB1 的 36 MHz 当成 TIM3 的时钟,算出来时间差了一倍,后来才注意到 APB1 分频不为 1 时,定时器时钟会自动倍频到 72 MHz。还有 PA6 在任务一里要设成普通 GPIO 输出,任务二里要设成复用推挽,这两个地方不能配错。

呼吸灯部分,线性改占空比也能亮,但低亮度变化有点快,改成平方映射以后看着更顺一点。整体上,用 Keil 的逻辑分析仪把 CNT、CCR1 和输出波形对起来看,比只看灯的现象直观很多。

八、参考资料

  1. STM32F103C8T6 数据手册,PA6/TIM3_CH1 引脚复用表。
  2. 《STM32F10xxx 参考手册》V10,第 13 章通用定时器,PWM 模式部分。
  3. STM32CubeMX & Keil——STM32F103C8T6:PWM 控制 LED 灯,https://blog.csdn.net/Morzart/article/details/134123197
  4. STM32CubeMX PWM 输出实验,https://blog.csdn.net/Xkccsdn147/article/details/134191212
  5. STM32 定时器 PWM 呼吸灯实验,https://blog.csdn.net/weixin_52345779/article/details/135313203

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询