STM32之TIM 舵机控制PWM


/************高级定时器 TIM 参数定义,只限 TIM1 和 TIM8************/
/*************************************************************************************
PWM 信号的频率的计算为: F = TIM_CLK/{(ARR+1)*(PSC+1)}, 
其中 TIM_CLK 等于 72MHZ

TIM1 ch1输出比较通道
TIM1 chn1输出比较通道的互补通道
TIM1 输出比较通道的刹车通道

当使用不同的定时器的时候,对应的 GPIO 是不一样的,这点要注意
这里我们使用高级控制定时器 TIM1
************************************************************************************/


//定时器复用功能引脚初始化  
/* 使用TIM1 通道 ch1 PA8 ch1n PB13 */
static void TIM1_GPIO_CH12_Config(void)
{
      GPIO_InitTypeDef GPIO_InitStructure;
      // 输出比较通道 GPIO 初始化 
      // TIM1 输出比较通道
      // 输出比较通道 GPIO 初始化
      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);
      // 输出比较通道互补通道 GPIO 初始化
      // TIM1 输出比较通道的互补通道
      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);


      // 输出比较通道刹车通道 GPIO 初始化
      // TIM1 输出比较通道的刹车通道
/*     	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

     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);
	  
    // BKIN 引脚默认先输出低电平
      GPIO_ResetBits(GPIOB,GPIO_Pin_12);
*/
}



#define ADVANCE_TIM_PSC (720-1)           //周期 分频数PSC
#define ADVANCE_TIM_PERIOD (2000-1)        //计数个数ARR
#define ADVANCE_TIM_PULSE 150   			//占空比  与ARR相比较

// PWM 信号的频率 F = TIM_CLK/{(ARR+1)*(PSC+1)}
//定时器模式配置
static void TIM1_Mode_Config(void)
{
      // 开启定时器时钟,即内部时钟 CK_INT=72M
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,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(TIM1, &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( 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;
      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_TIM1_Init(void)
{
  TIM1_GPIO_CH12_Config();
  TIM1_Mode_Config();
  //外面使用这个控制函数控制占空比
	//TIM_SetCompare1(TIM1 , 70);
}

STM32F103ZET6高级控制和通用定时器通道引脚分布

  高级定时器 通用定时器
  TIM1 TIM8 TIM2 TIM5 TIM3 TIM4
CH1 PA8/PE9 PC6 PA0/PA15 PA0 PA6/PC6/PB4 PB6/PD12
CH1N PB13/PA7/PE8 PA7
CH2 PA9/PE11 PC7 PA1/PB3 PA1 PA7/PC7/PB5 PB7/PD13
CH2N PB14/PB0/PE10 PB0
CH3 PA10/PE13 PC8 PA2/PB10 PA2 PB0/PC8 PB8/PD14
CH3N PB15/PB1/PE12 PB1
CH4 PA11/PE14 PC9 PA3/PB11 PA3 PB1/PC9 PB9/PD15
ETR PA12/PE7 PA0 PA0/PA15 PD2 PE0
BKIN PB12/PA6/PE15 PA6

其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出
高级控制定时器(TIM1 和 TIM8)和通用定时器在基本定时器的基础上引入了外部引脚,可以实现输入捕获和输出比较功能。高级控制定时器比通用定时器增加了可编程死区互补输出、重复计数器、带刹车(断路)功能,这些功能都是针对工业电机控制方面。

输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常用的有测量输入信号的脉宽和测量 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]配置。
 

定时器初始化结构体详解
 

在标准库函数头文件 stm32f4xx_tim.h 中对定时器外设建立了四个初始化结构体,分别为 时 基 初 始 化 结 构 体 TIM_TimeBaseInitTypeDef 、 输 出 比 较 初 始 化 结 构 体TIM_OCInitTypeDef、输入捕获初始化结构体 TIM_ICInitTypeDef 和断路和死区初始化结构体 TIM_BDTRInitTypeDef,高级控制定时器可以用到所有初始化结构体,通用定时器不能使用 TIM_BDTRInitTypeDef 结构体,基本定时器只能使用时基结构体。接下来我们具体讲解下这四个结构体
 

1. TIM_TimeBaseInitTypeDef


时 基 结 构 体 TIM_TimeBaseInitTypeDef 用 于 定 时 器 基 础 参 数 设 置 , 与TIM_TimeBaseInit 函数配合使用完成配置。


定时器基本初始化结构体

typedef struct {
uint16_t TIM_Prescaler; // 预分频器
uint16_t TIM_CounterMode; // 计数模式
uint32_t TIM_Period; // 定时器周期
uint16_t TIM_ClockDivision; // 时钟分频
uint8_t TIM_RepetitionCounter; // 重复计算器
} TIM_TimeBaseInitTypeDef;

TIM_Prescaler:驱动 CNT 计数器的时钟 = Fck_int/(psc+1)

定时器预分频器设置,时钟源经该预分频器才是定时器计数时钟CK_CNT,它设定 PSC 寄存器的值。计算公式为: 计数器时钟频率 (fCK_CNT) 等于fCK_PSC / (PSC[15:0] + 1),可实现 1 至 65536 分频。
TIM_CounterMode设置计数模式

定时器计数方式,可设置为向上计数、向下计数以及中心对齐。高级控制定时器允许选择任意一种。
TIM_Period定时器周期,自动重装载寄存器的值,累计 TIM_Period+1 个频率后产生一个更新或者中断

实际就是设定自动重载寄存器 ARR 的值, ARR 为要装载到实际自动重载寄存器(即影子寄存器) 的值, 可设置范围为 0 至 65535。
TIM_ClockDivision时钟分频

设置定时器时钟 CK_INT 频率与死区发生器以及数字滤波器采样时钟频率分频比。可以选择 1、 2、 4 分频。
TIM_RepetitionCounter:重复计数器的值

重复计数器,只有 8 位,只存在于高级定时器。在开启了 TIM1 的时钟之后,我们要设置 ARR (TIM_Period)和 PSC (TIM_Prescaler)两个寄存器的值来控制输出 PWM 的周期。

TIM_OCInitTypeDef


输出比较结构体 TIM_OCInitTypeDef 用于输出比较模式,与 TIM_OCxInit 函数配合使用完成指定定时器输出通道初始化配置。高级控制定时器有四个定时器通道,使用时都必须单独设置。 PWM 通道设置是通过函数 TIM_OC1Init()~TIM_OC4Init()来设置的,不同的通道的设置函数不一样,使用的是通道 1,就使用的函数是 TIM_OC1Init()。 TIM_OutputNState, TIM_OCNPolarity,TIM_OCIdleState 和 TIM_OCNIdleState 是高级定时器 TIM1 和 TIM8 才用到的。


定时器比较输出初始化结构体
 

typedef struct {
uint16_t TIM_OCMode; // 比较输出模式
uint16_t TIM_OutputState; // 比较输出使能
uint16_t TIM_OutputNState; // 比较互补输出使能
uint32_t TIM_Pulse; // 脉冲宽度
uint16_t TIM_OCPolarity; // 输出极性--高级定时器 TIM1 和 TIM8 才用到的。
uint16_t TIM_OCNPolarity; // 互补输出极性--高级定时器 TIM1 和 TIM8 才用到的
uint16_t TIM_OCIdleState; // 空闲状态下比较输出状态--高级定时器 TIM1 和 TIM8 才用到的
uint16_t TIM_OCNIdleState; // 空闲状态下比较互补输出状态--高级定时器 TIM1 和 TIM8 才用到的
} 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 函数配合使用完成定时器输入通道初始化配置。
定时器输入捕获初始化结构体

typedef struct {
uint16_t TIM_Channel; // 输入通道选择
uint16_t TIM_ICPolarity; // 输入捕获触发选择
uint16_t TIM_ICSelection; // 输入捕获选择
uint16_t TIM_ICPrescaler; // 输入捕获预分频器
uint16_t TIM_ICFilter; // 输入捕获滤波器
} TIM_ICInitTypeDef;

(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 寄存器的详细描述。
断路和死区初始化结构体

typedef struct {
uint16_t TIM_OSSRState; // 运行模式下的关闭状态选择
uint16_t TIM_OSSIState; // 空闲模式下的关闭状态选择
uint16_t TIM_LOCKLevel; // 锁定配置
uint16_t TIM_DeadTime; // 死区时间
uint16_t TIM_Break; // 断路输入使能控制
uint16_t TIM_BreakPolarity; // 断路输入极性
uint16_t TIM_AutomaticOutput; // 自动输出使能
} 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 互补输出实验
 

舵机是一种电机,它使用一个反馈系统来控制电机的位置。大多数舵机是可以最大旋转180°的。也有一些能转更大角度,甚至360°。舵机比较多的用于对角度有要求的场合,比如摄像头,智能小车前置探测器,需要在某个范围内进行监测的移动平台。又或者把舵机放到玩具,让玩具动起来。还可以用多个舵机,做个小型机器人,舵机就可以作为机器人的关节部分。其实舵机就是一种伺服电机

舵机三根线:

一根是红色,连到+5V上。一根棕色(有些是黑的),连到GND。还有一根是黄色或者橘色,连到控制引脚。

怎么控制?

        PWM波,这是什么东西呢?其实就是一种方波,其频率为50Hz,周期就是20ms,在每个周期里面,高电平的占空比在0.5ms到2.5ms之间。而0.5ms代表的是0度,2.5ms代表的是180度。其他的度数可以直接按照比例换算过去

通过信号线给舵机发送一系列的周期信号(一般的舵机的能接收的信号周期为20ms),然后通过控制周期信号的高电平的持续时间来达到控制舵机转动的目的。我手上的舵机就是根据高电平持续时间(0.5ms~2.5ms)来实现0~180的转动的。

周期信号的产生可以使用很多方式,但是使用PWM来控制高电平的占空比不失为一种最好的应用方式。在STM32中,STM32的定时器也都提供有PWM的功能。下面就说明一下STM32输出PWM的具体实现方式。

使用STM32控制单个舵机

    在STM32中控制舵机,实际上就是开发STM32上的PWM功能,这部分功能需要配置STM32的定时器和GPIO复用共功能,然后就是通过修改定时器计数器的比较寄存器的数值来达到控制PWM的高电平占空比的目的。

(1) 定时器 IO 配置
(2) 定时器时基结构体 TIM_TimeBaseInitTypeDef 配置
(3) 定时器输出比较结构体 TIM_OCInitTypeDef 配置
(4) 定时器断路和死区结构体 TIM_BDTRInitTypeDef 配置
 


PWM 输出配置步骤(通过 TIM1_CH1 输出PWM 来控制 舵机?)

1) 开启 TIM1 时钟,配置 PA8 为复用输出。
要使用 TIM1,我们必须先开启 TIM1 的时钟,这里我们还要配置 PA8 为复用输出(当然还要时能 PORTA 的时钟),这是因为 TIM1_CH1 通 
道将使用 PA8 的复用功能作为输出。
库函数使能 TIM3 时钟的方法是:RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器 3 时钟
然后设置 PA8 为复用功能输出的。
2)设置 TIM1 的 ARR 和 PSC。
配置TIM_TimeBaseInitTypeDef结构体
TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值
3) 设置 TIM1_CH1 的 PWM 模式及通道方向, 使能 TIM1 的 CH1 输出。
配置TIM_OCInitTypeDef结构体
4) 使能 TIM1
需要使能 TIM1。使能 TIM1 的方法:TIM_Cmd(TIM1, ENABLE); //使能 TIM1
5) 设置 MOE 输出,使能 PWM 输出。(高级定时器才需要)
普通定时器在完成以上设置了之后, 就可以输出 PWM 了,但是高级定时器,我们还需要使能刹车和死区寄存器( TIM1_BDTR)的 MOE 位,以使能整个 OCx(即 PWM)输出。 库数的设置函数为:TIM_CtrlPWMOutputs(TIM1,ENABLE);// MOE 主输出使能
6) 修改 TIM1_CCR1 来控制占空比
最后,在经过以上设置之后, PWM 其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改 TIM1_CCR1 则可以控制 CH1 的输出占空比。
在库函数中,修改 TIM1_CCR1 占空比的函数是:
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
理所当然,对于其他通道,分别有一个函数名字,函数格式为 TIM_SetComparex(x=1,2,3,4)。

TIM2的通道一二,可惜被占用换成3

void RCC_config_TIM2_CH1(void )
{ 
    //使能复用以及GPIOB时钟  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA,ENABLE);
    //使能TIM2时钟 
     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

}

void TIM2_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    //PA0---TIM2通道1复用引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOB, &GPIO_InitStructure);
    //PA1--TIM2通道2复用引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOB, &GPIO_InitStructure);
}

void TIM2_CH1_PWM_OUT(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;

	uint16_t Prescaler =0,Period,Pulse;

	Prescaler = /*72M/36M - 1=*/ 1;
	Period = 36000-1;

        Pulse = 36000 *0.2;
	/*
	TIM2时基单元配置
	重要配置:TIM_Prescaler(预分频值)TIM_Period(定是周期)
	将TIM_Period设置成999,则计数器会数1000个(TIM_Period+1)
	节拍为一个定时器的周期。这个和后面需要配置的TIM_Pulse共同
	控制着定时器输出波形的占空比。
	
	TIM_Prescaler用来指定TIM时钟的分频值。也就是说它是进一步来
	分频TIM clock的。	简单来说也就是定时器每一次数数的时间间隔是多少。
	*/
	TIM_TimeBaseStructure.TIM_Prescaler = Prescaler;//预分频值
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_OutputState_Enable;
	TIM_TimeBaseStructure.TIM_Period = Period;//定是周期 决定输出频率
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分频因子
	TIM_TimeBaseInit(  TIM2, &TIM_TimeBaseStructure);

	/*
	TIM2通道1:pwm模式配置
	重要配置:TIM_Pulse(脉冲宽度)
	*/
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = Pulse;
	TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High;
	TIM_OC1Init( TIM2,  &TIM_OCInitStructure);
	TIM_OC2Init( TIM2,  &TIM_OCInitStructure);
        
	TIM_OC1PreloadConfig(TIM2,  TIM_OCPreload_Enable);//使能或者失能 TIMx 在 CCR1 上的预装载寄存器
        TIM_OC2PreloadConfig(TIM2,  TIM_OCPreload_Enable);//使能或者失能 TIMx 在 CCR1 上的预装载寄存器

	TIM_ARRPreloadConfig(TIM2, ENABLE);//使能或者失能 TIMx 在 ARR 上的预装载寄存器
	TIM_Cmd(TIM2, ENABLE);


}

void ADVANCE_TIM2_Init(void)
{
    RCC_config_TIM2_CH1();
    TIM2_GPIO_Config();
    TIM2_CH1_PWM_OUT();
    TIM_SetCompare1(TIM2 , 100);   // 修改 TIM1_CCR1 来控制占空比
    TIM_SetCompare2(TIM2 , 100);   // 修改 TIM1_CCR1 来控制占空比

}
//设置 TIMx 捕获比较 1 寄存器值
//每个捕获通道都有相对应的捕获寄存器 CCR1/2/3/4,
//原型  TIMx->CCR1 = Compare1;
//TIM_SetCompare1(TIM2 , 100);   // 修改 TIM1_CCR1 来控制占空比

猜你喜欢

转载自blog.csdn.net/c1063891514/article/details/81668181