④ STM32基础学习— 定时器PWM

1 stm32定时器介绍

定时器相关的库函数主要集中在固件库文件 stm32f10x_tim.hstm32f10x_tim.c 文件中。

STM32F1 的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。

定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。8个定时器:`高级定时器(TIM1和TIM8)通用定时器(TIM2——TIM5)基本定时器(TIM6和TIM7)

STM3F1 通用 TIMx (TIM2、TIM3、TIM4 、 TIM5)定时器功能包括:

  • 16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
  • 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。
  • 4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:

    • 输入捕获
    • 输出比较
    • PWM 生成(边缘或中间对齐模式)
    • 单脉冲模式输出
  • 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。

  • 如下事件发生时产生中断/DMA:
    • 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
    • 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
    • 输入捕获
    • 输出比较
    • 支持针对定位的增量(正交)编码器和霍尔传感器电路
    • 触发输入作为外部时钟或者按周期的电流管理

控制寄存器 1(TIMx_CR1),该寄存器

我们通过查看TIMx_CR1 最低位,也就是计数器的使能位,就知道该位必须置 1,才能让定时器开始计数。开始计数。从第 4 位 DIR 可以看出默认的计数方式是向上计数,同时也可以向下计数,第 5,6位是设置计数对齐方式的。从第 8 和第 9 位可以看出,我们还可以设置定时器的时钟分频因子为 1,2,4。

==预分频寄存器(TIMx_PSC)==

定时器的时钟来源有 4 个

  • 内部时钟(CK_INT)
  • 外部时钟模式 1:外部输入脚(TIx)
  • 外部时钟模式 2:外部触发输入(ETR)
  • 内部触发输入(ITRx):使用 A 定时器作为 B 定时器的预分频器(A 为 B 提供时钟)。

这些时钟,具体选择哪个可以通过 TIMx_SMCR 寄存器的相关位来设置。这里的 CK_INT时钟是从 APB1 倍频的来的,除非 APB1 的时钟分频数设置为 1,否则通用定时器 TIMx 的时钟是 APB1 时钟的 2 倍,当 APB1 的时钟不分频的时候,通用定时器 TIMx 的时钟就等于 APB1的时钟。这里还要注意的就是高级定时器的时钟不是来自 APB1,而是来自 APB2 的。

==状态寄存器(TIMx_SR)==

1.1 原理说明

每个定时器有4路输出通道:OC1——OC4有RCC给到TIM2——TIM7的时钟频率是72MHZ

1.2 固件库相关函数说明(下面以定时器3为例)

1.2.1 定时器的初始化

TIM3时钟使能:TIM3 是挂载在 APB1 ,通过 APB1 总线使能使能函数来使能 TIM3。

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

初始化定时器参数== :设置自动重装值,分频系数,计数方式

在库函数中,定时器的初始化参数是通过初始化函数 TIM_TimeBaseInit 实现的:

voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
  • 第一个参数确定是那个定时器
  • 第二个参数是定时器初始化参数结构体指针,结构体类型为TIM_TimeBaseInitTypeDef
typedef struct
{
    uint16_t TIM_Prescaler; 
    uint16_t TIM_CounterMode; 
    uint16_t TIM_Period; 
    uint16_t TIM_ClockDivision; 
    uint8_t TIM_RepetitionCounter; 
} TIM_TimeBaseInitTypeDef;
  • 第一个参数 TIM_Prescaler 是用来设置分频系数的。设置它来取得每次计数的时间。例如每次计数的时间为100us,我们称之为时钟源周期,因为输入时钟为84MHZ,所以设置预分频器为(8400-1)
  • 第二个参数 TIM_CounterMode 定时器有五种计数模式,向上计数、向下计数、三种中心对齐模式,本实验的基本定时器只能是向上计数,从0开始计数,并且无需初始化。TIM_CounterMode_Up 和向下计数模式 TIM_CounterMode_Down。
  • 第三个参数是设置自动重载计数周期值,这在前面也已经讲解过。
  • 第四个参数是用来设置时钟分频因子。
  • 定时器周期(Period) 刚刚我们知道了时钟源时间,一个时钟源时间我们刚刚设定为100us,如果我们有10000个这样的时间我们就有了1s定时。而系统是从0开始计数的所以我们设定时需要减一(10000-1)。
  • ClockDivision:时钟分频,设置定时器时钟 CK_INT 频率与数字滤波器采样时钟频率分频比, 基本定时器没有此功能,不用设置。
  • RepetitionCounter:重复计数器,属于高级控制寄存器专用寄存器位,利用它可以非常容易控制输出 PWM 的个数。 这里不用设置。
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 5000;
TIM_TimeBaseStructure.TIM_Prescaler =7199; 
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

1.2.2 设置 TIM3_DIER 允许更新中断

因为我们要使用 TIM3 的更新中断,寄存器的相应位便可使能更新中断。

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
  • 第一个参数是选择定时器号,取值为 TIM1~TIM17。
  • 第二个参数非常关键,是用来指明我们使能的定时器中断的类型,定时器中断的类型有很多种,包括更新中断 TIM_IT_Update,触发中断 TIM_IT_Trigger,以及输入捕获中断等。
  • 第三个参数,失能还是使能。

TIM3 的更新中断

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );

1.2.3 允许 TIM3 工作,使能TIM3

通过 TIM3_CR1 的 CEN 位来设置。在固件库里面使能定时器的函数是通过 TIM_Cmd 函数来实现的:

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

==使能定时器 3==

TIM_Cmd(TIM3, ENABLE); //使能 TIMx 外设

1.2.4 设置自动重装载使能

TIMx_CNT 寄存器,该寄存器是定时器的计数器,该寄存器存储了当前定时器的计数值。

1.2.5 中断服务函数

编写定时器中断服务函数,通过该函数来处理定时器产生的相关中断。在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,所以在状态寄存器 SR 的最低位。在处理完中断之后应该向 TIM3_SR 的最低位写 0,来清除该中断标志。

==读取中断状态寄存器的值判断中断类型的函数==

ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t)

==判断定时器 TIMx 的中断类型 TIM_IT 是否发生中断==

if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){}

==清除中断标志位的函数==

void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)

==清除定时器 TIMx 的中断 TIM_IT 标志位==

TIM_ClearITPendingBit(TIM3, TIM_IT_Update );

1.3 Code

==通用定时器初始化==

//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

    //定时器TIM3初始化
    TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值    
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位

    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

    //中断优先级NVIC设置
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器

    TIM_Cmd(TIM3, ENABLE);  //使能TIMx                     
}

==定时器3中断服务程序==

void TIM3_IRQHandler(void)   //TIM3中断
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
        LED1=!LED1;
    }
}

1.3 TIM-高级定时器

TIM1/TIM8是高级定时器,其他为通用定时器,高级定时器包括了通用定时器的功能。通用定时器功能比T基本定时器多了:输入捕获和输出比较功能。
而高级定时器又比通用定时器多了可编程死区互补输出、重复计数器、带刹车(断路)功能。(注意:STM32F103C8T6)没有定时器8

  • 输入捕获: 输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,通常用于测量输入信号的脉宽、测量 PWM 输入信号的频率及占空比。
  • 输出比较: 定时器通过对预设的比较值与计数器的值做匹配比较之后,并依据相应的输出模式从而实现各类输出。如PWM输出、电平翻转、单脉冲输出、强制输出等。我接下来可能要做电机系统,所以应该会用到PWM输出,在下面着重讲一下。
  • 可编程死区互补输出: 死区,简单解释:通常,大功率电机、变频器等,末端都是由大功率管、IGBT等元件组成的H桥或3相桥。每个桥的上半桥和下半桥是是绝对不能同时导通的,但高速的PWM驱动信号在达到功率元件的控制极时,往往会由于各种各样的原因产生延迟的效果,造成某个半桥元件在应该关断时没有关断,造成功率元件烧毁。死区就是在上半桥关断后,延迟一段时间再打开下半桥或在下半桥关断后,延迟一段时间再打开上半桥,从而避免功率元件烧毁。这段延迟时间就是死区。
  • 重复计数器 :其中重复计数器意思指的是对计数器溢出(包括上溢和下溢)的次数进行计数,是递减的,每到达0时才会产生一个更新事件。而TIM1_RCR就是重复计数器减为0时重新从TIM1_RCR(重复计数器寄存器)的值开始计数.
    解释来源
  • 带刹车(断路)功能 :没有找到具体描述,但是有很通俗的解释,就是紧急刹车停止pwm波。

2 PWM

2.1 什么是PWM

PWM定义:脉冲宽度调制(PulseWidthModulation,PWM)简称脉宽调制。通俗讲,PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用PWM进行编码。我们都知道单片机的引脚可以输出高低两种电平,高电平称之为1,而低电平称之为0。而所谓的PWM波指的是在一定周期内不同比例的高低电平,如下图所示,输出不同比例的方波,在一定时间内高电平的比例分别达到10%,50%,90%。

  • 占空比定义:占空比就是高电平所占整个周期的时间

第一个PWM波,周期为10ms,高电平的时间为4ms,所以占空比为40%,同理第二个PWM波为60%,第三个为80%。

PWM的频率: PWM的频率的整个周期的倒数,所以说上图PWM的周期为1/0.01,也就是100HZ。改变PWM的频率是通过改变整个的周期实现的。所以通过改变高低电平总共的时间、改变高电平占总周期的比例就可以实现任意频率、任意占空比的PWM波。

脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。PWM的作用,我们都知道对于一个发光二极管,在一定电压范围内,输入端的电压越高,二极管的亮度也就越大。我们可以用单片机控制二极管的亮灭,我们会发现单片机引脚只能输出两种电压,即1与0;但是我们想控制二极管亮度。这是我们可以用PWM波控制,通过输出不同比例的高低电平,等效于一定的电压值,此时,就可以对二极管亮度调节了。

STM32 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出,这样,STM32 最多可以同时产生 30 路 PWM 输出!这里我们仅利用 TIM3的 CH2 产生一路 PWM 输出。

STM32 的通用定时器 TIMx 产生 PWM 输出,我们还会用到 3 个寄存器,来控制 PWM 的。这三个寄存器分别是:捕获 /比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。

  • 捕获/比较模式寄存器(TIMx_CCMR1/2),该寄存器总共有 2 个,TIMx _CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 2,而 TIMx_CCMR2 控制 CH3 和 4。

  • 捕获/比较使能寄存器(TIMx_CCER)

这里只用到了 CC2E 位,该位是输入/捕获 2 输出使能位,要想PWM 从 IO 口输出,这个位必须设置为 1,所以我们需要设置该位为 1。

  • 捕获/比较寄存器(TIMx_CCR1~4)

在输出模式下,该寄存器的值与 CNT 的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽了。

STM32 的重映射控制是由复用重映射和调试 IO 配置寄存器(AFIO_MAPR)控制的。

2.2 PWM输出

脉冲宽度调制模式可以生成一个信号,该信号频率由TIMx_ARR自动重载寄存器值决定,其占空比则由TIMx_CCRx捕获比较寄存器值决定。通过向TIMx_CCMRx寄存器中的OCxM位写入110(PWM模式1)或111(PWM模式2),可以独立选择各通道(每个OCx输出对应一个PWM)的PWM 模式。必须通过将TIMx_CCMRx寄存器中的OCxPE位置1使能相应预装载寄存器,最后通过将TIMx_CR1寄存器中的ARPE位置1使能自动重载预装载寄存器。由于只有在发生更新事件时预装载寄存器才会传送到影子寄存器,因此启动计数器之前,必须通过将TIMx_EGR寄存器中的UG位置1来初始化所有寄存器。

2.3 PWM的工作原理

在通用定时器框图中,PWM输出主要涉及到最顶上的一部分(计数时钟的选择)、中间部分(时基单元)、右下部分(PWM输出)这三个部分。

定时器中断一次的时间为Tout(溢出时间)=(ARR+1)(PSC+1)/Tclk,tclk为时钟频率,一般为72000000,arr:自动重装值 psc:时钟预分频数。

  • 在PWM输出模式下,除了CNT(计数器当前值)、ARR(自动重装载值)之外,还多了一个值CCRx(捕获/比较寄存器值)
  • 当CNT小于CCRx时,TIMx_CHx通道输出低电平
  • 当CNT等于或大于CCRx时,TIMx_CHx通道输出高电平

2.3 PWM的通道

每一个捕获/比较通道都是围绕着一个捕获/比较寄存器(包含影子寄存器),包括捕获的输入部分(数字滤波、多路复用和预分频器),和输出部分(比较器和输出控制)。 输入部分对相应的TIx输入信号采样,并产生一个滤波后的信号TIxF。然后,一个带极性选择的边缘检测器产生一个信号(TIxFPx),它可以作为从模式控制器的输入触发或者作为捕获控制,该信号通过预分频进入捕获寄存器(ICxPS)。

输出部分产生一个中间波形OCxRef(高有效)作为基准,链的末端决定最终输出信号的极性。

捕获/比较模块由一个预装载寄存器和一个影子寄存器组成。读写过程仅操作预装载寄存器。

  • 在捕获模式下,捕获发生在影子寄存器上,然后再复制到预装载寄存器中
  • 在比较模式下,预装载寄存器的内容被复制到影子寄存器中,然后影子寄存器的内容和计数器进行比较
  • CCR1寄存器:捕获/比较值寄存器:设置比较值
  • CCMR1寄存器:OC1M[2:0]位:对于PWM方式下,用于设置PWM模式1或者PWM模式2
  • CCER寄存器:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效
  • CCER寄存器:CC1E位:输入/捕获1输出使能。0:关闭,1:打开

2.4 PWM输出的模式

通过设置寄存器TIMx_CCMR1的OC1M[2:0]位来确定PWM的输出模式:

  • PWM模式1:在向上计数时,一旦TIMx_CNT<timx_ccr1时通道1为有效电平,否则为无效电平;在向下计数时,一旦timx_cnt>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。</timx_ccr1时通道1为有效电平,否则为无效电平;在向下计数时,一旦timx_cnt>
  • PWM模式2:在向上计数时,一旦TIMx_CNT<timx_ccr1时通道1为无效电平,否则为有效电平;在向下计数时,一旦timx_cnt>TIMx_CCR1时通道1为有效电平,否则为无效电平。</timx_ccr1时通道1为无效电平,否则为有效电平;在向下计数时,一旦timx_cnt>

2.5 PWM的计数模式

2.5.1 向上计数模式

下面是一个PWM模式1的例子。当TIMx_CNT<TIMx_CCRx时PWM信号参考OCxREF为高,否则为低。如果TIMx_CCRx中的比较值大于自动重装载值(TIMx_ARR),则OCxREF保持为’1’。如果比较值为0,则OCxREF保持为’0’。

2.5.2 向下计数模式

在PWM模式1,当TIMx_CNT>TIMx_CCRx时参考信号OCxREF为低,否则为高。如果TIMx_CCRx中的比较值大于TIMx_ARR中的自动重装载值,则OCxREF保持为’1’。该模式下不能产生0%的PWM波形。

2.5.3 中央对齐模式

当TIMx_CR1寄存器中的CMS位不为’00’时,为中央对齐模式(所有其他的配置对OCxREF/OCx信号都有相同的作用)。根据不同的CMS位设置,比较标志可以在计数器向上计数时被置’1’、在计数器向下计数时被置’1’、或在计数器向上和向下计数时被置’1’。TIMx_CR1寄存器中的计数方向位(DIR)由硬件更新,不要用软件修改它。

  • TIMx_ARR=8
  • PWM模式1
  • TIMx_CR1寄存器中的CMS=01,在中央对齐模式1时,当计数器向下计数时设置比较标志

2.6 捕获/比较模式寄存器1(TIMx_CCMR1)

捕获/比较模式寄存器总共2个,TIMx_CCMR1和TIMx_CCMR2。TIMx_CCMR1控制CH1和CH2,TIMx_CCMR2控制CH3和CH4。该寄存器的某些位在不同模式下功能不一样,上面一层对应输出而下面一层对应输入。

2.7 捕获/比较使能寄存器(TIMx_CCER)

2.8 捕获/比较寄存器1(TIMx_CCR1)

2.9 PWM 步骤

实例:TIM3来产生PWM输出,并使用TIM3的通道2,把通道2重映射到PB5,产生PWM来控制LED的亮度。

  • 使能定时器和相关IO口时钟。调用函数:RCC_APB1PeriphClockCmd()RCC_APB2PeriphClockCmd()
  • 初始化IO口为复用功能输出。调用函数:GPIO_Init()
  • 这里我们是要把PB5用作定时器的PWM输出引脚,所以要重映射配置,所以需要开启AFIO时钟。同时设置重映射。调用函数RCC_APB2PeriphClockCmd()GPIO_PinRemapConfig()
  • 初始化定时器。调用函数:ARR,PSC等:TIM_TimeBaseInit()
  • 初始化输出比较参数。调用函数:TIM_OC2Init()
  • 使能预装载寄存器。调用函数:TIM_OC2PreloadConfig()
  • 使能定时器。调用函数:TIM_Cmd()
  • 不断改变比较值CCRx,达到不同的占空比效果。调用函数:TIM_SetCompare2()

2.10 PWM Code 说明

开启TIM3时钟以及复用功能时钟,配置PB5为复用输出

==使能 TIM3 时钟==

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器 3 时钟

==库函数设置 AFIO 时钟的方法==

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //复用时钟使能

==设置 PB5 为复用功能输出==

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出

初始化 TIM3,设置 TIM3 的 ARR 和 PSC。在开启了 TIM3 的时钟之后,我们要设置 ARR 和 PSC 两个寄存器的值来控制输出 PWM 的

周期。当 PWM 周期太慢(低于 50Hz)的时候,我们就会明显感觉到闪烁了。因此,PWM 周期在这里不宜设置的太小。

TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化 TIMx 的

==结构体 TIM_OCInitTypeDef的定义==

typedef struct
{
    uint16_t TIM_OCMode;
    uint16_t TIM_OutputState; 
    uint16_t TIM_OutputNState; */
    uint16_t TIM_Pulse; 
    uint16_t TIM_OCPolarity; 
    uint16_t TIM_OCNPolarity; 
    uint16_t TIM_OCIdleState; 
    uint16_t TIM_OCNIdleState; 
} TIM_OCInitTypeDef;
  • 参数 TIM_OCMode 设置模式是 PWM 还是输出比较,这里我们是 PWM 模式。
  • 参数 TIM_OutputState 用来设置比较输出使能,也就是使能 PWM 输出到端口。
  • 参数 TIM_OCPolarity 用来设置极性是高还是低。
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择 PWM 模式 2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //初始化 TIM3 OC2

2.11 PWM Code

==TIM3 PWM部分初始化==

//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{  
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);    //使能定时器3时钟
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟

    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5    

   //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形    GPIOB.5
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

   //初始化TIM3
    TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
    TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

    //初始化TIM3 Channel2 PWM模式     
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
    TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2

    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器

    TIM_Cmd(TIM3, ENABLE);  //使能TIM3


}