|
/**********************************WAYNE*********************************/
#include<reg52.h>
#include<intrins.h>
#include"DS18B20_3.H" //18B20溫度傳感器頭文件,18B20的服務程序都在這里
#define uchar unsigned char
#define uint unsigned int
unsigned int distemp=8; //紅外接收返回值
unsigned char IRCOM[7];
unsigned char temp;
unsigned char sec, min, hour, day, month, year;
unsigned char aa=0; //遙控器中間變量
unsigned char bb=1; //顯示界面中間變量
unsigned char cc=0; //自動切換中間變量
unsigned char dd=0; //掉電模式中間變量
unsigned char ee=0;
unsigned char flag;
uchar code table[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //數碼管段碼
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
sbit T_CLK = P3^5; //實時時鐘時鐘線引腳
sbit T_IO = P3^6; //實時時鐘數據線引腳
sbit T_RST = P3^7; //實時時鐘復位線引腳
sbit Y1=P2^6; //第一位數碼管共陽極引腳
sbit Y2=P2^3; //第二位數碼管共陽極引腳
sbit Y3=P2^1; //第三位數碼管共陽極引腳
sbit Y4=P2^0; //第四位數碼管共陽極引腳
sbit led=P0^7; //數碼管小數點陰極引腳
sbit IRIN = P3^2; //紅外接收器數據線與單片機引腳之間的定義
/*********************************延時函數**************************************/
void Delay_1ms(uint i) //1ms延時
{
uchar x,j;
for(j=0;j<i;j++)
for(x=0;x<=148;x++);
}
void delay1(unsigned char x) //延時函數x*0.14MS
{
unsigned char i;
while(x--)
{
for (i = 0; i<13; i++) {}
}
}
/**********************************往DS1302寫入1Byte數據*************************************/
void v_RTInputByte(uchar ucDa)
{
uchar i;
ACC = ucDa;
T_RST = 1;
for(i=8; i>0; i--)
{
T_IO = ACC0;
T_CLK = 1;
T_CLK = 0;
ACC = ACC >> 1;
}
}
/******************************從DS1302讀取1Byte數據*****************************************/
uchar uc_RTOutputByte(void)
{
uchar i;
T_RST = 1;
for(i=8; i>0; i--)
{
ACC = ACC >>1;
T_IO=1;
ACC7 = T_IO;
T_CLK = 1;
T_CLK = 0;
}
return(ACC);
}
/*******************************往DS1302寫入數據****************************************/
void v_W1302(uchar ucAddr, uchar ucDa)
{
T_RST = 0;
T_CLK = 0;
T_RST = 1;
v_RTInputByte(ucAddr); // 寫地址
_nop_();
_nop_();
v_RTInputByte(ucDa); // 寫1Byte數據
T_CLK = 1;
T_RST = 0;
}
/**********************************讀取DS1302某地址的數據*************************************/
uchar uc_R1302(uchar ucAddr)
{
uchar ucDa;
T_RST = 0;
T_CLK = 0;
T_RST = 1;
v_RTInputByte(ucAddr); //寫地址,命令
_nop_();
_nop_();
ucDa = uc_RTOutputByte(); //讀1Byte數據
T_CLK = 1;
T_RST = 0;
return(ucDa);
}
/*********************************DEC碼轉換為BCD碼**************************************/
uchar dectobcd(uchar dec)
{
uchar bcd;
bcd = 0;
while(dec >= 10)
{
dec -= 10;
bcd++;
}
bcd <<= 4;
bcd |= dec;
return bcd;
}
/*******************************BCD碼轉換為DEC碼****************************************/
uchar bcdtodec(uchar bcd)
{
uchar data1;
data1 = bcd & 0x0f; //取BCD低4位
bcd = bcd & 0x70; //剔除BCD的最高位和低4位。
data1 += bcd >> 1;
data1 += bcd >> 3; //用位移代替乘法運算
return data1;
}
/*********************************往DS1302中寫入數據**************************************/
void Write_DS1302Init(void)
{
v_W1302(0x8e,0x00); //屏蔽一下語句,則掉電走時有效;屏蔽則掉電走時失效,且每次上電后顯示12:00(時)/2012(年)/1(月)1(日)
v_W1302(0x80,0x00); //寫入秒
v_W1302(0x82,0x00); //寫入分
v_W1302(0x84,0x12); //寫入小時
v_W1302(0x86,0x01); //寫入日
v_W1302(0x88,0x01); //寫入月
v_W1302(0x8a,0x00); //寫入星期
v_W1302(0x8c,0x12); //寫入年
v_W1302(0x8e,0x80);
}
/*********************************數碼管位選碼**************************************/
void Y_1() //選通第一位數碼管
{
Y1=0;
Y2=1;
Y3=1;
Y4=1;
}
void Y_2() //選通第二位數碼管
{
Y1=1;
Y2=0;
Y3=1;
Y4=1;
}
void Y_3() //選通第三位數碼管
{
Y1=1;
Y2=1;
Y3=0;
Y4=1;
}
void Y_4() //選通第四位數碼管
{
Y1=1;
Y2=1;
Y3=1;
Y4=0;
}
void Y_5() //切斷所有數碼管,用于數碼管消隱
{
Y1=1;
Y2=1;
Y3=1;
Y4=1;
}
/*******************************顯示程序****************************************/
void Run_DS1302(void)
{
v_W1302(0x8f, 0x00);
sec = bcdtodec(uc_R1302(0x81)); //讀出DS1302中的秒
min = bcdtodec(uc_R1302(0x83)); //讀出DS1302中的分
hour = bcdtodec(uc_R1302(0x85)); //讀出DS1302中的小時
day = bcdtodec(uc_R1302(0x87)); //讀出DS1302中的日
month = bcdtodec(uc_R1302(0x89)); //讀出DS1302中的月
year = bcdtodec(uc_R1302(0x8d)); //讀出DS1302中的年
v_W1302(0x8f,0x80);
if(distemp == 0)
{ distemp = 8;
aa++;
}
if(distemp ==7)
{ distemp = 8;
ee++;
}
if(ee == 2)
ee=0;
if(aa==4) //判斷顯示數據
aa=0;
if(aa == 0)
{
bb = 1; //顯示時間
}
if(aa == 1)
{
bb = 2; //顯示溫度
}
if(aa == 2)
{
bb = 3; //顯示年份
}
if(aa == 3)
{
bb = 4; //顯示日期
}
if(ee == 1)
bb = 5;
if(bb == 1) //時間顯示界面
{ if(hour / 10 % 10!=0) //十位為0則不顯示
{P1 = ~table[hour / 10 % 10]; //顯示小時的十位數據
led=1;
Y_1(); //選通第一位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
}
P1 = ~table[hour % 10]; //顯示小時的個位數據
if(sec%2==0) //判斷是否秒閃爍
led=1;
else led=0;
Y_2(); //選通第二位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
P1 = ~table[min / 10 % 10]; //顯示分鐘的十位數據
if(sec%2==0) //判斷是否秒閃爍
led=1;
else led=0;
Y_3(); //選通第三位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
P1 = ~table[min % 10]; //顯示分鐘的個位數據
led=1;
Y_4(); //選通第四位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
}
if(bb == 2) //溫度顯示界面
{
P1 = ~table[(flag-1) / 10 % 10]; //顯示溫度的十位數據
led=1;
Y_2(); //選通第二位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
P1 = ~table[(flag-1) % 10]; //顯示溫度的個位數據
led=1;
Y_3(); //選通第三位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
P1 = ~0x58; //顯示攝氏溫度標志
led=0;
Y_4(); //選通第四位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
}
if(bb == 3) //年份顯示界面
{
P1 = ~0x6e; //顯示年份千位數據,默認為2
led=1;
Y_1(); //選通第一位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
P1 = ~0x77; //顯示年份百位數據,默認為0
led=1;
Y_2(); //選通第二位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
P1 = ~table[year / 10 % 10]; //顯示年份十位數據
led=1;
Y_3(); //選通第三位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
P1 = ~table[year % 10]; //顯示年份個位數據
led=1;
Y_4(); //選通第四位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
}
if(bb == 4) //月日顯示界面
{ if(month / 10 % 10!=0) //十位為0則不顯示
{P1 = ~table[month / 10 % 10]; //顯示月十位數據
led=1;
Y_1(); //選通第一位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
}
P1 = ~table[month % 10]; //顯示月個位數據
led=0;
Y_2(); //選通第二位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
if(day / 10 % 10!=0) //十位為0則不顯示
{P1 = ~table[day / 10 % 10]; //顯示日十位數據
led=1;
Y_3(); //選通第三位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
}
P1 = ~table[day % 10]; //顯示日個位數據
led=1;
Y_4(); //選通第四位數碼管
Delay_1ms(1); //短暫停留
P1 = 0xff; //數碼管消隱
led=1;
Y_5(); //切斷所有數碼管
}
if(bb == 5)
{
P1=0xff;
if(sec%2==0) //判斷是否秒閃爍
led=1;
else led=0;
Y_1(); //選通第四位數碼管
Delay_1ms(1); //短暫停留
}
}
/**********************************自動切換程序*************************************/
void zdqh()
{
if(distemp==6)
{distemp=8;
cc++;
}
if(cc==2) //切換為手動顯示
cc=0;
if(cc==1) //切換為自動循環顯示
{
if(sec%10==0) //每10秒內,前7秒顯示時間界面
aa = 0;
if(sec==7||sec==37) //7秒和37秒切換為溫度顯示
aa = 1;
if(sec==17||sec==47) //17秒和47秒切換為年份顯示
aa = 2;
if(sec==27||sec==57) //27秒和57秒切換為月日顯示
aa = 3;
}
}
/*********************************調節程序**************************************/
void tj()
{
if(distemp == 1) //判斷按下的鍵值
{distemp=8; //返回值回位
if(bb==1) //判斷當前顯示界面
{
hour++; //小時加一調節
if(hour==24) //限制小時數據在0~23之間
hour=0;
temp=dectobcd(hour); //將十進制數轉換成十六禁止數
v_W1302(0x8e,0x00); //禁止寫保護
v_W1302(0x84,temp); //寫入小時數據
v_W1302(0x80,0x00);
v_W1302(0x8e,0x80); //打開寫保護
}
if(bb==4) //判斷當前顯示界面
{
month++; //月加一調節
if(month==13) //限制月數據在1~12之間
month=1;
temp=dectobcd(month); //將十進制數轉換成十六禁止數
v_W1302(0x8e,0x00); //禁止寫保護
v_W1302(0x88,temp); //寫入月數據
v_W1302(0x8e,0x80); //打開寫保護
}
}
if(distemp == 2) //判斷按下的鍵值
{distemp=8; //返回值回位
if(bb==1) //判斷當前顯示界面
{
min++;//分鐘加一調節
if(min==60)//限制分鐘數據在0~59之間
min=0;
temp=dectobcd(min);//將十進制數轉換成十六禁止數
v_W1302(0x8e,0x00);//禁止寫保護
v_W1302(0x82,temp);//寫入分鐘數據
v_W1302(0x80,0x00);
v_W1302(0x8e,0x80);//打開寫保護
}
if(bb==3)//判斷當前顯示界面
{
year++;//年份加一調節
if(year==100)//限制年份數據在0~99之間
year=0;
temp=dectobcd(year);//將十進制數轉換成十六禁止數
v_W1302(0x8e,0x00);//禁止寫保護
v_W1302(0x8c,temp);//寫入年數據
v_W1302(0x8e,0x80);//打開寫保護
}
if(bb==4)//判斷當前顯示界面
{
day++; //日加一調節
if(day==32) //限制日數據在1~31之間
day=1;
temp=dectobcd(day); //將十進制數轉換成十六禁止數
v_W1302(0x8e,0x00); //禁止寫保護
v_W1302(0x86,temp); //寫入日數據
v_W1302(0x8e,0x80); //打開寫保護
}
}
if(distemp == 3) //判斷按下的鍵值
{distemp=8; //返回值回位
if(bb==1) //判斷當前顯示界面
{
hour--; //小時減一調節
if(hour==-1) //限制小時數據在0~23之間
hour=23;
temp=dectobcd(hour); //將十進制數轉換成十六禁止數
v_W1302(0x8e,0x00); //禁止寫保護
v_W1302(0x84,temp); //寫入小時數據
v_W1302(0x80,0x00);
v_W1302(0x8e,0x80); //打開寫保護
}
if(bb==4) //判斷當前顯示界面
{
month--; //月減一調節
if(month==0) //限制月數據在1~12之間
month=12;
temp=dectobcd(month); //將十進制數轉換成十六禁止數
v_W1302(0x8e,0x00); //禁止寫保護
v_W1302(0x88,temp); //寫入月數據
v_W1302(0x8e,0x80); //打開寫保護
}
}
if(distemp == 4) //判斷按下的鍵值
{distemp=8; //返回值回位
if(bb==1) //判斷當前顯示界面
{
min--; //分鐘減一調節
if(min==-1) //限制分鐘數據在0~59之間
min=59;
temp=dectobcd(min); //將十進制數轉換成十六禁止數
v_W1302(0x8e,0x00); //禁止寫保護
v_W1302(0x82,temp); //寫入分鐘數據
v_W1302(0x80,0x00);
v_W1302(0x8e,0x80); //打開寫保護
}
if(bb==3) //判斷當前顯示界面
{
year--; //年份減一調節
if(year==-1) //限制年份數據在0~99之間
year=99;
temp=dectobcd(year); //將十進制數轉換成十六禁止數
v_W1302(0x8e,0x00); //禁止寫保護
v_W1302(0x8c,temp); //寫入年數據
v_W1302(0x8e,0x80); //打開寫保護
}
if(bb==4) //判斷當前顯示界面
{
day--; //日減一調節
if(day==0) //限制日數據在1~31之間
day=31;
temp=dectobcd(day); //將十進制數轉換成十六禁止數
v_W1302(0x8e,0x00); //禁止寫保護
v_W1302(0x86,temp); //寫入日數據
v_W1302(0x8e,0x80); //打開寫保護
}
}
}
/*******************************掉電模式程序****************************************/
void xmms()
{
if(dd == 1) //單片機進入掉電工作模式,該模式下只有首位數碼管的小數點常亮
{
P0=~0xff; //在掉電模式下,只有第一位數碼管的小數點亮
led=1;
Y_5();
aa=0;
ee=0;
PCON=0x02; //設置掉電模式寄存器,這句一定要放在該子程序的最后
}
}
/********************************自動校時***************************************/
void zdjs()
{
if(hour==3&&min==0&&sec==30)
{
v_W1302(0x8e,0x00);
v_W1302(0x80,0x00);
v_W1302(0x8e,0x80);
}
}
/********************************主函數***************************************/
void Main(void)
{
EA=1; //打開總中斷
EX0=1; //允許外部0中斷
IT0=1; //設置外部中斷0為邊沿方式觸發
IRIN=1;
Write_DS1302Init();
while(1) //無限循環以下子程序
{
Run_DS1302(); //顯示程序
flag=ReadTemperature(); //將18b2頭文件運行返回的函數結果送到變量flag中,用于顯示
tj(); //調節程序
xmms(); //休眠模式
zdqh(); //自動切換
zdjs(); //自動校時
}
}
/*********************紅外接收程序**********************/
void IR_IN() interrupt 0 //外部中斷0
{
unsigned char p,q,R=0;
EA = 0;
delay1(15);
if (IRIN==1)
{ EA =1;
return;
}
while (!IRIN)
{delay1(1);}
for (p=0;p<4;p++)
{
for (q=0;q<8;q++)
{
while (IRIN)
{delay1(1);}
while (!IRIN)
{delay1(1);}
while (IRIN)
{
delay1(1);
R++;
if (R>=30)
{ EA=1;
return;}
}
IRCOM[p]=IRCOM[p] >> 1;
if (R>=8) {IRCOM[p] = IRCOM[p] | 0x80;}
R=0;
}
}
if (IRCOM[2]!=~IRCOM[3])
{ EA=1;
return; }
switch(IRCOM[2])
{
case 0x07: //顯示切換鍵
distemp = 0;
break;
case 0x44: //左加一鍵
distemp = 1;
break;
case 0x45: //右加一鍵
distemp = 2;
break;
case 0x46: //左減一鍵
distemp = 3;
break;
case 0x47: //右減一鍵
distemp = 4;
break;
case 0x16: //掉電模式開關鍵
distemp = 5;
break;
case 0x10: //自動切換開關鍵
distemp = 6;
break;
case 0x1c: //待機模式開關鍵
distemp = 7;
break;
}
if(distemp == 5) //開啟、關閉掉電模式,因掉電模式只能由外部中斷喚醒,所以下面的程序必須放在中斷函數中
{distemp = 8; //返回值回位
dd++;
}
if(dd == 2)
dd = 0;
if(dd == 0) //退出掉電模式
{PCON=0x00; //設置掉電模式工作寄存器
}
if(dd == 1) //掉電模式下,其他按鍵無效
distemp = 8; //不返回任何鍵值
if(ee==1)
{if(distemp==0||distemp==1||distemp==2||distemp==3||distemp==4||distemp==6)
distemp = 8;
}
EA = 1; //打開總中斷
}
|
|