?? ddd.c
字號:
/*--------------------------------------
快熱式熱水器程序
MCU AT89C51 XAL 12MHz
Build by Gavin Hu, 2005.3.18
--------------------------------------*/
//#pragma src
#include <reg51.h>
#include <intrins.h>
#include <math.h>
void delay(unsigned int); //延時函數
void display(void); //顯示函數
unsigned char keyscan(void); //按鍵掃描處理函數
void heatctrl(void); //加熱控制函數
void temptest(void); //測溫函數
sbit swkey=P1^0; //開關鍵
sbit upkey=P1^1; //加熱檔位“+”鍵
sbit downkey=P1^2; //加熱檔位“-”鍵
sbit buzz=P1^05; //蜂鳴器輸出端
sbit triac=P1^6; //可控硅觸發信號輸出端
sbit relay=P1^7; //繼電器控制信號輸出端
sbit led1=P2^5; //加熱檔位指示燈1
sbit led2=P2^6; //加熱檔位指示燈2
sbit led3=P2^7; //加熱檔位指示燈3
signed char data ctemp; //當前測得水溫寄存器
unsigned char data dispram[2]={0x10,0x10}; //顯示區緩存
unsigned char data heatpower,px0count; //加熱檔位寄存器、外中斷0計數器
bit tempov,t0tst,testok; //超溫標志、測溫開始標志、測溫完成標志
/*----------------------------------------------
主函數 void main(void)
無參數,無返回值
循環調用顯示、鍵掃描、溫度檢測、加熱控制函數
----------------------------------------------*/
void main(void)
{
unsigned char i,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(); //調用加熱控制函數
}//end for (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; //送顯示(帶滅零)
}//end while (1)
}
/*--------------------------------------
延時函數 void delay(unsigned int dt)
參數:dt,無返回值
延時時間=dt*500機器周期
--------------------------------------*/
void delay(unsigned int dt)
{
register unsigned char bt; //定義寄存器變量
for (; dt; dt--)
for (bt=250; --bt; ); //此句編譯時以“DJNZ”實現,250*2=500機器周期
}
/*--------------------------------------
顯示函數 void display(void)
無參數,無返回值
兩位共陽數碼管掃描顯示
--------------------------------------*/
void display(void)
{
unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf,0xff};
unsigned char i,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; //消影
}
}
/*----------------------------------------------------------
按鍵掃描處理函數 unsigned char keyscan(void)
無參數,返回值:無符號字符型,無鍵按下為0,有鍵按下為其它
影響全局變量:heatpower
----------------------------------------------------------*/
unsigned char keyscan(void)
{
unsigned char i,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); //返回有鍵按下
}
else if (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); //返回有鍵按下
}
else if (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); //返回無鍵按下
}
else return (0); //無任何鍵按下時由此返回
}
/*--------------------------------------
加熱控制函數 void heatctrl(void)
無參數,無返回值
判斷是否加熱、加熱功率及檔位指示燈處理
--------------------------------------*/
void heatctrl(void)
{
if (!tempov) //當沒有超溫標志時
{
relay=0; //接通繼電器
buzz=1; //關閉蜂鳴器
switch (heatpower) //判斷加熱檔位
{
case 0: {EX1=0;ET1=0;triac=1;led1=1;led2=1;led3=1;break;}//0檔不加熱,指示燈不亮
case 1:
case 2:
case 3:
case 4: {led1=0;led2=1;led3=1;EX1=1;break;} //1~4檔1號指示等亮
case 5:
case 6:
case 7:
case 8: {led1=0;led2=0;led3=1;EX1=1;break;} //5~8檔1號、2號指示燈亮
case 9: {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; //蜂鳴報警
}
}
/*--------------------------------------
測溫函數 void temptest(void)
無參數,無返回值,
影響全局變量:ctemp,tempov
測量并查表計算溫度,判斷是否超溫
--------------------------------------*/
void temptest(void)
{
signed char temp,tempmin,tempmax;
unsigned int t0rig;
unsigned int code temptab[]={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,\
0x25e5,0x256d,0x24ee,0x2489,0x2414,0x23bc,0x2356,0x22d9,0x2278,0x2203}; //溫度頻率表
px0count=2; //測頻中斷函數參數
t0tst=1; //置測頻程序開始標志
EX0=1; //打開測頻外中斷
testok=0; //清除測頻程序完成標志
while (!testok) display(); //等待測試完成
t0rig=(unsigned int)TH0<<8|TL0; //字節合成字
tempmin=0; //以下是二分查表法計算溫度值
tempmax=100; //tempmin和tempmax為溫度表的范圍
while (1)
{
temp=(tempmax+tempmin)/2; //假定當前溫度為最大值與最小值之中點值
if (t0rig==temptab[temp]) break; //若實際值等于假定值結束查找
else if (t0rig>temptab[temp]) tempmax=temp;//若實際值大于假定值,減小查找范圍的最大值
else tempmin=temp; //若實際值小于假定值,增大查找范圍的最小值
if (tempmax-tempmin<=1) //若查找范圍已縮小到1度之間,
{ //判斷實際值更接近哪個端點
if (temptab[tempmax]+temptab[tempmin]>2*t0rig) temp=tempmax;//接近最大值取最大值
else temp=tempmin; //接近最小值取最小值
break; //結束查找
}
}
ctemp=temp; //刷新當前溫度寄存器
if (temp>65) tempov=1; //如果溫度超過65度置位超溫標志
else if (temp<45) tempov=0; //當溫度回落到45度以下時清除超溫標志
}
/*------------------------------------------
測溫頻率測試函數 void tempfrequency(void)
使用外部X0中斷,寄存器組1
測出溫度——頻率轉換電路的頻率
------------------------------------------*/
void tempfrequency(void) interrupt 0 using 1
{
if (--px0count) return; //找齊起點或計數
if (t0tst) //如果是起點
{
t0tst=0; //清除測頻開始標志
px0count=100; //取100個方波為一次測頻
TH0=0;
TL0=0; //清除計時器T0
TR0=1; //開始計時
}
else //如果是終點
{
TR0=0; //停止計時
EX0=0; //停止測頻外中斷
testok=1; //置位測頻完成標志
}
}
/*--------------------------------------
加熱控制過〇檢測函數 void pass0(void)
使用外部X1中斷,寄存器組2
檢測過〇點,給定時器T1賦初值
--------------------------------------*/
void pass0(void) interrupt 2 using 2
{
unsigned char code powertab[]={0xd8,0xf0,0xe2,0x63,0xe5,0x25,0xe8,0x3e,0xeb,0x16,0xed,0xda,0xf0,0xb2,0xf3,0xcb,0xf7,0x8d,0xf7,0x8d};//10個功率檔位的可控硅導通角延時參數表
TH1=powertab[2*heatpower]-1;
TL1=powertab[2*heatpower+1]; //市電過零后,根據當前設置的檔位給定時器T1賦延時參數
ET1=1; //允許定時器T1中斷
TR1=1; //打開定時器T1
}
/*------------------------------------------
可控硅觸發信號控制函數 void triacctrl(void)
使用定時器T1中斷,寄存器組3
向可控硅送出觸發信號
------------------------------------------*/
void triacctrl(void) interrupt 3 using 3
{
register unsigned char i;
triac=0; //輸出可控硅導通信號
ET1=0; //關閉定時器T1中斷
TR1=0; //終止定時器運行
for (i=0;i<2;i++); //延時,保證導通信號有足夠的寬度
triac=1; //完成可控硅導通信號
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -