標(biāo)題:
STM32編程實現(xiàn)直流有刷電機位置速度電流三閉環(huán)PID控制程序
[打印本頁]
作者:
zx0922
時間:
2021-6-27 20:31
標(biāo)題:
STM32編程實現(xiàn)直流有刷電機位置速度電流三閉環(huán)PID控制程序
固件庫開發(fā)的直流電機pid控制系統(tǒng)
單片機源程序如下:
/**
******************************************************************************
* 文件名程: BDCMOTOR.c
* 作 者: 學(xué)習(xí)小組
* 功 能: 有刷直流電機驅(qū)動板基本驅(qū)動程序
******************************************************************************
* 說明:
******************************************************************************
*/
/* 包含頭文件 ----------------------------------------------------------------*/
#include "BDCMotor.h"
/* 私有類型定義 --------------------------------------------------------------*/
/* 私有宏定義 ----------------------------------------------------------------*/
/* 私有變量 ------------------------------------------------------------------*/
TIM_HandleTypeDef htimx_BDCMOTOR;
__IO int16_t PWM_Duty=BDCMOTOR_DUTY_ZERO; // 占空比:PWM_Duty/BDCMOTOR_TIM_PERIOD*100%
/* 擴展變量 ------------------------------------------------------------------*/
/* 私有函數(shù)原形 --------------------------------------------------------------*/
/* 函數(shù)體 --------------------------------------------------------------------*/
/**
* 函數(shù)功能: 基本定時器硬件初始化配置
* 輸入?yún)?shù): htim_base:基本定時器句柄類型指針
* 返 回 值: 無
* 說 明: BDCMOTOR相關(guān)GPIO初始化配置,該函數(shù)被HAL庫內(nèi)部調(diào)用.
*/
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
/* BDCMOTOR相關(guān)GPIO初始化配置 */
if(htim == &htimx_BDCMOTOR)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 引腳端口時鐘使能 */
__HAL_RCC_GPIOE_CLK_ENABLE();
BDCMOTOR_TIM_CH1_GPIO_CLK_ENABLE();
BDCMOTOR_TIM_CH1N_GPIO_CLK_ENABLE();
SHUTDOWN_GPIO_CLK_ENABLE();
/* BDCMOTOR輸出脈沖控制引腳IO初始化 */
GPIO_InitStruct.Pin = BDCMOTOR_TIM_CH1_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AFx_TIMx;
HAL_GPIO_Init(BDCMOTOR_TIM_CH1_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = BDCMOTOR_TIM_CH1N_PIN;
HAL_GPIO_Init(BDCMOTOR_TIM_CH1N_PORT, &GPIO_InitStruct);
__HAL_RCC_GPIOE_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_11;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
GPIO_InitStruct.Pin = SHUTDOWN_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = 0;
HAL_GPIO_Init(SHUTDOWN_PORT, &GPIO_InitStruct);
/* 使能電機控制引腳 */
ENABLE_MOTOR();
}
}
/**
* 函數(shù)功能: BDCMOTOR定時器初始化
* 輸入?yún)?shù): 無
* 返 回 值: 無
* 說 明: 無
*/
void BDCMOTOR_TIMx_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig; // 定時器時鐘
TIM_OC_InitTypeDef sConfigOC;
TIM_BreakDeadTimeConfigTypeDef sBDTConfig; // 定時器死區(qū)時間比較輸出
/* 基本定時器外設(shè)時鐘使能 */
BDCMOTOR_TIM_RCC_CLK_ENABLE();
/* 定時器基本環(huán)境配置 */
htimx_BDCMOTOR.Instance = BDCMOTOR_TIMx; // 定時器編號
htimx_BDCMOTOR.Init.Prescaler = BDCMOTOR_TIM_PRESCALER; // 定時器預(yù)分頻器
htimx_BDCMOTOR.Init.CounterMode = TIM_COUNTERMODE_UP; // 計數(shù)方向:向上計數(shù)
htimx_BDCMOTOR.Init.Period = BDCMOTOR_TIM_PERIOD; // 定時器周期
htimx_BDCMOTOR.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; // 時鐘分頻
htimx_BDCMOTOR.Init.RepetitionCounter = BDCMOTOR_TIM_REPETITIONCOUNTER; // 重復(fù)計數(shù)器
/* 初始化定時器比較輸出環(huán)境 */
HAL_TIM_PWM_Init(&htimx_BDCMOTOR);
/* 定時器時鐘源配置 */
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; // 使用內(nèi)部時鐘源
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);
/* 定時器比較輸出配置 */
sConfigOC.OCMode = TIM_OCMODE_PWM1; // 比較輸出模式:PWM1模式
sConfigOC.Pulse = PWM_Duty; // 占空比
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; // 輸出極性
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_LOW; // 互補通道輸出極性
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 快速模式
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; // 空閑電平
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; // 互補通道空閑電平
HAL_TIM_PWM_ConfigChannel(&htimx_BDCMOTOR, &sConfigOC, TIM_CHANNEL_1);
/* 啟動定時器 */
HAL_TIM_Base_Start(&htimx_BDCMOTOR);
}
/**
* 函數(shù)功能: 基本定時器硬件反初始化配置
* 輸入?yún)?shù): htim_base:基本定時器句柄類型指針
* 返 回 值: 無
* 說 明: 該函數(shù)被HAL庫內(nèi)部調(diào)用
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==BDCMOTOR_TIMx)
{
/* 基本定時器外設(shè)時鐘禁用 */
BDCMOTOR_TIM_RCC_CLK_DISABLE();
HAL_GPIO_DeInit(BDCMOTOR_TIM_CH1_PORT,BDCMOTOR_TIM_CH1_PIN);
HAL_GPIO_DeInit(BDCMOTOR_TIM_CH1N_PORT,BDCMOTOR_TIM_CH1N_PIN);
}
}
/************************************END OF FILE**************************/
復(fù)制代碼
/**
******************************************************************************
* 文件名程: main.c
* 作 者: 學(xué)習(xí)小組
* 功 能: 位置速度電流閉環(huán)控制
******************************************************************************
* 說明:
******************************************************************************
*/
/* 包含頭文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "key.h"
#include "encoder.h"
#include "usartx.h"
#include "adc.h"
#include "BDCMotor.h"
/* 私有類型定義 --------------------------------------------------------------*/
typedef struct
{
__IO int32_t SetPoint; // 設(shè)定目標(biāo) Desired Value
__IO float SumError; // 誤差累計
__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 ADC_Base 8 // 取2的整數(shù)倍作為緩存區(qū)大小,得到14bits
/* 使用DMA傳輸數(shù)據(jù),采集n個數(shù)據(jù)點的時間是0.65ms,采樣率大約是 1500 KHz */
#define ADC_BUFFER 1024 // 采樣數(shù)據(jù)緩存區(qū)
#define SPEEDRATIO 270
#define ENCODER_RESOLUTION 11
#define PPR ((SPEEDRATIO*ENCODER_RESOLUTION)*4) // Pulse/Round 每圈可捕獲到的脈沖數(shù)
/*************************************/
// 定義PID相關(guān)宏
// 這三個參數(shù)設(shè)定對電機運行影響非常大
// PID參數(shù)跟采樣時間息息相關(guān)
/*************************************/
#define CUR_P_DATA 0.35f // P參數(shù)
#define CUR_I_DATA 0.6f // I參數(shù)
#define CUR_D_DATA 0.0f // D參數(shù)
#define TARGET_CURRENT 300 // 最大電流值 300mA
#define SPD_P_DATA 4.5f // P參數(shù)
#define SPD_I_DATA 0.5f // I參數(shù)
#define SPD_D_DATA 0.0f // D參數(shù)
#define TARGET_SPEED 20.0f // 目標(biāo)速度 20r/m
#define LOC_P_DATA 0.009f // P參數(shù)
#define LOC_I_DATA 0.002f // I參數(shù)
#define LOC_D_DATA 0.04f // D參數(shù)
#define TARGET_LOC (3*PPR) // 目標(biāo)位置 11880Pulse = 1r
/* 私有變量 ------------------------------------------------------------------*/
__IO uint8_t Start_flag = 0; // PID 開始標(biāo)志
uint32_t Motor_Dir = CW; // 電機方向
__IO int32_t tmpPWM_DutySpd = 0;
__IO int32_t tmpPWM_Duty = 0;
/* 用于保存轉(zhuǎn)換計算后的數(shù)值 */
__IO float ADC_VoltBus; // 總線電壓值
__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
/* AD轉(zhuǎn)換結(jié)果值 */
__IO int16_t ADC_ConvValueHex[ADC_BUFFER]; // AD轉(zhuǎn)換結(jié)果緩存
__IO int32_t AverSum = 0; // 平均值的累加值
__IO int32_t AverCnt = 0; // 平均值的計數(shù)器
__IO uint32_t OffsetCnt_Flag = 0 ; // 偏差值的計數(shù)器標(biāo)志
__IO int32_t OffSetHex ; // 偏差值
/* 擴展變量 ------------------------------------------------------------------ */
extern __IO uint32_t uwTick;
/* PID結(jié)構(gòu)體 */
PID_TypeDef cPID,sPID,lPID; // PID參數(shù)結(jié)構(gòu)體
/* 擴展變量 ------------------------------------------------------------------*/
/* 私有函數(shù)原形 --------------------------------------------------------------*/
void PID_ParamInit(void) ;
int32_t CurPIDCalc(int32_t NextPoint);
int32_t SpdPIDCalc(float NextPoint);
int32_t LocPIDCalc(int32_t NextPoint);
int32_t ADC_GetSampleAvgN(int16_t *Data, uint32_t N );
/* 函數(shù)體 --------------------------------------------------------------------*/
/**
* 函數(shù)功能: 系統(tǒng)時鐘配置
* 輸入?yún)?shù): 無
* 返 回 值: 無
* 說 明: 無
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__HAL_RCC_PWR_CLK_ENABLE(); // 使能PWR時鐘
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); // 設(shè)置調(diào)壓器輸出電壓級別1
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 外部晶振,8MHz
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // 打開HSE
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // 打開PLL
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL時鐘源選擇HSE
RCC_OscInitStruct.PLL.PLLM = 8; // 8分頻MHz
RCC_OscInitStruct.PLL.PLLN = 336; // 336倍頻
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // 2分頻,得到168MHz主時鐘
RCC_OscInitStruct.PLL.PLLQ = 7; // USB/SDIO/隨機數(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)時鐘:168MHz
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB時鐘: 168MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // APB1時鐘:42MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // APB2時鐘:84MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
HAL_RCC_EnableCSS(); // 使能CSS功能,優(yōu)先使用外部晶振,內(nèi)部時鐘源為備用
// HAL_RCC_GetHCLKFreq()/1000 1ms中斷一次
// HAL_RCC_GetHCLKFreq()/100000 10us中斷一次
// HAL_RCC_GetHCLKFreq()/1000000 1us中斷一次
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); // 配置并啟動系統(tǒng)滴答定時器
/* 系統(tǒng)滴答定時器時鐘源 */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* 系統(tǒng)滴答定時器中斷優(yōu)先級配置 */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/**
* 函數(shù)功能: 主函數(shù).
* 輸入?yún)?shù): 無
* 返 回 值: 無
* 說 明: 無
*/
int main(void)
{
/* 復(fù)位所有外設(shè),初始化Flash接口和系統(tǒng)滴答定時器 */
HAL_Init();
/* 配置系統(tǒng)時鐘 */
SystemClock_Config();
/* 串口初始化 */
MX_USARTx_Init();
/* 按鍵初始化 */
KEY_GPIO_Init();
/* 編碼器初始化及使能編碼器模式 */
ENCODER_TIMx_Init();
/* ADC-DMA 初始化 */
MX_ADCx_Init();
/* 啟動AD轉(zhuǎn)換并使能DMA傳輸和中斷 */
HAL_ADC_Start_DMA(&hadcx,(uint32_t*)ADC_ConvValueHex,ADC_BUFFER);
__HAL_DMA_DISABLE_IT(&hdma_adcx,DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_adcx,DMA_IT_TE);
__HAL_DMA_DISABLE_IT(&hdma_adcx,DMA_IT_FE);
__HAL_DMA_DISABLE_IT(&hdma_adcx,DMA_IT_DME);
/* 高級控制定時器初始化并配置PWM輸出功能 */
BDCMOTOR_TIMx_Init();
/* 啟動定時器通道和互補通道PWM輸出 */
PWM_Duty = 0;
__HAL_TIM_SET_COMPARE(&htimx_BDCMOTOR,TIM_CHANNEL_1,PWM_Duty); // 0%
/* PID 參數(shù)初始化 */
PID_ParamInit();
/* 無限循環(huán) */
while (1)
{
/* 停止按鈕 */
if(KEY1_StateRead()==KEY_DOWN)
{
HAL_TIM_PWM_Start(&htimx_BDCMOTOR,TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);
__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)滴答定時器中斷回調(diào)函數(shù)
* 輸入?yún)?shù): 無
* 返 回 值: 無
* 說 明: 每隔一定的時間就執(zhí)行pid算法
*/
void HAL_SYSTICK_Callback(void)
{
__IO int32_t ADC_Resul= 0;
__IO float Volt_Result = 0;
__IO float ADC_CurrentValue; // 電流
/* 位置環(huán)周期250ms */
if(uwTick % 250 == 0)
{
/* 獲取當(dāng)前位置值,編碼器4倍頻之后的數(shù)值 */
Sample_Pulse = (OverflowCount*CNT_MAX) + (int32_t)__HAL_TIM_GET_COUNTER(&htimx_Encoder);
/* 計算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)周期100ms */
if(uwTick % 100 == 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線編碼器,270減速比,一圈脈沖信號是11*270*4 PPR */
Spd_RPM = ((((float)Spd_PPS/(float)PPR)*10.0f)*(float)60);//單位是rpm
/* 計算PID結(jié)果 */
if(Start_flag == 1)
{
sPID.SetPoint = tmpPWM_DutySpd;
tmpPWM_Duty = SpdPIDCalc(Spd_RPM);
/* 根據(jù)速度環(huán)的計算結(jié)果判斷當(dāng)前運動方向 */
if(tmpPWM_Duty < 0)
{
Motor_Dir = CW;
BDDCMOTOR_DIR_CW();
tmpPWM_Duty = -tmpPWM_Duty;
}
else
{
Motor_Dir = CCW;
BDDCMOTOR_DIR_CCW();
}
/* 設(shè)定電流環(huán)的目標(biāo)值,電流沒有負數(shù) */
if(tmpPWM_Duty >= TARGET_CURRENT)
tmpPWM_Duty = TARGET_CURRENT;
}
}
/* 電流環(huán)周期是40ms,電流單次采集周期大約是 2ms,最好不要低于2ms */
if(uwTick % 40 == 0)
{
ADC_Resul = AverSum/AverCnt ;
/* 連續(xù)采樣16次以后,作為偏差值 */
OffsetCnt_Flag++;
if(OffsetCnt_Flag >= 16)
{
if(OffsetCnt_Flag == 16)
{
OffSetHex /= OffsetCnt_Flag-1;
}
OffsetCnt_Flag = 32;
ADC_Resul -= OffSetHex;//減去偏差值
}
else
OffSetHex += ADC_Resul;
/* 計算電壓值和電流值 */
Volt_Result = ( (float)( (float)(ADC_Resul) * VOLT_RESOLUTION) );
ADC_CurrentValue = (float)( (Volt_Result / GAIN) / SAMPLING_RES);
if(Volt_Result<0)
Volt_Result = 0;
/* 清空計數(shù) */
AverCnt = 0;
AverSum = 0;
/* 計算PID結(jié)果 */
if(Start_flag == 1)
{
cPID.SetPoint = tmpPWM_Duty ;
PWM_Duty = CurPIDCalc( (int32_t)ADC_CurrentValue);
if(PWM_Duty >= BDCMOTOR_DUTY_FULL)
PWM_Duty = BDCMOTOR_DUTY_FULL;
if(PWM_Duty <=0)
PWM_Duty = 0;
__HAL_TIM_SET_COMPARE(&htimx_BDCMOTOR,TIM_CHANNEL_1,PWM_Duty);
}
printf("LOC:%d Sped: %2.2f r/m Curr: %d mA \n",Sample_Pulse,
Spd_RPM ,(int32_t)ADC_CurrentValue);
}
}
/**
* 函數(shù)功能: ADC轉(zhuǎn)換完成回調(diào)函數(shù)
* 輸入?yún)?shù): hadc:ADC外設(shè)設(shè)備句柄
* 返 回 值: 無
* 說 明: 中斷一次的時間是1.479ms,利用過采樣和求均值方法,提高分辨率
*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
int32_t ADConv = 0 ;
/* ADC采集太快,需要先停止再處理數(shù)據(jù) */
HAL_ADC_Stop_DMA(hadc);
/* 采集總線電壓 */
SetChannelAsRank1(hadc,ADC_VOLT_CHANNEL);
HAL_ADC_Start(hadc);
/* 去掉高和低總共SORT_NUM個采樣數(shù)據(jù),取中間部分的數(shù)據(jù)做平均 */
ADConv = ADC_GetSampleAvgN((int16_t*)&ADC_ConvValueHex,ADC_BUFFER);
/* 累加采樣結(jié)果并記錄采樣次數(shù)*/
AverSum += ADConv;
AverCnt++;
/* 讀取總線電壓值 */
HAL_ADC_Stop(hadc);
SetChannelAsRank1(hadc,ADC_CURRENT_CHANNEL);
HAL_ADC_Start_DMA(hadc,(uint32_t*)ADC_ConvValueHex,ADC_BUFFER);
}
/**
* 函數(shù)功能: ADC看門狗中斷回調(diào)函數(shù)
* 輸入?yún)?shù): ADC句柄
* 返 回 值: 無
* 說 明: 檢測到電壓過低或者過高的時候就調(diào)用這個函數(shù),停止輸出.
*/
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc)
{
/* 使能電機控制引腳 */
static uint8_t i = 0;
i++;
if(ADC_VoltBus > VOLT_LIMIT_MIN && ADC_VoltBus < VOLT_LIMIT_MAX)
i = 0 ;
else if(i>=6)
{
SHUTDOWN_MOTOR();
HAL_TIM_PWM_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Stop(&htimx_BDCMOTOR,TIM_CHANNEL_1);
PWM_Duty = 0;
printf("Bus Voltage is out of range!!\n");
printf("Please Reset the Target!\n");
while(1);
}
}
/**
* 函數(shù)功能: 得到N 個ADC 采樣的均值
* 輸入?yún)?shù): 要做平均的ADC 采樣數(shù)
* 返 回 值: 均值
* 說 明: 計算平均值,獲得14bitsADC值
*/
int32_t ADC_GetSampleAvgN(int16_t *Data, uint32_t N)
{
int32_t avg_sample =0x00;
uint32_t index=0x00;
/* 累加N 個ADC 采樣 */
for (index = 0; index < N; index++)
{
avg_sample += ((int32_t)Data[index]);
}
/* 計算N 個ADC 采樣的均值 */
avg_sample >>= ADC_Base;
/* 返回均值 */
return avg_sample;
}
/******************** PID 控制設(shè)計 ***************************/
/**
* 函數(shù)功能: PID參數(shù)初始化
* 輸入?yún)?shù): 無
* 返 回 值: 無
* 說 明: 無
*/
void PID_ParamInit()
{
cPID.LastError = 0; // Error[-1]
cPID.PrevError = 0; // Error[-2]
cPID.Proportion = CUR_P_DATA; // 比例常數(shù) Proportional Const
cPID.Integral = CUR_I_DATA; // 積分常數(shù) Integral Const
cPID.Derivative = CUR_D_DATA; // 微分常數(shù) Derivative Const
cPID.SetPoint = TARGET_CURRENT;// 設(shè)定目標(biāo)Desired Value
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ù)名稱:電流閉環(huán)PID控制設(shè)計
* 輸入?yún)?shù):當(dāng)前控制量
* 返 回 值:目標(biāo)控制量
* 說 明:無
*/
int32_t CurPIDCalc(int32_t NextPoint)
{
int32_t iError,dError;
iError = cPID.SetPoint - NextPoint; //偏差
/* 設(shè)定閉環(huán)死區(qū) */
if((iError >= -3) && (iError <= 3))
iError = 0;
cPID.SumError += iError; //積分
dError = iError - cPID.LastError; //微分
cPID.LastError = iError;
return (int32_t)(cPID.Proportion * (float)iError //比例項
+ cPID.Integral * (float)cPID.SumError //積分項
+ cPID.Derivative * (float)dError); //微分項
}
/**
* 函數(shù)名稱:速度閉環(huán)PID控制設(shè)計
* 輸入?yún)?shù):當(dāng)前控制量
* 返 回 值:目標(biāo)控制量
* 說 明:無
*/
int32_t SpdPIDCalc(float NextPoint)
{
float iError,dError;
iError = sPID.SetPoint - NextPoint; //偏差
if((iError<0.3f )&& (iError>-0.3f))
iError = 0.0f;
……………………
…………限于本文篇幅 余下代碼請從51黑下載附件…………
復(fù)制代碼
所有代碼51hei提供下載:
STM32編程實現(xiàn)直流有刷電機位置速度電流三閉環(huán)PID控制.7z
(1.54 MB, 下載次數(shù): 135)
2021-6-27 21:13 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
作者:
friendsl
時間:
2021-6-28 17:01
只有代碼,沒有原理圖,作為參考吧。
作者:
riptell
時間:
2023-3-7 16:33
參考一下
作者:
li64331218
時間:
2023-3-8 13:35
可參考! 配一下簡單的說明更好了
作者:
bb1237
時間:
2023-5-23 16:13
有原理圖嗎?
作者:
gfsgffdeee
時間:
2023-8-21 16:07
參考一下,求原理圖
作者:
wang7128953
時間:
2024-12-28 17:25
求參考原理圖,現(xiàn)在做牙科項目
作者:
linlin1
時間:
2025-1-16 16:04
stm32比51更強大
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1