示波器图中,紫色线高点是3.5v,低点是1.5v
一一对应程序中的getset(350),getset(150)
仿真正确
此pid封装成.c .h文件形式,可以直接调用
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
(1) 了解工业过程控制的一般情况;
(2) 掌握数字PID控制器程序设计方法;
2.实验内容
设计单片机控制电路,采用TLC5615和LTC1292芯片采集电压和输出电压,并编写数字PI控制器程序,对直流电机进行控制,要求采样周期100毫秒,对设定值转速和实际转速进行实时显示。
PID采用增量式,定点计算,输入要滤波,输出要限幅。
3、预备知识
控制系统软件的设计,一般必须有严格的时间限制,故必须基于定时中断进行设计,在中断中运行实时性要求的程序,如A/D采样程序、PID控制程序、D/A输出程序、数码管显示刷新程序和键盘扫描程序等。在主程序中进行一些实时性要求低的程序,如打印程序、数据输入程序等。
4、实验步骤
从D/A输出点接一个二阶惯性对象,将对象输出接A/D输入点。
在PC机输入源程序并汇编,然后下载到单片机上,进行调试。
注意二阶系统的电路需要与单片机共地
(1) 整理好实验程序。
(2) 总结比例参数P积分参数I和采样周期对控制系统性能的影响。
单片机源程序如下:
PID.C
- #include "pid.h"
- PID pid;
- void PIDParament_Init() //
- {
- pid.choose_model = MODEL_PID;
- pid.T=5; //采样周期
- pid.set =280; //用户设定值
- pid.Kp=20; //比例系数
- pid.Ti=100; //积分比例常数
- pid.Td=5; //微分时间常数
- pid.OUT0=0; //一个维持的输出
- pid.pwmcycle = 280; //PWM的周期
- }
-
- void pid_calc() //pid计算
- {
- float dk1;float dk2;
- float t1,t2,t3;
- // if(pid.Tdata < (pid.T)) //最小计算周期未到
- // {
- // return ;
- // }
- // pid.Tdata = 0;
- pid.curr=LTC1292(); //A/D输入值
-
- pid.En=pid.set-pid.curr; //本次误差
-
-
- dk1=pid.En-pid.En_1; //本次误差与上次误差之差
- dk2=pid.En-2*pid.En_1+pid.En_2; //理解为第二个误差
-
- t1=pid.Kp*dk1; //比例
-
- t2=(pid.Kp*pid.T)/pid.Ti; //积分
- t2=t2*pid.En;
-
- t3=(pid.Kp*pid.Td)/pid.T; //微分
- t3=t3*dk2;
-
- switch(pid.choose_model)
- {
- case MODEL_P: pid.Dout= t1; //仅使用P计算
-
- break;
-
- case MODEL_PI: pid.Dout= t1+t2; //使用PI计算
-
- break;
-
- case MODEL_PID: pid.Dout= t1+t2+t3; //使用PID计算
- break;
- }
-
- pid.currpwm+=pid.Dout; //本次应该输出的PID
- // if(pid.currpwm>pid.pwmcycle) //判断本次输出的PID在输出要求之间
- // {
- // pid.currpwm=pid.pwmcycle;
- // }
- // if(pid.currpwm<0)
- // {
- // pid.currpwm=0;
- // }
- if(pid.currpwm>1023*15) pid.currpwm=1023*15;//输出扩大,使效果明显
- if(pid.currpwm<0) pid.currpwm=0;
- pid.En_2=pid.En_1;//每次更新的交换,先交换e2的值,再交换e1
- pid.En_1=pid.En;
- //此处输出PWM
- TLC5615(pid.currpwm/15);
- }
复制代码- #include <reg52.h>
- #include <pid.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define ulong unsigned long
- //sfr AUXR =0x8E;
- sbit ADAT=P2^5;
- sbit ACLK=P2^6;
- sbit ACS =P2^7;
- sbit Set=P3^7;
- uint LTC1292(void) //输入值
- {
- uint i,x;
- ACLK=0; ADAT=1; ACS=0;
- for(i=0;i<14;i++)
- {
- ACLK=1;
- x<<=1;
- if(ADAT==1) x++;
- ACLK=0;
- }
- ACS=1;
- return (x&0xfff);
- }
- sbit DDAT = P3^4;
- sbit DCS = P3^3;
- sbit DCLK = P3^2;
- void TLC5615(uint j) //输出值,PID计算后输出
- {
- uchar i;
- DCLK=0; DCS=0;
- j=j<<6;
- for(i=0;i<12;i++)
- {
- j=j<<1; DDAT=CY;
- DCLK=0; DCLK=1;
- }
- DCLK=0; DCS=1;
- }
- #define kp 20 //比例系数
- #define ki 1 //积分系数
- #define kd 15 //微分系数
- #define TIM -10000 //采样周期
- int e0=0,e1=0,e2=0; //三个时刻
- int s; //增量式PID计算本次应该输出的增量值
- uint r,y; //r是实际要求的输出,Y是A/D传过来的输出
- long u;
- void PID_in() interrupt 3
- {
- // float dk1,dk2;
- // float t1,t2,t3;//分别为比例、积分、微分
- TH1=TIM>>8; TL1=TIM&0Xff;
- // y=LTC1292(); //A/D输入值
- // e2=e1=e0;
- // e0=r-y; //本次误差
- //
- // dk1 = e0-e1;//上一次误差
- // dk2 = e0-2*e1+e2;//上上次误差
- //
- // u+=dk1*kp+e0*ki+dk2*kd;
- // if(u>1023*kd) u=1023*kd;
- // if(u<0) u=0;
- // s=u/kd;
- // TLC5615(s);
- pid_calc();
- }
- uint GetSet(ulong x)
- {
- ulong m;
- m=x*4095;
- return m/500;
- }
- void main()
- {
- IE=0x88;TMOD=0X11;
- TH1=TIM>>8; TL1=TIM&0xff;TR1=1;
- PIDParament_Init();
- while(1)
- {
-
- if(Set) pid.set=GetSet(350);
- else pid.set=GetSet(150);
-
- }
- }
复制代码
仿真代码资料51hei附件下载:
PID资料.7z
(106.09 KB, 下载次数: 78)
|