基于STM32的TIM—高级定时器的输入捕获、输出比较、PWM互补(详细讲解+标准库HAL库代码)

目录

前言

一、定时器分类

二、高级控制定时器

 三、高级控制定时器功能框图

①:时钟源

内部时钟源 (CK_INT)

外部时钟模式 1:外部输入引脚 TIx(x=1,2,3,4)

 外部时钟模式 2:外部触发输入 ETR

 内部触发输入 (ITRx)

 ② 控制器

 ③ 时基单元

④  计数器 CNT

 ⑤ 自动重载寄存器 ARR

⑥  重复计数器 RCR

四、定时器的输入捕获

① 输入通道

② 输入滤波器和边沿检测器

 ③ 捕获通道

④  预分频器

⑤ 捕获寄存器

 五、定时器的输出比较

① 比较寄存器

②  死区发生器

③ 输出控制

④ 输出引脚

六  定时器的断路功能 (不过多讲述,博主没怎么用到)

 七、PWM输出代码带死区时间讲解

7.1 PWM 输出模式

7.2 一般电机的边沿对其模式

7.3  FOC 电机的中心对齐模式

标准库代码(互补输出带死区时间)

HAL库代码(互补输出带死区时间)

 总结


前言

         本章所运用的知识点都是博主从各个网站搜集来的(侵删@@野火),也附带一点自己的看法。本章所用到的开发板是野火的霸道F103系列开发板,需要完整可运行代码的同学也可以找@我拿。

        上一章我们讲完了基本定时器的使用,这一章我们来学习通用、高级定时器,需要学习通用定时器的小伙伴们,可以跳转此链接:https://blog.csdn.net/weixin_61384226/article/details/134968683?spm=1001.2014.3001.5501

 创作不易,点个关注吧


一、定时器分类


        STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级 定时器。基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。通用定时器 TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较, 可以输入捕捉,每个定时器有四个外部 IO。高级定时器 TIM1/8 是一个 16 位的可以向上/下计数 的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定 时器有 8 个外部 IO。更加具体的分类详情见图定时器分类。

二、高级控制定时器

        高级控制定时器 (TIM1 和 TIM8) 和通用定时器在基本定时器的基础上引入了外部引脚,可以实 现输入捕获和输出比较功能。高级控制定时器比通用定时器增加了可编程死区互补输出、重复计 数器、带刹车 (断路) 功能,这些功能都是针对工业电机控制方面。不做详细的 介绍,主要介绍常用的输入捕获和输出比较功能(高级和通用相同,这里用高级来讲解。 高级控制定时器时基单元包含一个 16 位自动重装载寄存器 ARR,一个 16 位的计数器 CNT,可 向上/下计数,一个 16 位可编程预分频器 PSC,预分频器时钟源有多种可选,有内部的时钟、外 部时钟。还有一个 8 位的重复计数器 RCR,这样最高可实现 40 位的可编程定时。

 三、高级控制定时器功能框图

        高级控制定时器功能框图包含了高级控制定时器最核心内容,掌握了功能框图,对高级控制定时 器就有一个整体的把握,在编程时思路就非常清晰,图中有些寄存器是带影子的,表示其有 影子寄存器。

 

①:时钟源

高级(通用)控制定时器有四个时钟源可选:

  • 内部时钟源 CK_INT
  • 外部时钟模式 1:外部输入引脚 TIx(x=1,2,3,4)
  • 外部时钟模式 2:外部触发输入 ETR
  • 内部触发输入 (ITRx)
内部时钟源 (CK_INT)

        内部时钟 CK_INT 即来自于芯片内部,等于 72M一般情况下,我们都是使用内部时钟。当从模 式控制寄存器 TIMx_SMCR 的 SMS 位等于 000 时,则使用内部时钟。

外部时钟模式 1:外部输入引脚 TIx(x=1,2,3,4)

1:时钟信号输入引脚

        当使用外部时钟模式 1 的时候,时钟信号来自于定时器的输入通道,总共有 4 个,分别为 TI1/2/3/4, 即 TIMx_CH1/2/3/4。具体使用哪一路信号,由 TIM_CCMRx 的位 CCxS[1:0] 配置,其中 CCMR1 控制 TI1/2,CCMR2 控制 TI3/4。

2:滤波器

        如果来自外部的时钟信号的频率过高或者混杂有高频干扰信号的话,我们就需要使用滤波器对 信号重新采样,来达到降频或者去除高频干扰的目的,具体的由 TIMx_CCMRx 的位 ICxF[3:0] 配 置。

3:边沿检测

        边沿检测的信号来自于滤波器的输出,在成为触发信号之前,需要进行边沿检测,决定是上升沿 有效还是下降沿有效,具体的由 TIMx_CCER 的位 CCxP 和 CCxNP 配置。

4:触发选择

        当使用外部时钟模式 1 时,触发源有两个,一个是滤波后的定时器输入 1(TI1FP1)和滤波后的 定时器输入 2(TI2FP2),具体的由 TIMxSMCR 的位 TS[2:0] 配置。

5:从模式选择

         选定了触发源信号后,最后我们需把信号连接到 TRGI 引脚,让触发信号成为外部时钟模式 1 的 输入,最终等于 CK_PSC,然后驱动计数器 CNT 计数。具体的配置 TIMx_SMCR 的位 SMS[2:0] 为 111 即可选择外部时钟模式 1。

6:使能计数器

        经过上面的 5 个步骤之后,最后我们只需使能计数器开始计数,外部时钟模式 1 的配置就算完 成。使能计数器由 TIMx_CR1 的位 CEN 配置。

 外部时钟模式 2:外部触发输入 ETR

1:时钟信号输入引脚

        当使用外部时钟模式 2 的时候,时钟信号来自于定时器的特定输入通道 TIMx_ETR,只有 1 个。

2:外部触发极性

        来自 ETR 引脚输入的信号可以选择为上升沿或者下降沿有效,具体的由 TIMx_SMCR 的位 ETP 配置。

3:外部触发预分频器

        由于 ETRP 的信号的频率不能超过 TIMx_CLK(72M)的 1/4,当触发信号的频率很高的情况下, 就必须使用分频器来降频,具体的由 TIMx_SMCR 的位 ETPS[1:0] 配置。

4:滤波器

        如果 ETRP 的信号的频率过高或者混杂有高频干扰信号的话,我们就需要使用滤波器对 ETRP 信 号重新采样,来达到降频或者去除高频干扰的目的。具体的由 TIMx_SMCR 的位 ETF[3:0] 配置, 其中的 fDTS 是由内部时钟 CK_INT 分频得到,具体的由 TIMx_CR1 的位 CKD[1:0] 配置。

5:从模式选择

        经过滤波器滤波的信号连接到 ETRF 引脚后,触发信号成为外部时钟模式 2 的输入,最终等于 CK_PSC,然后驱动计数器 CNT 计数。具体的配置 TIMx_SMCR 的位 ECE 为 1 即可选择外部时 钟模式 2。

6:使能计数器

         经过上面的 5 个步骤之后,最后我们只需使能计数器开始计数,外部时钟模式 2 的配置就算完 成。使能计数器由 TIMx_CR1 的位 CEN 配置。

 内部触发输入 (ITRx)

        内部触发输入是使用一个定时器作为另一个定时器的预分频器。硬件上高级控制定时器和通用 定时器在内部连接在一起,可以实现定时器同步或级联。主模式的定时器可以对从模式定时器执 行复位、启动、停止或提供时钟。

 ② 控制器

        高级控制定时器控制器部分包括触发控制器、从模式控制器以及编码器接口。触发控制器用来针 对片内外设输出触发信号,比如为其它定时器提供时钟和触发 DAC/ADC 转换。 编码器接口专门针对编码器计数而设计。从模式控制器可以控制计数器复位、启动、递增/递减、 计数。有关控制器部分只需熟练阅读寄存器描述即可

 ③ 时基单元

        高级控制定时器时基单元功能包括四个寄存器,分别是计数器寄存器 (CNT)、预分频器寄存器 (PSC)、自动重载寄存器 (ARR) 和重复计数器寄存器 (RCR)。其中重复计数器 RCR 是高级定时器 独有,通用和基本定时器没有前面三个寄存器都是 16 位有效,TIMx_RCR 寄存器是 8 位有效。

④  计数器 CNT

高级控制定时器的计数器有三种计数模式,分别为递增计数模式、递减计数模式和递增/递减 (中 心对齐) 计数模式。

(1) 递增计数模式下,计数器从 0 开始计数,每来一个 CK_CNT 脉冲计数器就增加 1,直到计数器 的值与自动重载寄存器 ARR 值相等,然后计数器又从 0 开始计数并生成计数器上溢事件,计数 器总是如此循环计数。如果禁用重复计数器,在计数器生成上溢事件就马上生成更新事件 (UEV); 如果使能重复计数器,每生成一次上溢事件重复计数器内容就减 1,直到重复计数器内容为 0 时 才会生成更新事件。

(2) 递减计数模式下,计数器从自动重载寄存器 ARR 值开始计数,每来一个 CK_CNT 脉冲计数 器就减 1,直到计数器值为 0,然后计数器又从自动重载寄存器 ARR 值开始递减计数并生成计数 器下溢事件,计数器总是如此循环计数。如果禁用重复计数器,在计数器生成下溢事件就马上生 成更新事件;如果使能重复计数器,每生成一次下溢事件重复计数器内容就减 1,直到重复计数 器内容为 0 时才会生成更新事件。

(3) 中心对齐模式下,计数器从 0 开始递增计数,直到计数值等于 (ARR-1) 值生成计数器上溢事 件,然后从 ARR 值开始递减计数直到 1 生成计数器下溢事件。然后又从 0 开始计数,如此循环。 每次发生计数器上溢和下溢事件都会生成更新事件。

 ⑤ 自动重载寄存器 ARR

        自动重载寄存器 ARR 用来存放与计数器 CNT 比较的值,如果两个值相等就递减重复计数器。可 以通过 TIMx_CR1 寄存器的 ARPE 位控制自动重载影子寄存器功能,如果 ARPE 位置 1,自动重 载影子寄存器有效,只有在事件更新时才把 TIMx_ARR 值赋给影子寄存器。如果 ARPE 位为 0, 则修改 TIMx_ARR 值马上有效。

⑥  重复计数器 RCR

        在基本/通用定时器发生上/下溢事件时直接就生成更新事件,但对于高级控制定时器却不是这样, 高级控制定时器在硬件结构上多出了重复计数器,在定时器发生上溢或下溢事件是递减重复计 数器的值,只有当重复计数器为 0 时才会生成更新事件。在发生 N+1 个上溢或下溢事件 (N 为 RCR 的值) 时产生更新事件。

四、定时器的输入捕获

 

 顾名思义,输入捕获可以对输入的信号的上升沿、下降沿或者双边沿进行捕获,常用的有测量输入信号的脉 宽,测量 PWM 输入信号的频率和占空比这两种。

输入捕获的大概的原理就是,当捕获到信号的跳变沿的时候,把计数器 CNT 的值锁存到捕获寄 存器 CCR 中,把前后两次捕获到的 CCR 寄存器中的值相减,就可以算出脉宽或者频率。如果捕获的脉宽的时间长度超过你的捕获定时器的周期,就会发生溢出,这个我们需要做额外的处理。

① 输入通道

        需要被测量的信号从定时器的外部引脚 TIMx_CH1/2/3/4 进入,通常叫 TI1/2/3/4,在后面的捕获 讲解中对于要被测量的信号我们都以 TIx 为标准叫法。

② 输入滤波器和边沿检测器

上面介绍过,还要说的就是

        当输入的信号存在高频干扰的时候,我们需要对输入信号进行滤波,即进行重新采样,根据采样 定律,采样的频率必须大于等于两倍的输入信号。比如输入的信号为 1M,又存在高频的信号干 扰,那么此时就很有必要进行滤波,我们可以设置采样频率为 2M,这样可以在保证采样到有效 信号的基础上把高于 2M 的高频干扰信号过滤掉。

 ③ 捕获通道

        捕获通道就是图中的 IC1/2/3/4,每个捕获通道都有相对应的捕获寄存器 CCR1/2/3/4,当发生捕获 的时候,计数器 CNT 的值就会被锁存到捕获寄存器中。

        这里我们要搞清楚输入通道和捕获通道的区别,输入通道是用来输入信号的,捕获通道是用来捕 获输入信号的通道,一个输入通道的信号可以同时输入给两个捕获通道。比如输入通道 TI1 的信 号经过滤波边沿检测器之后的 TI1FP1 和 TI1FP2 可以进入到捕获通道 IC1 和 IC2,其实这就是我 们后面要讲的 PWM 输入捕获,只有一路输入信号(TI1)却占用了两个捕获通道(IC1 和 IC2)。 当只需要测量输入信号的脉宽时候,用一个捕获通道即可。输入通道和捕获通道的映射关系具体 由寄存器 CCMRx 的位 CCxS[1:0] 配置。

④  预分频器

        ICx 的输出信号会经过一个预分频器,用于决定发生多少个事件时进行一次捕获。具体的由寄存 器 CCMRx 的位 ICxPSC 配置,如果希望捕获信号的每一个边沿,则不分频。

⑤ 捕获寄存器

         经过预分频器的信号 ICxPS 是最终被捕获的信号,当发生捕获时(第一次),计数器 CNT 的值会 被锁存到捕获寄存器 CCR 中,还会产生 CCxI 中断,相应的中断位 CCxIF(在 SR 寄存器中)会 被置位,通过软件或者读取 CCR 中的值可以将 CCxIF 清 0。如果发生第二次捕获(即重复捕获: CCR 寄存器中已捕获到计数器值且 CCxIF 标志已置 1),则捕获溢出标志位 CCxOF(在 SR 寄存 器中)会被置位,CCxOF 只能通过软件清零

 五、定时器的输出比较

        输出比较就是通过定时器的外部引脚对外输出控制信号,有冻结、将通道 X(x=1,2,3,4)设置为 匹配时输出有效电平、将通道 X 设置为匹配时输出无效电平、翻转、强制变为无效电平、强制变 为有效电平、PWM1 和 PWM2 这八种模式,具体使用哪种模式由寄存器 CCMRx 的位 OCxM[2:0] 配置。其中 PWM 模式是输出比较中的特例,使用的也最多。

① 比较寄存器

        当计数器 CNT 的值跟比较寄存器 CCR 的值相等的时候,输出参考信号 OCxREF 的信号的极性 就会改变,其中 OCxREF=1(高电平)称之为有效电平,OCxREF=0(低电平)称之为无效电平, 并且会产生比较中断 CCxI,相应的标志位 CCxIF(SR 寄存器中)会置位。然后 OCxREF 再经过 一系列的控制之后就成为真正的输出信号 OCx/OCxN。

②  死区发生器

        在生成的参考波形 OCxREF 的基础上,可以插入死区时间,用于生成两路互补的输出信号 OCx 和 OCxN,死区时间的大小具体由 BDTR 寄存器的位 DTG[7:0] 配置。死区时间的大小必须根据与 输出信号相连接的器件及其特性来调整。下面我们简单举例说明下带死区的 PWM 信号的应用, 我们以一个板桥驱动电路为例。

        在这个半桥驱动电路中,Q1 导通,Q2 截止,此时我想让 Q1 截止 Q2 导通,肯定是要先让 Q1 截 止一段时间之后,再等一段时间才让 Q2 导通,那么这段等待的时间就称为死区时间,因为 Q1 关闭需要时间(由 MOS 管的工艺决定)。如果 Q1 关闭之后,马上打开 Q2,那么此时一段时间 内相当于 Q1 和 Q2 都导通了,这样电路会短路。 图带死区插入的互补输出 是针对上面的半桥驱动电路而画的带死区插入的 PWM 信号,图中的死区时间要根据 MOS 管的工艺来调节。

③ 输出控制

        在输出比较的输出控制中,参考信号 OCxREF 在经过死区发生器之后会产生两路带死区的互补 信号 OCx_DT 和 OCxN_DT(通道 1~3 才有互补信号,通道 4 没有,其余跟通道 1~3 一样),这 两路带死区的互补信号然后就进入输出控制电路,如果没有加入死区控制,那么进入输出控制电 路的信号就直接是 OCxREF。

        进入输出控制电路的信号会被分成两路,一路是原始信号,一路是被反向的信号,具体的由寄 存器 CCER 的位 CCxP 和 CCxNP 控制。经过极性选择的信号是否由 OCx 引脚输出到外部引脚 CHx/CHxN 则由寄存器 CCER 的位 CxE/CxNE 配置。

如果加入了断路(刹车)功能,则断路和死区寄存器 BDTR 的 MOE、OSSI 和 OSSR 这三个位会 共同影响输出的信号。

④ 输出引脚

        输出比较的输出信号最终是通过定时器的外部 IO 来输出的,分别为 CH1/2/3/4,其中前面三个通 道还有互补的输出通道 CH1/2/3N。更加详细的 IO 说明还请查阅相关的数据手册。

六  定时器的断路功能 (不过多讲述,博主没怎么用到)

        断路功能就是电机控制的刹车功能,使能断路功能时,根据相关控制位状态修改输出信号电平。 在任何情况下,OCx 和 OCxN 输出都不能同时为有效电平,这关系到电机控制常用的 H 桥电路 结构原因。

        断路源可以是时钟故障事件,由内部复位时钟控制器中的时钟安全系统 (CSS) 生成,也可以是外 部断路输入 IO,两者是或运算关系。

        系统复位启动都默认关闭断路功能,将断路和死区寄存器 (TIMx_BDTR) 的 BKE 为置 1,使能断 路功能。可通过 TIMx_BDTR 寄存器的 BKP 位设置,设置断路输入引脚的有效电平,设置为 1 时 输入 BRK 为高电平有效,否则低电平有效。

发送断路时,将产生以下效果:

  • TIMx_BDTR 寄存器中主输出模式使能 (MOE) 位被清零,输出处于无效、空闲或复位状态; 
  • 根据相关控制位状态控制输出通道引脚电平;当使能通道互补输出时,会根据情况自动控 制输出通道电平; 
  • 将 TIMx_SR 寄存器中的 BIF 位置 1,并可产生中断和 DMA 传输请求。
  • •如果 TIMx_BDTR 寄存器中的自动输出使能 (AOE) 位置 1,则 MOE 位会在发生下一个 UEV 事件时自动再次置 1。

 七、PWM输出代码带死区时间讲解

7.1 PWM 输出模式

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

        PWM 模式分为两种,PWM1 和 PWM2,总得来说是差不多,就看你怎么用而已,具体的区别见 表格 PWM1 与 PWM2 模式的区别。

         下面我们以 PWM1 模式来讲解,PWM 信号主要都是用来控制电机,一般的电机控制用的都是边沿对齐模式,FOC 电机一 般用中心对齐模式。我们这里只分析这两种模式在信号感官上(即信号波形)的区别,具体在电 机控制中的区别不做讨论,到了你真正需要使用的时候就会知道了。

7.2 一般电机的边沿对其模式

        在递增计数模式下,计数器从 0 计数到自动重载值(TIMx_ARR 寄存器的内容),然后重新从 0 开始计数并生成计数器上溢事件    

    

        在边沿对齐模式下,计数器 CNT 只工作在一种模式,递增或者递减模式。这里我们以 CNT 工作 在递增模式为例,在中,ARR=8,CCR=4,CNT 从 0 开始计数,当 CNT< CCR的值,OCxREF 为有效的高电平,于此同时,比较中断寄存器 CCxIF 置位。当 CCR<=CNT<=ARR的时候,OCxREF 为无效的低电平。然后 CNT 又从 0 开始计数并生成计数器上溢事件,以此循环往复。

7.3  FOC 电机的中心对齐模式

         在中心对齐模式下,计数器 CNT 是工作做递增/递减模式下。开始的时候,计数器 CNT 从 0 开始 计数到自动重载值减 1(ARR-1),生成计数器上溢事件;然后从自动重载值开始向下计数到 1 并生成计数器下溢事件。之后从 0 开始重新计数。

        图 PWM1 模式的中心对齐波形 是 PWM1 模式的中心对齐波形,ARR=8,CCR=4。第一阶段计数 器 CNT 工作在递增模式下,从 0 开始计数,当 CNT<CCR 时,OCxREF 为有效的高电平,当 CCR=<CNT<ARR的时候,OCxREF 为无效的低电平,第二阶段计数器 CNT 工作在递减模式,从 ARR 的值开始递减,当CNT>CCR,OCxREF 为无效的低电平,当CCR=>CNT>=1.,OCxREF 为 有效的高电平。

        在波形图上我们把波形分为两个阶段,第一个阶段是计数器 CNT 工作在递增模式的波形,这个 阶段我们又分为 ① 和 ② 两个阶段,第二个阶段是计数器 CNT 工作在递减模式的波形,这个阶段 我们又分为 ③ 和 ④ 两个阶段。要说中心对齐模式下的波形有什么特征的话,那就是 ① 和 ③ 阶 段的时间相等,② 和 ④ 阶段的时间相等。

        中心对齐模式又分为中心对齐模式 1/2/3 三种,具体由寄存器 CR1 位 CMS[1:0] 配置。具体的区 别就是比较中断中断标志位 CCxIF 在何时置 1:中心模式 1 在 CNT 递减计数的时候置 1,中心对 齐模式 2 在 CNT 递增计数时置 1,中心模式 3 在 CNT 递增和递减计数时都置 1。

标准库代码(互补输出带死区时间)

初始化

static void ADVANCE_TIM_GPIO_Config(void) 
{
  GPIO_InitTypeDef GPIO_InitStructure;

  // 输出比较通道 GPIO 初始化
	RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);

  // 输出比较通道互补通道 GPIO 初始化
	RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1N_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ADVANCE_TIM_CH1N_PORT, &GPIO_InitStructure);

  // 输出比较通道刹车通道 GPIO 初始化
	RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_BKIN_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ADVANCE_TIM_BKIN_PORT, &GPIO_InitStructure);
	// BKIN引脚默认先输出低电平
	GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT,ADVANCE_TIM_BKIN_PIN);	
}


///*
// * 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有
// * TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,
// * 另外三个成员是通用定时器和高级定时器才有.
// *-----------------------------------------------------------------------------
// *typedef struct
// *{ TIM_Prescaler            都有
// *	TIM_CounterMode			     TIMx,x[6,7]没有,其他都有
// *  TIM_Period               都有
// *  TIM_ClockDivision        TIMx,x[6,7]没有,其他都有
// *  TIM_RepetitionCounter    TIMx,x[1,8,15,16,17]才有
// *}TIM_TimeBaseInitTypeDef; 
// *-----------------------------------------------------------------------------
// */

/* ----------------   PWM信号 周期和占空比的计算--------------- */
// ARR :自动重装载寄存器的值
// CLK_cnt:计数器的时钟,等于 Fck_int / (psc+1) = 72M/(psc+1)
// PWM 信号的周期 T = (ARR+1) * (1/CLK_cnt) = (ARR+1)*(PSC+1) / 72M
// 占空比P=CCR/(ARR+1)

static void ADVANCE_TIM_Mode_Config(void)
{
  // 开启定时器时钟,即内部时钟CK_INT=72M
	ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);

/*--------------------时基结构体初始化-------------------------*/
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
	TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD;	
	// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
	TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC;	
	// 时钟分频因子 ,配置死区时间时需要用到
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;		
	// 计数器计数模式,设置为向上计数
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;		
	// 重复计数器的值,没用到不用管
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	
	// 初始化定时器
	TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);

	/*--------------------输出比较结构体初始化-------------------*/		
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	// 配置为PWM模式1
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	// 输出使能
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	// 互补输出使能
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; 
	// 设置占空比大小
	TIM_OCInitStructure.TIM_Pulse = ADVANCE_TIM_PULSE;
	// 输出通道电平极性配置
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	// 互补输出通道电平极性配置
	TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
	// 输出通道空闲电平极性配置
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
	// 互补输出通道空闲电平极性配置
	TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
	TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable);

	/*-------------------刹车和死区结构体初始化-------------------*/
	// 有关刹车和死区结构体的成员具体可参考BDTR寄存器的描述
	TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
	// 输出比较信号死区时间配置,具体如何计算可参考 BDTR:UTG[7:0]的描述
	// 这里配置的死区时间为152ns
  TIM_BDTRInitStructure.TIM_DeadTime = 11;
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
	// 当BKIN引脚检测到高电平的时候,输出比较信号被禁止,就好像是刹车一样
  TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
  TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure);
	
	// 使能计数器
	TIM_Cmd(ADVANCE_TIM, ENABLE);	
	// 主输出使能,当使用的是通用定时器时,这句不需要
	TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE);
}

void ADVANCE_TIM_Init(void)
{
	ADVANCE_TIM_GPIO_Config();
	ADVANCE_TIM_Mode_Config();		
}

HAL库代码(互补输出带死区时间)

TIM_HandleTypeDef  TIM_TimeBaseStructure;
TIM_OC_InitTypeDef TIM_OCInitStructure;

__IO uint16_t ChannelPulse = 500;

/**
  * @brief  配置TIM复用输出PWM时用到的I/O
  * @param  无
  * @retval 无
  */
static void TIMx_GPIO_Config(void) 
{
	/*定义一个GPIO_InitTypeDef类型的结构体*/
	GPIO_InitTypeDef GPIO_InitStructure;

	/*开启定时器相关的GPIO外设时钟*/
	ADVANCE_OCPWM_GPIO_CLK_ENABLE();
	ADVANCE_OCNPWM_GPIO_CLK_ENABLE();

	/* 定时器功能引脚初始化 */															   
	GPIO_InitStructure.Pin = ADVANCE_OCPWM_PIN;	
	GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;    
	GPIO_InitStructure.Pull = GPIO_NOPULL;
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; 	
	HAL_GPIO_Init(ADVANCE_OCPWM_GPIO_PORT, &GPIO_InitStructure);	

	GPIO_InitStructure.Pin = ADVANCE_OCNPWM_PIN;	
	HAL_GPIO_Init(ADVANCE_OCNPWM_GPIO_PORT, &GPIO_InitStructure);
	
	
}

/*
 * 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有
 * TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,
 * 另外三个成员是通用定时器和高级定时器才有.
 *-----------------------------------------------------------------------------
 * TIM_Prescaler         都有
 * TIM_CounterMode			 TIMx,x[6,7]没有,其他都有(基本定时器)
 * TIM_Period            都有
 * TIM_ClockDivision     TIMx,x[6,7]没有,其他都有(基本定时器)
 * TIM_RepetitionCounter TIMx,x[1,8]才有(高级定时器)
 *-----------------------------------------------------------------------------
 */
static void TIM_Mode_Config(void)
{
	TIM_BreakDeadTimeConfigTypeDef TIM_BDTRInitStructure;
	// 开启TIMx_CLK,x[1,8] 
	ADVANCE_TIM_CLK_ENABLE(); 
	/* 定义定时器的句柄即确定定时器寄存器的基地址*/
	TIM_TimeBaseStructure.Instance = ADVANCE_TIM;
	/* 累计 TIM_Period个后产生一个更新或者中断*/		
	//当定时器从0计数到999,即为1000次,为一个定时周期
	TIM_TimeBaseStructure.Init.Period = 1000-1;
	// 高级控制定时器时钟源TIMxCLK = HCLK=168MHz 
	// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=1MHz
	TIM_TimeBaseStructure.Init.Prescaler = 72-1;	
	// 采样时钟分频
	TIM_TimeBaseStructure.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	// 计数方式
	TIM_TimeBaseStructure.Init.CounterMode=TIM_COUNTERMODE_UP;
	// 重复计数器
	TIM_TimeBaseStructure.Init.RepetitionCounter=0;	
	// 初始化定时器TIMx, x[1,8]
	HAL_TIM_PWM_Init(&TIM_TimeBaseStructure);

	/*PWM模式配置*/
	//配置为PWM模式1
	TIM_OCInitStructure.OCMode = TIM_OCMODE_PWM1;
	TIM_OCInitStructure.Pulse = ChannelPulse;
	TIM_OCInitStructure.OCPolarity = TIM_OCPOLARITY_HIGH;
	TIM_OCInitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH;
	TIM_OCInitStructure.OCIdleState = TIM_OCIDLESTATE_SET;
	TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET;
	//初始化通道1输出PWM 
	HAL_TIM_PWM_ConfigChannel(&TIM_TimeBaseStructure,&TIM_OCInitStructure,TIM_CHANNEL_1);

	/* 自动输出使能,断路、死区时间和锁定配置 */
	TIM_BDTRInitStructure.OffStateRunMode = TIM_OSSR_ENABLE;
	TIM_BDTRInitStructure.OffStateIDLEMode = TIM_OSSI_ENABLE;
	TIM_BDTRInitStructure.LockLevel = TIM_LOCKLEVEL_1;
	TIM_BDTRInitStructure.DeadTime = 11;
	TIM_BDTRInitStructure.BreakState = TIM_BREAK_ENABLE;
	TIM_BDTRInitStructure.BreakPolarity = TIM_BREAKPOLARITY_LOW;
	TIM_BDTRInitStructure.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
	HAL_TIMEx_ConfigBreakDeadTime(&TIM_TimeBaseStructure, &TIM_BDTRInitStructure);

	/* 定时器通道1输出PWM */
	HAL_TIM_PWM_Start(&TIM_TimeBaseStructure,TIM_CHANNEL_1);
	/* 定时器通道1互补输出PWM */
	HAL_TIMEx_PWMN_Start(&TIM_TimeBaseStructure,TIM_CHANNEL_1);
}

/**
  * @brief  初始化高级控制定时器定时,1s产生一次中断
  * @param  无
  * @retval 无
  */
void TIMx_Configuration(void)
{
	TIMx_GPIO_Config();	

	TIM_Mode_Config();
}

 总结

关于定时器的就将这么多,不管你是要用定时、输出还是输入,都根据结构体去配置即可,希望我写的对大家有帮助,别忘了关注三联,谢谢!

  • 30
    点赞
  • 112
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F1系列微控制器是一种基于ARM Cortex-M3内核的高性价比单片机,其中的高级定时器(Advanced Timer)可以实现多种功能,包括输出互补PWM信号。 使用HAL库,我们可以很方便地进行高级定时器的配置和使用。下面是使用HAL库实现输出互补PWM的步骤: 1. 初始化定时器:选择一个合适的高级定时器(比如TIM1),通过HAL_TIM_PWM_Init()函数进行初始化。 2. 配置定时器参数:设置定时器的时钟频率、预分频系数、计数周期等参数,通过HAL_TIM_Base_Config()函数进行配置。 3. 配置PWM输出通道:选择需要的PWM输出通道(比如通道1和通道2),通过HAL_TIM_PWM_ConfigChannel()函数进行配置。 4. 配置PWM信号的占空比:设置PWM信号的占空比,通过HAL_TIM_PWM_Start()函数启动PWM输出。 5. 配置互补输出:使能PWM互补输出,设置互补输出的引脚极性,通过HAL_TIMEx_PWMN_Start()函数启动互补输出。 下面是一个示例代码,实现使用TIM1输出互补PWM信号: #include "stm32f1xx_hal.h" void TIM1_Init(void) { TIM_HandleTypeDef htim1; TIM_OC_InitTypeDef sConfig; htim1.Instance = TIM1; htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 9999; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim1); sConfig.OCMode = TIM_OCMODE_PWM1; sConfig.Pulse = 5000; // 设置占空比为50% sConfig.OCPolarity = TIM_OCPOLARITY_HIGH; sConfig.OCNPolarity = TIM_OCNPOLARITY_LOW; sConfig.OCFastMode = TIM_OCFAST_DISABLE; sConfig.OCIdleState = TIM_OCIDLESTATE_RESET; sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET; HAL_TIM_PWM_ConfigChannel(&htim1, &sConfig, TIM_CHANNEL_1); HAL_TIM_PWM_ConfigChannel(&htim1, &sConfig, TIM_CHANNEL_2); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2); } 通过上述代码,我们实现了TIM1通道1和通道2的输出互补PWM信号,输出互补的引脚极性根据设置的参数反向生成。在实际使用时,可以根据需求修改参数来满足具体的应用场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值