【STM32】定时器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)代码

类似于舵机

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值