STM32 单片机 PID 加温项目的调试经验与心得分享
手上有一个项目需要有加热功能(目标 65℃左右),刚开始也没怎么在意,最开始只是想着
一个普通的加热功能无非就是接近目标温度的时候开始间段加温(类似发光二极管闪烁的状
态),等到了实际加热的时候发现用这种方法可以控温,但是控温上下幅值过高,虽说项目
对精度要求不高,个人有点强迫症,想着要做就做好,然后在网上查询了一下控温方式的几
种算法,基本上 90%的都是用 PID,好那就开始着手研究 PID 了,查阅了大量的相关文献,
对 PID 的原理也懂了(能查到的都是通篇大道理,可是能实际应用的少之又少),关于 PID
的算法网上也是一大堆,说实话我也看不懂,也没心思取研究他的算法,干脆直接在网上找
源代码好了,源代码倒是很多,大部分都不是很完善,没办法只要算法是正确的就行了,有
了算法,具体怎么用就只能靠自己写了。
下面开始直入核心阶段
1:什么是 PID,PID 的发展史,,这些问题自行百度,我只简单的描述一下,比如设定 65℃,
当温度上升到 60℃的时候开始启用 PID 加热方式,然后由 PID 进行温度控制,因为有 PID
的存在,实际温度会在 65℃上下浮动,浮动的精度由多种因素决定。精度控制在+-0.5℃还
是很好控制的。
2 :PID 公式,PID 公式网上也是一搜一大把,我也看不懂,在网上找到了 PID 公式的源代
码那就不需要研究他是怎么计算的,没什么意义,就跟 1+1 为什么等于 2 一样,我们要用的
是公式计算出来的值,至于为什么得到了这样的一个值不是我们所关心的,这个值具体怎么
用在网上能找到的相关问题很少,至少我是没找到的,后来经过我反复印证,PID 公式计算
出来的这个值是一个任意值,所谓的任意值指的是我想要一个什么样的结果就让 PID 计算出
什么样的结果,比如,我要让 PID 输出的结果在 0-100 也可以,0-1000-10000-50000 都可
以,包括输出负数也是可以的,PID 核心的东西是我们要用到的这个值,既然这个值是由我
们来控制的,那么我就把这个值控制在 0-100,这个值我们已经决定好了,这个值怎么应用
到实际工程当中呢?
我的目标温度是 65℃,实际温度<=60 的时候由单片机持续输出低电平信号(持续加热),
当温度>=60.1℃的时候开始用 PID 加热方式,所谓的 PID 加热方式就是,把 PID 计算出来的
值用作加热的时间,这个时间怎么对应呢,刚刚我们提到过 PID 的值由我们决定让他的结果
在 0-100 之内,然后我们利用定时器设置一个定时时间在 10 毫秒钟的加热周期(这里按照自
己实际项目来调整,只能先进行测试之后得到一个大概值,在结合实际情况来调整),当 PID
算出来的结果是 100,那么就是加热 10ms*100(也就是持续加热 1 秒中),当 PID 的值是 25
的时候就是加热 10*25=250ms(还有 750ms 是处于不加温的时间段),这个时候 PID 的值和加
热的时间已经对应上了,这个不难理解,到了这里 PID 这个公式本身也算是讲完了,但是在
实际应用的时候还有非常多的问题,这次一并把个人所得得经验也分享出来,刚刚讲到到了
60.1℃就开启 PID 算法(开启就是让 PID 公式计算一次,得到一个值,既然是要让 PID 自行
控温,那么就需要不停得让 PID 进行计算,一旦 PID 得值发生了变化,控制加热得时间也就
变化了,那么 PID 多长时间计算一次呢,这个问题没有人能回答,只能说按照实际工程来调
整,我测试加热得时候是每 2 秒中计算一次,如果用在电机上进行调速 2 秒中计算一次肯定
不行,调速的话肯定是毫秒级别了),
3:PID 参数的调整,第 2 部分所以的功能已经完善了,但是要想达到很高的精度还得进行
PID 的三个参数调整,P 值,I 值,D 值,这个三个参数调整也是最费时间的,也是最难调整
的,我也是查阅了大量相关资料才慢慢调出来,前前后后调了 3 天,第 4 天才算是稳定下来
了。
说一下我的调整经验吧,首先调 P 值,I 和 D 全部设定为 0,P 值可以从 1 开始调,慢慢加,
调到什么样才算正常呢?还是拿我的经验来说吧,目标温度 65℃,当 PID 控制温度在 65℃
上下徘徊的时候就是最佳状态(我的实际情况是 P 值设定为 15 的时候,最高温度是在 66.3,
最低温度在 63.9),简单的说就是 P 值调到在目标值在设定值上下徘徊的时候就对了(徘徊
幅度越小越好)。
好了这个时候就开始调整 I 值,I 值得设定也是和 P 值一样,慢慢调试,我刚开始是从 1 开
始往上加,结果发现整个 PID 都失去控制了,因为是第一次用 PID 也是没经验,查了资料才
知道 I 值一般都是很小,然后开始从 0.1 开始调整,反正就是一直调整呢,最后把 I 值调整
在 0.05 的时候温度已经很平稳了,这个时候实际温度稳定在 64.5-65.4 之间了,和没有 I
值得时候相对稳定一些了,关键得问题是时间越长越稳定,个人觉得 I 值调整是在 P 值得基
础上让实际温度和无限接近设定温度(上下浮动越小越好),I 值确定了,开始调 D 值,D 值
调整的目的是为了弥补 PID 因为环境温度变化或者是加热器件的功率变化导致控温误差变
大而来的,所以我在调整 D 值得时候拿一个扇子给加热器件进行加速散热,后来把 D 值确定
在 0.03 的时候发现用扇子额外散热和不用扇子的已经没有什么区别了。调完 I 值得时候可
以发现 D 值调不调整感觉意义也不大了,之前查到得资料 D 值得作用就是能预测未来(预测
未来是个人得一个理解,这也是 PID 得精华所在),这个所谓得预测未来的值,是当外界加
热环境或者加热功率发生了变化依然不影响之前所调整得精度,比如你夏天调好得精度,不
会因为到了冬天而让精度发生了变化,当然了这个也不是绝对得,比如你之前用的是 100W
得加热方式在调整,你突然把加热器换成 2000W 的加热器,那肯定是不行的,也没有哪个
PID 算法能做到这么大的范围让它自动调整(串级 PID 估计可以达到这个条件)。
//--------------------------------------------------------------------------------------------------------------------
---------------------------------------------
4:下面开始分享 PID 源代码是怎么使用的,
float pid_p;//P 值
float pid_i;//I 值
float pid_d;//D 值
unsigned intZLG_pid_val_mid;//PID 计算的值存放变量,
/************************ZLG_PID 控制算法*************/
void ZLG_PID()
{
int dError=0,Error=0,B;
//---------------------
Error=ZLG_SpeedSet-ZLG_CurrentSpeed;//当前误差 //PID 算法第一步 设定转速减去当前转速 赋值给 Error
ZLG_sumError=Error+ZLG_sumError;//误差和
dError=Error-ZLG_lastError;//误差偏差
ZLG_lastError=Error;
B=pid_p*Error+pid_i*ZLG_sumError+pid_d*dError;
//----------------------
if(B>100)
ZLG_pid_val_mid=100;//pid_val_midPWM 占空比宽带/
//--------------------
if(B<0)
ZLG_pid_val_mid=0;// PWM 占空比宽带
//----------------------
if(B>=0&&B<=100)
ZLG_pid_val_mid=B;//PID 计算出来的值存放在这里,
}
这个函数就是 PID 的核心,每调用一次就进行一次 PID 的计算(每计算一次也就会得到一个 PID 计算出来的值,这个值就是我上面提到的
加热时间)
PID 本身的计算方法这里就已经完成了,但是这个值具体怎么使用呢,PID 本身又该怎么调用呢?
我这里用到了 2 个定时器,定时器 1 每隔 2 秒中进行一次 PID 运算(2 秒中的时间也是我调试出来的,具体项目具体调整),代码如下:
if(TIM4->SR&0X0001)//溢出中断
{
P0_xin_hao_Time++;//P0 信号灯闪烁
//----------------------------
//ZLG
PID 运算
if(biao_zhi_wei.ZLG_PID_kai_guan==1)//ZLGPID 启动了,温度到了 60.1℃开始进行 PID 计算
{
}
次 PID 运算。
}
这是 STM32 的代码。
ZLG_PID_Time++;//PID 计算周期变量
if(ZLG_PID_Time>=2)//定时器 1 秒进入一次中断 2 次就是 2 秒,所以每隔 2 秒做一
{
}
ZLG_PID_Time=0;//清 0
ZLG_PID();//每 2 秒中计算一次 ZLG_PID 的值
我这里只贴出了运算,具体定时器启动的设置就不贴出来了,大概原理就是当温度到了
60.1℃定时器 1 开始启动,每隔 2 秒中产生一次中断,在中断里面进行一次 PID 运算,这个
非常简单。
定时器 2 做为加热时间的判断(类似于 PWM),通样只贴出部判断部分代码,代码如下:
if(biao_zhi_wei.ZLG_PID_kai_guan==1)//ZLGPID 启动了,温度到了 60.1℃之后进行加热时间的判
断
{
ZLG_c++;
//每次定时器溢出加 1
//ccc=ZLG_c;
if(ZLG_pid_val_mid>=ZLG_c)
ZLG_LED=0;
//BEEP=0;
{
}
if(ZLG_pid_val_mid
}
if(ZLG_c>=100)
{
}
ZLG_c=0;
//ccc=ZLG_c;
}
}
这段代码的原理就是,每产生一次中断(中断时间 10ms)计数器+1(自己定义的一个变量),
当 PID 的值>=PID 计算出来的值那就输出低电平(开启加热),反过来就是输出高电平了,如
果 PID 计算出来得值超过了 100,那就持续加热就完了.
到了这里,PID 得所有东西都讲完了,PID 本身也不是很难,只要知道怎么用剩下得就是慢
慢调整了,而且用在加热上面算是最简单了。
简单的叙述一下 PID 的加热原理
1:当目标温度接近设定温度(我设计的是相差 5)开启 PID 运算
2:定时器 1 每隔 2 秒中产生一次 PID 运算(这个时间实际情况调整)
3:定时器 2 每隔 10ms 产生一次中断并做记录(也是实际情况调整),PID 计算出来的值和记
录值想比较,时间到了就切换加热或者不加热
前 3 条整个 PID 的动作都完成了,剩下的就是调整 PID 的
P
I
D 三个参数
调整方法
先调 P 值,效果达到实际温度在目标温度上下徘徊,徘徊浮动越小越好,此时 P 值调完,
再调 I 值,I 值非常,我调整的是 0.05,这个时候在调整 I 值得时候会发现实际温度和目标
温度非常接近,上下浮动也是非常小,直至达到要求。
最后调 D 值,P 和 I 调完后我发现 D 调不调精度都是很好,后来查到 D 值得作用就是能预测
未来(这是我自己得理解,也许有误),D 值得作用上面也提到了,这里就不再提了。
以上都是个人经验所得,个人能力有限,也许很多地方理解错误了,请多包涵。。。