发送断路时,将产生以下效果:
TIMx_BDTR 寄存器中主输出模式使能 (MOE) 位被清零,输出处于无效、空闲或
复位状态;
根据相关控制位状态控制输出通道引脚电平;当使能通道互补输出时,会根据情
况自动控制输出通道电平;
将 TIMx_SR 寄存器中的 BIF 位置 1 ,并可产生中断和 DMA 传输请求。
如果 TIMx_BDTR 寄存器中的 自动输出使能 (AOE) 位置 1 ,则 MOE 位会在发生下
一个 UEV 事件时自动再次置 1 。
一 . 一 输入捕获应用
输入捕获一般应用在两个方面,一个方面是脉冲跳变沿时间测量,另一方面是 PWM
输入测量
测量脉宽或者频率
1. 测量频率
当捕获通道 TIx 上出现上升沿时,发生第一次捕获,计数器 CNT 的值会被锁存到捕获
寄存器 CCR 中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标
志变量来记录),并把捕获寄存器中的值读取到 value1 中。当出现第二次上升沿时,发生
第二次捕获,计数器 CNT 的值会再次被锁存到捕获寄存器 CCR 中,并再次进入捕获中断,
在捕获中断中,把捕获寄存器的值读取到 value3 中,并清除捕获记录标志。利用 value3 和
value1 的差值我们就可以算出信号的周期(频率)。
2. 测量脉宽
当捕获通道 TIx 上出现上升沿时,发生第一次捕获,计数器 CNT 的值会被锁存到捕获
寄存器 CCR 中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标
志变量来记录),并把捕获寄存器中的值读取到 value1 中。然后把捕获边沿改变为下降沿
捕获,目的是捕获后面的下降沿。当下降沿到来的时候,发生第二次捕获,计数器 CNT 的
值会再次被锁存到捕获寄存器 CCR 中,并再次进入捕获中断,在捕获中断中,把捕获寄存
器的值读取到 value3 中,并清除捕获记录标志。然后把捕获边沿设置为上升沿捕获。
3.PWM 输入模式
测量脉宽和频率还有一个更简便的方法就是使用 PWM 输入模式,该模式是输入捕获
的特例,只能使用通道 1 和通道 2 ,通道 3 和通道 4 使用不了。与上面那种只使用一个捕
获寄存器测量脉宽和频率的方法相比, PWM 输入模式需要占用两个捕获寄存器。
当使用 PWM 输入模式的时候,因为一个输入通道 (TIx) 会占用两个捕获通道 (ICx) ,所
以一个定时器在使用 PWM 输入的时候最多只能使用两个输入通道 (TIx) 。
我们以输入通道 TI1 工作在 PWM 输入模式为例来讲解下具体的工作原理,其他通道
以此类推即可。
PWM 信号由输入通道 TI1 进入,因为是 PWM 输入模式的缘故,信号会被分为两路,
一路是 TI1FP1 ,另外一路是 TI2FP2 。其中一路是周期,另一路是占空比,具体哪一路信
号对应周期还是占空比,得从程序上设置哪一路信号作为触发输入,作为触发输入的哪一
路信号对应的就是周期,另一路就是对应占空比。作为触发输入的那一路信号还需要设置
极性,是上升沿还是下降沿捕获,一旦设置好触发输入的极性,另外一路硬件就会自动配
置为相反的极性捕获,无需软件配置。一句话概括就是:选定输入通道,确定触发信号,
然后设置触发信号的极性即可,因为是 PWM 输入的缘故,另一路信号则由硬件配置,无
需软件配置。
当使用 PWM 输入模式的时候必须将从模式控制器配置为复位模式(配置寄存器
SMCR 的位 SMS[2:0] 来实现),即当我们启动触发信号开始进行捕获的时候,同时把计数
器 CNT 复位清零
一 . 二 输出比较应用
输出比较模式总共有 8 种,具体的由寄存器 CCMRx 的位 OCxM[2:0] 配置。我们这里
只讲解最常用的 PWM 模式,其他几种模式具体的看数据手册即可。
32.4.1 PWM 输出模式
PWM 输出就是对外输出脉宽(即占空比)可调的方波信号,信号频率由自动重装寄
存器 ARR 的值决定,占空比由比较寄存器 CCR 的值决定。
PWM 模式分为两种, PWM1 和 PWM2 ,总得来说是差不多,就看你怎么用而已,具
体的区别见表
1. PWM 边沿对齐模式
在递增计数模式下,计数器从 0 计数到自动重载值(
TIMx_ARR 寄存器的内容),然后重新
从 0 开始计数并生成计数器上溢事件
图 32-13 PWM1 模式的边沿对齐波形
在边沿对齐模式下,计数器 CNT 只工作在一种模式,递增或者递减模式。这里我们以
CNT 工作在递增模式为例,在中, ARR=8 , CCR=4 , CNT 从 0 开始计数,当 CNT 的
值时, OCxREF 为 有 效的 高 电平 ,于 此同 时, 比 较中 断寄 存器 CCxIF 置位。当
CCR= 时, OCxREF 为无效的低电平。然后 CNT 又从 0 开始计数并生成计数
器上溢事件,以此循环往复。
2. PWM 中心对齐模式
图 32-14 PWM1 模式的中心对齐波形
在中心对齐模式下,计数器 CNT 是工作做递增 / 递减模式下。开始的时候,计数器
CNT 从 0 开始计数到自动重载值减 1(ARR-1) ,生成计数器上溢事件;然后从自动重载值开
始向下计数到 1 并生成计数器下溢事件。之后从 0 开始重新计数。
图 32-14 是 PWM1 模式的中心对齐波形, ARR=8 , CCR=4 。第一阶段计数器 CNT 工
作在递增模式下,从 0 开始计数,当 CNT 的值时, OCxREF 为有效的高电平,当
CCR= 时, 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 。
二 定时器初始化结构体详解
在标准库函数头文件 stm32f4xx_tim.h 中对定时器外设建立了四个初始化结构体,分别
为 时 基 初 始 化 结 构 体 TIM_TimeBaseInitTypeDef 、 输 出 比 较 初 始 化 结 构 体
TIM_OCInitTypeDef 、输入捕获初始化结构体 TIM_ICInitTypeDef 和断路和死区初始化结构
体 TIM_BDTRInitTypeDef ,高级控制定时器可以用到所有初始化结构体,通用定时器不能
使用 TIM_BDTRInitTypeDef 结构体,基本定时器只能使用时基结构体。接下来我们具体讲
解下这四个结构体。
1. TIM_TimeBaseInitTypeDef
时 基 结 构 体 TIM_TimeBaseInitTypeDef 用 于 定 时 器 基 础 参 数 设 置 , 与
TIM_TimeBaseInit 函数配合使用完成配置。
代码清单 32-1 定时器基本初始化结构体
1 typedef struct {
2 uint16_t TIM_Prescaler; // 预分频器
3 uint16_t TIM_CounterMode; // 计数模式
4 uint32_t TIM_Period; // 定时器周期
5 uint16_t TIM_ClockDivision; // 时钟分频
6 uint8_t TIM_RepetitionCounter; // 重复计算器
7 } TIM_TimeBaseInitTypeDef;
(5) TIM_Prescaler :定时器预分频器设置,时钟源经该预分频器才是定时器计数时钟
CK_CNT ,它设定 PSC 寄存器的值。计算公式为:计数器时钟频率 (f CK_CNT ) 等于
f CK_PSC / (PSC[15:0] + 1) ,可实现 1 至 65536 分频。
(6) TIM_CounterMode :定时器计数方式,可设置为向上计数、向下计数以及中心对齐。
高级控制定时器允许选择任意一种。
(7) TIM_Period :定时器周期,实际就是设定自动重载寄存器 ARR 的值, ARR 为要装载
到实际自动重载寄存器(即影子寄存器)的值,可设置范围为 0 至 65535 。
(8) TIM_ClockDivision :时钟分频,设置定时器时钟 CK_INT 频率与死区发生器以及数字
滤波器采样时钟频率分频比。可以选择 1 、 2 、 4 分频。
(9) TIM_RepetitionCounter :重复计数器,只有 8 位,只存在于高级定时器。
2. TIM_OCInitTypeDef
输出比较结构体 TIM_OCInitTypeDef 用于输出比较模式,与 TIM_OCxInit 函数配合使
用完成指定定时器输出通道初始化配置。高级控制定时器有四个定时器通道,使用时都必
须单独设置。
代码清单 32-2 定时器比较输出初始化结构体
1 typedef struct {
2 uint16_t TIM_OCMode; // 比较输出模式
3 uint16_t TIM_OutputState; // 比较输出使能
4 uint16_t TIM_OutputNState; // 比较互补输出使能
5 uint32_t TIM_Pulse; // 脉冲宽度
6 uint16_t TIM_OCPolarity; // 输出极性
7 uint16_t TIM_OCNPolarity; // 互补输出极性
8 uint16_t TIM_OCIdleState; // 空闲状态下比较输出状态
9 uint16_t TIM_OCNIdleState; // 空闲状态下比较互补输出状态
10 } TIM_OCInitTypeDef;
(1) TIM_OCMode :比较输出模式选择,总共有八种,常用的为 PWM1/PWM2 。它设定
CCMRx 寄存器 OCxM[2:0] 位的值。
(2) TIM_OutputState :比较输出使能,决定最终的输出比较信号 OCx 是否通过外部引脚输
出。它设定 TIMx_CCER 寄存器 CCxE/CCxNE 位的值。
(3) TIM_OutputNState: 比较互补输出使能,决定 OCx 的互补信号 OCxN 是否通过外部引脚
输出。它设定 CCER 寄存器 CCxNE 位的值。
(4) TIM_Pulse :比较输出脉冲宽度,实际设定比较寄存器 CCR 的值,决定脉冲宽度。可
设置范围为 0 至 65535 。
(5) TIM_OCPolarity :比较输出极性,可选 OCx 为高电平有效或低电平有效。它决定着定
时器通道有效电平。它设定 CCER 寄存器的 CCxP 位的值。
(6) TIM_OCNPolarity :比较互补输出极性,可选 OCxN 为高电平有效或低电平有效。它
设定 TIMx_CCER 寄存器的 CCxNP 位的值。
(7) TIM_OCIdleState :空闲状态时通道输出电平设置,可选输出 1 或输出 0 ,即在空闲状
态 (BDTR_MOE 位为 0) 时,经过死区时间后定时器通道输出高电平或低电平。它设定
CR2 寄存器的 OISx 位的值。
(8) TIM_OCNIdleState :空闲状态时互补通道输出电平设置,可选输出 1 或输出 0 ,即在
空闲状态 (BDTR_MOE 位为 0) 时,经过死区时间后定时器互补通道输出高电平或低电
平,设定值必须与 TIM_OCIdleState 相反。它设定是 CR2 寄存器的 OISxN 位的值。
3. TIM_ICInitTypeDef
输入捕获结构体 TIM_ICInitTypeDef 用于输入捕获模式,与 TIM_ICInit 函数配合使用
完成定时器输入通道初始化配置。如果使用 PWM 输入模式需要与 TIM_PWMIConfig 函数
配合使用完成定时器输入通道初始化配置。
代码清单 32-3 定时器输入捕获初始化结构体
1 typedef struct {
2 uint16_t TIM_Channel; // 输入通道选择
3 uint16_t TIM_ICPolarity; // 输入捕获触发选择
4 uint16_t TIM_ICSelection; // 输入捕获选择
5 uint16_t TIM_ICPrescaler; // 输入捕获预分频器
6 uint16_t TIM_ICFilter; // 输入捕获滤波器
(1) TIM_Channel :捕获通道 ICx 选择,可选 TIM_Channel_1 、 TIM_Channel_2 、
TIM_Channel_3 或 TIM_Channel_4 四个通道。它设定 CCMRx 寄存器 CCxS 位 的值。
(2) TIM_ICPolarity :输入捕获边沿触发选择,可选上升沿触发、下降沿触发或边沿跳变触
发。它设定 CCER 寄存器 CCxP 位和 CCxNP 位的值。
(3) TIM_ICSelection :输入通道选择,捕获通道 ICx 的信号可来自三个输入通道,分别为
TIM_ICSelection_DirectTI 、 TIM_ICSelection_IndirectTI 或 TIM_ICSelection_TRC ,具
体的区别见图 32-15 。如果是普通的输入捕获, 4 个通道都可以使用,如果是 PWM 输
入则只能使用通道 1 和通道 2 。它设定 CCRMx 寄存器的 CCxS[1:0]位的值。
(4) TIM_ICPrescaler :输入捕获通道预分频器,可设置 1 、 2 、 4 、 8 分频,它设定 CCMRx
寄存器的 ICxPSC[1:0] 位的值。如果需要捕获输入信号的每个有效边沿,则设置 1 分频
即可。
(5) TIM_ICFilter :输入捕获滤波器设置,可选设置 0x0 至 0x0F 。它设定 CCMRx 寄存器
ICxF[3:0]位的值。一般我们不使用滤波器,即设置为 0。
4. TIM_BDTRInitTypeDef
断路和死区结构体 TIM_BDTRInitTypeDef 用于断路和死区参数的设置,属于高级定时
器专用,用于配置断路时通道输出状态,以及死区时间。它与 TIM_BDTRConfig 函数配置
使用完成参数配置。这个结构体的成员只对应 BDTR 这个寄存器,有关成员的具体使用配
置请参考手册 BDTR 寄存器的详细描述。
代码清单 32-4 断路和死区初始化结构体
1 typedef struct {
2 uint16_t TIM_OSSRState; // 运行模式下的关闭状态选择
3 uint16_t TIM_OSSIState; // 空闲模式下的关闭状态选择
4 uint16_t TIM_LOCKLevel; // 锁定配置
5 uint16_t TIM_DeadTime; // 死区时间
6 uint16_t TIM_Break; // 断路输入使能控制
7 uint16_t TIM_BreakPolarity; // 断路输入极性
8 uint16_t TIM_AutomaticOutput; // 自动输出使能
9 } TIM_BDTRInitTypeDef;
(1) TIM_OSSRState :运行模式下的关闭状态选择,它设定 BDTR 寄存器 OSSR 位的值。
(2) TIM_OSSIState :空闲模式下的关闭状态选择,它设定 BDTR 寄存器 OSSI 位的值。
(3) TIM_LOCKLevel :锁定级别配置, BDTR 寄存器 LOCK[1:0] 位的值。
(4) TIM_DeadTime :配置死区发生器,定义死区持续时间,可选设置范围为 0x0 至 0xFF 。
它设定 BDTR 寄存器 DTG[7:0] 位的值。
(5) TIM_Break :断路输入功能选择,可选使能或禁止。它设定 BDTR 寄存器 BKE 位的值。
(6) TIM_BreakPolarity :断路输入通道 BRK 极性选择,可选高电平有效或低电平有效。它
设定 BDTR 寄存器 BKP 位的值。
(7) TIM_AutomaticOutput :自动输出使能,可选使能或禁止,它设定 BDTR 寄存器 AOE
位的值。
三 PWM互补输出实验
输出比较模式比较多,这里我们以 PWM 输出为例讲解,并通过示波器来观察波形。
实验中不仅在主输出通道输出波形,还在互补通道输出与主通道互补的的波形,并且添加
了断路和死区功能。
硬件设计
根据开发板引脚使用情况,并且参考 中定时器引脚信息 ,使用高级定时器
TIM1 的通道 1 及其互补通道作为本实验的波形输出通道,对应选择 PA8 和 PB13 引脚。将
示波器的两个输入通道分别与 PA8 和 PB13 引脚连接,用于观察波形,还有注意共地。
为增加断路功能,需要用到 TIM1_BKIN 引脚,这里选择 PB12 引脚。程序我们设置该
引脚为高电平有效,当 BKIN 引脚被置高低电平的时候,两路互补的 PWM 输出就被停止,
就好像是刹车一样。
32.6.2 软件设计
1. 编程要点
(1) 定时器用到的 GP IO 初始化
(2) 定时器时基结构体 TIM_TimeBaseInitTypeDef 初始化
(3) 定时器输出比较结构体 TIM_OCInitTypeDef 初始化
(4) 定时器刹车和死区结构体 TIM_BDTRInitTypeDef 初始化
#include "advancetime.h"
//先把TIM1的gpio进行初始化:推挽复用输出
static void ADVANCE_TIM_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 输出比较通道PA8初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 输出比较通道互补通道PB13初始化
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 输出比较通道刹车通道 PB12 初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_ResetBits(GPIOB,GPIO_Pin_12);// BKIN引脚默认先输出低电平
}
//再配置定时器结构体成员初始化
static void ADVANCE_TIM_Mode_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);// 开启定时器时钟,即内部时钟CK_INT=72M
/*--------------------时基结构体初始化:确定计数器时钟频率与周期-------------------------*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period= (8-1);// 自动重装载ARR寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Prescaler= (9-1); // 驱动CNT计数器的时钟 = Fck_int/(psc+1) 72/(8+1) = 8M 信号频率:(8-1+1)/8 = 1M
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;// 时钟分频因子,不分频 ,配置死区时间时需要用到,随便配也可以 详见TIMxCR1寄存器8-9位
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;// 重复计数器的值,没用到不用管
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);// 初始化定时器
/*--------------------输出比较结构体初始化-------------------*/
TIM_OCInitTypeDef TIM_OCInitStructure;//设置c99标准支持任意地方初始化这个变量
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;// 配置为PWM模式1:平时用它
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 互补输出使能
TIM_OCInitStructure.TIM_Pulse = 4;// 设置占空比大小
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 输出通道电平极性配置
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;// 互补输出通道电平极性配置
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;// 输出通道空闲电平极性配置:当pwm用刹车时候会被禁止电平,这时候用这个set1电平
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;// 互补输出通道空闲电平极性配置
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM1, 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;//写入寄存器值11 即1011
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
// 当BKIN引脚检测到高电平的时候,输出比较信号被禁止,就好像是刹车一样
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
TIM_Cmd(TIM1, ENABLE); // 使能计数器
TIM_CtrlPWMOutputs(TIM1, ENABLE);// 主输出使能,当使用的是通用定时器时,这句不需要
}
void ADVANCE_TIM_Init(void)
{
ADVANCE_TIM_GPIO_Config();
ADVANCE_TIM_Mode_Config();
}
#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "rcc.h"
#include "exti.h"
#include "systick.h"
#include "usart.h"
#include
#include "basetime.h"
#include "advancetime.h"
//高级定时器1的通道1与互补通道输出1Mh 占空比50%的pwm,带刹车功能与死区时间。
int main(void)
{
ADVANCE_TIM_Init();
while (1){
}
}