项目介绍
本项目基于2024年寒假在家一起练(TMS430F280049C)平台,根据传统经典PID算法搭建。
功能:
1.可以通过按键和摇杆分别调节设定温度、控制参数和LED显示模式
2.可以依据当前的温度和设定温度差,依据PID算法调节PWM输出,实现温度稳定
设计思路
PID的设计
具体的温控分析,可以参考我的另一篇《基于RT1021平台的PID温控系统的设计》,本项目中的PID的设计,考虑少,抗饱和的处理简单。在实际控制中,发现就算不进行加热,温度本身就存在小幅度(1℃)波动,但是变化很慢。为了实现稳定温度控制,我们依旧采用拉长时间和减小控制变化的方式来实现温度的稳定。
按键采集和摇杆采集
按键的采集需要依据ADC采集,摇杆的采集经电路处理变成频率和占空比的变化。由于AD采集和ECAP采集都存在波动,在一段时间的数据监控中发现AD的采集波动比较稳定,ECAP采集的波动比较大,考虑到实际中,我们考虑的是离散的量。将AD和ECAP采集离散成指定的数值,得出摇杆上下左右和按键的增减的操作。
硬件框图
- IPS-LCD 采用SPI-Bus协议与DSP芯片沟通,实现LCD刷写
- NSHT112 采用IIC-Bus协议与DSP芯片沟通,实现温度读写。
- 按键通过分压电路实现AD采集获取按键按下,摇杆则通过ECAP获取频率和占空比来获取方向。
- LED通过GPIO与DSP芯片连接,从而通过GPIO的电平控制,实现LED的不同点亮方式。
软件流程图
温度读取是持续的,由于一次读取需要20ms的转换周期。但是PID的计算需要固定周期的,每30ms进行一次运算和赋值,放在硬中断中,运算时间快,不会占用中断。每5次(共150ms)作为基于一个设定温度的PID的运算周期,无论是否稳定,都要调节运算设定值,实现目标值拖动温度达到设定值。
按键和摇杆的采集放在100ms周期,在100ms的那一瞬间对AD采集值和ECAP采集值处理,而AD的采集和ECAP的采集是持续进行的,保证处理在100ms,运算快,不占用中断。
硬件介绍
NSHT112
上图是依据手册编写的关于NSHT112的控制逻辑,采用IIC-Bus协议实现NSHT112温湿度的读取,需要注意one-shot模式只能在关闭模式下启动,以及连续转换状态需要设置转换频率。为了提高速度转换频率,最佳方案自然是关闭模式+one-shot模式。一次转换需要20ms,one-shot的转换间隔更短,远短于连续模式最短的时间。
实现的功能及图片展示
功能1:温度控制
由图中可以看出来,在调节过程中,实际的实现了PID的随动,由于温度控制本身的困难性,所以实际控制是依据1℃控制,调整参数则以0.01的增幅,但是控制实际只取整数,本来是打算做很高精度,但是实际控制中很困难。
功能2:参数调节
初始界面
摇杆上下调节参数选择
摇杆左右调节参数变动
通过左右摇杆可以控制参数数值
按键控制设定温度
通过按键可以增减设定温度
功能3:灯光显示
由图中可以看出来,在不同的温度区间内,LED的表现。
主要代码片段及说明
NSHT112读取温湿度
NSHT112.NumOfDataBytes = 2; //发送数据数量
NSHT112.pControlAddr = &ControlAddr;
NSHT112.pRX_MsgBuffer = RX_MsgBuffer;
CPUTimer_startTimer(myCPUTIMER0_BASE);
//发指令
ControlAddr = 0x01;
I2C_ControllerTransmitter(&NSHT112);
//收数据
ControlAddr = 0x00;
I2C_ControllerReceiver(&NSHT112);
First_Value_Set = RX_MsgBuffer[0]+(RX_MsgBuffer[1]>>4)*0.0625;
依据NSHT112的I^2C的协议,实现协议读写。
PID算法
//
// PID
//
struct _pid
{
float SetValue; //定义设定值
float ActualValue; //定义实际值
float err ; // 定义偏差值
float err_last; //定义上一个偏差值
float Kp,Ki,Kd; //定义比例、积分、微分系数
uint8_t TargetValue; //定义控制器执行的变量
float integral; //定义积分值
}pid;
void PID_init()
{
pid.SetValue = 0.0;
pid.ActualValue = 0.0;
pid.err = 0.0;
pid.err_last = 0.0;
pid.TargetValue = 0;
pid.integral = 0.0;
pid.Kp = 2.3;
pid.Ki = 0.15;
pid.Kd =0;
}
void PID_realize(float Temp)
{
pid.ActualValue = Temp;
pid.err = pid.SetValue - pid.ActualValue ;
pid.integral += pid.err ;
pid.TargetValue = pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);
pid.err_last = pid.err;
if(pid.TargetValue>50)
{
pid.TargetValue = 50;
pid.integral = 0;
}
if(pid.TargetValue<5)
{
pid.TargetValue = 5;
}
}
采用传统经典PID加上限幅算法,刚开始主要是P环节的动作,在升温过程中,I环节的参与,不断累积误差,增大输出。在输出增到设定的最大占空比的时候,清空I环节,避免I环节的不断累积导致在温度靠近时,温度还有很大的过去累积需要消除,提高占空比对偏差减少的响应。在低占空比的时候,I环节适当的调节,可以避免出现静态误差问题以及提高升温速度。
摇杆位置获取
cap2Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_2);
cap3Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_3);
cap4Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_4);
Per = (cap2Count/100)+(cap3Count/100);
Duty = (cap3Count)/((cap3Count+cap2Count)*0.01);
if(Per/100 == Left_PWM_V)
{
switch(ctrlflg)
{
case 0:pid.Kp += 0.1;break;
case 1:pid.Ki += 0.1;break;
case 2:if(LED_MODE<(LED_MAX-1))LED_MODE++;break;
}
}else if(Per/100 == Righ_PWM_V)
{
switch(ctrlflg)
{
case 0:if(pid.Kp>0)pid.Kp -= 0.1;break;
case 1:if(pid.Ki>0)pid.Ki -= 0.1;break;
case 2:if(LED_MODE>0)LED_MODE--;break;
}
}
if(Duty == Top_Pwm_V)
{
if(ctrlflg>0)ctrlflg--;
}else if(Duty == Buttom_Pwm_V)
{
if(ctrlflg<2)ctrlflg++;
}
仿真分析
- 由图可以分析出,在调节滑阻的过程中
- 第一段是两个滑阻均很低的情况
- 第二段是改变左边滑阻,改变频率,可以看出来周期明显的拉长
- 第三段是改变右边滑阻,改变占空比,可以看出来周期不变的情况下,占空比明显增大。
实际测试
图中是在正常居中情况下的分析仪波形
图中是在中间居上情况下的分析仪波形
图中是中间居下情况下的分析仪波形
图中是中间居右情况下的分析仪波形
图中是中间居左情况下的分析仪波形
实测总结
可以看出波形的频率和占空比很大程度与摇杆有关,但是也存在波动和误差。
按键获取
//
// Convert, wait for completion, and store results
//
ADC_forceMultipleSOC(myADC0_BASE, (ADC_FORCE_SOC0 | ADC_FORCE_SOC1));
//
// Wait for ADCA to complete, then acknowledge flag
//
while(ADC_getInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1) == false)
{
}
ADC_clearInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1);
//
// Store results
//
myADC0Result0 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
if(myADC0Result0 > Top_Key_ADC)
{
}else if(myADC0Result0 > Under_Key_ADC)
{
if(SetTemp < 50)SetTemp += 0.05;
}else if(myADC0Result0 > Two_Key_ADC)
{
if(SetTemp > First_Value_Set+5)
{
SetTemp -= 0.05;
}
}
持续采集ADC,但数据的处理在中断中,对当前的AD采样作为识别的按键标志。
遇到的主要难题及解决方法
问题1:温度控制的非线性
由于温度是多因素决定的,本身的控制比较复杂,理论上应该采用观测器去做状态观测,再自修正。
解决方法
这个问题通过拉长控制周期,缩短控制偏差,缓慢增长的方法,在短时间内做线性控制,从而实现稳定控制。
问题2:摇杆和AD采集的波动
在实际分析仪的波形获取可以很直观的看出来波动的产生,很容易造成误判。
解决方法
实际控制有一种策略,应对正常用户的操作的实际情况,其实我们往往不需要过于强烈的反应,按下过程持续很长时间,这段时间都可以获取信息,由于波动不是持续很长一段时间,所以通过稀疏采样,可以减少波动的命中率,我们采用100ms的采样,很大程度避免了偏差,也不影响使用的正常体验。