STM32通过PID调节器实现速度闭环控制

        采用stm32使用PID控制器实现对步进电机转速的控制。

一、课题概括

1、该课题主要使用了正点原子的探索者开发板,42步进电机,步进电机驱动器,编码器、电源等。

2、课题完成功能。实现通过按键KEY0启动系统开环控制,KEY2实现PID闭环控制。

二、实物接线

        接线图如图,步进电机采用驱动器驱动,并且采用了通用定时器TIM3的通道1(PA6),输出PWM信号,用来驱动步进电机。编码器用来检测电机的转速,并用联轴器连接,采用的定时器TIM4的编码器模式(PD12、PD13)检测编码器信号。

三、程序代码

一、转速测量代码

计算出电机转速的代码,每20ms采集一次代码编码器的值,并计算出转速

编码器采集代码为:

encoderValue_old = __HAL_TIM_GET_COUNTER(&htim4);
HAL_Delay(20);
encoderValue_new = __HAL_TIM_GET_COUNTER(&htim4);
encoder_speed = calculateEncoderSpeed(encoderValue_old,encoderValue_new);

采集完成后计算速度的函数为: 

float calculateEncoderSpeed(uint16_t encoderValue_old , uint16_t encoderValue_new)
{
		float speed;
		float econder_value;
		//获得编码器数值
		if(encoderValue_new >= encoderValue_old)
		{
		econder_value = encoderValue_new - encoderValue_old;   
		}
		else
		{
			econder_value = 65535 - encoderValue_old + encoderValue_new;
		}
        //计算出当前转速
		if(econder_value)
		{
    speed = (50*econder_value)/4096;
		}
		return speed;
}

转速知道了,那怎么和PWM频率对应起来呢,我们选择的驱动器挡位是3200个脉冲/圈,通过改变频率,不断增加频率,采集的PWM和速度的对应关系计算函数是

uint16_t count_pwm(float speed)
{
		return (uint16_t)(275.79*(pow(speed,-1.026)));
}
二、PID调节函数

PID调节主要是通过PID控制代码调节

if(pid_con == 1)
		{
			if(sys_state == SYSTEM_RUN)
			{
				PID_Update_speed = PID_Update(&PID_Init_value,set_speed,encoder_speed);
				
			  speed_pwm = count_pwm(PID_Update_speed);
				ModifyPWMFrequency(speed_pwm);
			}
		}

通过PID_Update计算处PID的值

float PID_Update(PIDController* pid, float setpoint, float process_variable) {
    // 计算误差
    float error = setpoint - process_variable;

    // 计算积分项
	if(error<1.0)
	{
    pid->integral += error;
	}
    // 计算微分项
    float derivative = error - pid->prev_error;

    // 计算控制输出
    float output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative;

    // 更新上一次误差
    pid->prev_error = error;
    return output;
}

计算出输出后,然后修改PWM的值

void ModifyPWMFrequency(uint16_t frequency)
{
		
		HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
		htim3.Init.Period = frequency;
		HAL_TIM_PWM_Init(&htim3);
		__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, frequency/2);
		HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
		
}

四、实验效果

通过SerialPlot软件可以绘制出串口的数值,观察控制曲线

参数为0.5,0.3,0
参数为1,0.3,0
参数为1.5,0.3,0

参数为1.5,0.3,0.5

 

可以看出,P参数影响系统的调节速度,I可以减小系统的静态误差,D参数可以减少系统的上升时的震荡。

  • 14
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是基于STM32F10x单片机实现PID算法温度控制PWM输出的代码示例: ```c #include "stm32f10x.h" #include "PWMOUT.h" #define PWM_PIN GPIO_Pin_0 #define PWM_PORT GPIOA #define PWM_CLK RCC_APB2Periph_GPIOA #define TEMP_PIN GPIO_Pin_1 #define TEMP_PORT GPIOA #define TEMP_CLK RCC_APB2Periph_GPIOA #define TEMP_ADC ADC1 #define TEMP_ADC_CLK RCC_APB2Periph_ADC1 #define TEMP_ADC_CHANNEL ADC_Channel_1 #define PWM_FREQ 1000 // PWM频率为1kHz #define PWM_PERIOD 1000 // PWM周期为1ms #define PWM_MAX_DUTY 900 // PWM最大占空比为90% #define PWM_MIN_DUTY 100 // PWM最小占空比为10% #define TEMP_SETPOINT 50 // 设定温度为50℃ #define KP 2.0 // 比例系数 #define KI 0.5 // 积分系数 #define KD 0.1 // 微分系数 volatile uint16_t temp_value = 0; // 温度传感器采集值 volatile uint16_t pwm_duty = 0; // PWM占空比 volatile float error = 0; // 误差 volatile float last_error = 0; // 上一次误差 volatile float integral = 0; // 积分项 volatile float derivative = 0; // 微分项 void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(PWM_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin = PWM_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(PWM_PORT, &GPIO_InitStructure); RCC_APB2PeriphClockCmd(TEMP_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin = TEMP_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(TEMP_PORT, &GPIO_InitStructure); } void ADC_Configuration(void) { ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(TEMP_ADC_CLK, ENABLE); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(TEMP_ADC, &ADC_InitStructure); ADC_RegularChannelConfig(TEMP_ADC, TEMP_ADC_CHANNEL, 1, ADC_SampleTime_239Cycles5); ADC_Cmd(TEMP_ADC, ENABLE); ADC_ResetCalibration(TEMP_ADC); while(ADC_GetResetCalibrationStatus(TEMP_ADC)); ADC_StartCalibration(TEMP_ADC); while(ADC_GetCalibrationStatus(TEMP_ADC)); } void TIM_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD - 1; TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / (PWM_FREQ * PWM_PERIOD) - 1; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM2, &TIM_OCInitStructure); TIM_Cmd(TIM2, ENABLE); } void SysTick_Handler(void) { static uint16_t count = 0; if(count++ >= 10) // 100ms采集一次温度 { count = 0; ADC_SoftwareStartConvCmd(TEMP_ADC, ENABLE); while(!ADC_GetFlagStatus(TEMP_ADC, ADC_FLAG_EOC)); temp_value = ADC_GetConversionValue(TEMP_ADC); error = TEMP_SETPOINT - temp_value; integral += error; derivative = error - last_error; last_error = error; pwm_duty = KP * error + KI * integral + KD * derivative; if(pwm_duty > PWM_MAX_DUTY) pwm_duty = PWM_MAX_DUTY; if(pwm_duty < PWM_MIN_DUTY) pwm_duty = PWM_MIN_DUTY; TIM_SetCompare1(TIM2, pwm_duty); } } int main(void) { GPIO_Configuration(); ADC_Configuration(); TIM_Configuration(); SysTick_Config(SystemCoreClock / 1000); // 1ms中断一次 while(1); } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值