- #include<reg52.h>
- #include<serial.h>
- #include<math.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define target 65 //设定温度目标值
- int aa=0,bb=0; // aa,bb是用于显示时间的变量
- signed long error=0,d_error=0,dd_error=0; //相当于公式中的e(k),e(k-1),e(k-2);
- int k=14,ti=5;td=16,det_t,pwm,m=0;
- //unsigned char YSJS=0;
- float t;
- uint tmpvalue=0, value; //tmpvalue是暂时值 value是最终温度值
- int high,low;
- sbit P23=P2^3;
- sbit P22=P2^2;
- sbit DQ = P2^1; //P2.1作为连接DS18B20的I/O口
- sbit p0=P1^0;
- sbit p1=P1^1;
- sbit p2=P1^2;
- sbit p3=P1^3; //P1.3和P1.4作为升温电路的控制端
- sbit p4=P1^4;
- sbit p5=P1^5; //P1.5~P1.7控制八个七段数码管的亮灭
- sbit p6=P1^6;
- sbit p7=P1^7;
-
- void delayms(int o) //用于数码管显示的延时
- {
- unsigned char a1,b1,c1;
- int x=o;
- for(;o>0;o--)
- for(c1=4;c1>0;c1--)
- for(b1=21;b1>0;b1--)
- for(a1=14;a1>0;a1--);
- }
- void init() //定时器初始化
- {
- TMOD=0x21;
- TH0=(65536-50000)/256;
- TL0=(65536-50000)%256;
- EA=1;
- ET0=1;
- TR0=1;
- }
-
- /***************八段管显示码***************/
- code uchar LEDmap[] ={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};
- code uchar BITaddr[] ={0x0f, 0x2f, 0x4f, 0x6f, 0x8f, 0xaf, 0xdf, 0xef}; //数码管位选地址
- uchar code LEDmap1[] ={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; //带小数点数字编码
- /***************ds18b20的程序***************/
- void delay(unsigned int i)
- {
- while(i--);
- }
- void Init_DS18B20(void)
- {
- unsigned char x=0;
- DQ = 1; //DQ复位
- delay(8); //稍做延时
- DQ = 0; //单片机将DQ拉低
- delay(80); //精确延时 大于 480us
- DQ = 1; //拉高总线
- delay(14);
- x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
- delay(20);
- }
- //读一个字节
- int ReadOneChar()
- {
- unsigned char i=0;
- unsigned char dat = 0;
- for (i=8;i>0;i--)
- {
- DQ = 0; // 给脉冲信号
- dat>>=1;
- DQ = 1; // 给脉冲信号
- if(DQ)
- dat|=0x80;
- delay(4);
- }
- return(dat);
- }
- //写一个字节
- void WriteOneChar(unsigned char dat)
- {
- unsigned char i=0;
- for (i=8; i>0; i--)
- {
- DQ = 0;
- DQ = dat&0x01;
- delay(5);
- DQ = 1;
- dat>>=1;
- }
- }
- //DS18B20程序读取温度
- void ReadTemperature()
- {
- Init_DS18B20();
- WriteOneChar(0xCC); // 跳过读序号列号的操作
- WriteOneChar(0x44); // 启动温度转换
- Init_DS18B20();
- WriteOneChar(0xCC); //跳过读序号列号的操作
- WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
- low=ReadOneChar();
- high=ReadOneChar();
- tmpvalue = high;
- tmpvalue =(tmpvalue<<8);
- tmpvalue=tmpvalue | low;
- value=tmpvalue*0.0625;
- t=tmpvalue*0.625;
- }
- /***************主函数****************/
- void main()
- {
- int i=0;
- init(); //初始化子程序
- uart_init();
- P23 = 1;
- P22 = 1;
- delayms(9500);
- P23 = 0;
- P22 = 0;
- while(1)
- {
-
- if((bb%3)==0) //每三秒扫描一次 ,采样周期3s
- {
- dd_error=d_error;
- d_error=error;
- error = (signed long)(target-value);//求e(k) //求e(k-1) //求e(k-2)
- det_t=k*(error-d_error)+(k*3/ti)*error+(k*td/3)*(error-2*d_error+dd_error); //增量公式 */
- // det_t=20*(error-d_error)+0.15*error+10*(error-2*d_error+dd_error); //增量公式 */
- pwm=det_t;
- if((error>10)||(pwm>60))pwm=60;
- }
- ReadTemperature();
- p5=0;p6=0;p7=0;P0=LEDmap[bb%10];delayms(1); //在数码管上显示时间
- p5=1;p6=0;p7=0;P0=LEDmap[bb%100/10];delayms(1);
- p5=0;p6=1;p7=0;P0=LEDmap[bb%1000/100];delayms(1);
- p5=1;p6=1;p7=0;P0=LEDmap[bb/1000];delayms(1); //
- p5=0;p6=0;p7=1;P0=LEDmap[(int)t%10];delayms(1); //温度小数显示
- p5=1;p6=0;p7=1;P0=LEDmap1[value%10];delayms(1); //温度个位及小数点显示
- p5=0;p6=1;p7=1;P0=LEDmap[value%100/10];delayms(1); //温度十位显示
- if(i++>100)
- {
- Uart_SendChar(0x5a);
- Uart_SendChar(value%100/10);
- Uart_SendChar(value%10);
- Uart_SendChar((int)t%10);
- Uart_SendChar(0);
- i=0;
- }
-
- }
- }
- void timer0() interrupt 1
- {
- TH0=(65536-50000)/256;
- TL0=(65536-50000)%256;
- aa++;
- if(aa==20){aa=0;bb++;} //计时1s
- if(m<pwm){p3=1;p4=1;} //电机启动,加热
- if((m>=(pwm))||(value>=target)){p3=0;p4=0;} //电机关闭,停止加热
- if(m==60)m=0;
- m++;
- }
复制代码
从硬件电路开始学习,然后编写程序对加热杯内的水温进行控制。能够完成水温在65摄氏度的稳定性实验,并计算了超调和稳态误差。升温速率可以为1--4度/分钟,分阶段升温。编制了信号采样程序,转换显示以及在数码管上时钟显示(秒表)。达到设定温度稳定后加入扰动,控制加热算法,使其快速达到温度设定值。
|