|
/**********************************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; //打开总中断
}
|
|