太阳能热水器的通用控制器研制武汉工程大学刘增华李伟1、系统功能与指标1.1功能特点具有目前产品的一般功能:1)设置上限水位:设置水位上限,可选择50% ~99%之间(我们选取80%),并且在使用中,不得自动上水。
2)设置水箱水温:设置电加热的温度上限,可选择0°C~80°C(我们选取60°C),自动加热。
3)水位指示:LED五段显示。
4)水温指示:LCD液晶数字显示。
5) 自动上水:为防止空晒,当水位低于10%时,系统强制上水;当水位低于30%时,提示报警,若没有使用,启动自动上水,若使用,则报警提示先上水,再使用。
6)辅助加热:当出现阴雨天气,水温达不到要求,启动辅助电加热,电加热温度上限设置为60°C。
同时还具有新加功能:1)智能模式:检测淋浴水温,自动调节凉水的流量,自动调节,使水温保持在设定温度的2°C范围内,并保持有足够的流量。
1.2技术指标1)设置上限水位:设置水位上限,可选择50% ~99%之间(我们选取80%),并且在使用中,不得自动上水。
2)设置水箱水温:设置电加热的温度上限,可选择60°C,自动加热。
3)水位指示:分段显示(5段显示)。
4)水温指示:数字显示(精度为1度)。
5)自动上水:为防止空晒,当水位低于30%时,提示报警,若没有使用,启动自动上水。
若使用,则报警提示先上水,再使用。
6)智能模式:检测淋浴水温,自动调节热水、凉水的流量,自动调节,使水温保持在设定温度的2°C范围内,并保持有足够的流量。
2、系统结构设计2.1系统的工作原理太阳能热水器辅助控制系统结构如图1所示。
在太阳能热水器的储水箱内增加一个电加器,采用220V市电加热,由辅助控制系统的继电器控制通断电,用来在温度达不到要求的时候进行辅助加热来保证热水温度。
水位、水温探测器从保温储水箱顶部安装在水箱中,通过电缆线接入用户室内控制器。
流量控制阀用通过步进电机来精确控制冷水即自来水的流量,来保证热水与冷水混合后的温度达到用户的要求。
当水位不足报警时,通过电磁阀启动上水,上水的过程中,不允许淋浴,且放水电磁阀关闭。
当需要淋浴时,放水电磁阀打开,通过自动控制冷水电磁阀的开度来保证冷水与热水混合后的温度与用户设定值基本一致(水温保持在设定温度的2°C范围内),淋浴过程中,系统禁止上水和辅助加热。
当淋浴完后按下”淋浴完键”,系统停止放水并且电机要复位。
系统的总体结构图如下。
淋浴器图1 太阳能热水器辅助控制系统结构图2.2 控制系统与电路结构组成控制系统采用FPGA内部构建Core8051单片机来控制水温水位等,其内部接线图如图2所示。
整个系统采用Fusion StartKit开发平台,嵌入8051内核为核心,对水温、水位等参数进行智能检测和显示,读取电磁阀的状态,经键盘操作和单片机内部运算比较,控制相应得执行机构进行通、断电及报警提示,其控制系统组成如图3。
图2 FPGA内部Core8051引脚分配图图3 太阳能热水器控制系统的组成Core8051的P0口作液晶的数据口,P2.0-P2.2为液晶的使能控制口,P2.3-P2.5分别接步进电机驱动器CP-,u/d-,FREE-, CP为脉冲信号输入端;U/D为电机正、反转控制端;FREE 为电机脱机控制端,通过不断的对淋浴水温进行智能检测和显示,经单片机内部运算与设定温度进行比较,控制输入步进电机的脉冲信号及正反转状态,来调节流量控制阀的开度,从而来保证喷头水温与用户设定水温的相一致。
P2.6接数字温度传感器ds1820,用来检测水箱温度并通过芯片及单片机内部处理后显示在液晶上,P2.7也接温度传感器用来检测淋浴喷头的水温。
如果水箱温度不足时(达设置水温下限),则加热继电器动作,启动辅助加热装置,当水温达加热温度上限时加热继电器断开,辅助加热装置关闭。
水位用5段led灯显示,如果水位不足则报警蜂鸣器响,若没使用则上水继电器动作,电磁阀开通,自动上水至水位上限后关闭。
3、单元电路设计3.1水位检测图4 由555定时器构成的液位测量电图水位检测原理如下:由两块铝板组成电容构成介质变化型电容传感器,电容大小为:lS C ε= 式中:ε为介质,S 为对应的面积,l 为长度。
假设电容器为两平极结构,作绝缘处理后的电容器两极间浸入不同的界质中,由于电容器中的介质相对介电系数不同,电容量是不同的,即检测电容传感器在水位变化导致电容器的电容C 变化情况。
电容传感器处在大气中、浸入水中不同深度,其电容量的变化,可反映出水位的变化。
在大气中相对介电常数为1,电容传感器的电容量为C1,在水中相对介电常数更大,达到80,电容传感器的电容量将随着浸入深度加大而变大。
由于上下两部分的介质不同,则总电容有两个电容并联组成: 设铝板总高度为H ,液位高度为h ,则上下两部的介质分别为空气和水。
h H bhl S C -•==11εb hbh l S C 80802=•==ε式中:空气的介电常数为1,b 为铝板的宽度。
本传感器采用NE555制作为脉冲波发生器,输出的频率反映液位的变化,根据实际测试:uF C 1.0min =、uF C 2.2max =取中心工作频率为1KHz ,确定电阻值。
当水箱里无水时(水位最低),最小。
将水位划分为五段:0.1-0.2m 、0.2-0.3m,、0.3-0.4m 、0.4-0.5m 、0.5-0.6m ,分别对应于显示灯LED1、LED2、LED3、LED4、LED5。
当水位发生C1C2变化引起电容的变化,经多谐振荡器输出周期性方波的频率f也随之发生变化[f=1.43/(R1+2R2)C],根据单片机的计数器T0扑捉到的时钟的个数,再经单片机内部比较处理来决定点亮的LED灯。
譬如当水位处于h1位段时,输出的频率满足点亮LED1的条件,则LED1亮,指示水位位于0.1-0.2m处,由此来实现水位的显示。
LED灯显示采用动态扫描方式,即在某一时刻,只有一个灯被点亮。
当水位低于h2时,启动蜂鸣器报警,提示需加水,若无人使用则自动启动加水。
实验表明,为能很好的满足电路的要求,R1用可调电阻,R2应选取阻值较大一点的电阻,这里我们选R2=8.1KΩ,R1阻值范围为0-30 KΩ。
3.2 温度检测对水温信号的检测采用一线式数字温度传感器DS1820,它以9 位数字量的形式反映器件的温度值。
通过使用连接到VDD 引脚的外部电源来向ds1820供电,如图5 所示,这种方法的优点是在I/O 线上不要求强的上拉,总线上主机不需向上连接便在温度变换期间使线保持高电平。
这就允许在变换时间内其它数据在单线上传送。
图5 温度传感器接线图3.3步进电机控制电路的设计为了能调控水温,需要节流阀控制冷水的流量,由于商品化的电动阀价格太高,本方案选用节流阀+步进电机的组合控制。
步进电机,选用的二相四拍步进,步距角为1.8°。
同时,采用BY-2HB03M的驱动器来驱动,控制二相四拍步进电机的步进及正反转。
通过单片机控制步进电机即可控制节流阀,达到控制淋浴水温的目的。
步进电机控制电路连接图如图6所示。
图6 步进电机控制连线图3.4 光电隔离与辅助加热电路设计下图7为太阳能热水器辅助加热电路设计,当室外光照不足(阴天,雨天)时,对水箱的水提前加热是非常有必要的,而这一电路恰好能完成该功能。
工作原理为:当Core8051的P1.2口输出高电平时,三极管T1导通,使得继电器线圈通电闭合,电阻丝R1’-R4’发热,从而完成加热任务。
Vcc 图7 辅助加热电路图加热电阻丝220VACK13.5继电器驱动电路电路如图8所示,三极管Q 为NPN 驱动三极管,工作在开关状态;二极管D 为继电器线圈在由吸合变为断开时提供续流,以免产生高压,从而保护三极管Q 。
VCC+24v-图8 继电器驱动电路因为硬件设计中要用到两个电磁阀,淋浴时的放水电磁阀和向水箱上水的电磁阀,故需要两个继电器来控制。
4、控制器的软件设计控制器软件设计采用模块化结构,包括主程序,键盘扫描子程序,显示子程序,步进电机控制程序,液位比较子程序及温度计算子程序。
系统主程序主要完成水箱及喷头温度和水位的检测,温度的设置,水位不足报警,自动上水及一些初始化功能。
系统主程序流程图如图8所示。
5、测试结果该控制器的设计主要采用Actel公司Fusion系列60万门的AFS600芯片,通过嵌入8051内核来实现,充分利用该平台提供的资源,来完成本次设计任务。
该控制器与市面上的太阳能控制器比较,主要解决了两大主要问题:1.水温的控制调节问题。
该控制器采用精确度很高且跟随性很好的步进电机在很短的时间内进行精确自动调节淋浴水温,保证设定水温与实际水温误差在2℃,并且水温从低向设定水温自动调节,杜绝因水温调节过高而发生烫伤事件。
2. 自动上水问题。
该控制器能实现完成自动上水过程,当检测水位低于水位下限时,先检测热水器是否处于使用状态,若使用中则报警并提示上水再使用,此过程中由于水位留有余量,用户仍然可以继续完成淋浴;若没使用,则启动自动上水至设定的水位上限。
此外,由于增加了一个温度传感器用来检测淋浴水温,使得控制器更加智能化。
致谢本次设计制作历时5个月,在本次设计的过程中,在对Fusion 开发平台熟悉的过程中得到广州周立功刘银华经理及武汉周立功陈光华工程师的细心帮助;在对硬件搭建及软件编程的过程中得到沈浩研究生的大力帮助;在整个设计过程中得到了熊俊俏老师的鼎力相助和悉心指导,在此一并表示深深地感谢!//太阳能热水器智能控制系统程序://定义头文件和各个输入管脚以及变量声明#include <reg52.h>#include <absacc.h>#include <stdio.h>#include <intrins.h>#define uint unsigned int//定义变量类型名#define uchar unsigned char/*定义8255a字符型字位口*/#define DIGPORT XBYTE[0x1FFF]//PA口地址,位选码地址#define WORDPORT XBYTE[0X3FFF]//PB口地址,断选码地址#define CCOM XBYTE[0X7FFFF]//控制字寄存器地址#define KPORT XBYTE[0X5FFF]//PC口,键盘扫描地址//DS1302_RST=1//定义DS1302时钟芯片引脚操作#define Set_DS1302_RST DS1302_RST=1//DS1302_RST=0#define Clr_DS1302_RST DS1302_RST=0//DS1302_SDA=1#define Set_DS1302_SDA DS1302_SDA=1//DS1302_SDA=0#define Clr_DS1302_SDA DS1302_SDA=0//DS1302_SCLK=1#define Set_DS1302_SCLK DS1302_SCLK=1//DS1302_SCLK=0#define Clr_DS1302_SCLK DS1302_SCLK=0//定义读时间控制字#define DS1302_SEC_Reg 0x80#define DS1302_MIN_Reg 0x82#define DS1302_HR_Reg 0x84#define DS1302_DATE_Reg 0x86#define DS1302_MONTH_Reg 0x88#define DS1302_DAY_Reg 0x8a#define DS1302_YEAR_Reg 0x8c#define DS1302_CONTROL_Reg 0x8e#define DS1302_CHARGER_Reg 0x90#define DS1302_CLKBURST_Reg 0xbe//全局变量//为了方便,我把个位和十位分开了uchar year1=0x88;uchar year0=0x88;uchar month=0x88;uchar date=0x88;uchar day=0x88;uchar hour=0x88;uchar minute=0x88;uchar second=0x88;/*定义P1口各管脚*/sbit L0=P2^0;sbit L1=P2^1;sbit L2=P2^2;sbit L3=P2^3;sbit K0=P2^4;sbit P1_0=P1^0;sbit P1_1=P1^1;sbit P1_2=P1^2;sbit Hig=P1^4;sbit DS1302_SDA=P1^5;//定义DS1302时钟引脚与单片机引脚的连接sbit DS1302_SCLK=P1^6;sbit DS1302_RST=P1^7;/*声明调用函数*/void inital(void);void timer1_svr(void);void display(void);void delay(uchar j);void DS1302_Write(uchar reg,uchar dat);uchar DS1302_Read(uchar reg);void DS1302_Init(void);void ReadTime(void);void WtTmCr();void LvRead();void TmRead();void key(void);uchar kbscan(void);void DS1302(void);void int0_int(void);void int1_int(void);/*定义调用存储单元*//*显示缓冲区(依次为高位低位)*/uchar BUFFER[3]={0,0,0};uchar WTLV;//水位值uchar TMP;//水温值uchar WTLVSET;//水位设定值uchar TMPSET;//水温设定值uchar buf[4]={0,0,0,0};/*数码管显示编码"0"-"9","A","-"*/uchar code TABLE[]={0x7B,0x30,0xEA,0xF8,0xB1,0xD9,0xDB,0x70,0xFB,0xF9,0xF3,0x80};main(){inital();//初始化中断、定时器、I/O口kbscan();//键盘扫描key();//键盘处理TmRead();//读取温度LvRead();//读取水位DS1302();//读取时间display();//显示}void inital(){P1_0= P1_1= P1_2=K0=0;//初始化外部驱动口DS1302_Init();EA=1;//开外部中断IT0=1;//外部中断下降沿触发EX0=1;//允许外部中断0Hig=1;P1.3输出高电平TMOD=0x11;定时器工作于方式1TH1=0X8A;//定时器1赋初值TL1=0XD0;ET1=1;定时器1开定时中断TR1=1;//开启定时器1CCOM=0X80;//初始化8255A,送控制字,工作方式0}uchar kbscan(void){uchar recode;if((KPORT&0X0F)!=0X0F) //若有键按下 {delay(2); //延时抖动if((KPORT&0X0F)!=0X0F){recode=KPORT;return(recode);}}elsereturn(0);}void key(void){uchar key;key=kbscan();delay(2);if(key==0x01){P1_1=1;//上水}if(key==0x02) //设置水位{if(WTLVSET==4)WTLVSET=0;elseWTLVSET+=WTLVSET;BUFFER[0]=WTLVSET;//显示设置水位display();}if(key==0x04)//电加热{P1_0=1;}if(key==0x08)//设置温度{if(TMPSET>=80)TMPSET=30;elseTMPSET=TMPSET+10;//增加十度 BUFFER[0]=TMPSET; 显示设置水温 display();}}void timer1_svr() interrupt 1{TH1=0X8A;//重新给定时器1赋值TL1=0XD0;Hig=!Hig;//充放电变换if(Hig)//充电开始时启动定时器0{TL0=TH0=0X00;//定时器0赋初值0TR0=1;//启动定时器0}}void int0_int(void) interrupt 0//外部中断0,测水位{EX0=0;EX1=1;TR0=0;buf[0]=TL0;buf[1]=TH0;}void int1_int(void) interrupt 2//外部中断1,测水温{EX1=0;EX0=1;TR0=0;buf[2]=TL0;buf[3]=TH0;}void TmRead()//水温值处理{uint val;val=buf[3]*256+buf[2];if(val<7549)TMP=97-int(val*8/1000);elseif(val<20000)TMP=50-int(val/1000);elseTMP=30-int(val*5/10000);}void LvRead()//水位值处理{if(buf[1]>60){WTLV=1;//L3=0;L2=1;L1=1;L0=1;}else if(buf[1]>45){WTLV=2;L3=1;L2=0;L1=1;L0=1;}else if(buf[1]>36){WTLV=3;L3=1;L2=1;L1=0;L0=1;}else{WTLV=4;L3=1;L2=1;L1=1;L0=0;}}void WtTmCr()//水位、水温控制{if(WTLV==4)P1_1=0;if(WTLV==1)P1_1=1;if(TMP>=TMPSET)P1_0=0;if(TMP<TMPSET&&hour==0x19)P1_0=1;}void display(void){uchar i; //显示缓冲区首址uchar delay; //显示延时uchar disp; //显示内容uchar digit; //定义数码管显示位digit=0x0200;for(i=2;i>=0;i--){if(BUFFER[i]>100) disp=BUFFER[i]%10+10;//显示高位else disp=BUFFER[i]%10;DIGPORT=digit;WORDPORT=TABLE[disp];for(delay=0;delay=200;delay++);digit=digit>>1;//显示低位disp=BUFFER[i]/10;DIGPORT=digit;WORDPORT=TABLE[disp];for(delay=0;delay=200;delay++);digit=digit>>1;}}void delay(uchar j)//延时程序{uchar a,b;for(a=0;a<j;a++)for(b=0;b<200;b++);}void DS1302()//时间程序{ReadTime();BUFFER[1]=second;BUFFER[2]=hour;}void DS1302_Write(uchar reg,uchar dat)//写入时间 {uchar i;Clr_DS1302_RST;_nop_();_nop_();Clr_DS1302_SCLK;_nop_();_nop_();Set_DS1302_RST;_nop_();_nop_();for(i=8;i>0;i--){if(reg&0x01) Set_DS1302_SDA;else Clr_DS1302_SDA;_nop_();_nop_();Set_DS1302_SCLK;_nop_();_nop_();Clr_DS1302_SCLK;_nop_();_nop_();reg>>=1;}for(i=8;i>0;i--){if(dat&0x01) Set_DS1302_SDA;else Clr_DS1302_SDA;_nop_();_nop_();Set_DS1302_SCLK;_nop_();_nop_();Clr_DS1302_SCLK;_nop_();_nop_();dat>>=1;}Clr_DS1302_RST;_nop_();_nop_();}uchar DS1302_Read(uchar reg)//读取时间{uchar dat=0,i;Clr_DS1302_RST;_nop_();_nop_();Clr_DS1302_SCLK;_nop_();_nop_();Set_DS1302_RST;_nop_();_nop_();for(i=8;i>0;i--){if(reg&0x01) Set_DS1302_SDA;else Clr_DS1302_SDA;_nop_();_nop_();Set_DS1302_SCLK;_nop_();_nop_();Clr_DS1302_SCLK;_nop_();_nop_();reg>>=1;}for(i=8;i>0;i--){dat>>=1;if(DS1302_SDA) dat|=0x80;Set_DS1302_SCLK;_nop_();_nop_();Clr_DS1302_SCLK;_nop_();_nop_();}Clr_DS1302_RST;_nop_();_nop_();return(dat);}void DS1302_Init(void)//初始化DS1302{DS1302_Write(DS1302_CONTROL_Reg,0x00);//关闭写保护 DS1302_Write(DS1302_SEC_Reg,0x80);//暂停DS1302_Write(DS1302_CHARGER_Reg,0xa9);//涓流充电 DS1302_Write(DS1302_YEAR_Reg,0x04); //年DS1302_Write(DS1302_MONTH_Reg,0x12); //月DS1302_Write(DS1302_DATE_Reg,0x09); //日DS1302_Write(DS1302_DAY_Reg,0x04); //周DS1302_Write(DS1302_HR_Reg,0x10); //时DS1302_Write(DS1302_MIN_Reg,0x25); //分DS1302_Write(DS1302_SEC_Reg,0x00); //秒DS1302_Write(DS1302_CONTROL_Reg,0x80);//打开写保护 }void ReadTime(void)//读取时间{uchar dat;dat=DS1302_Read(DS1302_YEAR_Reg);//年year0=dat&0x0f;year1=dat>>4;dat=DS1302_Read(DS1302_MONTH_Reg);//月month=dat;dat=DS1302_Read(DS1302_DATE_Reg);//日date=dat;dat=DS1302_Read(DS1302_DAY_Reg);//周day=dat;dat=DS1302_Read(DS1302_HR_Reg);//时hour=dat;dat=DS1302_Read(DS1302_MIN_Reg);//分 minute=dat;dat=DS1302_Read(DS1302_SEC_Reg);//秒 second=dat;}。