问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

新手STM32:基于HAL库的定时器和PWM输出

创作时间:
作者:
@小白创作中心

新手STM32:基于HAL库的定时器和PWM输出

引用
CSDN
1.
https://blog.csdn.net/qq_74267512/article/details/144313107

本文是一篇面向STM32新手的详细教程,主要介绍了基于HAL库的定时器控制和PWM输出实现。文章从理论到实践,详细讲解了定时器和PWM的基本概念、配置步骤和代码实现,适合嵌入式开发爱好者和工程师参考学习。

一、定时器与PWM概述

(1)定时器概述

在STM32微控制器的丰富功能模块中,定时器起着不可或缺的关键作用。以STM32F103C8T6这款广泛应用的芯片为例,它配备了总计8个定时器,依据功能特性和复杂程度可细分为高级定时器(TIM1和TIM8)、通用定时器(TIM2-5)以及基本定时器(TIM6和TIM7)。通用定时器凭借其全面且灵活的功能特性,在众多应用场景中脱颖而出,成为开发者频繁选用的得力工具。

  • 高级定时器:TIM1和TIM8
  • 通用定时器:TIM2-5
  • 基本定时器:TIM6和TIM7

通用定时器不仅能够精准地实现定时功能,还可对输入信号的脉冲长度进行精确测量(即输入捕获功能),以及依据实际需求输出各种特定波形,涵盖输出比较、产生PWM(脉冲宽度调制)波形以及单脉冲输出等多样化操作。这种多功能性使其在诸如工业自动化控制、智能家电控制、通信设备定时同步以及电机控制等众多领域得以大展身手。例如,在工业自动化生产线中,可借通用定时器精准把控各工序执行时间间隔与顺序;于电机控制里,借PWM功能灵活调节电机转速与转矩,实现高效稳定运行。

(2)PWM概述

PWM(脉冲宽度调制)技术的核心要素在于占空比。占空比,作为衡量脉冲信号特征的关键指标,被定义为在一个完整信号周期内,高电平持续时间与整个信号周期时长的百分比比值,即占空比 = Tp/T(Tp为高电平时间,T为信号周期)。通过细腻且精准地调整占空比数值,能够巧妙地改变信号中高电平与低电平的持续时长比例关系,进而实现对外部设备的精准功率控制或模拟信号等效输出效果。

占空比(Duty Cycle),是指在一个周期内,高电平时间占整个信号周期的百分比,即高电平时间与周期的比值:占空比=Tp/T

调节占空比可以得到不同的电平持续时间。

二、HAL库实现定时器控制

基于前文的讲述,我们可以开始对定时器进行一些基本的操作了。本次实验,我们将设置一个5秒的定时器,每隔5秒从串口发送“hello windows!”;同时设置一个2秒的定时器,让LED等周期性地闪烁,实现一个多任务并发运行的功能。

(1)CUBEMX配置

首先新建一个芯片为STM32F103C8T6的项目,然后进行一些基本的配置。

SYS:配置为Serial Wire
RCC:配置为高速外部晶振

因为我们需要配置一个定时闪烁的LED灯,所以需要配置一个GPIO口进行输出,我选择的PA5进行电平输出。

然后配置我们的GPIO口,我们采用低电平点亮的方式,也就是当我们的GPIO口输出低电平时,LED灯亮起,所以我们的初始GPIO输出电平设为高电平,其他的配置保持在默认选项就行。

接下来配置我们的定时器,选择通用定时器TIM2,配置我们的时钟源为内部时钟;预分频系数配置为71(因为系统处理时会自动为我们的预分频系数加1,所以实际上的预分频系数为72),因为系统时钟树我们会设置为72MHz,分频下来就得到1MHz;计数次数设置为5000次,那么每完成一次计数,经过的时间为 5000/1MHz=0.005秒也就是5ms,换言之,每过5ms定时器TIM2就会进行一次定时中断。

配置步骤如下:

因为我们还需要定时向串口发送数据,所以需要再配置一个定时器来控制这一部分的功能。 我们同样选择一个通用定时器,这里我选择了TIM3,配置步骤与数据和TIM2相同。

接下来开启我们的定时器中断并生成中断配置代码。

接下来配置我们的系统时钟树,按照下图步骤进行配置。

因为我们还存在串口数据的发送,所以还需要配置我们的USART。我们选择配置USART1,选择Asynchronous(异步通信)并开启中断。

接下来就可以生成我们的代码文件了,按照下图的标注进行配置。

点击右上角的GENERATE CODE生成我们的代码,在加载结束后弹出的窗口点击Open Project打开我们的keil项目。

(2)代码编写

首先,我们需要在主函数内打开我们的定时器,所使用的函数为HAL_TIM_Base_Start_IT。

对于参数,“h”指的是HAL库,“tim2”指的就是TIM2,TIM3也是一样的操作。这样子就打开了我们的定时器。

因为这次代码的功能完全由中断实现,因此我们不需要再在while循环内书写代码,只需要在主函数外用一个中断回调函数实现我们的功能。

在主函数内随便找个位置书写我们的中断回调函数,为了方便起见,大家可以在注释标注USER CODE的地方书写我们自己的代码,也就是在main函数下面的

在这个函数内,首先定义我们函数内部的变量,这是我们用来保存定时器当前定时值的参数。前文所说,每当计数器结束一个周期,时间就经过0.005秒,同时我们的计数器的值也会增加1,将我们需要的时间与定时器一个周期的时间也就是0.005秒进行相除就能得到我们的计数器周期的值。然后分别配置两个定时器在各自的周期内完成自己的工作就行了。

代码的部分就这样,接下来我们就可以进行代码的烧录了。

(3)结果展示

因为这次用到了串口的缘故,为了使烧录与接收串口通信不那么麻烦,我选择了用FLYMCU烧录工具直接使用USB to TTL进行烧录。

有需要的伙伴和不了解怎样用TTL烧录的小伙伴可以看我的另一篇文章新手STM32:利用HAL库实现USART串口通信-CSDN博客文章浏览阅读727次,点赞10次,收藏14次。在本次的学习过程中,我们系统且深入地探索了串口通信领域的相关知识。首先,着重对串口通信的电平协议展开了详细的学习与研究。串口通信的电平协议作为数据传输的基础规范,有着至关重要的意义。其中涵盖了如 TTL 电平,其以较为简洁的电平逻辑,通常运用 +5V 表示逻辑 1,0V 表示逻辑 0,这种电平标准在芯片内部或短距离通信场景中发挥着关键作用,因其成本低廉且电路设计相对简易;

https://blog.csdn.net/qq_74267512/article/details/144295977?fromshare=blogdetail&sharetype=blogdetail&sharerId=144295977&sharerefer=PC&sharesource=qq_74267512&sharefrom=from_link

因为我们开启的是USART1,所以我们需要找到USART1的TX与RX,它们分别是PA9和PA10,不清楚的小伙伴可以对照下图来看,我们待会儿的PWM也会对照下图。

进行烧录后,运行就能得到下面的情况。

LED灯每两秒翻转一次状态
每五秒向上位机发送一次串口数据

三、PWM实现呼吸灯控制

(1)CUBEMX配置

对于SYS和RCC的配置与上述相同,这里不再赘述。我们直接开始配置定时器。

其实配置定时器的步骤也和上面一致,唯一不同的是打开PWM通道,同时计数次数也要做出相应的更改,这次我们配置TIM3和TIM4这两个通用定时器。我们选择打开其PWM的通道2,如下图所示。

由于我们采用的是PWM输出,他有固定的IO口,所以我们不需要再额外配置GPIO口

接下来的配置都和上述一致,我只是把不同的点和值得注意的点写了出来,但是大家在配置的时候还是需要按部就班地配置。

(2)代码编写

因为我这次配置了两个外接LED灯,我想配置成两个不同呼吸频率的灯,通过对比来直观展现出占空比变化的影响。

首先还是打开我们的定时器,因为这次打开了我们的PWM,所以我们需要的函数也发生了相应的更改。

我们使用HAL_TIM_PWM_Start来实现开启定时器和PWM通道的功能。

第一个参数就是我们要打开的定时器,前文已经介绍过,第二个参数是我们打开的PWM通道,因为我们之前再CUBE里面配置的是通道二,所以我们这里就需要输入TIM_CHANNEL_2来进行通道打开。

现在来实现我们的呼吸功能,所谓呼吸灯其实是不断地修改PWM的占空比来达到我们的LED灯逐渐变亮和逐渐变暗的功能。为了实现呼吸灯先逐渐变亮后逐渐变暗的功能,首先我们得设定一个阈值,在达到阈值前,我们的占空比逐渐增大;在达到阈值后,我们的占空比逐渐变小直到为0或者其他特定值后再反过来增加。

而实现点灯的IO口,我们可以按照刚才给出的开发板的接口图对照,其中T3C2指的就是TIM3_CHANNEL2,而所对应的接口为PA7,同理可以找到T4C2的接口为PB7,将我们的两个灯以低电平点亮的方式外接在开发板上。

而实现将PWM输出的函数为:__HAL_TIM_SetCompare

从左至右的三和参数分别为:定时器、通道、占空比。其实现的功能就是在定时器指定的通道输出指定占空比的PWM脉冲。了解这些后,就可以开始我们的代码书写了。

while (1)
{
    /* USER CODE END WHILE */
        HAL_Delay(50);  //控制呼吸灯呼吸速率
                   //控制占空比大小,即修改CCRx的大小
        if(TIM3_direction){
            TIM3_pwmVal=TIM3_pwmVal+10;
            
        }else{
            TIM3_pwmVal=TIM3_pwmVal-10;
        }
        //设置了ARR为499,因此每计数500为一个周期
        if(TIM3_pwmVal > 500){ 
            TIM3_direction = 0;  //改变呼吸灯方向
        }else if(TIM3_pwmVal == 0){
            TIM3_direction = 1;  //改变呼吸灯方向
        }
        //修改定时器3通道2的PWM的占空比
        __HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,TIM3_pwmVal);
          if(TIM4_direction){
            TIM4_pwmVal=TIM4_pwmVal+20;
            
        }else{
            TIM4_pwmVal=TIM4_pwmVal-20;
        }
        if(TIM4_pwmVal > 500){ 
            TIM4_direction = 0;  //改变呼吸灯方向
        }else if(TIM4_pwmVal == 0){
            TIM4_direction = 1;  //改变呼吸灯方向
        }
        //修改定时器4通道2的PWM的占空比
        __HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_2,TIM4_pwmVal);
    /* USER CODE BEGIN 3 */
  }

当然,别忘了定义我们的全局变量,这是完成我们呼吸灯的重要参数。

uint16_t TIM3_pwmVal=0;     //TIM3的占空比
uint16_t TIM4_pwmVal=0;     //TIM3的占空比
uint16_t TIM3_direction=1;  //控制TIM3的呼吸;1是越来越亮,0是越来越暗
uint16_t TIM4_direction=1;  //控制TIM4的呼吸;1是越来越亮,0是越来越暗

代码的具体位置无所谓,但是要在我们的int main前面。接下来就可以进行代码的烧录了。

(3)结果展示

编译完成无错误后,就可以将我们的代码烧录进去。结果应该和下图一致。

(4)Keil仿真

因为身边没有真实的滤波器,所以我们选择用Keil仿真来看一下PWM的输出波形。

首先点击Keil工具栏中的魔术棒,点击Debug选项卡,按照下图方式配置。

配置完成后点击OK,再点击

开始Debug调试,然后通过下面两种方式找到我们的逻辑分析仪。

方法一

方法二

打开逻辑分析仪后,点击左上角的Set Up添加端口。

按照下面的方式添加我们的端口。

添加定时器3的通道2

添加定时器4的通道2

记得要将输出模式改为bit方便观察。

点击close后,我们的两个端口就保存好了。接下来找到

,先点击左边按钮复位,复位后点击右边按钮运行。

这就是我们得到的波形,因为PWM的占空比是逐步变化的,我们将时间轴拉长一点观察的更加清晰。

四、总结

本文聚焦于STM32定时器与PWM输出,利用HAL库实现多任务与呼吸灯控制,涵盖理论阐释、实践步骤及结果验证,为嵌入式开发人员掌握定时器和PWM技术提供全面指引。

(1)定时器与PWM核心要点

定时器分类及特性:STM32F103C8T6集成8种定时器,含高级、通用、基本三类。通用定时器应用广,具定时、输入捕获、输出波形等多功能,为本文技术实践基石。

PWM原理剖析:占空比定义为周期内高电平占比,精准调控此参数可塑造多样电平持续时长,为PWM控制设备核心机制,如呼吸灯亮度渐变依赖占空比动态调整。

(2)基于HAL库的定时器控制实践

CUBEMX配置流程:项目起始于芯片选型STM32F103C8T6,细致配置SYS、RCC、GPIO、定时器(TIM2与TIM3)、USART1及系统时钟树参数,同时激活定时器中断,为功能实现设硬件基础与中断响应框架。

代码编写策略:主函数开启定时器中断后,于中断回调函数部署功能逻辑。借定时器周期与计数值关联,精准达成5秒串口数据发送与2秒LED闪烁多任务协同,展示定时器精准定时调度能力,满足复杂任务时序需求。

实践成果展示:借FLYMCU与USB to TTL高效烧录,运行呈现预期效果。LED闪烁规律、串口数据按时发送,验证定时器设置与中断处理精准可靠,为实际多任务场景提供可行范例。

(3)PWM实现呼吸灯控制探索

配置环节要点:SYS、RCC沿用通用设置,TIM3和TIM4定时器配置独特点在开启PWM通道2及适配计数次数,因PWM输出固有IO特性,免额外GPIO配置,简化硬件布局且契合PWM信号传输路径。

代码功能架构:代码以while (1)循环为核心,借HAL_TIM_PWM_Start开启定时器与PWM通道,__HAL_TIM_SetCompare动态调控占空比。依占空比增减逻辑与阈值判定,驱动呼吸灯亮暗循环切换,双灯不同呼吸频率设定凸显PWM灵活控制优势。

实践成果反馈:烧录后呼吸灯动态变化契合预期,Keil仿真借逻辑分析仪呈现TIM3与TIM4通道2 PWM波形。占空比渐变波形直观展示呼吸灯控制原理,为优化与故障排查供有力支撑,提升开发效率与精准度。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号