51单片机带闹钟可调时间的电子时钟程序设计

2019-02-24 11:19:48

51单片机带闹钟可调时间的电子时钟程序设计

硬件部分:

   基于51单片机、 ds1302时钟芯片、 ds18b20温度芯片、 以及1602液晶显示的    实时时间   和   实时温度显示 。同时可通过按键 设置 年、月、日、时、分、星期。并且可以设置闹钟  当闹钟时间到时 蜂鸣器持续发出 滴..声 同时led灯不停闪烁   且在一分钟内没有按指定停止按键 闹钟将自动停止  。。。


软件部分:


#include

#define uchar unsigned char

#define uint unsigned int

sbit spk=P1^7;

sbit led=P1^5;

sbit DQ=P1^0;

sbit RS=P2^4;

sbit RW=P2^5;

sbit EN=P2^6;

sbit key1=P2^0;

sbit key2=P2^1;

sbit key3=P2^2;

sbit key4=P2^3;

sbit IO=P3^6;

sbit RST=P3^7;

sbit SCLK=P3^5;

uchar code table[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};

int nian,xing,yue,ri,shi,fen,miao;

uchar num,temp,c,d,time[7],a,b,aa,bb,ns,ng,ys,yg,rs,rg,ss,sg,fs,fg,ms,mg,flag;


/*******************1602************************/


void delay(int z)

{

 int x,y;

 for(x=z;x>0;x--)

  for(y=100;y>0;y--); 

}


void write_com(uchar com)   //写命令

{

 RS=0;

 P0=com;

 delay(5);

 EN=1;

 delay(5);

 EN=0;

}


void write_data(uchar date)      //写数据

{

 RS=1;

 P0=date;

 delay(5);

 EN=1;

 delay(5);

 EN=0;

}

void init()          //初始化

{

 RW=0;

 EN=0;

 write_com(0x38);    //显示模式设置

 write_com(0x0c);    //开显示 不显示光标 不闪

 write_com(0x06); //写一个字符 地址指针 光标 加一 整屏不移动

 write_com(0x01);    //显示清零


 write_com(0x80+0x04);

 write_data('2');     

 write_com(0x80+0x05);

 write_data('0');     

 write_com(0x80+0x00);

 write_data('c');     

 write_com(0x80+0x01);

 write_data('a');

 write_com(0x80+0x02);

 write_data('i');      

 write_com(0x80+0x4e);

 write_data(0xdf);    

 write_com(0x80+0x4f);

 write_data('C');     

 write_com(0x80+0x4b);

 write_data(0x2e);       //显示"。"

}

 

/**************DS18B20****************/


void delay1(unsigned int t) //延时函数

{

 while(t--);

}


void init1()  //初始化

{

 uchar n=0;

 DQ=1;      //DQ复位

 delay1(8);  

 DQ=0;      //主机将DQ拉低

 delay1(80);     //大于480us的延时

 DQ=1;

 delay1(5);    //延时15~60us

 n=DQ;

 delay1(5);   //若n=0初始成功 n=1初始失败(可设置返回值查看n是否为1) 

}

 

void write_byte(uchar dat)    //写入一个字节

{

 uint i;

 for(i=0;i<8;i++)

 {

  DQ=0;

  DQ=dat&0x01;

  delay1(12);

  DQ=1;

  dat>>=1;

 }

 delay1(4);

}


uchar read_byte()    //读入一个字节

{

 uint k=0;

 uchar value=0;

 for(k=0;k<8;k++)

 {

  DQ=0;

  value>>=1;

  DQ=1;

  if(DQ)

  value|=0x80;

  delay1(4);

 } 

 return value; 

}


uchar read_temp()    //读取温度函数

{

 uchar a=0,b=0;

 init1();

 write_byte(0xcc);

 write_byte(0x44);

 delay1(200);


 init1();

 write_byte(0xcc);

 write_byte(0xbe);

 a=read_byte();  

 b=read_byte();

 c=b;

 d=a;

 b<<=4;

 b+=(a&0xf0)>>4; 

 return b;

}


/***********************1302**********************/


void wirte_byte1(uchar date)    //写入一个字节

{

 uchar i;

 for(i=8;i>0;i--)

 {

  IO=date&0x01;

  SCLK=0;

  SCLK=1;

  date=date>>1;

   }

}


uchar read_byte1()       //读一个字节

{

 uchar dat,i;

 for(i=8;i>0;i--)

 {

  dat=dat>>1;

  SCLK=0;

  if(IO)

  dat=dat|0x80;

  SCLK=1;

 }

 return(dat);

}


void write_ds1302(uchar add,uchar date)     //将数据写入1302中

{

 RST=0;

 SCLK=0;

 RST=1;

 wirte_byte1(add);

 wirte_byte1(date);

 RST=0;

 SCLK=1;

}


uchar read_ds1302(uchar add)  //读出1302中数据

{

 uchar temp;

 RST=0;

 SCLK=0;

 RST=1;

 wirte_byte1(add);

 temp=read_byte1();

 RST=0;

 SCLK=0;

 return (temp);

}


uchar huan_BCD(uint z)   //将数据 转换成BCD

{

 uint a,b;

  a=z/10;

  b=z;

  a=a&0xff;

  b=b&0xff;

  a<<=4;

  a=a|b;

 return (a);

}


void xian_shi()       //液晶显示函数

{

 if(b==0&a==0)

 { 

  ms=time[0]/16;

  mg=time[0];


  fs=time[1]/16;

  fg=time[1];

  fen=fs*10+fg;

 

  ss=time[2]/16;

  sg=time[2];

  shi=ss*10+sg;


  rs=time[3]/16;

  rg=time[3];

  ri=rs*10+rg;


  ys=time[4]/16;

  yg=time[4];

  yue=ys*10+yg;


  ns=time[6]/16;

  ng=time[6];

  nian=ns*10+ng;


  xing=time[5]; 

 }

 if(a==1|b==1)

 {

  ss=shi/10;

  sg=shi;


  write_com(0x80+0x41);

  write_data(0xff);


  write_com(0x80+0x40);    

  write_data(table[ss]);

  write_com(0x80+0x41);    

  write_data(table[sg]);


 }

 if(a==2|b==2)

    { 

  fs=fen/10;

  fg=fen;


  write_com(0x80+0x44);

  write_data(0xff);


  write_com(0x80+0x43);    

  write_data(table[fs]);

  write_com(0x80+0x44);    

  write_data(table[fg]);

 }


 if(a==3)

    { 

  rs=ri/10;

  rg=ri;


  write_com(0x80+0x0d);

  write_data(0xff);


  write_com(0x80+0x0c);    

  write_data(table[rs]);

  write_com(0x80+0x0d);    

  write_data(table[rg]);

 }

 if(a==4)

    { 

  ys=yue/10;

  yg=yue;


  write_com(0x80+0x0a);

  write_data(0xff);


  write_com(0x80+0x09);    

  write_data(table[ys]);

  write_com(0x80+0x0a);    

  write_data(table[yg]);

 }

 if(a==5)

    { 

  ns=nian/10;

  ng=nian;


  write_com(0x80+0x07);

  write_data(0xff);


  write_com(0x80+0x06);    

  write_data(table[ns]);

  write_com(0x80+0x07);    

  write_data(table[ng]);

 }

 if(a==6)

    { 

  write_com(0x80+0x0f);

  write_data(0xff);

  write_com(0x80+0x0f);    

  write_data(table[xing]);

 }

  write_com(0x80+0x06); //在液晶第一行第七八位显示  年   

  write_data(table[ns]);

  write_com(0x80+0x07);    

  write_data(table[ng]);


  write_com(0x80+0x08);    

  write_data('-');


  write_com(0x80+0x09); //在液晶第一行第十十一位显示  月   

  write_data(table[ys]);

  write_com(0x80+0x0a);    

  write_data(table[yg]);


  write_com(0x80+0x0b);    

  write_data('-');


  write_com(0x80+0x0c); //在液晶第一行第十三 十四位显示  日   

  write_data(table[rs]);

  write_com(0x80+0x0d);    

  write_data(table[rg]);


  write_com(0x80+0x0f);   //在液晶第一行第十七位显示  星期 

  write_data(table[xing]);


  write_com(0x80+0x40);   //在液晶第二行第二三位显示    时 

  write_data(table[ss]);

  write_com(0x80+0x41);    

  write_data(table[sg]);


  write_com(0x80+0x42);    

  write_data(':');


  write_com(0x80+0x43);   //在液晶第二行第五六位显示  分 

  write_data(table[fs]);

  write_com(0x80+0x44);    

  write_data(table[fg]);


  write_com(0x80+0x45);    

  write_data(':');


  write_com(0x80+0x46);   //在液晶第二行第八九位显示  秒 

  write_data(table[ms]);

  write_com(0x80+0x47);    

  write_data(table[mg]);

}


void keyscan()    //按键设置函数  可任意设置年月日时分秒星期的数值

{

 if(key4!=0)

 {

  if(key1==0)   //key1按键 选择需设置的位

  {

   if(key1==0)

   { 

    a++;

    delay(1);

   }

         while(!key1)

   {      

    delay(1);

   }       

  }

 

  if(a!=0)

  {

   if(key2==0)    //key2按键 可将需设置的数 调大

   {

    if(a==1)

    {

     shi++;

     if(shi>=24)

     {

      shi=0;

     }

    }

    if(a==2)

    {

     fen++;

     if(fen>=60)

     {

      fen=0;

     }

    }

    if(a==3)

    {

     ri++;

     if(ri>=32)

     {

      ri=1;

     }

    }

    if(a==4)

    {

     yue++;

     if(yue>=12)

     {

      yue=1;

     }

    }

    if(a==5)

    {

     nian++;

     if(nian>=99)

     {

      nian=0;

     }

    }

    if(a==6)

    {

     xing++;

     if(xing>=8)

     {

      xing=1;

     }

    }

   }

   if(key3==0)    //key3按键 可将需设置的数 调小

   {

   

    if(a==1)

    {

     shi--;

     if(shi<0)

     {

      shi=23;

     }

    }

    if(a==2)

    {

     fen--;

     if(fen<0)

     {

      fen=59;

     }

    }

    if(a==3)

    {

     ri--;

     if(ri<1)

     {

      ri=31;

     }

    }

    if(a==4)

    {

     yue--;

     if(yue<1)

     {

      yue=12;

     }

    }

    if(a==5)

    {

     nian--;

     if(nian<0)

     {

      nian=99;

     }

    }

    if(a==6)

    {

     xing--;

     if(xing<1)

     {

      xing=7;

     }

    } 

   } 

   if(a==7)       //当按下key1 7次后  将个数据写入1302 

   {

    a=0;

    write_ds1302(0x8e,0x00);   //WP=0 写操作

    write_ds1302(0x80,0x00);   //0x80是写秒数据 

    write_ds1302(0x82,huan_BCD(fen)); //0x82是写分数据 

    write_ds1302(0x84,huan_BCD(shi)); //0x84是写时数据

    write_ds1302(0x86,huan_BCD(ri)); //0x84是写日数据

    write_ds1302(0x88,huan_BCD(yue)); //0x84是写月数据

    write_ds1302(0x8a,huan_BCD(xing)); //0x84是写星期数据

    write_ds1302(0x8c,huan_BCD(nian)); //0x84是写年数据

    write_ds1302(0x8e,0x80);   //WP=1 写保护    

   }

  }

 }

}


void naozhong()      //通过按键设置闹钟  时 分

{

 if(key1!=0)

 {

  if(key4==0)

  {

   if(key4==0)

   { 

    b++;

    delay(1);

   }

         while(!key4)

   {      

    delay(1);

   }

  }

  if(b!=0)

  {

   if(key2==0)    //key2按键 可将需设置的数 调大

   {

    if(b==1)

    {

     shi++;

     if(shi>=24)

     {

      shi=0;

     }

    }

    if(b==2)

    {

     fen++;

     if(fen>=60)

     {

      fen=0;

     }

    }

   }

   if(key3==0)    //key3按键 可将需设置的数 调小

   {

    if(b==1)

    {

     shi--;

     if(shi<0)

     {

      shi=23;

     }

    }

    if(b==2)

    {

     fen--;

     if(fen<0)

     {

      fen=59;

     }

    }

   }

   aa=huan_BCD(shi);   //将设置的时钟 赋值给aa

   bb=huan_BCD(fen); //将设置的分钟 赋值给bb

   if(b==3)       //当按下key4 3次后 闹钟设置完成 

   {

    b=0;

   }

  }

 }

}


void main()

{

 uint i,temp;

 init();

 TMOD=0x10;

 EA=1;

 TH1=(65536-51200)/256;

 TL1=(65536-51200)%256;

 ET1=1;

 while(1)

 {

  temp=0x81;          //读的初始地址                   

        for(i=0;i<7;i++)             //分别把秒分时日月年星期数据读出分7次读好一次地址加2" temp+=2;"

      {

         time[i]=read_ds1302(temp);

      temp+=2;

        }

  if(bb==time[1]&aa==time[2]&!time[0])  //如果读出来的时钟 分钟与1302读出来的值相等且读出来的秒钟为零时 进入中断

  {

   TR1=1;

   flag=1;   //标志位设置为1

  }

  if(key3==0)   //进入闹钟后 可由key3按下 停止中断 标志位置零 允许调时闹钟设置按键动作 停止闹铃

  {

   led=1;

   spk=1;

   flag=0;

   TR1=0;

  }

        if(flag!=1)   //当进入闹钟中断后 调时与设置闹钟的按键  无效

     {

         naozhong();

   keyscan();

  }

  xian_shi();

  temp=read_temp();

  write_com(0x80+0x49);    

  write_data(table[temp/10]);    //在液晶第二行第十位显示温度的十位

  write_com(0x80+0x4a);  

  write_data(table[temp]);    //在液晶第二行第十一位显示温度的个位

  write_com(0x80+0x4c);    

  write_data(table[(d&0x0f)*625/1000]);   //在液晶第二行第十三位显示温度的小数点后一位

  write_com(0x80+0x4d);    

  write_data(table[(d&0x0f)*625/100]);   //在液晶第二行第十四位显示温度的小数点后二位 

 }

}



void timer1() interrupt 3     //定时器 

{

 uint t;

 TH1=(65536-50000)/256;

 TL1=(65536-50000)%256;

 t++;

 spk=0;      //蜂鸣器  发出 滴答 声

 led=!led;      //发光二极管  不停闪烁

 delay1(10);

 if(t==1120)    //约1分钟后 闹钟自动停止 标志位

 {

  led=1;

  spk=1;

  t=0;

  TR1=0;

  flag=0;

 }


}