STM32控制編碼器電機(jī)速度閉環(huán)實(shí)現(xiàn)



利用STM32高級(jí)定時(shí)器的互補(bǔ)輸出模式驅(qū)動(dòng)電機(jī)運(yùn)行
/**
? * 函數(shù)功能: BDCMOTOR定時(shí)器初始化
? * 輸入?yún)?shù): 無
? * 返 回 值: 無
? * 說? ? 明: 無
? */
void BDCMOTOR_TIMx_Init(void)
{
? TIM_ClockConfigTypeDef sClockSourceConfig;? ? ? ? ? ? ?// 定時(shí)器時(shí)鐘
? TIM_OC_InitTypeDef sConfigOC;? ? ? ? ? ? ? ? ? ? ? ? ? // 定時(shí)器通道比較輸出
? TIM_BreakDeadTimeConfigTypeDef? sBDTConfig;? ? ? ? ? ? // 定時(shí)器死區(qū)時(shí)間比較輸出
? /* 基本定時(shí)器外設(shè)時(shí)鐘使能 */
? BDCMOTOR_TIM_RCC_CLK_ENABLE();
? /* 定時(shí)器基本環(huán)境配置 */
? htimx_BDCMOTOR.Instance = BDCMOTOR_TIMx;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 定時(shí)器編號(hào)
? htimx_BDCMOTOR.Init.Prescaler = BDCMOTOR_TIM_PRESCALER;? ? ? ? ? ? ? ? ? // 定時(shí)器預(yù)分頻器
? htimx_BDCMOTOR.Init.CounterMode = TIM_COUNTERMODE_UP;? ? ? ? ? ? ? ? ? // 計(jì)數(shù)方向:向上計(jì)數(shù)
? htimx_BDCMOTOR.Init.Period = BDCMOTOR_TIM_PERIOD;? ? ? ? ? ? ? ? ? ? ? ? // 定時(shí)器周期
? htimx_BDCMOTOR.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;? ? ? ? ? ? ? // 時(shí)鐘分頻
? htimx_BDCMOTOR.Init.RepetitionCounter = BDCMOTOR_TIM_REPETITIONCOUNTER;? // 重復(fù)計(jì)數(shù)器
? /* 初始化定時(shí)器比較輸出環(huán)境 */
? HAL_TIM_PWM_Init(&htimx_BDCMOTOR);
? /* 定時(shí)器時(shí)鐘源配置 */
? sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;? ? ? ?// 使用內(nèi)部時(shí)鐘源
? HAL_TIM_ConfigClockSource(&htimx_BDCMOTOR, &sClockSourceConfig);
? /* 死區(qū)剎車配置,配置有效電平是低電平 */
? sBDTConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE ;
? sBDTConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW ;
? sBDTConfig.BreakState = TIM_BREAK_DISABLE ;
? sBDTConfig.DeadTime = 0 ;
? sBDTConfig.LockLevel = TIM_LOCKLEVEL_OFF ;
? sBDTConfig.OffStateIDLEMode= TIM_OSSI_DISABLE ;
? sBDTConfig.OffStateRunMode = TIM_OSSR_ENABLE ;
? HAL_TIMEx_ConfigBreakDeadTime(&htimx_BDCMOTOR,&sBDTConfig);
? /* 定時(shí)器比較輸出配置 */
? sConfigOC.OCMode = TIM_OCMODE_PWM1;? ? ? ? ? ? ? ? ? // 比較輸出模式:PWM1模式
? sConfigOC.Pulse =? PWM_Duty;? ? ? ? ? ? ? ? ? ? ? ? ?// 占空比
? sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;? ? ? ? ? // 輸出極性
? sConfigOC.OCNPolarity = TIM_OCNPOLARITY_LOW;? ? ? ? // 互補(bǔ)通道輸出極性
? sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;? ? ? ? ? ?// 快速模式
? sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;? ? ? ?// 空閑電平
? sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;? ? ?// 互補(bǔ)通道空閑電平
? HAL_TIM_PWM_ConfigChannel(&htimx_BDCMOTOR, &sConfigOC, TIM_CHANNEL_1);
? HAL_TIM_Base_Start(&htimx_BDCMOTOR);
}

電機(jī)控制的幾個(gè)基本操作又一下幾個(gè)函數(shù)完成
/**
? * 函數(shù)功能: 設(shè)置電機(jī)速度
? * 輸入函數(shù): Duty,輸出脈沖占空比
? * 返 回 值: 無
? * 說? ? 明: 無
? */
void SetMotorSpeed(int16_t Duty)
{
? __HAL_TIM_SetCompare(&htimx_BDCMOTOR,TIM_CHANNEL_1,Duty);
}
/**
? * 函數(shù)功能: 設(shè)置電機(jī)轉(zhuǎn)動(dòng)方向
? * 輸入函數(shù): Dir,電機(jī)轉(zhuǎn)動(dòng)方向
? * 返 回 值: 無
? * 說? ? 明: 無
? */
void SetMotorDir(int16_t Dir)
{
? if(Dir)
? {
? ? HAL_TIM_PWM_Start(&htimx_BDCMOTOR,TIM_CHANNEL_1);
? ? HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);? ? ? ? ?// 停止輸出
? }
? else
? {
? ? HAL_TIM_PWM_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);
? ? HAL_TIMEx_PWMN_Start(&htimx_BDCMOTOR,TIM_CHANNEL_1);? ? ? ? ?// 停止輸出
? }
}
/**
? * 函數(shù)功能: 設(shè)置電機(jī)停止
? * 輸入函數(shù): 無
? * 返 回 值: 無
? * 說? ? 明: 無
? */
void SetMotorStop()
{
? HAL_TIM_PWM_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);
? HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);? ? ? ? ?// 停止輸出
}
/**
? * 函數(shù)功能: 設(shè)置電機(jī)啟動(dòng)
? * 輸入函數(shù): 無
? * 返 回 值: 無
? * 說? ? 明: 無
? */
void SetMotorStart()
{
? HAL_TIM_PWM_Start(&htimx_BDCMOTOR,TIM_CHANNEL_1);
? HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);? ? ? ? ?// 停止輸出
}

電機(jī)速度控制反饋信號(hào)是利用STM32定時(shí)器編碼器模式讀取電機(jī)編碼器脈沖信號(hào)
/**
? * 函數(shù)功能: 通用定時(shí)器初始化并配置編碼器模式
? * 輸入?yún)?shù): 無
? * 返 回 值: 無
? * 說? ? 明: 無
? */
void ENCODER_TIMx_Init(void)
{
? ENCODER_TIM_RCC_CLK_ENABLE();
? htimx_Encoder.Instance = ENCODER_TIMx;
? htimx_Encoder.Init.Prescaler = ENCODER_TIM_PRESCALER;
? htimx_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP;
? htimx_Encoder.Init.Period = ENCODER_TIM_PERIOD;
? htimx_Encoder.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
? sEncoderConfig.EncoderMode? ? ? ? = TIM_ENCODERMODE_TIx;
? sEncoderConfig.IC1Polarity? ? ? ? = TIM_ICPOLARITY_RISING;
? sEncoderConfig.IC1Selection? ? ? ?= TIM_ICSELECTION_DIRECTTI;
? sEncoderConfig.IC1Prescaler? ? ? ?= TIM_ICPSC_DIV1;
? sEncoderConfig.IC1Filter? ? ? ? ? = 0;
? sEncoderConfig.IC2Polarity? ? ? ? = TIM_ICPOLARITY_RISING;
? sEncoderConfig.IC2Selection? ? ? ?= TIM_ICSELECTION_DIRECTTI;
? sEncoderConfig.IC2Prescaler? ? ? ?= TIM_ICPSC_DIV1;
? sEncoderConfig.IC2Filter? ? ? ? ? = 0;
? __HAL_TIM_SET_COUNTER(&htimx_Encoder,0);
? HAL_TIM_Encoder_Init(&htimx_Encoder, &sEncoderConfig);
? __HAL_TIM_CLEAR_IT(&htimx_Encoder, TIM_IT_UPDATE);? // 清除更新中斷標(biāo)志位
? __HAL_TIM_URS_ENABLE(&htimx_Encoder);? ? ? ? ? ? ? ?// 僅允許計(jì)數(shù)器溢出才產(chǎn)生更新中斷
? __HAL_TIM_ENABLE_IT(&htimx_Encoder,TIM_IT_UPDATE);? // 使能更新中斷
? HAL_NVIC_SetPriority(ENCODER_TIM_IRQn, 0, 0);
? HAL_NVIC_EnableIRQ(ENCODER_TIM_IRQn);
? HAL_TIM_Encoder_Start(&htimx_Encoder, TIM_CHANNEL_ALL);
}



編碼器電機(jī)速度閉環(huán)控制由PID算法在調(diào)控周期里進(jìn)行反饋調(diào)整
/**
? * 函數(shù)名稱:速度閉環(huán)PID控制設(shè)計(jì)
? * 輸入?yún)?shù):當(dāng)前控制量
? * 返 回 值:目標(biāo)控制量
? * 說? ? 明:無
? */
int32_t SpdPIDCalc(float NextPoint)
{
? float iError,iIncpid;
? iError = (float)sPID.SetPoint - NextPoint; //偏差
? if((iError<0.2f )&& (iError>-0.2f))
? ? iError = 0.0f;
? iIncpid=(sPID.Proportion * iError)? ? ? ? ? ? ? ? ?//E[k]項(xiàng)
? ? ? ? ? ? ? -(sPID.Integral * sPID.LastError)? ? ?//E[k-1]項(xiàng)
? ? ? ? ? ? ? +(sPID.Derivative * sPID.PrevError);? //E[k-2]項(xiàng)
? sPID.PrevError = sPID.LastError;? ? ? ? ? ? ? ? ? ? //存儲(chǔ)誤差,用于下次計(jì)算
? sPID.LastError = iError;
? return(iIncpid);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //返回增量值
}
? /* 速度環(huán)周期100ms */
? if(uwTick % pid_n_s == 0) //到達(dá)一個(gè)調(diào)控周期
? {
? ? //Spd_Pulse? 編碼器捕獲值 Pulse = 累計(jì)捕獲中斷次數(shù)*65535 + 通過編碼器接口HAL接口讀取的脈沖數(shù)
Spd_Pulse = (OverflowCount*CNT_MAX) + (int32_t)__HAL_TIM_GET_COUNTER(&htimx_Encoder);
? ? //檢測周期里累計(jì)的脈沖數(shù)=編碼器捕獲的脈沖數(shù) - 上次捕獲的脈沖值
? ? Spd_PPS = Spd_Pulse - LastSpd_Pulse;
//記錄為上次捕獲的脈沖值(為下次計(jì)算使用
? ? LastSpd_Pulse = Spd_Pulse ;
? ? /*變量pid_1=(圈數(shù)/周期)*/
float pid_1 = (float)Spd_PPS/(float)PPR ;
//pid_1:pid_n_s周期內(nèi)電機(jī)轉(zhuǎn)動(dòng)的圈數(shù)=周期內(nèi)捕獲的脈沖數(shù) / 每圈的脈沖數(shù)
/*變量pid_2=(轉(zhuǎn)/毫秒)*/
float pid_2 = pid_1 / (float)pid_n_s ;
//pid_2:計(jì)算實(shí)際測量速度(轉(zhuǎn)/毫秒)=周期內(nèi)轉(zhuǎn)過的圈數(shù) / 周期時(shí)間值 (因?yàn)橹芷趩挝粸楹撩耄?/span>
/*Spd_RPM=(轉(zhuǎn)/秒)*/
Spd_RPM = pid_2 * (float)1000 ;//單位轉(zhuǎn)換為(轉(zhuǎn)/秒)
? ?
? ? /* 計(jì)算PID結(jié)果 */
? ? if(Start_flag == 1)
? ? {
? ? ? PWM_Duty += SpdPIDCalc(Spd_RPM);
? ? ? /* 判斷當(dāng)前運(yùn)動(dòng)方向 */
? ? ? if(PWM_Duty < 0)
? ? ? {
? ? ? ? Motor_Dir = CW;
? ? ? ? BDDCMOTOR_DIR_CW();
? ? ? ? SetMotorSpeed(-PWM_Duty);
? ? ? }
? ? ? else
? ? ? {
? ? ? ? Motor_Dir = CCW;
? ? ? ? BDDCMOTOR_DIR_CCW();
? ? ? ? SetMotorSpeed(PWM_Duty);
? ? ? }
? ? }
? }
