|
我们将在固件中实现一个基本PID(比例 - 积分 - 微分)控制器,并使用示波器和LED指示灯观察运行结果。
该PID(比例 - 积分 - 微分)温度控制系统的主要组件包含EFM8微控制器、DAC和MAX31855热电偶数字转换器。该系列总共有6部分: ● Part 1:电路原理设计 ● Part 2:板级集成 ● Part 3:实现与可视化
PID过程 在第一篇文章中,我们介绍了用于驱动通过加热元件电阻的相对较大的电流的电路,在第二篇文章中,我们讨论了与SPI接口相关的时序细节和固件,这使我们能够集成PID系统的三个主要组件。现在我们准备实现一个基本的PID控制程序。以下是我们将转换为EFM8代码的一般过程: 1. 选择比例,积分和微分增益的值。 2. 清除应从零开始的变量,即积分增益使用的累积误差和导数增益使用的先前误差值。 3. 从MAX31855收集数据并将其转换为温度值(以摄氏度为单位)。 4. 通过从设定点温度中减去测量温度来计算当前误差。 5. 将当前误差添加到积分增益使用的累积误差。 6. 通过从当前误差中减去先前的误差来计算误差的变化率(与微分增益一起使用)。 7. 通过将先前的误差设置为等于当前误差来更新先前的误差(用于下一次迭代)。 8. 通过将P增益乘以当前误差,I增益乘以累积误差,并将D增益乘以误差的变化率来计算PID控制输出,然后将这三次乘法的结果相加。 9. 根据可接受的范围限制PID控制输出。我们的电流驱动电路只能提供大约1 A的电流,我们不能低于零电流。 (请记住,在这个系统中,我们只能产生热量;我们无法移除热量。因此,低于零的PID输出值没有物理意义。例如,如果我们使用环境控制系统,情况就不是这样了。有一个加热器和一个空调器。在这种情况下,负PID输出将告诉系统完全停用加热器,然后启动空调。) 10. 应用PID控制输出(在我们的例子中,这意味着将新值写入控制加热器驱动电压的DAC通道)。 11. 等到当前PID间隔到期后再开始下一次迭代。
时间发生了什么? 您在上述过程中可能注意到的一件事是,当我们整合和区分误差时,我们没有合并时间量。在连续时间表示中,误差在时间上是不同的并且与时间相关。但是,在我们的离散时间实现中,我们不需要明确考虑增量时间dt,因为我们的PID间隔是常数,我们在每次迭代期间计算积分和微分误差。例如,导数误差的目的是告诉我们测量温度的变化速度(以及在什么方向,正面或负面)。通过简单地从当前误差中减去先前的误差,我们可以确定在前一个PID间隔期间温度变化了多少。下一个导数误差将告诉我们在后续PID间隔期间温度变化了多少,等等。因此,数量dt有效地包括在计算中 - 一个导数误差可以直接与所有其他导数误差进行比较,因为它们是参考相同的时间间隔计算的。
可视化 除非你是那种能够看到某些东西并确定其确切温度的人,否则如果没有某种可视化系统变化的方法,你将无法知道你的PID控制器在做什么。对于项目的这个阶段,我们将以两种方式评估我们的PID功能:1)通过使用oscope显示施加到加热元件电阻器的电压,以及2)通过在测量温度接近时增加LED的亮度设定点温度。当测量温度等于(或超过)设定点温度时,我们还会通过打开第二个LED来使LED技术更具信息性。
我们用于该项目的PCB包括一个RGB LED模块以及允许我们通过DAC输出精确控制每个LED亮度的电路。我们将使用红色LED表示温度变化,使用绿色LED指示测量温度已达到设定值。
您可以通过不同的方式通过LED亮度传达温度信息。我们的方法如下:当我们首次激活PID控制器时,我们将当前测量温度和设定值之间的差值存储为Initial_Error。在每次迭代期间,我们计算1减去当前误差与初始误差的比率,然后我们根据预定的8位DAC值缩放该减法的结果: DAC值=(1-电流误差/初始误差)×DAC值,以获得最佳亮度
因此,当PID控制器首次启动时,(1 - (电流错误)/(初始错误))将接近零,LED将熄灭。随着测量温度的增加,电流误差将减小,因此(1 - (电流误差)/(初始误差))将朝1增加,因此DAC值将朝“DAC值增加,以获得最佳亮度。”我选择100作为最佳亮度值,因为我不喜欢盯着这些LED,当它们一直加速到完全20 mA时(DAC值255对应20 mA,因此100约为8 mA)。
这是完成LED功能的代码。 - /*-----This section executes before the main while loop.-----*/
- /*-----------------------------------------------------------*/
- GatherMAX31855Data();
- while(TEMP_DATA_READY == FALSE); //wait until the SPI transaction is complete
- Measured_Temp = ConvertMAX31855Data_to_TempC();
- //the initial error is needed only for the LED functionality
- Initial_Error = Setpoint_Temp - Measured_Temp;
- /*-----------------------------------------------------------*/
- /*-----This section is included in the while loop.-----*/
- /*-----------------------------------------------------*/
- /*The red LED stays off if for some reason the current
- * error exceeds the initial error.*/
- if(Error > Initial_Error)
- LED_Temp_Indicator = 0;
- /*This calculation is explained in the article.*/
- else
- LED_Temp_Indicator = (1 - (Error/Initial_Error)) * 100;
- /*Here we turn on the green LED if we have
- * reached the setpoint. Notice that there
- * is no code that sets the green LED's DAC
- * value back to zero. This means that once
- * the green LED is on, it stays on.*/
- if(Measured_Temp >= Setpoint_Temp)
- LED_Setpoint_Reached = 100;
- UpdateDAC(DAC_RGB_R, LED_Temp_Indicator);
- UpdateDAC(DAC_RGB_G, LED_Setpoint_Reached);
- /*-----------------------------------------------------*/
复制代码
固件 以下是PID代码(包括用于控制LED的代码)。 注释和描述性标识符应该使一切都清楚。 请注意,PID控制输出限制为200。我们可以高达255,但仅仅演示功能不需要完整的加热器电流。 - Setpoint_Temp = 50;
- K_proportional = 40;
- K_integral = 10;
- K_derivative = 0;
- Error_Integral = 0;
- Previous_Error = 0;
- /*Apparently the MAX31855 generates better
- * temperature data if it has a little extra time
- * after power-up. This is why we have a 1-second
- * delay here.*/
- Delay_10ms(100);
- GatherMAX31855Data();
- while(TEMP_DATA_READY == FALSE); //wait until the SPI transaction is complete
- Measured_Temp = ConvertMAX31855Data_to_TempC();
- //the initial error is needed only for the LED functionality
- Initial_Error = Setpoint_Temp - Measured_Temp;
- while (1)
- {
- GatherMAX31855Data();
- while(TEMP_DATA_READY == FALSE); //wait until the SPI transaction is complete
- Measured_Temp = ConvertMAX31855Data_to_TempC();
- Error = Setpoint_Temp - Measured_Temp;
- /*We don't want the integral error to get
- * way too large. This is a standard problem
- * referred to as integral windup. One solution
- * is to simply restrict the integral error to
- * reasonable values.*/
- Error_Integral = Error_Integral + Error;
- if(Error_Integral > 50)
- Error_Integral = 50;
- else if(Error_Integral < -50)
- Error_Integral = -50;
- Error_Derivative = Error - Previous_Error;
- Previous_Error = Error;
- PID_Output = (K_proportional*Error) + (K_integral*Error_Integral) + (K_derivative*Error_Derivative);
- /*We need to restrict the PID output to
- * acceptable values. Here we have limited it
- * to a maximum of 200, which corresponds
- * to about 780 mA of heater-drive current, and
- * a minimum of 0, because we cannot drive
- * less than 0 A through the heating
- * element.*/
- if(PID_Output > 200)
- PID_Output = 200;
- else if(PID_Output < 0)
- PID_Output = 0;
- //here we convert the PID output from a float to an unsigned char
- Heater_Drive = PID_Output;
- UpdateDAC(DAC_HEATER, Heater_Drive);
- /*The red LED stays off if for some reason the current
- * error exceeds the initial error.*/
- if(Error > Initial_Error)
- LED_Temp_Indicator = 0;
- /*This calculation is explained in the article.*/
- else
- LED_Temp_Indicator = (1 - (Error/Initial_Error)) * 100;
- /*Here we turn on the green LED if we have
- * reached the setpoint. Notice that there
- * is no code that sets the green LED's DAC
- * value back to zero. This means that once
- * the green LED is on, it stays on.*/
- if(Measured_Temp >= Setpoint_Temp)
- LED_Setpoint_Reached = 100;
- UpdateDAC(DAC_RGB_R, LED_Temp_Indicator);
- UpdateDAC(DAC_RGB_G, LED_Setpoint_Reached);
- /*Here we wait until the PID interval has expired,
- * then we begin a new iteration. The interval is
- * currently set to 1 second.*/
- PID_WAIT = TRUE;
- while(PID_WAIT == TRUE);
- }
复制代码
结果 以下两个视频可让您了解系统的工作原理。我们将在未来的文章中更多地讨论调整 - 即正确选择比例,积分和微分增益。现在,我们将简单地看一下仅比例系统和比例积分(即无导数)系统的结果。比例增益设置为40,积分增益设置为10(这些值主要基于系统特性的基本考虑,尽管我根据经验观察调整了比例增益)。
第一个视频显示了P-only系统将温度从大约30°C提升到50°C的设定值。首先,示波器轨迹增加到最大驱动电压,然后您会注意到红色LED随着测量温度的增加而逐渐变亮。随着测量温度接近设定点,驱动电压最终降低。但是,绿色LED从不打开,然后驱动电压再次开始增加。该系统往往比设定点低几度;这种稳态误差是P系统的共同缺点。
绿色LED指示达到设定值,但对于仅P系统,测量温度往往比设定值低几度。因此,绿色LED永远不会打开。
现在我们引入一些积分增益来减少稳态误差。该PI系统执行相同的控制任务,即将温度从30℃升至50℃的设定点。驱动电压最初增加到最大值,红色LED逐渐变亮,如第一个视频中那样,但随后绿色LED亮起,表示我们达到了设定值。积分误差不会立即降至零,因此驱动电压暂时保持最大值;在此期间,测量温度高于设定值。最终,积分误差“展开”足以导致驱动电压降低。
我们可以引入积分增益来减少稳态误差。使用PI系统,绿色LED亮起,表示我们达到了设定值。 |