⑤检查查找范围,若Tmax一Tmin≤1,则判断TOrig更接近最大值对应的频率Tab[Tmax]还是最小值对应的频率Tab[Tmin],实际温度值取频率更接近的那个值即完成查找。
⑥若Tmax-Tmin>l,则重复第②、③、④、⑤步骤、直到完成查找。
温度检测程序完成温度计算后,便刷新系统当前温度寄存器,并判断有无超温、置位或清除相应的标志位。
图12所示为温度检测程序流程图。
图12温度检测程序流程图
单片机使用外中断INTO和计时器TO检测输入频率的大小。
为了减少测量的系统误差相对值和随机误差对测量精度的影响,程序中取100个方波周期的和作为测量结果。
程序中使用静态变量pxOcount进行外中断的计数,在测量开始时,给pxOcount赋值2是为了让频率测量有准确的起点。
另外,为了区分测频的开始和结束,还使用了测频开始标志位TOtst和测频完成标志位Testok。
图13所示为频率测试程序流程图。
图13频率测试程序流程图
5调试及性能分析
快热式热水器硬件电路不包含任何可调节元件,因此只要器件质量可靠,引脚焊接正确,硬件电路无须调试。
该电路中测温部分的振荡电路对电容Cl的容量比较敏感,若此电路要批量化生产,可在热敏电阻R24上再串一个可变电阻,以补偿C1的容量变化。
在初次试做本电路或关键硬件参数有调整时,应对系统软件中控制加热功率的可控硅导通角延时参数表和温度/频率转换表这两部分进行调试。
可控硅导通角延时参数主要由市电的频率和过零检测电路的脉冲宽度决定,可以先根据市电频率,按等功率的要求计算理论值,再根据过零检测电路的脉冲宽度加以调整。
温度/频率转换表可以用对照标准温度计实测的办法进行测试。
图14.14所示为用实际电路在实验室测得的温度/频率曲线图。
用这个方案设计的快热式家用电热水器,电路简单,成本较低,经试验运行证明工作稳定,可靠,在无须改变硬件的条件下,如加入PID等自动控制程序还可以升级成自动控温的电热水器。
图14温度/频率曲线图
6控制源程序清单
以下是快热式电热水器控制源程序清单,采用C51编写,在KeilC51环境下调试通过,并下载到AT89C51测试运行成功。
/*--------------------------------------
快热式热水器程序
MCUAT89C51XAL12MHz
BuildbyGavinHu,2005.3.18
--------------------------------------*/
//#pragmasrc
#include
#include
#include
voiddelay(unsignedint);//延时函数
voiddisplay(void);//显示函数
unsignedcharkeyscan(void);//按键扫描处理函数
voidheatctrl(void);//加热控制函数
voidtemptest(void);//测温函数
sbitswkey=P1^0;//开关键
sbitupkey=P1^1;//加热档位“+”键
sbitdownkey=P1^2;//加热档位“-”键
sbitbuzz=P1^05;//蜂鸣器输出端
sbittriac=P1^6;//可控硅触发信号输出端
sbitrelay=P1^7;//继电器控制信号输出端
sbitled1=P2^5;//加热档位指示灯1
sbitled2=P2^6;//加热档位指示灯2
sbitled3=P2^7;//加热档位指示灯3
signedchardatactemp;//当前测得水温寄存器
unsignedchardatadispram[2]={0x10,0x10};//显示区缓存
unsignedchardataheatpower,px0count;//加热档位寄存器、外中断0计数器
bittempov,t0tst,testok;//超温标志、测温开始标志、测温完成标志
/*----------------------------------------------
主函数voidmain(void)
无参数,无返回值
循环调用显示、键扫描、温度检测、加热控制函数
----------------------------------------------*/
voidmain(void)
{
unsignedchari,j;
ctemp=15;//初始化水温寄存器
heatpower=5;//初始化加热档位为5当
tempov=0;//清除超温标志
swkey=0;//默认开关键被按下,进入待机状态
TMOD=0x11;//设定T0和T1工作方式为16位定时器
TCON=0x05;//设置外中断0和1为下降沿触发
IP=0x01;//设置外中断0优先
IE=0x80;//打开总中断
while
(1)
{
i=1;
do{
for(j=0;j<100;j++)//循环100次约0.5s
{
if(keyscan())i=6;//如果有键按下,显示当前档位3s
display();//调用显示函数一次约4ms
heatctrl();//调用加热控制函数
}//endfor(b=0;b<100;b++)
temptest();//每0.5s进行一次测温
}while(--i);//通过改变循环次数i的大小决定是否刷新显示
j=abs(ctemp);//取温度绝对值
dispram[1]=j%10;//取个位数送显示
j/=10;//取十位数
dispram[0]=j?
j:
0x11;//送显示(带灭零)
}//endwhile
(1)
}
/*--------------------------------------
延时函数voiddelay(unsignedintdt)
参数:
dt,无返回值
延时时间=dt*500机器周期
--------------------------------------*/
voiddelay(unsignedintdt)
{
registerunsignedcharbt;//定义寄存器变量
for(;dt;dt--)
for(bt=250;--bt;);//此句编译时以“DJNZ”实现,250*2=500机器周期
}
/*--------------------------------------
显示函数voiddisplay(void)
无参数,无返回值
两位共阳数码管扫描显示
--------------------------------------*/
voiddisplay(void)
{
unsignedcharcodetable[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf,0xff};
unsignedchari,a;
a=0xfe;//位选赋初值
for(i=0;i<2;i++)//循环扫描两位数码管
{
P2|=0x1f;//清除位选
P0=table[dispram[i]];//送显示段码
P2&=a;//选通一位
delay(4);//延时2ms
a=_crol_(a,1);//改变位选字
P0=0xff;//消影
}
}
/*----------------------------------------------------------
按键扫描处理函数unsignedcharkeyscan(void)
无参数,返回值:
无符号字符型,无键按下为0,有键按下为其它
影响全局变量:
heatpower
----------------------------------------------------------*/
unsignedcharkeyscan(void)
{
unsignedchari,ch;
if(upkey==0)//“+”键
{
buzz=0;//打开蜂鸣器(发出按键音)
for(i=0;i<5;i++)display();//延时消抖
buzz=1;//关闭蜂鸣器
if(heatpower<9)heatpower++;//档位加一
dispram[0]=0;
dispram[1]=heatpower;//显示当前档位
while(upkey==0)display();//等待键释放
return
(1);//返回有键按下
}
elseif(downkey==0)//“-”键
{
buzz=0;//打开蜂鸣器(发出按键音)
for(i=0;i<5;i++)display();//延时消抖
buzz=1;//关闭蜂鸣器
if(heatpower>0)heatpower--;//档位减一
dispram[0]=0;
dispram[1]=heatpower;//显示当前档位
while(downkey==0)display();//等待键释放
return
(2);//返回有键按下
}
elseif(swkey==0)//开关键
{
buzz=0;//打开蜂鸣器(发出按键音)
for(i=0;i<30;i++)display();//延时消抖
buzz=1;//关闭蜂鸣器
swkey=1;//置位开关键
while(swkey==0)display();//等待键释放
ch=IE;//暂存中断控制字IE
IE=0x00;//禁止中断
P0=0xff;
P1=0xff;
P2=0xff;//清除端口输出
dispram[0]=0x10;
dispram[1]=0x10;//显示“--”
display();
while
(1)
{
while(swkey)display();//等待开关键按下
buzz=0;//打开蜂鸣器(发出按键音)
for(i=0;i<10;i++)display();//延时消抖
buzz=1;//关闭蜂鸣器
if(swkey==0)break;//确认开关键被按下
}
while(swkey==0)display();//等待键释放
IE=ch;//还原中断控制字IE
return(0);//返回无键按下
}
elsereturn(0);//无任何键按下时由此返回
}
/*--------------------------------------
加热控制函数voidheatctrl(void)
无参数,无返回值
判断是否加热、加热功率及档位指示灯处理
--------------------------------------*/
voidheatctrl(void)
{
if(!
tempov)//当没有超温标志时
{
relay=0;//接通继电器
buzz=1;//关闭蜂鸣器
switch(heatpower)//判断加热档位
{
case0:
{EX1=0;ET1=0;triac=1;led1=1;led2=1;led3=1;break;}//0档不加热,指示灯不亮
case1:
case2:
case3:
case4:
{led1=0;led2=1;led3=1;EX1=1;break;}//1~4档1号指示等亮
case5:
case6:
case7:
case8:
{led1=0;led2=0;led3=1;EX1=1;break;}//5~8档1号、2号指示灯亮
case9:
{EX1=0;ET1=0;led1=0;led2=0;led3=0;triac=0;break;}//9档全功率,指示灯全亮
}
}
else//当有超温标志时
{
relay=1;//断开继电器
EX1=0;ET1=0;triac=1;//关闭可控硅
buzz=0;//蜂鸣报警
}
}
/*--------------------------------------
测温函数voidtemptest(void)
无参数,无返回值,
影响全局变量:
ctemp,tempov
测量并查表计算温度,判断是否超温
--------------------------------------*/
voidtemptest(void)
{
signedchartemp,tempmin,tempmax;
unsignedintt0rig;
unsignedintcodetemptab[]={0x6262,0x61eb,0x6171,0x60f7,0x6047,0x5ff7,0x5f6e,0x5eef,0x5e53,0x5dbe,0x5d4b,0x5ca5,0x5c17,\
0x5b6b,0x5ada,0x5a5c,0x599b,0x58ff,0x5869,0x57b0,0x570d,0x5663,0x55c6,0x550e,0x5444,0x5396,\
0x52dd,0x5240,0x5189,0x50b0,0x5005,0x4f20,0x4e69,0x4db1,0x4cef,0x4c42,0x4b64,0x4aaa,0x49e1,\
0x48fc,0x4847,0x476c,0x46b1,0x4604,0x4503,0x4449,0x4356,0x4299,0x41c0,0x40ce,0x3ff0,0x3f2b,\
0x3e33,0x3d86,0x3ca6,0x3bd2,0x3b26,0x3a39,0x3973,0x38a6,0x37ef,0x373f,0x3687,0x35c3,0x3507,\
0x3487,0x33bc,0x32ed,0x324f,0x319e,0x3106,0x3053,0x2fa6,0x2f2a,0x2e88,0x2e00,0x2d63,0x2cd6,\
0x2c65,0x2bae,0x2b28,0x2a97,0x2a07,0x298e,0x2914,0x287a,0x280d,0x278a,0x2703,0x2687,0x2626,\
0