標(biāo)題:
STM32編程實(shí)現(xiàn)直流電機(jī)位置速度PID雙閉環(huán)控制 HAL庫(kù)源程序
[打印本頁(yè)]
作者:
嬡悅意
時(shí)間:
2021-7-23 15:44
標(biāo)題:
STM32編程實(shí)現(xiàn)直流電機(jī)位置速度PID雙閉環(huán)控制 HAL庫(kù)源程序
雙環(huán)閉環(huán)
單片機(jī)源程序如下:
/**
******************************************************************************
* 文件名程: main.c
* 作 者: 學(xué)習(xí)小組
* 功 能: GM37-545_位置速度閉環(huán)控制
******************************************************************************
* 說(shuō)明:
******************************************************************************
*/
/* 包含頭文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "key.h"
#include "encoder.h"
#include "usartx.h"
#include "BDCMotor.h"
/* 私有類(lèi)型定義 --------------------------------------------------------------*/
typedef struct
{
__IO int32_t SetPoint; //設(shè)定目標(biāo) Desired Value
__IO float SumError; //誤差累計(jì)
__IO float Proportion; //比例常數(shù) Proportional Const
__IO float Integral; //積分常數(shù) Integral Const
__IO float Derivative; //微分常數(shù) Derivative Const
__IO int LastError; //Error[-1]
__IO int PrevError; //Error[-2]
}PID_TypeDef;
/* 私有宏定義 ----------------------------------------------------------------*/
#define SPEEDRATIO 270
#define ENCODER_RESOLUTION 11
#define PPR ((SPEEDRATIO*ENCODER_RESOLUTION)*4) // Pulse/Round 每圈可捕獲到的脈沖數(shù)
/*************************************/
// 定義PID相關(guān)宏
// 這三個(gè)參數(shù)設(shè)定對(duì)電機(jī)運(yùn)行影響非常大
// PID參數(shù)跟采樣時(shí)間息息相關(guān)
/*************************************/
#define SPD_P_DATA 50.0f // P參數(shù)
#define SPD_I_DATA 8.5f // I參數(shù)
#define SPD_D_DATA 0.0f // D參數(shù)
#define TARGET_SPEED 10.0f // 目標(biāo)速度 10r/m
#define LOC_P_DATA 0.01f // P參數(shù)
#define LOC_I_DATA 0.0f // D參數(shù)
#define LOC_D_DATA 0.08f // D參數(shù)
#define TARGET_LOC (3*PPR) // 目標(biāo)位置 11880 Pulse = 1r
/* 私有變量 ------------------------------------------------------------------*/
__IO uint8_t Start_flag = 0; // PID 開(kāi)始標(biāo)志
uint32_t Motor_Dir = CW; // 電機(jī)方向
__IO int32_t tmpPWM_DutySpd = 0;
__IO int32_t tmpPWM_Duty = 0;
__IO int32_t Sample_Pulse; // 編碼器捕獲值 Pulse
__IO int32_t LastSample_Pulse; // 編碼器捕獲值 Pulse
__IO int32_t Spd_PPS; // 速度值 Pulse/Sample
__IO float Spd_RPM; // 速度值 r/m
/* 擴(kuò)展變量 ------------------------------------------------------------------ */
extern __IO uint32_t uwTick;
/* PID結(jié)構(gòu)體 */
PID_TypeDef sPID,lPID; // PID參數(shù)結(jié)構(gòu)體
/* 擴(kuò)展變量 ------------------------------------------------------------------*/
/* 私有函數(shù)原形 --------------------------------------------------------------*/
void PID_ParamInit(void) ;
int32_t SpdPIDCalc(float NextPoint);
int32_t LocPIDCalc(int32_t NextPoint);
/* 函數(shù)體 --------------------------------------------------------------------*/
/**
* 函數(shù)功能: 系統(tǒng)時(shí)鐘配置
* 輸入?yún)?shù): 無(wú)
* 返 回 值: 無(wú)
* 說(shuō) 明: 無(wú)
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__HAL_RCC_PWR_CLK_ENABLE(); // 使能PWR時(shí)鐘
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); // 設(shè)置調(diào)壓器輸出電壓級(jí)別1
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 外部晶振,8MHz
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // 打開(kāi)HSE
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // 打開(kāi)PLL
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL時(shí)鐘源選擇HSE
RCC_OscInitStruct.PLL.PLLM = 8; // 8分頻MHz
RCC_OscInitStruct.PLL.PLLN = 336; // 336倍頻
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // 2分頻,得到168MHz主時(shí)鐘
RCC_OscInitStruct.PLL.PLLQ = 7; // USB/SDIO/隨機(jī)數(shù)產(chǎn)生器等的主PLL分頻系數(shù)
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 系統(tǒng)時(shí)鐘:168MHz
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB時(shí)鐘: 168MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // APB1時(shí)鐘:42MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // APB2時(shí)鐘:84MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
HAL_RCC_EnableCSS(); // 使能CSS功能,優(yōu)先使用外部晶振,內(nèi)部時(shí)鐘源為備用
// HAL_RCC_GetHCLKFreq()/1000 1ms中斷一次
// HAL_RCC_GetHCLKFreq()/100000 10us中斷一次
// HAL_RCC_GetHCLKFreq()/1000000 1us中斷一次
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); // 配置并啟動(dòng)系統(tǒng)滴答定時(shí)器
/* 系統(tǒng)滴答定時(shí)器時(shí)鐘源 */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* 系統(tǒng)滴答定時(shí)器中斷優(yōu)先級(jí)配置 */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/**
* 函數(shù)功能: 主函數(shù).
* 輸入?yún)?shù): 無(wú)
* 返 回 值: 無(wú)
* 說(shuō) 明: 無(wú)
*/
int main(void)
{
/* 復(fù)位所有外設(shè),初始化Flash接口和系統(tǒng)滴答定時(shí)器 */
HAL_Init();
/* 配置系統(tǒng)時(shí)鐘 */
SystemClock_Config();
/* 串口初始化 */
MX_USARTx_Init();
/* 按鍵初始化 */
KEY_GPIO_Init();
/* 編碼器初始化及使能編碼器模式 */
ENCODER_TIMx_Init();
/* 高級(jí)控制定時(shí)器初始化并配置PWM輸出功能 */
BDCMOTOR_TIMx_Init();
/* 啟動(dòng)定時(shí)器通道和互補(bǔ)通道PWM輸出 */
PWM_Duty = 0;
__HAL_TIM_SET_COMPARE(&htimx_BDCMOTOR,TIM_CHANNEL_1,PWM_Duty); // 0%
/* PID 參數(shù)初始化 */
PID_ParamInit();
/* 無(wú)限循環(huán) */
while (1)
{
/* 停止按鈕 */
if(KEY1_StateRead()==KEY_DOWN)
{
if( lPID.Proportion < 0 )
{
Motor_Dir = CW;
BDDCMOTOR_DIR_CW();
PWM_Duty = -PWM_Duty;
}
else
{
Motor_Dir = CCW;
BDDCMOTOR_DIR_CCW();
}
__HAL_TIM_SET_COMPARE(&htimx_BDCMOTOR,TIM_CHANNEL_1,0); // 0%
Start_flag = 1;
}
if(KEY2_StateRead()==KEY_DOWN)
{
SHUTDOWN_MOTOR();
HAL_TIM_PWM_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1); // 停止輸出
}
if(KEY3_StateRead()==KEY_DOWN) // 圈數(shù)+1
{
lPID.SetPoint += PPR;
}
if(KEY4_StateRead()==KEY_DOWN) // 圈數(shù)-1
{
lPID.SetPoint -= PPR;
}
}
}
/**
* 函數(shù)功能: 系統(tǒng)滴答定時(shí)器中斷回調(diào)函數(shù)
* 輸入?yún)?shù): 無(wú)
* 返 回 值: 無(wú)
* 說(shuō) 明: 每隔一定的時(shí)間就執(zhí)行pid算法
*/
void HAL_SYSTICK_Callback(void)
{
__IO int32_t ADC_Resul= 0;
__IO float Volt_Result = 0;
/* 位置環(huán)周期100ms */
if(uwTick % 100 == 0)
{
/* 獲取當(dāng)前位置值,編碼器4倍頻之后的數(shù)值 */
Sample_Pulse = (OverflowCount*CNT_MAX) + (int32_t)__HAL_TIM_GET_COUNTER(&htimx_Encoder);
/* 計(jì)算PID結(jié)果 */
if(Start_flag == 1)
{
tmpPWM_DutySpd = LocPIDCalc(Sample_Pulse);
/* 設(shè)定速度環(huán)的目標(biāo)值 */
if(tmpPWM_DutySpd >= TARGET_SPEED)
tmpPWM_DutySpd = TARGET_SPEED;
if(tmpPWM_DutySpd <= -TARGET_SPEED)
tmpPWM_DutySpd = -TARGET_SPEED;
}
}
/* 速度環(huán)周期50ms */
if(uwTick % 50 == 0)
{
/* 獲得當(dāng)前速度 */
Sample_Pulse = (OverflowCount*CNT_MAX) + \
(int32_t)__HAL_TIM_GET_COUNTER(&htimx_Encoder);
Spd_PPS = Sample_Pulse - LastSample_Pulse;
LastSample_Pulse = Sample_Pulse ;
/* 11線(xiàn)編碼器,270減速比,一圈脈沖信號(hào)是11*270*4 PPR */
Spd_RPM = ((((float)Spd_PPS/(float)PPR)*20.0f)*(float)60);//單位是rpm
/* 計(jì)算PID結(jié)果 */
if(Start_flag == 1)
{
sPID.SetPoint = tmpPWM_DutySpd;
PWM_Duty = SpdPIDCalc(Spd_RPM);
if(PWM_Duty < 0)
{
Motor_Dir = CW;
BDDCMOTOR_DIR_CW();
PWM_Duty = -PWM_Duty;
}
else
{
Motor_Dir = CCW;
BDDCMOTOR_DIR_CCW();
}
__HAL_TIM_SET_COMPARE(&htimx_BDCMOTOR,TIM_CHANNEL_1,PWM_Duty );
}
printf("LOC:%d Sped: %2.2f r/m \n",Sample_Pulse,
Spd_RPM );
}
}
/******************** PID 控制設(shè)計(jì) ***************************/
/**
* 函數(shù)功能: PID參數(shù)初始化
* 輸入?yún)?shù): 無(wú)
* 返 回 值: 無(wú)
* 說(shuō) 明: 無(wú)
*/
void PID_ParamInit()
{
sPID.LastError = 0; // Error[-1]
sPID.PrevError = 0; // Error[-2]
sPID.Proportion = SPD_P_DATA; // 比例常數(shù) Proportional Const
sPID.Integral = SPD_I_DATA; // 積分常數(shù) Integral Const
sPID.Derivative = SPD_D_DATA; // 微分常數(shù) Derivative Const
sPID.SetPoint = TARGET_SPEED; // 設(shè)定目標(biāo)Desired Value
lPID.LastError = 0; // Error[-1]
lPID.PrevError = 0; // Error[-2]
lPID.Proportion = LOC_P_DATA; // 比例常數(shù) Proportional Const
lPID.Integral = LOC_I_DATA; // 積分常數(shù) Integral Const
lPID.Derivative = LOC_D_DATA; // 微分常數(shù) Derivative Const
lPID.SetPoint = TARGET_LOC; // 設(shè)定目標(biāo)Desired Value
}
/**
* 函數(shù)名稱(chēng):速度閉環(huán)PID控制設(shè)計(jì)
* 輸入?yún)?shù):當(dāng)前控制量
* 返 回 值:目標(biāo)控制量
* 說(shuō) 明:無(wú)
*/
int32_t SpdPIDCalc(float NextPoint)
{
float iError,dError;
iError = sPID.SetPoint - NextPoint; //偏差
if((iError<0.2f )&& (iError>-0.2f))
iError = 0.0f;
sPID.SumError += iError; //積分
/* 設(shè)定積分上限 */
if(lPID.SumError >= TARGET_SPEED*10)
lPID.SumError = TARGET_SPEED*10;
if(lPID.SumError <= -TARGET_SPEED*10)
lPID.SumError = -TARGET_SPEED*10;
dError = iError - sPID.LastError; //微分
sPID.LastError = iError;
return (int32_t)(sPID.Proportion * (float)iError //比例項(xiàng)
+ sPID.Integral * (float)sPID.SumError //積分項(xiàng)
+ sPID.Derivative * (float)dError); //微分項(xiàng)
}
/**
* 函數(shù)名稱(chēng):位置閉環(huán)PID控制設(shè)計(jì)
* 輸入?yún)?shù):當(dāng)前控制量
* 返 回 值:目標(biāo)控制量
* 說(shuō) 明:無(wú)
*/
int32_t LocPIDCalc(int32_t NextPoint)
{
int32_t iError,dError;
iError = lPID.SetPoint - NextPoint; //偏差
/* 設(shè)定閉環(huán)死區(qū) */
if((iError >= -50) && (iError <= 50))
{
iError = 0;
lPID.SumError = 0;
}
/* 積分分離 */
if((iError >= -1000) && (iError <= 1000))
{
lPID.SumError += iError; //積分
/* 設(shè)定積分上限 */
if(lPID.SumError >= 1000)
lPID.SumError = 1000;
if(lPID.SumError <= -1000)
lPID.SumError = -1000;
}
dError = iError - lPID.LastError; //微分
lPID.LastError = iError;
return (int32_t)(lPID.Proportion * (float)iError //比例項(xiàng)
+ lPID.Integral * (float)lPID.SumError //積分項(xiàng)
+ lPID.Derivative * (float)dError); //微分項(xiàng)
}
/**********************************END OF FILE****************************/
復(fù)制代碼
所有代碼51hei附件下載:
STM32編程實(shí)現(xiàn)_位置速度PID雙閉環(huán)控制.7z
(1.53 MB, 下載次數(shù): 103)
2021-7-23 16:34 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1