51单片机检测水箱内温度,ph值;
使用pid算法控制温度到设置值;
普通控制ph值到设定值
温度低,启动加热;PH值过高,启动进水;PH值过低,启动进料。
水位过高,启动放水。
电路原理图如下:
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
程序流程图
元件清单:
元件 型号 数量
单片机 AT89C51 1
电容 10uf 1
电容 30pf 2
晶振 12MHZ 1
电阻 10k 1
按钮 7
温度传感器 DS18B20 1
模数芯片 ADC0832 1
电位器 1k 2
电阻 1k 4
三极管 PNP 4
继电器 5V 4
显示器 LCD1602 1
排阻 10k 1
单片机源程序如下:
- #include "reg51.h"
- #include "lcd1602.h"
- #include "Ds18b20.h"
- #include "ADC0832.h"
- #include"pid_pwm.h"
- #define uchar unsigned char
- #define uint unsigned int
- sbit k1=P3^2;//按钮
- sbit k2=P3^3;
- sbit k3=P3^4;
- sbit k4=P3^5;
- sbit k5=P3^6;
- sbit k6=P3^7;
- sbit out1=P2^4;//输出控制
- sbit out2=P2^5;
- sbit out3=P2^6;
- sbit out4=P2^7;
- uchar time=0,mode=0;//系统变量
- uchar wendu=0,ph=0,water=0;//温度,pH值,水位
- uchar lim1=25,lim2=7,lim3=100;//阀值
- uchar disp1[]="T:000 P:00 H:000";
- uchar disp2[]=" 000 00 000";
- uchar pwm=0;
- //主函数
- void main()
- {
- uchar i=0;
- init_1602();
- TMOD|=0X01;
- TH0=0X3C;
- TL0=0XB0;
- ET0=1;//打开定时器0中断允许
- EA=1;//打开总中断
- TR0=1;//打开定时器
- while(1)
- {
- //PWM输出
- if(i<99)
- i++;
- else
- i=0;
- if(i<pwm)
- out4=0;
- else
- out4=1;
- //按键检测
- if(!k1)
- {
- if(lim1<120)
- lim1++;
- while(!k1);
- }
- if(!k2)
- {
- if(lim1>0)
- lim1--;
- while(!k2);
- }
- if(!k3)
- {
- if(lim2<14)
- lim2++;
- while(!k3);
- }
- if(!k4)
- {
- if(lim2>0)
- lim2--;
- while(!k4);
- }
- if(!k5)
- {
- if(lim3<127)
- lim3++;
- while(!k5);
- }
- if(!k6)
- {
- if(lim3>0)
- lim3--;
- while(!k6);
- }
- }
- }
- //定时器中断
- void Timer0() interrupt 1
- {
- uint i=0;
- if(time<10)//0.5s
- time++;
- else
- {
- time=0;
- Ds18b20ReadTemp();//测温
- wendu=ds18b20_temp;
- ph=ADC(1);//PH
- i=ph;
- ph=i*14/127;
- water=ADC(2);//水位
- //显示
- disp1[2]=wendu/100+0x30;
- disp1[3]=wendu%100/10+0x30;
- disp1[4]=wendu%10+0x30;
- disp1[8]=ph/10+0x30;
- disp1[9]=ph%10+0x30;
- disp1[13]=water/100+0x30;
- disp1[14]=water%100/10+0x30;
- disp1[15]=water%10+0x30;
- write_string(1,0,disp1);
- disp2[2]=lim1/100+0x30;
- disp2[3]=lim1%100/10+0x30;
- disp2[4]=lim1%10+0x30;
- disp2[8]=lim2/10+0x30;
- disp2[9]=lim2%10+0x30;
- disp2[13]=lim3/100+0x30;
- disp2[14]=lim3%100/10+0x30;
- disp2[15]=lim3%10+0x30;
- write_string(2,0,disp2);
- //PID控制
- pwm=PID(lim1,wendu);
- //PH值控制
- if(ph>lim2)
- out1=0;
- else
- out1=1;
- if(ph<lim2)
- out3=0;
- else
- out3=1;
- //水位控制
- if(water>lim3)
- out2=0;
- else
- out2=1;
- }
- TH0=0X3C;
- TL0=0XB0;
- }
复制代码- #include"pid_pwm.h"
- uchar P_dat=1,I_dat=1,D_dat=1;//PID参数
- uint pid_dat[]={0,0,0,0,0}; //临时数据
- //PID计算,返回占空比
- uchar PID(uint mub,uint dat)//调整目标+测量数据
- {
- uchar i=0;
- uint j=0,sum=0,k=0;
- //存储数据
- for(i=0;i<4;i++)
- pid_dat[i]=pid_dat[i+1];
- pid_dat[4]=dat;
- //P调节
- j=0;
- if(dat<mub)
- {
- j=j+(mub-dat)*P_dat;
- if(j>100)
- j=100;
- }
- else
- {
- k=(dat-mub)*P_dat;
- if(j>k)
- j=j-k;
- }
- //I调节
- sum=0;
- for(i=0;i<5;i++)
- sum+=pid_dat[i];
- sum=sum/5;
- if(sum>mub)//减小
- {
- k=(sum-mub)*I_dat;
- if(j>k)
- j=j-k;
- }
- else //增加
- {
- k=(mub-sum)*I_dat;
- j+=k;
- if(j>100)
- j=100;
- }
- //D调节
- if(dat>pid_dat[3])//减小
- {
- k=(dat-pid_dat[3])*D_dat;
- if(j>k)
- j=j-k;
- }
- else //增加
- {
- k=(pid_dat[3]-dat)*D_dat;
- j+=k;
- if(j>100)
- j=100;
- }
- return j;
- }
复制代码
Keil代码与Proteus仿真下载:
51水箱水质温度检测系统.7z
(911.22 KB, 下载次数: 102)
|