? 小車使用的電機是12v供電的直流電機,帶編碼器反饋,這樣就可以采用閉環(huán)速度控制,這里電機使用PWM驅(qū)動,速度控制框圖如下:
由以上框圖可知,STM32通過定時器模塊輸出PWM波來控制兩個直流電機的轉(zhuǎn)動,通過改變PWM占空比的大小可以改變電機的轉(zhuǎn)速,由于我們的控制目標(biāo)是實現(xiàn)電機運行在速度范圍內(nèi)任意給定的速度,這里就需要采用閉環(huán)控制的思想,通過編碼器獲取電機的實時轉(zhuǎn)速,通過與給定速度做差,將偏差作為PID控制器的輸入,通過PID控制改變PWM占空比的大小,從而使電機的速度運行在給定的速度上。
這里使用的電機驅(qū)動芯片為TB6612,該芯片可以十分方便的驅(qū)動兩個直流電機的運行,其驅(qū)動邏輯表如下:
AIN1,AIN2的不同組合可以實現(xiàn)電機的正反轉(zhuǎn)和停車,PWMA為PWM的輸入引腳,通過輸入不同的占空比可以改變電機轉(zhuǎn)速的快慢。BIN1,BIN2,PWMB是控制另一路電機的引腳。
首先我們需要利用STM32的定時器模塊輸出兩路PWM波,這是使電機轉(zhuǎn)起來的第一步。初始化PWM:
//初始化PWM引腳
void motorPWMPin_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_11
;//TIM1_Chn_1,TIM1_Chn_2
GPIO_Init(GPIOE,&GPIO_InitStructure);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_TIM1);
}
//初始化PWM
void motorPWM_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrecture;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
TIM_TimeBaseInitStrecture.TIM_Period = 400;/*PWM's frequency is 20KHz*/
TIM_TimeBaseInitStrecture.TIM_Prescaler =21-1;//將TIM1的時鐘頻率設(shè)定為8MHz
TIM_TimeBaseInitStrecture.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStrecture.TIM_CounterMode =
TIM_CounterMode_Up;//定時器向上計數(shù)
TIM_TimeBaseInitStrecture.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStrecture);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High ;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1,&TIM_OCInitStructure);
TIM_OC2Init(TIM1,&TIM_OCInitStructure);
// TIM_Cmd(TIM1,ENABLE);
TIM_CtrlPWMOutputs(TIM1,ENABLE);
}
然后初始化電機控制引腳,程序如下:
//初始化電機控制引腳
void motorCtrlPin_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
//PE7,PE8控制電機A,PE9,PE10控制電機B
GPIO_InitStructure.GPIO_Pin =
GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOE, &GPIO_InitStructure);
}
需要注意的是設(shè)置PWM輸出引腳時要講引腳復(fù)用到定時器TIM1,而電機控制引腳只需要設(shè)置成簡單的推挽輸出模式即可。
接著我們需要使用兩個定時器的編碼器功能用于讀取電機的實時轉(zhuǎn)動速度,這里我使用的是定時器3和定時器4.
這里的編碼器是精度較低的霍爾感應(yīng)式編碼器,但是基本滿足控制精度的要求,驅(qū)動代碼如下:
void encoderA_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
/*CLOCK Enable*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //PC6,PC7
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//復(fù)用引腳模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //無上下拉
/*Configure PC6,PC7 as encoder A,B Input*/
GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM3);
GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM3);
GPIO_Init(GPIOC,&GPIO_InitStructure); //initialize PORTC
/* Timer configuration in Encoder mode */
/* Enable the TIM3 Update Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0; //不分頻
TIM_TimeBaseStructure.TIM_Period = 65535; //設(shè)置為最大
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up ; //向上計數(shù)
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,
TIM_ICPolarity_Rising , TIM_ICPolarity_Rising );//上升沿計數(shù)
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 10;//設(shè)置濾波系數(shù)
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_ClearFlag(TIM3, TIM_FLAG_Update); //清除更新中斷
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //使能更新中斷
TIM3->CNT = 0;//將計數(shù)值設(shè)為0
TIM_Cmd(TIM3, ENABLE);//enable TIM3
printf("Encoder_A initializztion is OK\n");
}
stm32視頻資料
(stm32直流電機驅(qū)動)
http://www.makeru.com.cn/live/1392_1218.html?s=45051
(stm32 USART串口應(yīng)用)
http://www.makeru.com.cn/live/1392_1164.html?s=45051
PWM脈寬調(diào)制技術(shù)