定时器详解 -- 定时器中断、PWM输出 --stm32

这篇具有很好参考价值的文章主要介绍了定时器详解 -- 定时器中断、PWM输出 --stm32。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

STM32定时器

STM32F103系列芯片拥有多种定时器,包括基本定时器、通用定时器和高级定时器,每种定时器都具有一些特定的功能。
pwm 中断,STM32-每日一学,单片机知识小专栏,stm32,单片机,嵌入式硬件

计数模式

向上计数:计数器从0计数到自动重装载值(ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
向下计数:计数器从自动重装载值(ARR)开始向下计数到0,然后重新从自动重装载值(ARR)开始向下计数,并且产生一个计数器溢出事件。
向上向下双向计数(中央对齐模式):计数器从0开始计数到自动重装载值-1,产生一个计数器溢出事件,然后计数器从ARR开始向下计数,计数到1再次产生一个计数器溢出事件,以此往复。

定时器工作原理

STM32F103系统构架知:TIM1、8在APB2上,TIM2、3、4、5、6、7在APB1上,APB1操作速度限于36MHz,APB2操作于全速72MHz。
pwm 中断,STM32-每日一学,单片机知识小专栏,stm32,单片机,嵌入式硬件

基本定时器:TIM6、TIM7

TIM6、TIM7定时器主要功能:16位自动重装载累加计算器,16位可编程预分频器(1~65536),触发DAC的同步电路、产生DMA中断请求。

基本定时器框图pwm 中断,STM32-每日一学,单片机知识小专栏,stm32,单片机,嵌入式硬件
时钟源: STM32F103基本定时器的时钟源,可以使用内部时钟源或外部时钟源。当使用内部时钟源(CN_INT)时,计时器的时钟频率由STM32内部时钟提供。当使用外部时钟源时,计时器的时钟频率由外部时钟信号提供,可以使用外部晶体振荡器、RC振荡器等外部时钟源。

预分频器:PSC预分频寄存器,用于设定定时器时钟的分频系数。

CNT计数器:用于记录定时器的当前值,从0开始计数,当CNT到达ARR时计数器重新从0开始计数(向上计数模式)。

自动重装载寄存器:ARR用于设定计时器的计时时长,当CNT到达该值时自动重新计数。
pwm 中断,STM32-每日一学,单片机知识小专栏,stm32,单片机,嵌入式硬件
如何定时呢?
首先确定TIM6\TIM7时钟源(内部时钟CK_INT)经APB1预分频后分频提供,如果APB1预分频系数是1则频率不变,在库函数中APB1预分频的系数是2,即PCLK1=36MHz,所以定时器的时钟频率TIMxCLK为72Mhz(36*2)

计数器计数的计算方式:

CK_CNT = TIMxCLK/(PSC+1)     //CK_CNT最大65536

PSC是预分频器值

定时时间计算(计数器的中断周期*中断的次数):

Tout = ((ARR+1)*(PSC+1))/TIMxCLK

假设需要计时1s产生一次中断(已知TIMxCLk为72MHz):
先设ARR值为9999(ARR+1就是10000)
1 = (10000(PSC+1))/72000000*
因此PSC=7199

所以CK_CNT计算有什么用?

假设PSC是7199 所以CN_CNK=1000(hz)的时钟  计数一次花费时间1/1000 = 0.0001s = 0.1ms
所以Tout = (ARR+1)*(0.0001) 已知定时1s = Tout  所以ARR = 9999

示例代码

使用定时器TIM6中断方法控制LED灯闪烁,设置定时器1s中断一次,中断服务函数中控制LED实现LED闪烁功能。

定时器头文件定义

#ifndef __TIME_H
#define __TIME_H

#include "stm32f10x.h"

#define TIM         TIM4    
#define TIM_CLK     RCC_APB1Periph_TIM4     //RCC时钟
#define TIM_ARR     10000-1                 //定义ARR值
#define TIM_PSC     7200-1                  //定义PSC值
#define TIM_IRQ     TIM4_IRQn               //定义中断编号
#define TIM_IRQHandler TIM4_IRQHandler      //重定义中断函数

void TIM_Init_Config(void);     

#endif /* __TIME_H */

定时器源文件

#include "bsp_time.h"

//中断优先级配置
void TIM_NVIC_Config(void){
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);             //设置优先级分组
    NVIC_InitStructure.NVIC_IRQChannel = TIM_IRQ;               //指定需要配置的中断信号
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;   //先占优先级 1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;          //从优先级   1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //使能NVIC
    NVIC_Init(&NVIC_InitStructure);                             //初始化NVIC寄存器
}


//定时器配置
void TIM_Init_Config(void){
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    RCC_APB1PeriphClockCmd(TIM_CLK, ENABLE);                    //开启TIM4定时器所对应的APB1总线时钟
    TIM_TimeBaseInitStruct.TIM_Prescaler = TIM_PSC;             //设置TIM4的预分频系数
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//计数模式设置为递增模式
    TIM_TimeBaseInitStruct.TIM_Period = TIM_ARR;                //设置TIM4自动重载寄存器的值,用于设定定时器的定时时长
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;    //设置TIM4的时钟分割比,即分割细度
//    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM, &TIM_TimeBaseInitStruct);
    
    TIM_ITConfig(TIM, TIM_IT_Update, ENABLE);//使能TIM4的溢出中断,将TIM_IT_Update设置为ENABLE即可。这一步非常重要,否则定时器无法产生中断信号,不会触发相应的中断服务程序。
    
    TIM_NVIC_Config();
    
    TIM_Cmd(TIM, ENABLE);   //使能定时器 -- 开启定时器
}

中断函数

//"stm32f10x_it.c"源文件
void TIM_IRQHandler(void){
    if(TIM_GetITStatus(TIM, TIM_IT_Update)!= RESET){
        LED_TOGGLE;
        TIM_ClearITPendingBit(TIM, TIM_IT_Update);
    }
}

代码讲解

定时器结构体成员

/**
  * @brief  TIM Time Base Init structure definition
  * @note   This structure is used with all TIMx except for TIM6 and TIM7.    
  */


typedef struct
{
  uint16_t TIM_Prescaler;         /*!< Specifies the prescaler value used to divide the TIM clock.
                                       This parameter can be a number between 0x0000 and 0xFFFF */


  uint16_t TIM_CounterMode;       /*!< Specifies the counter mode.
                                       This parameter can be a value of @ref TIM_Counter_Mode */


  uint16_t TIM_Period;            /*!< Specifies the period value to be loaded into the active
                                       Auto-Reload Register at the next update event.
                                       This parameter must be a number between 0x0000 and 0xFFFF.  */


  uint16_t TIM_ClockDivision;     /*!< Specifies the clock division.
                                      This parameter can be a value of @ref TIM_Clock_Division_CKD */


  uint8_t TIM_RepetitionCounter;  /*!< Specifies the repetition counter value. Each time the RCR downcounter
                                       reaches zero, an update event is generated and counting restarts
                                       from the RCR value (N).
                                       This means in PWM mode that (N+1) corresponds to:
                                          - the number of PWM periods in edge-aligned mode
                                          - the number of half PWM period in center-aligned mode
                                       This parameter must be a number between 0x00 and 0xFF.
                                       @note This parameter is valid only for TIM1 and TIM8. */
} TIM_TimeBaseInitTypeDef;

TIM_Prescaler:指分配器的预分频值,一般为一定的预定值,大小范围为0到65536
TIM_CounterMode:指定时器的计数模式,一般有递增和递减模式

#define TIM_CounterMode_Up                 ((uint16_t)0x0000)
#define TIM_CounterMode_Down               ((uint16_t)0x0010)
#define TIM_CounterMode_CenterAligned1     ((uint16_t)0x0020)
#define TIM_CounterMode_CenterAligned2     ((uint16_t)0x0040)
#define TIM_CounterMode_CenterAligned3     ((uint16_t)0x0060)

TIM_Period:定时器的自动重装载值,大小范围为0到65536
TIM_ClockDivision:TIM的时钟分割比,即分割细度
TIM_RepetitionCounter: 指定TIM1和TIM8定时器的重复计数器值。当重复计数器的值减少到0时,将会产生一个溢出事件,并将TIMx的计数器重新从重复计数器的值开始计数。

定时器初始化函数

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)    //x从1到17

TIMx:定时器选择,可从1到17

使能/失能中断溢出函数

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)    //x从1到17

开启/关闭定时器函数

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)    //x从1到17

定时器中断标志位获取和清除

FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);        //获取定时器中断标志状态,检查x定时器是否发生中断事件

                                                                           //TIM_FLAG是需要检测的中断标志
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);                  //清除定时器中断标志,将x定时器指定的中断标志清零

ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);              //获取定时器中断状态,检查x定时器是否产生中断信号
                                                                           //TIM_IT用于检测需要的中断源

void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);            //清除定时器的中断状态

定时器中断标志状态函数一般先于定时器中断状态函数使用,并且在启用中断之前使用它们以确保不会丢失年中断信号;定时器中断状态函数则用于在ISR(中断服务程序)中检查中断状态。

通用定时器:TIM2、TIM3、TIM4、TIM5

定时器时钟来源:

  • 内部定时器(CK_INT)
  • 外部时钟模式1:外部输入脚(TIx)
  • 外部时钟模式2:外部触发输入(ETR)
  • 内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器作为另一个定时器的预分频器。

编程步骤:

  • 配置系统时钟
  • 配置NVIC
  • 配置定时器
  • 配置定时器中断服务函数

高级定时器:TIM1、TIM8

待补写

定时器PWM输出原理

PWM输出就是对外输出脉宽(占空比)可调的方波信号,信号频率由自动重装载寄存器ARR的值决定,占空比由比较寄存器CCR的值决定。

通用定时器3控制通道1输出PWM脉冲

pwm 中断,STM32-每日一学,单片机知识小专栏,stm32,单片机,嵌入式硬件
从上图通用定时器框图可以看出一个定时器只有一个计数器,所以同一个定时器输出的PWM频率是一样的,可以改变的是占空比大小(可以通过改变比较寄存器改变占空比大小)。

查看定时器TIM3复用的引脚图,如下所示
pwm 中断,STM32-每日一学,单片机知识小专栏,stm32,单片机,嵌入式硬件

代码

PWM头文件定义

#ifndef __PWM_H
#define __PWM_H
#include "stm32f10x.h"

#define PWM_TIM     TIM3
#define PWM_TIM_CLK RCC_APB1Periph_TIM3

#define PWM_TIM_GPIP_PORT   GPIOA
#define PWM_TIM_GPIO_CLK    RCC_APB2Periph_GPIOA
#define PWM_TIM_GPIO_Pin    GPIO_Pin_6

void PWM_TIM_Mode_Init(uint16_t freq, uint16_t duty);

#endif /* __PWM_H */

PWM源文件

#include "bsp_pwm.h"

/**
* @brief 初始化PWM的GPIO为复用模式
*
* @retval None
*/
void PWM_TIM_GPIO_Init(void){
    GPIO_InitTypeDef GPIO_InitStruct;
    RCC_APB2PeriphClockCmd(PWM_TIM_GPIO_CLK, ENABLE);   //开启GPIOA时钟
    GPIO_InitStruct.GPIO_Pin = PWM_TIM_GPIO_Pin;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;        //设置引脚为复用推挽输出模式
    GPIO_Init(PWM_TIM_GPIP_PORT, &GPIO_InitStruct);     //初始化函数
}

/**
* @brief 初始化TIM为PWM输出模式
*
* @param freq PWM的频率(kHz)
* @param duty PWM的占空比(0~100)
* @retval None
*/
void PWM_TIM_Mode_Init(uint16_t freq, uint16_t duty){
    uint16_t arr = 36000/freq;      //freq是频率,单位是khz   //将频率
    PWM_TIM_GPIO_Init();
    //配置定时器
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_OCInitTypeDef TIM_OCInitStruct;
    //开启定时器时钟
    RCC_APB1PeriphClockCmd(PWM_TIM_CLK, ENABLE);
    
    TIM_TimeBaseInitStruct.TIM_Period = arr-1;
    TIM_TimeBaseInitStruct.TIM_Prescaler =1; //时钟预分频数  设置频率f = 36mhz  因为 t = TIMx_CLK/(PSC+1) --> t = 1/(36Mhz) --> f = 1/t  --> f = 1/t = 36mhz
    TIM_TimeBaseInitStruct.TIM_ClockDivision = 0;   //采样分频
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;    //计数模式
    TIM_TimeBaseInit(PWM_TIM, &TIM_TimeBaseInitStruct);
    
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;      //设置为PWM1模式
    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;  //输出使能
    TIM_OCInitStruct.TIM_Pulse = (arr+1)*duty/100-1;    //设置占空比
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;      //输出极性
    //初始化PWM_TIM输出比较通道1
    TIM_OC1Init(PWM_TIM, &TIM_OCInitStruct);
    //使能OC1输出比较多预装载以及TIMx的配置寄存器
    TIM_OC1PreloadConfig(PWM_TIM, TIM_OCPreload_Enable);
    //开启定时器
    TIM_Cmd(PWM_TIM,ENABLE);
}

主程序

PWM_TIM_Mode_Init(20, 80);    //初始化时调用一次即可

TIM_OCInitTypeDef结构体讲解

typedef struct
{
  uint16_t TIM_OCMode;        /*!< 指定TIM输出比较的模式 */


  uint16_t TIM_OutputState;   /*!< 指定TIM输出比较通道的输出状态(开启或关闭) */


  uint16_t TIM_OutputNState;  /*!< 指定TIM互补输出比较通道的输出状态(开启或者关闭),只对定时器TIM1、TIM8有效 */


  uint16_t TIM_Pulse;         /*!< 指定TIM输出比较通道的占空比 */


  uint16_t TIM_OCPolarity;    /*!< 指定TIM输出比较通道的极性 */


  uint16_t TIM_OCNPolarity;   /*!< 指定TIM互补输出比较通道的极性 */


  uint16_t TIM_OCIdleState;   /*!< 指定TIM输出比较通道在闲置或者空档时的输出电平状态 */


  uint16_t TIM_OCNIdleState;  /*!< 指定TIM互补输出比较通道在空档状态下输出的电平状态 */
} TIM_OCInitTypeDef;

ARR决定PWM周期
CCRx决定PWM占空比大小
ARR计算:

由Tout = ((ARR+1)*(PSC+1))/TIMxCLK           --   已知TIMxCLK = 72Mhz且PSC设置为1
因此T=(arr+1)/36            -- 已知 t = 1/f
所以1/f = (arr+1)/36  
得 arr = 36000/f

总结

要多用,要多用!

参考资料

https://www.bilibili.com/video/BV1b54y1m71K/?spm_id_from=333.337.search-card.all.click&vd_source=101ae2594bcc6dbee11cc6670869bc2e

https://blog.csdn.net/qq_44016222/article/details/123507270?spm=1001.2100.3001.7377&utm_medium=distribute.pc_feed_blog_category.none-task-blog-classify_tag-20-123507270-null-null.nonecase&depth_1-utm_source=distribute.pc_feed_blog_category.none-task-blog-classify_tag-20-123507270-null-null.nonecase

https://www.guyuehome.com/39703#%E4%B8%89%E3%80%81%E5%AE%9A%E6%97%B6%E5%99%A8%E8%BE%93%E5%87%BAPWM

https://blog.csdn.net/qq_38410730/article/details/79996222

pwm 中断,STM32-每日一学,单片机知识小专栏,stm32,单片机,嵌入式硬件文章来源地址https://www.toymoban.com/news/detail-675043.html

到了这里,关于定时器详解 -- 定时器中断、PWM输出 --stm32的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32F1定时器-PWM输出

    STM32 PWM工作过程 ARR寄存器决定PWM周期,CCR寄存器决定占空比 通道1为例 的PWM输出电路图 CCR1:捕获比较(值)寄存器(x =1,2,3,4):设置比较值。 CCMR1:OC1M[2:0]位:对于PWM方式下,用于设置PWM模式1【110】 或者PWM模式2【111】 CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平

    2024年02月09日
    浏览(81)
  • STM32(7)-定时器输出PWM的原理分析

    概念+代码 OC(Output Compare)输出比较 输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形 每个高级定时器和通用定时器都拥有4个输出比较通道 高级定时器的前3个通道额外拥有死区生成和互补输出的功

    2024年02月04日
    浏览(56)
  • STM32使用CubeMx配置定时器输出PWM

            项目中经常使用到STM32来输出PWM,每次配置过后过不了多久就会忘记,稍微需要对配置做出修改时都要翻很久的手册,所以决定结合实例把PWM配置的详细步骤记录下来,这样在下次配置时可以很快的捡起来。         本文档的行文结构如下,首先,说明实际需

    2024年02月03日
    浏览(69)
  • STM32使用高级定时器输出互补pwm波

    最近做的一个项目用到stm32,网上查了很多资料,也踩了很多坑,这里记录一下配置的步骤和说明 硬件使用的是stm32h750vbt6; 软件用到了stm32cubemx和keil5; 打开Debug模式方便调试,可以忽略,不影响代码运行 在用cube配置时钟源时,有下面三个选项 Disable(禁用) BYPASS Clock Sou

    2024年02月16日
    浏览(74)
  • STM32TIM定时器PWM输出比较(适用于通用,高级定时器)

    在定时器中我们最常用的功能就是输出PWM,大多是用在电机控制方面,目前网络上相关资料也有很多,但是,很多不利于我们“现搜现用”我这里不是说我写的有多好,而是你搜索到此类文章时大部分是急于解决目前的问题,一段相关代码和讲解就行,当然不是学习背后的原

    2024年01月25日
    浏览(57)
  • STM32笔记——定时器输出比较功能(产生PWM波)

    目录 一、概述 二、PWM简单介绍  三、通用定时器输出比较 3.1 输出比较简介 3.2 输出比较通道 3.3 产生PWM的过程 四、实验硬件介绍及PWM模块程序 4.1 舵机简介 4.2 直流电机及驱动芯片TB6612  4.3 PWM模块驱动程序         主要介绍通用定时器输出比较功能,在GPIO口输出PWM来控

    2024年02月13日
    浏览(47)
  • STM32高级定时器输出指定数量PWM(STM32CubeMx配置)

    高级定时器中有一个重复计数器,本实验输出指定个数PWM就是利用了重复计数器的特性,先来看看重复计数器的特性是什么: 计数器每次上溢或下溢都能使重复计数器减1,减到0时,再发生一次溢出就会产生更新事件 这是什么意思呢,这里举个例子比如说我设定重复计数器的

    2024年02月02日
    浏览(88)
  • STM32实战-高级定时器带死区的互补PWM输出

    前言: 平时我们设计点击驱动电路时,一般会采用npn和pnp三极管,来控制电机的导通和关闭,但是三级管内部自带电容,断电后不会立马断掉,会经过很小的一段时间才会放电完毕,这时候要留有死区给电容放电,这就有了互补pwm波。   同时,当电机出现故障,如果利用软

    2024年02月08日
    浏览(49)
  • STM32一个定时器同时配置编码器和PWM输出时PWM无法正常输出的原因【避坑】

             最近我在做写代码的时候,因为定时器的资源紧张,就在一个定时器上同时配置了编码器和PWM,发现PWM无法正常输出,查了很久发现网上资料不多,在仔细翻阅手册研究后才发现是 时钟信号 的问题。 具体原因 定时器在设置编码器模式后,计数的时钟源就会变成编

    2024年02月04日
    浏览(56)
  • STM32——高级定时器输出指定个数PWM波原理及实战

    相比于通用定时器特性: 1)重复计数器 2)死区时间带可编程的互补输出 3)断路输入,用于将定时器的输出信号置于用户可选的安全配置中 1,配置定时器基础工作参数 HAL_TIM_PWM_Init() 2,定时器PWM输出MSP初始化 HAL_TIM_PWM_MspInit() 配置NVIC、CLOCK、GPIO等 3,配置PWM模式/比较值等

    2024年01月16日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包