用51单片机做的PID液位控制系统 程序PCB和设计实训报告一应俱全.
51单片机PID液位控制系统设计所有文件下载(包含程序 论文 pcb文件):
液位控制.rar
(453.09 KB, 下载次数: 259)
以下是单片机pid液位控制系统设计的论文预览:
桂林电子科技大学信息科技学院 《自动化仪表与过程控制》实训报告 班级:自动化一班 学号: 00000000000000 姓 名:00 指导教师:xxx 2015 年 6 月 15 日
实训题目:液位控制系统
1 系统设计 1.1 设计要求 1.1.1 基本原理 水箱为双容水箱,仅使用一个作为被控对象,即单容液位控制(将水箱设为自衡系统),水箱采用水泵进行给水,水泵为12V直流电机控制,可采用PWM方式。液位传感器为压力式,输出为电压信号。设计调节器(模拟或数字式),能够根据用户设定,将水位控制在要求值(采用PID或PI规律)。
1.1.2 性能指标要求 1、设计制作硬件系统电路,标记姓名学号及制作日期; 2、实现水泵的控制、信号检测(显示)及调节器控制规律; 3、系统能够尽快的克服扰动;
1.1.3 设计方法与步骤 1、根据设计基本原理和性能指标要求选择总体方案,画出设计框图; 2、参阅相关资料,根据设计框图进行电路的设计; 3、列出元件清单; 4、画原理图,布PCB图,并制作电路板; 5、根据器件由小到大的顺序安装电路,并进行自检测试; 6、数学建模、设计合适的控制参数; 7、调试所制作的电路; 1.2 设计思路及设计框图 1.2.1设计思路 调节器和PWM信号产生用51单片机执行,单片机与驱动模块之间使用光电耦合器进行隔离。液位变送器根据水压不同输出模拟电流信号(0-20mA),然后经250欧电阻转成0-5V的电压信号经过ADC0809芯片转换成数字信号,再把数字信号传给单片机的P1口,用单片机进行数据处理。用两位数码管显示AD值(调试用的),经多次测量AD值所对应的液位高度,记下多组数据,再用MATLAB,Polyfit(x,y,n) 函数,拟合曲线,得到线性关系,然后再把之前显示AD值的两位数码管用来显示拟合出来的AD值所对应的液位。另外两位数码管则用来显示设定液位的高度。 水泵的驱动用达林顿三级管驱动,可以通过单片机模拟出来的PWM控制水泵的转速。
1.2.2总体设计框图
2 各个模块的程序的设计 1、PID算法控制: #include"PID.H" /*PID参数初始化*/ voidIncPIDInit(void) { //sptr->SumError = 0; sptr->LastError = 0; //Error[-1] sptr->PrevError = 0; //Error[-2] sptr->Proportion = 100; //比例常数Proportional Const sptr->Integral = 1;//积分常数Integral Const sptr->Derivative = 1; //微分常数Derivative Const } /*增量式 PID 计算部分*/ intIncPIDCalc(int NextPoint) { register int iError,iIncpid; //当前误差 iError = sptr->SetPoint - NextPoint;//增量计算 iIncpid = sptr->Proportion *iError//E[k]项 -sptr->Integral*sptr->LastError//E[k-1]项 + sptr->Derivative *sptr->PrevError; //E[k-2]项 //存储误差,用于下次计算 sptr->PrevError = sptr->LastError; sptr->LastError = iError; //返回增量值 return(iIncpid); } 2、ADC0809模数转换: voidInitAdc(void) //ADC初始化 { ST=0; OE=0; ST=1; ST=0; } voidAdcObtainData(void) //ADC或出数据 { while(EOC==0); OE=1; getdata=P1; YEWEI=5*(getdata-50); SHI=YEWEI>>4; GE=YEWEI&0X0F; OE=0; DelayMs(200); //延时防止采集频率过快 } 3、数码管显示模块: voidTimer1Interrupt(void) interrupt 3 { TH1 = 0x0EC; TL1 = 0x78; switch(c) { case0:P2=0X8f;P0=dofly_DuanMa[0];break;//显示2位液位值break; case1:P2=0X4f;P0=dofly_DuanMa[YEWEI/100];break; case2:P2=0X2f;P0=dofly_DuanMa[YEWEI%100/10];break;//显示2位数液位break; case3:P2=0X1f;P0=dofly_DuanMa[YEWEI%10];break; } c++; if(c==4){c=0;} d++; if(d==400){d=0;} } 4、按键控制模块: voidSheZhi(void)//按键设置液位高度 { if(KeyPlus==0) //液位增加按键 { DelayMs(100);//防止按键抖动 while(!KeyPlus); KZ++; } if(KeyMinus==0) //液位降低按键 { DelayMs(100);//防止按键抖动 while(!KeyMinus); KZ--; } } 5、PWM电机控制模块: voidjishi(void) interrupt 1 using 1 //定时器中断0输出PWM { TH0 = (65536-50)/256; //求模 0.05ms TL0 = (65536-50)%256; //求余 /*用来电机调速*/ speed_L++; if(speed_L < PWM_L) //调速给出高电平占空比 { ENA= 0; } else if(speed_L > PWM_L) //调速给出低电平占空比 { ENA= 1; } if(speed_L == 256) //1S周期至256时清零 { speed_L= 0; ENA= 0; } CLK=~CLK; } 3 制作与调试过程 ①制作:本次实训在制作电路板的过程中,根据所查找的资料提供的原理图进行修改,从原理图中减去了很多的元件。然后用AD软件画出原理图,接着转为PCB,手动布线,并将PCB转印在板子上,腐蚀、打孔后,完成实训电路板。 ②调试:当电路板制作完成后,需要调试电路板能否完成实训要求的功能,在调试的过程中我发现了数码管是共阳的,随后在P2口焊上1K上拉电阻,本次实训没有用到三极管导致数码管不够亮,但是并不影响参数整定,而且晶振也换为12兆。 4功能测试 4.1测试仪器和设备 万用表、传感器设备、双容水箱 4.2性能指标测试 ①实现液位标定(误差%5) ②完成参数的整定 5.硬件工作模块
51最小系统
最小系统是指是指用最少的元件组成的单片机可以工作的系统,它包括单片机、复位电路和时钟电路。
复位电路:单片机第9脚为复位信号引脚(RST),复位信号高电平有效,但高电平维持时间必须维持在24个振荡周期以上才能完成复位。系统使用12MHZ晶振则复位需要两个机器周期。通电瞬间RC电路充电,RST引脚得到了一定脉宽的信号,只要信号脉宽维持在复位允许时间,单片机即可复位。
起振电路:在外部连接晶振和起振电容便可构成内部振荡电路,产生振荡时钟脉冲。
单片机:AT89S52,它是一种低功耗、高性能CMOS8位微控制器,具有8K系统可编程Flash储存器。
A/D转换
ADC0809是一款8通道复用的8位AD转换器,数据获取的关键部分是它的八位8位模/数转换器。这个部分由三部分组成:266R的阶梯网络,连接逼近的电阻和比较器。ADC0809为8路模拟信号的份上采集转换器。片内有8路模拟选通开关,以及相应的通道抵制锁存用译码电路,其转换时间为100US左右。
电机模块
5.实训心得 经过本次实训,让我对过程控制这一门课有了更深刻的了解。特别是双位控制和PID控制,不仅对理论有了跟深刻的了解,还对它们实际应用有了一定的认识。这次实训首先设计原理图和布局PCB,然后做板子。在设计原理图的时候没有注意到数码管是共阳的,也没加三极管,导致数码管很暗,后来在接数码管位选的IO口上接了一个1K的上拉电阻,有效的解决了这个问题。其中本次实训的关键在于调试,这也是最难,它不仅考验了知识,还考验了耐心。调试主要包括了测量参数,利用参数经数学计算工具拟合出曲线,还有就是不断的修改程序,首先就是调节P值,不让I作用,让水位能在设定值的附近比较稳定的上下波动,出现等幅振荡最好。最后加入I调节,调整I参数,是系统跟加好的稳定。不过本次实训中我只调了P,因为调了P水位也能比较稳定的在设定值的附近微小的波动。 附录1:原件清单 51单片机 ADC0809 数码管 达林顿三极管 四个独石电容 两个瓷片电容 多个电阻 RS232串口芯片 DB9 1K上拉电阻 若干插针 接线柱 12M晶振 三个按键 一个极性电容 光耦 下载接口
附录2:程序清单 - #include <reg51.h>
- #define uchar unsigned char
- #define uint unsigned int
- uint c=0; //获取液位AD值,
- unsigned char code dofly_DuanMa[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
- 0x90,0X88,0X83,0Xc6,0Xa1,0X86,0X8e};// 显示段码值0~9
- /*ADC0809*/
- sbit EOC=P3^2; //转换结束信号
- sbit OE=P3^3; //允许输出信号
- sbit ST=P3^4; //转换启动信号
- sbit CLK=P3^5; //时钟
- /*按键*/
- sbit KeyPlus=P2^0;//按键加
- sbit KeyMinus=P2^1;//按键减
- /*驱动*/
- sbit ENA=P3^6;//进出水控制
- double KZ=100;
- double YEWEI; //获取液位AD对应液位值,
- uint rout; // PID Response (Output)
- uint getdata;
- uint PWM_L;
- uint speed_L = 0;
- void DelayUs2x(unsigned char t)
- {
- while(--t);
- }
- void DelayMs(unsigned char t)
- {
- while(t--)
- {
- //大致延时1mS
- DelayUs2x(245);
- DelayUs2x(245);
- }
- }
- void InitTimer0(void)
- {
- TMOD = 0x11;
- TH0 = (65536-500)/256; //求模 0.5ms
- TL0 = (65536-500)%256; //求余
- TH1 = 0x0EC;
- TL1 = 0x78;
- EA = 1;
- ET0 = 1;
- TR0 = 1;
- ET1 = 1;
- TR1 = 1;
- }
- void InitAdc(void) //ADC初始化
- {
- ST=0;
- OE=0;
- ST=1;
- ST=0;
- }
- void AdcObtainData(void) //ADC或出数据
- {
- while(EOC==0);
- OE=1;
- getdata=P1;
- if(getdata<53)
- {
- getdata=53;
- }
- YEWEI=(double)5*((double)(getdata)-53);//AD值是70就对应100mm的液位高度
- OE=0;
- DelayMs(200); //延时防止采集频率过快
- }
- typedef struct PID
- {
- int SetPoint;//设定目标Desired Value
- //long SumError; //误差累计
- double Proportion; //比例常数Proportional Const
- double Integral; //积分常数Integral Const
- double Derivative; //微分常数Derivative Const
- int LastError; //Error[-1]
- int PrevError; //Error[-2]
- }
- PID;
- static PID sPID;
- static PID *sptr = &sPID;
- /*PID参数初始化*/
- void IncPIDInit(void)
- {
- //sptr->SumError = 0;
- sptr->LastError = 0; //Error[-1]
- sptr->PrevError = 0; //Error[-2]
- sptr->Proportion = 5; //比例常数Proportional Const
- sptr->Integral = 0;//积分常数Integral Const
- sptr->Derivative = 0; //微分常数Derivative Const
-
- }
-
- /*增量式 PID 计算部分*/
- int IncPIDCalc(int NextPoint)
- {
- register int iError,iIncpid; //当前误差
- iError = sptr->SetPoint - NextPoint;//增量计算
- iIncpid = sptr->Proportion * iError//E[k]项
- - sptr->Integral*sptr->LastError//E[k-1]项
- + sptr->Derivative * sptr->PrevError; //E[k-2]项
- //存储误差,用于下次计算
- sptr->PrevError = sptr->LastError;
- sptr->LastError = iError;
- //返回增量值
- return(iIncpid);
- }
- void SheZhi(void)//按键设置液位高度
- {
- if(KeyPlus==0) //液位增加按键
- {
- DelayMs(100); //防止按键抖动
- while(!KeyPlus);
- KZ=KZ+10;
- }
- if(KeyMinus==0) //液位降低按键
- {
- DelayMs(100); //防止按键抖动
- while(!KeyMinus);
- KZ=KZ-10;
- }
- }
- void Control(void) //液位控制
- {
- InitAdc();
- AdcObtainData();
- if(KZ>YEWEI)
- {
- if(KZ-YEWEI>50)
- {
- PWM_L=250;
- }
- else
- {
- rout=IncPIDCalc(YEWEI);
- PWM_L=(uchar)(rout);
- if(PWM_L>80)
- PWM_L=80;
- }
- }
- }
- void main(void)
- {
- InitTimer0();
- IncPIDInit(); //初始化PID
- while(1)
- {
- sptr->SetPoint = KZ ;
- SheZhi(); //调用设置函数
- Control();//调用控制函
- }
- }
- void jishi(void) interrupt 1 using 1 //定时器中断0输出PWM
- {
- TH0 = (65536-500)/256; //求模 0.5ms
- TL0 = (65536-500)%256; //求余
- /*用来水泵调速*/
- speed_L++;
- if(speed_L < PWM_L) //左轮PWM调速给出高电平占空比
- {
- ENA = 0;
- }
- else if(speed_L > PWM_L) //左轮PWM调速给出低电平占空比
- {
- ENA = 1;
- }
- if(speed_L == 300) //周期至300时清零
- {
- speed_L = 0;
- ENA = 0;
- }
- /*ADC时钟*/
- CLK=~CLK;
- }
- void Timer1Interrupt(void) interrupt 3
- {
- TH1 = 0x0ec;
- TL1 = 0x78;
- switch(c)
- {
- case 0:P2=0X8f;P0=dofly_DuanMa[((uint)YEWEI)/16];break;//显示2位当前液位值break;
- case 1:P2=0X4f;P0=dofly_DuanMa[((uint)YEWEI)%16];break;
- case 2:P2=0X2f;P0=dofly_DuanMa[(uint)KZ/16];break;//显示设定液位值break;
- case 3:P2=0X1f;P0=dofly_DuanMa[(uint)KZ%16];break;
- }
- c++;
- if(c==4){c=0;}
- }
复制代码
|