
STM32F103 定时器与 PWM 呼吸灯实验CubeMX HAL 库文章目录STM32F103 定时器与 PWM 呼吸灯实验CubeMX HAL 库一、实验要求二、硬件接线三、CubeMX 配置1. 新建工程和选芯片2. RCC 和 SYS3. 时钟树4. 任务一的 TIM3 配置5. 生成工程四、任务一定时器中断控制 LED1. 思路2. 主要代码3. 定时时间4. 现象五、任务二PWM 呼吸灯1. 思路2. 主要代码3. PWM 频率和占空比4. 现象六、Keil 仿真和 Logic Analyzer1. 设置 Use Simulator2. 进入仿真3. 打开 Logic Analyzer4. 看 PWM 波形5. 看任务一的波形七、实验总结八、参考资料一、实验要求使用 TIM2TIM5 中的一个定时器通道连接 LED用定时器计数方式控制 LED 以 2 s 的周期亮灭。使用定时器 PWM 模式让 LED 渐亮渐灭呼吸周期 12 s并调整占空比到比较舒服的效果。使用 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 选 HSEPLLMul 选 ×9System Clock Mux 选 PLLCLKAHB 不分频APB1 选 /2APB2 选 /1这样 SYSCLK 就是 8 MHz × 9 72 MHzHCLK 和 APB2 是 72 MHzAPB1 是 36 MHz。4. 任务一的 TIM3 配置任务一只需要 TIM3 定时不需要它控制引脚所以 PA6 还是普通 GPIO 输出。在Timers → TIM3里这样设置Clock SourceInternal ClockPrescaler7199Counter ModeUpCounter Period9999Auto-reload PreloadEnable打开TIM3 global interruptNVIC 里 TIM3 的优先级保持默认或者设成 2 都可以然后回到引脚图把 PA6 设成GPIO_Output输出电平先设成 Low速度 Low 就行。5. 生成工程在Project Manager里把工程名写成STM32F103C8T6_TIM3_PWMToolchain/IDE 选MDK-ARM V5然后点GENERATE CODE。四、任务一定时器中断控制 LED1. 思路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.InstanceTIM3;htim3.Init.Prescaler7199U;htim3.Init.CounterModeTIM_COUNTERMODE_UP;htim3.Init.Period9999U;htim3.Init.ClockDivisionTIM_CLOCKDIVISION_DIV1;htim3.Init.AutoReloadPreloadTIM_AUTORELOAD_PRELOAD_ENABLE;HAL_TIM_Base_Init(htim3);sClockSourceConfig.ClockSourceTIM_CLOCKSOURCE_INTERNAL;HAL_TIM_ConfigClockSource(htim3,sClockSourceConfig);sMasterConfig.MasterOutputTriggerTIM_TRGO_RESET;sMasterConfig.MasterSlaveModeTIM_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-InstanceTIM3){HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_6);}}3. 定时时间TIM3 的时钟是 72 MHzPSC7199所以计数频率是 10 kHz。ARR9999计数器从 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. 思路PSC71ARR999PWM 频率就是 1 kHz。CCR1 从 0 增加到 1000再减小回 0LED 就会从灭逐渐变亮再逐渐变灭。每 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.InstanceTIM3;htim3.Init.Prescaler71U;htim3.Init.CounterModeTIM_COUNTERMODE_UP;htim3.Init.Period999U;htim3.Init.ClockDivisionTIM_CLOCKDIVISION_DIV1;htim3.Init.AutoReloadPreloadTIM_AUTORELOAD_PRELOAD_ENABLE;HAL_TIM_Base_Init(htim3);sClockSourceConfig.ClockSourceTIM_CLOCKSOURCE_INTERNAL;HAL_TIM_ConfigClockSource(htim3,sClockSourceConfig);HAL_TIM_PWM_Init(htim3);sMasterConfig.MasterOutputTriggerTIM_TRGO_RESET;sMasterConfig.MasterSlaveModeTIM_MASTERSLAVEMODE_DISABLE;HAL_TIMEx_MasterConfigSynchronization(htim3,sMasterConfig);sConfigOC.OCModeTIM_OCMODE_PWM1;sConfigOC.Pulse0U;sConfigOC.OCPolarityTIM_OCPOLARITY_HIGH;sConfigOC.OCFastModeTIM_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(n0U;n(2U*BREATH_STEPS);n){if(nBREATH_STEPS){phasen;}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 MHzPWM 频率1 MHz / (999 1) 1 kHz占空比D CCR1 / (ARR 1) CCR1 / 1000所以 CCR10 是 0%CCR1500 是 50%CCR11000 是 100%。PWM 周期是 1 ms。4. 现象LED 会慢慢变亮再慢慢变暗周期大约 2 s。因为 PWM 是 1 kHz正常看的时候看不到灯在闪只能看到平均亮度在变。六、Keil 仿真和 Logic Analyzer1. 设置 Use Simulator打开 Keil 工程点Options for Target进Debug页左边选Use SimulatorDialog DLL填DARMSTM.DLLParameter填-pSTM32F103C82. 进入仿真按CtrlF5进入调试。进入后Keil 左下角会显示Simulation左边能看到寄存器在变化。3. 打开 Logic Analyzer在仿真状态下点View → Analysis Windows → Logic Analyzer4. 看 PWM 波形按F5全速跑一会儿再按Esc停下来。把时间轴缩到 03 ms 左右就能看到 1 ms 一个周期的 PWM 波形。测量的时候看两点TIM3_CNT从 0 计到 999一个锯齿波是 1 ms。PA6的高电平时间除以 1 ms就是占空比。比如高电平 0.5 ms就是 50%。前两张图片放大看出PA6占空比一直在变化后两张图可看出整体变化。5. 看任务一的波形把main.c里的DEMO_MODE改成1U重新编译再按CtrlF5进仿真。把 Logic Analyzer 的时间轴调到 3 s 左右添加TIM3_CNT、TIM3_SR、GPIOA_ODR就能看到 PA6 每 1 s 翻转一次。从第二张图红色圆圈部分不难看出 PA6 每 1 s 翻转一次七、实验总结这次实验主要是把定时器的 PSC、ARR 和 CCR 弄明白。任务一里 TIM3 只负责定时中断里翻转 PA6任务二里 TIM3_CH1 直接输出 PWMCCR1 决定高电平时间。我一开始把 APB1 的 36 MHz 当成 TIM3 的时钟算出来时间差了一倍后来才注意到 APB1 分频不为 1 时定时器时钟会自动倍频到 72 MHz。还有 PA6 在任务一里要设成普通 GPIO 输出任务二里要设成复用推挽这两个地方不能配错。呼吸灯部分线性改占空比也能亮但低亮度变化有点快改成平方映射以后看着更顺一点。整体上用 Keil 的逻辑分析仪把 CNT、CCR1 和输出波形对起来看比只看灯的现象直观很多。八、参考资料STM32F103C8T6 数据手册PA6/TIM3_CH1 引脚复用表。《STM32F10xxx 参考手册》V10第 13 章通用定时器PWM 模式部分。STM32CubeMX Keil——STM32F103C8T6PWM 控制 LED 灯https://blog.csdn.net/Morzart/article/details/134123197STM32CubeMX PWM 输出实验https://blog.csdn.net/Xkccsdn147/article/details/134191212STM32 定时器 PWM 呼吸灯实验https://blog.csdn.net/weixin_52345779/article/details/135313203