一、前言
利用STM32的TIM3的通道1输出PWM信号,驱动MG996R舵机,按键控制。
相关知识:TIM定时器基本原理,TIM输出PWM信号、MG996R舵机驱动原理
二、MG996R舵机简介
MG996R舵机单线驱动,是一款360°舵机,180°舵机与360°舵机的区别就是:180°舵机可以直接控制舵机旋转的角度,但舵机只能够旋转180°;360°舵机无法直接控制其旋转角度,只能控制其转动方向和速度。
舵机的驱动信号由周期为20ms的脉冲来控制:
- 当高电平持续时间为0.5~1.5ms时,舵机正转,时间越小转动越快
- 当高电平持续时间为1.5~2.5ms时,舵机反转,时间越大转动越快
- 当高电平持续时间为1.5ms或者其他时间时,舵机停止转动
三、通用定时器TIMx
通用TIMx定时器(TIM2、TIM3、TIM4和TIM5)功能主要包括如下:
16位向上、向下、向上/向下自动装载计数器
16位可编程(可以实时修改)预分频器,分频系数为1~65535
四种独立通道功能:
1.输入捕获
2.输出比较
3.PWM生成
4.单脉冲输出
使用外部信号控制定时器和定时器互连的同步电路
可以由如下事件触发中断或者DMA:
1.更新,即计数器溢出,或者计数器初始化
2.特定的触发事件,比如:计数器启动、停止、初始化等等
3.输入捕获
4.输出比较
支持针对定位的增量(正交)编码器和霍尔传感电路
触发输入作为外部时钟或者按周期的电流管理
可编程通用定时器的主要部分是一个16位计数器和其相关的自动装载寄存器,前面也说了,计数器可以向上、向下、双向计数。既然要计数,那就必须要知道计数的多少和每一次计数的时间。计数器的时钟由预分频器对时钟源分频得到。
时基单元包括:
计数器寄存器(TIMx_CNT)
预分频器寄存器(TIMx_PSC)
自动装载寄存器(TIMx_ARR)
计数器寄存器中存储的是当前计数的值,自动装载寄存器中存储的是目标计数值,当计数器溢出后,会重新装填目标计数值,而预分频器寄存器中的是对时钟的分频系数。
有专门的三个寄存器来控制PWM:
捕获/比较模式寄存器(TIMx_CCMR1/2)
捕获/比较使能寄存器(TIMx_CCER)
捕获/比较寄存器(TIMx_CCR1~4)
四、TIM3输出PWM信号代码详解
输出PWM用到的TIMx初始化结构体有:
1.时基初始化结构体TIM_TimeBaseInitTypeDef
2.输出比较初始化结构体TIM_OCInitTypeDef
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:预分频器设置,只有经过预分频器后的时钟才是CK_CNT,计数器时钟频率 (fCK_CNT) 等于fCK_PSC
/ (PSC[15:0] + 1),可实现 1 至 65536 分频。
TIM_CounterMode:定时器计数模式,可设置向上计数、向下计数和中心对齐计数三种模式。
TIM_Period:设置的是自动重装寄存器ARR的值,ARR为要装载到影子寄存器的值,可设置 1 至 65536 。
TIM_ClockDivision:时钟分频,设置定时器时钟 CK_INT 频率与死区发生器以及数字滤波器采样时钟频率分频比。可以选择 1、
2、 4 分频。 TIM_RepetitionCounter:重复计数器,只有八位,只存在与高级定时器。
typedef struct {
uint16_t TIM_OCMode; // 比较输出模式
uint16_t TIM_OutputState; // 比较输出使能
uint16_t TIM_OutputNState; // 比较互补输出使能
uint32_t TIM_Pulse; // 脉冲宽度
uint16_t TIM_OCPolarity; // 输出极性
uint16_t TIM_OCNPolarity; // 互补输出极性
uint16_t TIM_OCIdleState; // 空闲状态下比较输出状态
uint16_t TIM_OCNIdleState; // 空闲状态下比较互补输出状态
} TIM_OCInitTypeDef;
TIM_OCMode:比较输出模式选择,总共有八种,常用的为 PWM1/PWM2。它设定 CCMRx 寄存器 OCxM[2:0]位的值。
TIM_OutputState:比较输出使能,决定最终的输出比较信号 OCx 是否通过外部引脚输 出。它设定 TIMx_CCER 寄存器
CCxE/CCxNE 位的值。 TIM_OutputNState:比较互补输出使能,决定 OCx 的互补信号 OCxN 是否通过外部引脚
输出。它设定 CCER 寄存器 CCxNE 位的值。 TIM_Pulse:比较输出脉冲宽度,实际设定比较寄存器 CCR
的值,决定脉冲宽度。可 设置范围为 0 至 65535。 TIM_OCPolarity:比较输出极性,可选 OCx
为高电平有效或低电平有效。它决定着定 时器通道有效电平。它设定 CCER 寄存器的 CCxP 位的值。
TIM_OCNPolarity:比较互补输出极性,可选 OCxN 为高电平有效或低电平有效。它 设定 TIMx_CCER 寄存器的
CCxNP 位的值。 TIM_OCIdleState:空闲状态时通道输出电平设置,可选输出 1 或输出 0,即在空闲状 态(BDTR_MOE
位为 0)时,经过死区时间后定时器通道输出高电平或低电平。它设定 CR2 寄存器的 OISx 位的值。
TIM_OCNIdleState:空闲状态时互补通道输出电平设置,可选输出 1 或输出 0,即在 空闲状态(BDTR_MOE 位为
0)时,经过死区时间后定时器互补通道输出高电平或低电 平,设定值必须与 TIM_OCIdleState 相反。它设定是 CR2 寄存器的
OISxN 位的值。
当要输出PWM信号时只需要配置如下成员即可:
uint16_t TIM_OCMode; // 比较输出模式
uint16_t TIM_OCPolarity; // 输出极性
uint16_t TIM_OutputState; // 比较输出使能
输出极性决定了有效电平是高电平还是低电平
void GENERAL_TIM_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);
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);
// TIM_DeInit( TIM3 );
TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_PERIOD;
// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_PSC;
// 时钟分频因子 ,配置死区时间时需要用到
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
// 计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
// 初始化定时器
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
// 输出使能
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
// 输出通道电平极性配置
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR3;
TIM_OC3Init(GENERAL_TIM, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
// TIM_ARRPreloadConfig( TIM3, ENABLE );
TIM_Cmd( TIM3, ENABLE );
}
``
```c
// 输出PWM的频率为 72M/{ (ARR+1)*(PSC+1) }
#define GENERAL_TIM_PERIOD (200-1)
#define GENERAL_TIM_PSC (7200-1)
#define GENERAL_TIM_CCR3 0
主函数
while(1)
{
key=KEY_Scan(1); //得到键值
if(key)
{
switch(key)
{
case KEY1_PRES: //反向最大转速
TIM_SetCompare3(TIM3,25);
break;
case KEY0_PRES: //正向最大转速
TIM_SetCompare3(TIM3,5);
break;
case WE_UP_PRES:
TIM_SetCompare3(TIM3,15); //停止
break;
}
}
}
TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
函数改变ccr,从而改变PWM信号的占空比。
/*
20ms脉冲
5-14 正转,值越小,转的越快
16-25 反转,值越大,转的越快
*/