【STM32】定时器PWM功能深度解析:如何使用定时器2实现PWM输出
(基于江科大STM32教程)
一、理论部分
1、OC
(Output Compare)输出比较
通过比较CNT与CCR寄存器值的关系,对输出电平进行置1、置0或翻转的操作。
CNT:定时计数器寄存器; CCR:被比较单元,可操作更改;
如下图,设置模式为:
CNT向上计数,100溢出;CCR为30,CNT<=CCR置高电平,其余低。
2、PWM
(Pulse Width Modulation)脉冲宽度调制
在具有惯性的系统中(断电后不会立即停止,视觉上),可以通过对一系列脉冲的宽度进行调制(设置一定的CCR),来等效地获得所需要的模拟参量,如速度、亮度。
(1)PWM参数:
频率 = 1 / TS; 占空比 = TON / TS; 分辨率 = 占空比变化步距;
PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM占空比: Duty = CCR / (ARR + 1)
PWM分辨率: Reso = 1 / (ARR + 1)
(2)模式设置
3、基本流程
(1)时基
使用定时器TIM2,ARR,PSC根据需要重设定。
//时基
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=100-1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler=72-1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
(2)OC
配置OC,参数为结构体,包含诸多参数,在赋值前先使用TIM_OCStructInit(),初始化结构体,再更改需要的参数即可。
//OC
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse=0; //CCR
TIM_OC1Init(TIM2, &TIM_OCInitStructure); //OC1->GPIO(PA0)
TIM_Cmd(TIM2, ENABLE);
由于配置时基时采用TIM_CounterMode_Up向上计数,对应到此时OCMode配置为PWM1,表明CNT<CCR时输出高电平,CCR增大,占空比增大。此时不更改ARR(时基)来更改占空比,仅改变CCR。使用TIM_SetCompare1函数可以更改通道1的CCR,以此类推。
/**
* @brief Sets the TIMx Capture Compare1 Register value
* @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
* @param Compare1: specifies the Capture Compare1 register new value.
* @retval None
*/
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1)
{
/* Check the parameters */
assert_param(IS_TIM_LIST8_PERIPH(TIMx));
/* Set the Capture Compare1 Register value */
TIMx->CCR1 = Compare1;
}
(3)GPIO
经过OC后的电平需要通过GPIO口输出,那么需要配置相应的GPIO。
使用的TIM2通道1,对应的即为PA0,以此类推,如下:
同时参考8.1.11,OC的GPIO只能配置为复用推挽GPIO_Mode_AF_PP,如下:
//GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //只能使用复用推挽
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
每个高级定时器和通用定时器都拥有4个输出比较通道,高级定时器的前3个通道额外拥有死区生成和互补输出的功能。四个OC通道共用时基单元,更改对应通道的CCR以实现对应的PWM占空比。
二、代码部分
1、舵机
(1)驱动
舵机的三条接口分别对应5V电源(可从stlink上截取)、GND、PWM输入口。
根据下图可知,周期20ms,脉冲宽度在0.5ms~2.5ms,
freq=72M/(20k*72),T=20k*72/72M=20m,那么20k对应20ms,500~2500对应0.5~2.5ms
所以配置:ARR=20000-1,PSC=72-1
使用CH2,对应到PA1
//TIM
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=20000-1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler=72-1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//OC
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse=0; //CCR(500~2500)
TIM_OC2Init(TIM2, &TIM_OCInitStructure); //OC2->GPIO(PA1)
TIM_Cmd(TIM2, ENABLE);
(2)功能改良
采用长按按键有效,来驱动舵机(提供角加速度)
uint16_t Key_Judge(void)
{
temp=0;
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0)
{
temp=1;
}
return temp;
}
舵机角度在0~180连续(使用浮点型标记angle)活动,到达两侧后反向,转角在90度时速度较快,到达两侧时较慢,防止到达两侧时速度较快损坏。后期加入速度采集模块,添加反馈可以实现PID。
float angle=90;
uint16_t key_num;
uint8_t action=0;
uint8_t angle_action(void)
{
if(angle>=180)
action=1;
if(angle<=0)
action=0;
return action;
}
int main(void)
{
OLED_Init();
PWM_Init2();
Key_Init();
while(1)
{
key_num=Key_Judge();
if(key_num!=0)
{
if(!angle_action())
{
angle+=0.01*(181-angle);
}
else angle-=0.01*(angle+1);
}
PWM_Angle(angle);
OLED_ShowString(1, 1, "Angle:");
OLED_ShowNum(1, 8, angle, 3);
}
}
2、直流电机
(1)驱动
使用TB6612电机驱动模块,可驱动两个电机
PWMA AIN1 ANI2 AO1 AO2控制一个电机,PWMB BIN1 BNI2 BO1 BO2同理
以A通道为例,PWMA输入PWM波,AIN1、AIN2操控电机状态,对应的IO口要进行另外相应的初始化即可,模式如下:
(2)代码
类似于舵机
作者:Silveryyy