C51系列单片机课程设计:电子闹钟和万年历的程序

实在没有,c程序也可以,先给50分,收到答案后再追加50-100。[email protected]

第1个回答  2010-12-17
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

sbit dq=P3^7; //////18b20
sbit lcden=P2^7; ////lcd
sbit rs=P2^6;
sbit wr=P2^5;
sbit sck=P3^6; ////1302
sbit sda=P3^4;
sbit rst=P3^5;

sbit a=P1^0;
sbit b=P1^1;
sbit c=P1^2;
sbit d=P1^3;
sbit kj=P1^4;
sbit beep=P1^5;
uchar ritime;
uchar startflag;
uchar ridate[33];
uchar bitnum;
uchar rireceok;
uchar ricode[4];
uchar riprosok;
uchar dis[8];
void dis_key(void);
void riwork(void);
void ripros(void);
void keyscan(void);
void bep(void);
void timer0init(void);
void init0init(void);
uchar key0,key1,key2,key0num,passwordok;
uchar key,p,m,pnum,sha;
uchar password[9];
uchar password1[9]={6,7,4,6,8,8,6,4,6};
void password_scan();
void post_key();
void dj1();
void dj2();
//////////////////////函数声明1302
void wr1302_byte(uchar byte);
void wr1302 (uchar add,uchar dat);
uchar read1302(uchar add);
uchar time_date[7]={10,3,12,8,21,37,20};////年周月日时分秒
uchar time_add[7]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80};////写入地址
uchar read_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};////读出地址
uchar disp[13]; ////将读出时间装入
void set_rtc();
void read_rtc();
void timepost(); ////处理时间为10进制
void display();
void password_display();
void timeplay();
void runnian1(); ///闰年加
void runnian2(); ///闰年减
void keypost(); //按键处理
///////////////////////////// 函数声明 lcd ////////////////////
uchar code lcd_tab[]="0123456789- ():c";
uchar code lcd_tab1[]="Plese Password:";
uchar code table1[]="key=00-00-00-00";
uchar code table[]=" QQ:674688646";
uchar code numtab[]="0123456789ABCDEF";
uchar code numtab1[]=" 1234567890";
void delay(uint z);
void init_lcd();
void write_com(uchar com);
void write_date(uchar x);
///////////////////////////18b20////////////
void init18b20(void);
void wr1820_byte(uchar dat);
uchar read18b20_byte(void);
uchar read1820(void);
void delay1(uint t);
//////////////////////////////////////////

void timer0init(void) //开定时器2
{
TMOD=0X02;
TH0=0X00;
TL0=0X00;
ET0=1;
EA=1;
TR0=1;
}
void init0init(void) //外部中断
{
IT0=1;
EX0=1;
EA=1;
}
void riwork(void)
{
dis[0]=ricode[0]/16;
dis[1]=ricode[0]%16;
dis[2]=ricode[1]/16;
dis[3]=ricode[1]%16;
dis[4]=ricode[2]/16;
dis[5]=ricode[2]%16;
dis[6]=ricode[3]/16;
dis[7]=ricode[3]%16;
}
void ripros(void)
{ uchar j,k,i,value;
k=1;
for(j=0;j<4;j++)
{
for(i=0;i<8;i++)
{
value=value>>1;
if(ridate[k]>6)
{
value=value|0x80;
}
k++;
}
ricode[j]=value;
}
riprosok=1;
}
void timer0 () interrupt 1
{
ritime++;
}
void int0() interrupt 0
{
if(startflag==1)
{
if(ritime>32)//检测引导码
{
bitnum=0;
}
ridate[bitnum]=ritime;
ritime=0;
bitnum++;
if(bitnum==33)
{
bitnum=0;
rireceok=1;
}
}
else
{
startflag=1;
ritime=0;
}
}

void keyscan(void)
{ if(rireceok==1)
{bep(); //按键发声 但影响蜂鸣器操作
ripros();
rireceok=0;
}
if(riprosok==1)
{ riwork();
riprosok=0;
switch(ricode[2])
{ case 0x46:p=1;pnum++;break;

case 0x0c:key=1;break;
case 0x18:key=2;break;
case 0x5e:key=3;break;
case 0x08:key=4;break;
case 0x1c:key=5;break;
case 0x5a:key=6;break;
case 0x42:key=7;break;
case 0x52:key=8;break;
case 0x4a:key=9;break;
case 0x16:key=10;break;

case 0x09:key0=1;key0num++;break;
case 0x15:key1=1;break;
case 0x07:sha=1;key2=1;break;
if(key0==1){if(key0num==1)read_rtc();}
}
}
////按下设定键后读一次1302保证time_date内数据正常
}

void bep(void)
{
beep=0;delay(100);beep=1;
}
///////////////////////////////////////////////////////////
void write_com(uchar com) /////写命令
{
rs=0;
P0=com;
lcden=1;
delay(5);
lcden=0;
}
void write_date(uchar x)/////写数据
{
rs=1;
P0=x;
delay(5);
lcden=1;
delay(5);
lcden=0;
}

void init_lcd()// ///lcd初始化
{
wr=0;
lcden=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
}
void display()
{timepost();
write_com(0x80+2);
write_date(lcd_tab[2]);
write_date(lcd_tab[0]);
write_date(lcd_tab[disp[0]]);
write_date(lcd_tab[disp[1]]);
write_date(lcd_tab[10]);
write_date(lcd_tab[disp[3]]);
write_date(lcd_tab[disp[4]]);
write_date(lcd_tab[10]);
write_date(lcd_tab[disp[5]]);
write_date(lcd_tab[disp[6]]);
write_date(lcd_tab[11]);
write_date(lcd_tab[12]);
write_date(lcd_tab[disp[2]]);
write_date(lcd_tab[13]);
write_com(0x80+0x40+4);/////////第二行
write_date(lcd_tab[disp[7]]);
write_date(lcd_tab[disp[8]]);
write_date(lcd_tab[14]);
write_date(lcd_tab[disp[9]]);
write_date(lcd_tab[disp[10]]);
write_date(lcd_tab[14]);
write_date(lcd_tab[disp[11]]);
write_date(lcd_tab[disp[12]]);
write_date(lcd_tab[11]);
write_date(lcd_tab[read1820()/10]);/////显示温度
write_date(lcd_tab[read1820()%10]);
write_date(lcd_tab[15]);
}
//////////////// 1302 //////////////////////////////
void wr1302_byte(uchar byte) /////写入一个字节
{ uchar i;
for(i=0;i<8;i++)
{ sck=0;
sda=byte&0x01;
byte>>=1;
sck=1;
}
}
void wr1302 (uchar add,uchar dat)/////写进1302 时间和地址
{ rst=0;
_nop_();
sck=0;
_nop_();
rst=1;
_nop_();
wr1302_byte(add);
wr1302_byte(dat);
rst=0;
//_nop_();
//sda=1;
//sck=1;
}
uchar read1302(uchar add)
{ uchar i,temp;
rst=0;
_nop_();
sck=0;
_nop_();
rst=1;
_nop_();
wr1302_byte(add);////////////////////写入要读的地址
for(i=0;i<8;i++)
{
if(sda)temp=temp|0x80;
sck=0;
temp>>=1;
_nop_();
sck=1;
}
rst=0; //////// 延时很重要
_nop_();
sck=0;
_nop_();
sck=1;
_nop_();
sda=0;
_nop_();
sda=1;
_nop_();
return temp;
}
void set_rtc()
{
uchar i,j;
for(i=0;i<7;i++)
{
j=time_date[i]/10; ///////将10进制变成16进制
time_date[i]=time_date[i]%10;
time_date[i]=time_date[i]+j*16;
}
wr1302(0x8e,0x00);//////去除写保护
for(i=0;i<7;i++)
{
wr1302(time_add[i],time_date[i]);
}
wr1302(0x8e,0x80);//////加写保护
}

void read_rtc()
{uchar i,j;
for(i=0;i<7;i++)
{
time_date[i]=read1302(read_add[i]);
////将读到的bcd码转化成10进制码
j=time_date[i]&0x0f;
time_date[i]>>=4;
time_date[i]&=0x0f;
time_date[i]*=10;
time_date[i]=time_date[i]+j;

}
}
void timepost()
{ disp[0]=time_date[0]/10;/////年
disp[1]=time_date[0]%10;
disp[2]=time_date[1]%10;/////周
disp[3]=time_date[2]/10;/////月
disp[4]=time_date[2]%10;/////
disp[5]=time_date[3]/10;/////日
disp[6]=time_date[3]%10;////
disp[7]=time_date[4]/10;////时
disp[8]=time_date[4]%10;////
disp[9]=time_date[5]/10;////分
disp[10]=time_date[5]%10;////
disp[11]=time_date[6]/10;////秒
disp[12]=time_date[6]%10;////

}
void delay(uint z)
{
uint x,y;
for(x=0;x<20;x++)
for(y=z;y>0;y--);
}

/////////////////////////18b20////////
void delay1(uint t)
{
while (t--);
}

void init18b20(void)
{
uchar n;
dq=1;
delay1(8);
dq=0;
delay1(80);
dq=1;
delay1(8);
n=dq;
delay1(4);
}

void wr18b20_byte(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
dq=0;
dq=dat&0x01;
delay1(4);
dq=1;
dat>>=1;
}
delay1(4);
}
uchar read18b20_byte(void)
{
uchar i,value;
for(i=0;i<8;i++)
{ dq=0;
value>>=1;
dq=1;
if(dq)
value|=0x80;
delay1(4);
}
return value;
}
uchar read1820(void)
{ uchar a,b;
init18b20();
wr18b20_byte(0xcc);
wr18b20_byte(0x44);
delay1(50);
init18b20();
wr18b20_byte(0xcc);
wr18b20_byte(0xbe);
a=read18b20_byte();
b=read18b20_byte();
b<<=4;
b+=(a&0xf0)>>4;
return b;
}
///////////////////////////////////////////////////////
void keypost()
{ uchar n;
if(key0==1)
{
if(key0num==1)
{write_com(0x80+0x40+10);
write_com(0x0f);delay(1000);
if(key1==1)
{ key1=0;n=1;
time_date[6]++;
if(time_date[6]==60)time_date[6]=0;
display();
}
if(key2==1)
{
key2=0;n=1;
time_date[6]--;
if(time_date[6]==-1)time_date[6]=59;
display();

}
}
if(key0num==2)
{write_com(0x80+0x40+8);
write_com(0x0f);delay(1000);
if(key1==1)
{ key1=0;n=1;
time_date[5]++;
if(time_date[5]==60)time_date[5]=0;
display();
}
if(key2==1)
{
key2=0;n=1;
time_date[5]--;
if(time_date[5]==-1)time_date[5]=59;
display();
}
}
if(key0num==3)
{write_com(0x80+0x40+5);
write_com(0x0f);delay(1000);
if(key1==1)
{ key1=0;n=1;
time_date[4]++;
if(time_date[4]==24)time_date[4]=0;
display();
}
if(key2==1)
{
key2=0;n=1;
time_date[4]--;
if(time_date[4]==-1)time_date[4]=23;
display();
}
}
if(key0num==4)
{write_com(0x80+14);
write_com(0x0f);delay(1000);
if(key1==1)
{ key1=0;n=1;
time_date[1]++;
if(time_date[1]==8)time_date[1]=1;
display();
}
if(key2==1)
{
key2=0;n=1;
time_date[1]--;
if(time_date[1]==0)time_date[1]=7;
display();
}
}

if(key0num==5)
{write_com(0x80+10);
write_com(0x0f);delay(1000);
if(key1==1)
{ key1=0;n=1;
time_date[3]++;
runnian1();
display();
}

if(key2==1)
{
key2=0;n=1;
time_date[3]--;
if(time_date[3]<1)time_date[3]=31;
runnian2();
display();
}
}
if(key0num==6)
{write_com(0x80+7);
write_com(0x0f);delay(1000);
if(key1==1)
{ key1=0;n=1;
time_date[2]++;
if(time_date[2]>12)time_date[2]=1;
runnian2();
display();
}
if(key2==1)
{
key2=0;n=1;
time_date[2]--;
if(time_date[2]==0)time_date[2]=12;
runnian2();
display();
}
}
if(key0num==7)
{write_com(0x80+4);
write_com(0x0f);delay(1000);
if(key1==1)
{ key1=0;n=1;
time_date[0]++;
if(time_date[0]==100)time_date[0]=0;
runnian2();
display();
}
if(key2==1)
{
key2=0;n=1;
time_date[0]--;
if(time_date[0]==-1)time_date[0]=99;
runnian2();
display();
}
}

if(key0num==8)
{ key0num=0;key0=0;
write_com(0x0c);
if(n){n=0;set_rtc();}

}
}
else
{
read_rtc();
timepost();
display();
if(time_date[5]==0) ///整点报时
{if(time_date[6]==0)beep=0;
else beep=1;
}
}
}
void runnian1()////闰年加
{
if(time_date[2]==2) /////判断2月
{ if((time_date[0]+4)%4==0)
{ if(time_date[3]>29)time_date[3]=1;}//判断闰年
else
{if(time_date[3]>28)time_date[3]=1;}
}
else
{ if(time_date[2]<8)///判断月小于8
{
if((time_date[2]+1)%2==0)
{if(time_date[3]>31)time_date[3]=1;}
else
{if(time_date[3]>30)time_date[3]=1;}
}
if(time_date[2]>7)
{
if((time_date[2])%2==0)
{if(time_date[3]>31)time_date[3]=1;}
else
{if(time_date[3]>30)time_date[3]=1;}
}
}
}
void runnian2()//闰年减
{
if(time_date[2]==2) /////判断2月
{ if((time_date[0]+4)%4==0)
{ if(time_date[3]>29)time_date[3]=29;}//判断闰年
else
{if(time_date[3]>28)time_date[3]=28;}
}
else
{
if(time_date[2]<8)///判断月小于8
{
if((time_date[2]+1)%2==0)
{if(time_date[3]>31)time_date[3]=31;}
else
{if(time_date[3]>30)time_date[3]=30;}
}
if(time_date[2]>7)
{
if((time_date[2])%2==0)
{if(time_date[3]>31)time_date[3]=31;}
else
{if(time_date[3]>30)time_date[3]=30;}
}
}
}
void password_scan() ////////输入密码界面
{uchar l,i,j;
write_com(0x80);
for(l=0;l<15;l++)
{write_date(lcd_tab1[l]);}
write_com(0x80+0x40+4+i);
write_com(0x0f);delay(1000);
if(key!=0)
{
password[i]=key;
write_com(0x80+0x40+4+i);
write_date(numtab1[key]);
write_com(0x14);
i++;key=0;
}
if(i>0)
{if(sha==1)
{sha=0;i--;
write_com(0x80+0x40+4+i);
write_date(numtab1[0]);
write_com(0x10);
}
}
if(i==9)
{ i=0;
for(j=0;j<9;j++)
{
if(password1[j]==password[j])m++;
else {init_lcd();m=0;break;}
}
if(m==9)
{
m=0;passwordok=1;
p=0;pnum=0;key=0;
init_lcd();
for(i=0;i<15;i++)
{write_date(table[i]);}
write_com(0x80+0x40);
for(i=0;i<15;i++)
{write_date(table1[i]);}
}
}
}
void dis_key(void) //显示键值
{
write_com(0x80+0x40+4);
write_date(numtab[dis[0]]);
write_date(numtab[dis[1]]);
write_com(0x80+0x40+7);
write_date(numtab[dis[2]]);
write_date(numtab[dis[3]]);
write_com(0x80+0x40+10);
write_date(numtab[dis[4]]);
write_date(numtab[dis[5]]);
write_com(0x80+0x40+13);
write_date(numtab[dis[6]]);
write_date(numtab[dis[7]]);

}
void timeplay()
{
if(p==1)
{ uchar v;key0num=0;key0=0;
if(v==0){v=1;init_lcd();key=0;}
if(pnum==1)
{
password_scan();
}
if(pnum==2)
{ p=0;pnum=0;m=0;v=0;
init_lcd();
}
}
else keypost();
}
//////////////////////////主函数////////////////////////
void main()
{
init_lcd(); /////初始化lcd
timer0init();///// 开定时器中断
init0init();///// 开外部器中断
key=0;
while(1)
{
keyscan();

if(passwordok)
{ dis_key();
post_key();
if(p==1)
{ if(pnum==1)
{if(ricode[2]!=0x46)pnum=0;}
if(pnum==2)
{pnum=0;m=0;
passwordok=0;p=0;
break;
}
}
}
else timeplay();
}
}

void post_key()
{
if(key==1){key=0;kj=0;}
if(key==2){key=0;kj=1;}
if(key==3){key=0;dj1();}
if(key==4){key=0;dj2();}
}
void dj1()
{
uint i;
for(i=0;i<512;i++)
{if(rireceok==1)break;
a=0;b=0;delay(20);
a=1;b=0;delay(20);
b=0;c=0;delay(20);
b=1;c=0;delay(20);
c=0;d=0;delay(20);
c=1;d=0;delay(20);
d=0;a=0;delay(20);
d=1;delay(20);
}
}
void dj2()
{ uint i;
for(i=0;i<512;i++)
{if(rireceok==1)break;
d=0;a=0;delay(20);
a=1;d=0;delay(20);
c=0;d=0;delay(20);
c=0;d=1;delay(20);
b=0;c=0;delay(20);
c=1;b=0;delay(20);
a=0;b=0;delay(20);
a=0;b=1;delay(20);
}
}

使用方法 本程序用于HC6800 V2.6 实验箱,需要装上1602液晶屏,18b20 温度传感器,红外接收头,和步进电机,同时保证遥控器好用(要用配套的小遥控器并且要按键值和我的一样才能准确的操作本程序)
我的遥控器按键值如下
ch-0x45 ch 0x46 ch+0x47

<< 0x44 >> 0x40 >= 0x43

- 0x07 + 0x15 EQ 0x09

0 0x16 100+ 0x19 200+ 0x0d

1 0x0c 2 0x18 3 0x5e

4 0x08 5 0x1c 6 0x5a

7 0x42 8 0x52 9 0x4a

主要操作键为 ch EQ + - 123456789 等键,

程序下进去后 1602会显示日期 时间 温度
用EQ键可对日期 时间进行设定
用+ - 键对日期时间进行调节
调节日期时会自动识别大小月,及闰年并对日期进行相应调整

按下ch键后 会进入输入密码界面 依次输入674688646 会进入按键读值界面 ,输入错误可用 - 键退回
在按键读值界面 连续按两次ch 键后,程序 会退出到时间显示界面
在按键读值界面 按1 打开继电器 按2 关闭继电器 按3 步进电机正转一周,按 4 步进电机反转一周 ,步进电机转的过程中按其他键,步进电机停止
相似回答