电源-闭环控制升级之PID调节(附PID源

电源-闭环控制升级之PID调节(附PID源

前言电源方向资料免费开源到QQ群1:280730348和QQ群2:725438563。

嵌入式方向资料免费开源到QQ群1:976387827。

博客地址edadong.com,博文同步发布在知乎、bilibili,其中bilibili主要以视频为主。对开源项目的疑惑请尽量在b站下方留言,其次在群内商讨,目前BUCK和BOOST电路均有群友复刻成功,逆变电路、双向DC充放电电路我也验证过。

下面是BUCK电路的PID控制方案和具体电路,更详细的讲解请移步Bilibili:EDAdong。

软件思路PID其实属于比较常见且通用的闭环调节算法,经典古老但实用。在一般的单环或者双环闭环控制环节,拥有较为不错的效果。本次分享的PID属于增量式PID,大家可以去了解一下增量式PID和位置式PID的区别,一般来说在电源设计里面增量式PID会用的比较多一点。传统PID中,P环是根据当前误差量输出反馈量,I环是根据当前误差和上一次误差之差输出反馈量,D环是根据上次I环误差量和此次I环误差量进行刹车反馈,通过上一次误差量抑制当前误差。P环比较通俗易懂一点,所以传统PID里面P环会用的比较多一点。放在增量式PID中,传统PID的P环其实跟增量式的I环一样,所以这一点有所区分,大家需要注意。我通常是P环和I环一起调,以I环为主导。

本次PID代码在基于BUCK的实战演练项目中修改,直接可用,话不多说直接上代码

在PID.c文件中,可以看到buck_pid的调节函数,第一个参量NOW代表的是你当前采集到的数据(比如在本设计中就是电压所转换成的ADC值,范围0-4096)。第二个参量Target代表你要追踪的目标值(比如在本设计里面把目标电压转换成对应ADC值)。第三个参量SIGNLE_ADD_NUM_LIMIT代表单次增加量,每次PID调节的增量范围,这个值不能太大,否则系统就容易震荡起来。程序中设定的PID周期为1ms,每秒能执行1000次,每次如果拉满的话,那么1s理论上就能调节5000,但我们重装载值也就3600,而且越接近目标值,增量就会越小,所以这个参数你可以根据自己的系统去调节,目前我用的5基本跑单环速度和精度都没问题。第四个参量SUM_OUTPUT_NUM_LIMIT代表输出限制,比如我们重装载值为3600,那么这个值就可以设置成3599,确保占空比不会继续递增。后面的两个参量kp和ki分别代表增量式PID里面的积分调节和比例调节。

pid.c

1234567891011121314151617181920212223242526272829303132333435363738#include "pid.h"#include "main.h"PID_Struct pid1;float OUT=50;float buck_pid(float NOW,float Target,float SIGNLE_ADD_NUM_LIMIT,float SUM_OUTPUT_NUM_LIMIT,float kp,float ki)//SIGNLE_ADD_NUM_LIMIT是单次增加最大值 如100即为单次转换输出不能超过+-100{ //SUM_OUTPUT_NUM_LIMIT 是总输出限位 如100 即总输出不能超出+-100的范围 防止长时间低于或高于 对于突变反应不及时 pid1.Pv=NOW; pid1.Ek=Target-pid1.Pv; pid1.Pout=kp*(pid1.Ek-pid1.Ek_1); pid1.Iout=ki*pid1.Ek*pid1.T/pid1.Ti; pid1.Dout=pid1.Kp_D*pid1.Td*(pid1.Ek-pid1.Ek_1-pid1.Ek_1+pid1.Ek_2)/pid1.T; pid1.OUT_Single=pid1.Pout+pid1.Iout+pid1.Dout; if(pid1.OUT_Single>SIGNLE_ADD_NUM_LIMIT)pid1.OUT_Single=SIGNLE_ADD_NUM_LIMIT; else if(pid1.OUT_Single<-SIGNLE_ADD_NUM_LIMIT)pid1.OUT_Single=-SIGNLE_ADD_NUM_LIMIT; OUT+=pid1.OUT_Single; if(OUT>SUM_OUTPUT_NUM_LIMIT)OUT=SUM_OUTPUT_NUM_LIMIT; else if(OUT<0)OUT=0; pid1.Ek_2=pid1.Ek_1; pid1.Ek_1=pid1.Ek; return OUT;}void init_buck_PID(){ pid1.Kp_P=0; pid1.Kp_I=1; pid1.Kp_D=0; pid1.T=1;//Ms pid1.Td=2.5; pid1.Ti=150; pid1.Pv=1000; pid1.Ek_2=0; pid1.Ek_1=0; pid1.Ek=0;}

pid.h

123456789101112131415161718192021222324252627#ifndef _PID_H#define _PID_Htypedef struct{ float Sv;//期望值 float Pv;//实际值 float Ek_1; float Ek_2; float Ek; float T;//采样周期 float Ti;//积分常数 float Td;//微分常数 float Kp_P;//系数 float Kp_I;//系数 float Kp_D;//系数 float OUT_Single; float Pout; float Iout; float Dout;}PID_Struct;float buck_pid(float NOW,float Target,float SIGNLE_ADD_NUM_LIMIT,float SUM_OUTPUT_NUM_LIMIT,float kp,float ki);void init_buck_PID(void);extern float OUT;#endif

在定时器中断中(20KHz)每进入20次进行一次PID调节,也就是单次调节时间为1ms。

123456789101112131415161718192021222324252627282930//中断服务函数void TIM1_UP_IRQHandler(void) { static u16 pid_count; if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) //检查更新中断发生与否 { pid_count++; //PID调节 if(pid_count==20) { pid_count=0; if(pid_mode==1&&protect_status==0) { buck_pwm = buck_pid(ADC_ConvertedValue[0],(Target_V/3.3*4096/V_xishu),5,3599,kp,ki); set_pwm(TIM1,1,buck_pwm,3599); } else if(pid_mode==0&&protect_status==0) { buck_pwm=0; set_pwm(TIM1,1,buck_pwm,1000); } else if(protect_status==1) { buck_pwm=0; set_pwm(TIM1,1,buck_pwm,1000); } } TIM_ClearITPendingBit(TIM1, TIM_IT_Update); //清除TIMx更新中断标志 }}

主函数中只需要定义float kp和float ki两个参量,extern到main.h里面,再在main函数中初始化init_buck_PID();即可

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136#include "stm32f10x.h" #include "main.h" #include "delay.h" #include "timer.h" #include "timer3.h" #include "oled.h" #include "show.h" #include "adc.h" #include "sw.h"#include "key.h" u8 pid_mode=0;//=0不工作,=1工作u8 pid_status=0;//=0为电压环,=1为电流环u16 buck_pwm=500;//BOOST电路的PWMfloat DC_V=0.0f;//电压数据float Target_V=10.00f;//追踪的电压数据float DC_I=0.0f;//电流数据float V_yuzhi=13.00f;//保护的电压阈值float I_yuzhi=3.00f;//保护的电流阈值u8 protect_status=0;//保护状态u8 sw_status=0;//开关状态float kp=0.01;float ki=1;/************************************************************电压电流检测:电压PA0,电流PA1PWM波驱动引脚:PA8芯片使能引脚:PA9OLED屏幕:SCL:PB1,SDA:PB0继电器控制位:PA10按键:ADD:PB12 REDUCE:PB13 SET:PB14 MODE:PB15************************************************************/int main(void) { u8 key; Delay_Init(); //延时功能初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 BUCK_PWM_Init(); //BUCK电路初始化,20KHz工作频率,带中断。 Init_adc(); //ADC初始化 SW_Init( ); //继电器初始化 KEY_Init(); //按键初始化 TIM3_ENABLE_30S(); //开启定时器3工作,实现电压电流数据采集 OLED_Init(); //初始化OLED loop: SW_OFF; SD_OFF; sw_status=0; pid_mode=0;//失能PID OLED_Clear(); //OLED清零 canshu_view(); //启动界面 while(1) { key=KEY_Scan(0); //扫描按键 if(key==SW_PRES) { SD_ON; //打开芯片引脚使能 SW_ON; //打开继电器电路准备工作 Delay_Ms(500); break; } OLED_ShowNum(72,0,DC_V,2,16); OLED_ShowNum(96,0,(u16)(DC_V*100)%100,2,16); OLED_ShowNum(72,2,DC_I,2,16); OLED_ShowNum(96,2,(u16)(DC_I*100)%100,2,16); OLED_ShowNum(72,4,Target_V,2,16); OLED_ShowNum(96,4,(u16)(Target_V*100)%100,2,16); if(sw_status==0) { OLED_ShowCHinese(84,6,13);OLED_ShowCHinese(100,6,14); } else { OLED_ShowCHinese(84,6,11);OLED_ShowCHinese(100,6,12); } Delay_Ms(50); } while(1) { key=KEY_Scan(0); OLED_ShowNum(72,0,DC_V,2,16); OLED_ShowNum(96,0,(u16)(DC_V*100)%100,2,16); OLED_ShowNum(72,2,DC_I,2,16); OLED_ShowNum(96,2,(u16)(DC_I*100)%100,2,16); OLED_ShowNum(72,4,Target_V,2,16); OLED_ShowNum(96,4,(u16)(Target_V*100)%100,2,16); if(sw_status==0) { OLED_ShowCHinese(84,6,13);OLED_ShowCHinese(100,6,14); } else { OLED_ShowCHinese(84,6,11);OLED_ShowCHinese(100,6,12); } if(key==SW_PRES) { pid_mode=1; sw_status=1; } else if(key==ADD_PRES) { Target_V=Target_V+0.100001f; } else if(key==REDUCE_PRES) { Target_V=Target_V-0.099999f; } else if(key==CHOICE_PRES) { SW_OFF; SD_OFF; sw_status=0; pid_mode=0;//失能PID goto loop; } if((DC_V>V_yuzhi)||(DC_I>I_yuzhi)) { SW_OFF; SD_OFF; protect_status=1; sw_status=0; pid_mode=0;//失能PID goto loop; } }}

资料放百度网盘链接了:

通过网盘分享的文件:post12资料合集链接: https://pan.baidu.com/s/1O4975ZoDPHOWwQN88SApsA?pwd=fvay 提取码: fvay–来自百度网盘超级会员v6的分享

相关推荐

Mysteel半年报:2023上半年国内辣椒市场行情回顾及下半年展望
破天一剑手游官方版
365永久激活怎么做到的

破天一剑手游官方版

📅 08-17 👁️ 3213
【跨服魔王窟,自由移民】玩法合集
世界杯365体育

【跨服魔王窟,自由移民】玩法合集

📅 07-19 👁️ 5069
如何安装无线视频监控摄像头▷➡️
365永久激活怎么做到的

如何安装无线视频监控摄像头▷➡️

📅 07-11 👁️ 5758
怎样查询域名有效期?
世界杯365体育

怎样查询域名有效期?

📅 07-01 👁️ 2978
手机软件如何备份到电脑 手机软件如何备份安装包
世界杯365体育

手机软件如何备份到电脑 手机软件如何备份安装包

📅 08-17 👁️ 3738
不可理喻的解释
365永久激活怎么做到的

不可理喻的解释

📅 07-02 👁️ 1710
狗狗币在哪里买更安全?10 大购买平台对比、手续费及安全购买技巧
注册163邮箱账号的详细步骤(教你如何快速注册并设置163邮箱账号)