单片机
返回首页

用51单片机定时器中断设计电子钟

2015-08-18 来源:eefocus

把前天设计的时钟的功能补全了一些,贴上来,

 

#include
#define uchar unsigned char
sbit rd=P2^6;
sbit wr=P2^5;
sbit lcde=P2^7;
sbit k1=P1^0;
sbit k2=P1^1;
sbit k4=P1^3;
sbit k8=P1^7;
uchar code table1[]='2011-11-05';
uchar code table2[]='00:00:00';
uchar code table3[][3]={{'MON'},{'TUE'},{'WED'},{'THU'},{'FRI'},{'SAT'},{'SUN'}};         //定义了二维数组存放星期
uchar t,s1num;
char shi,fen,miao,week,nian;
uchar yue=1,ri=1;
void delay(uchar z)       //延迟zms函数
{
 uchar x,y;
 for(x=z;x>0;x--)
 for(y=110;y>0;y--);

}

 

void write_com(uchar com)       //液晶写指令操作
{
 rd=0;
 wr=0;
 delay(5);
 lcde=1;
 P0=com;
 lcde=0; 
}

void write_date(uchar date)        //液晶写数据操作
{
 rd=1;
 wr=0;
 delay(5);
 lcde=1;
 P0=date;
 lcde=0; 
}

void write_sfm(uchar add,uchar date)       //更新时分秒
{
 uchar shi,ge;
 shi=date/10;
 ge=date;
 write_com(0x80+0x40+add);
 write_date(0x30+shi);
 write_date(0x30+ge);
}

void write_week(uchar i)             //更新星期
{
 uchar j;
 write_com(0x80+0x0b);
 for(j=0;j<3;j++)
 {
  write_date(table3[i][j]);
  
 }
}


void write_riqi(uchar add,uchar riqi)    //更新年月日
{
 uchar shi,ge;
 shi=riqi/10;
 ge=riqi;
 write_com(0x80+0x00+add);
 write_date(0x30+shi);
 write_date(0x30+ge);
}

void init()                //初始化函数
{
 uchar i,j;

 


 write_com(0x38);
 write_com(0x0c);
 write_com(0x06);
 write_com(0x01);

 write_com(0x80+0x00);
 for(i=0;i<10;i++)
 write_date(table1[i]);

 write_com(0x80+0x00+0x0b);
 for(j=0;j<3;j++)
 write_date(table3[week][j]);

 write_com(0x80+0x46);
 for(i=0;i<8;i++)
 write_date(table2[i]);

 TMOD=0x01;              //定时器0工作方式1
 TH0=(65536-50000)/256;         //设定定时器初值
 TL0=(65536-50000)%6;         //12M晶振时50ms数为50000
 EA=1;
 ET0=1;
 TR0=1;
}

void keyscan()            //键盘扫描函数
{
 if(k1==0)               //按下k1键确定调时分秒
 {
 delay(5);
 if(k1==0)
 {
  s1num++;
  while(!k1)
  ;
  delay(5);
  while(!k1);
   if(s1num==1)     
   {
   TR0=0;                   //暂停计时器
   write_com(0x80+0x4d);     //光标在秒的位置闪烁
   write_com(0x0f);
   }
  
   if(s1num==2)         //光标在分的位置
   {
   TR0=0;
   write_com(0x80+0x4a);
   write_com(0x0f);
   }

   if(s1num==3)         //光标在小时的位置
   {
   TR0=0;
   write_com(0x80+0x47);
   write_com(0x0f);
   }
  if(s1num==4)         //光标在星期的位置
   {
   TR0=0;
   write_com(0x80+0x0d);
   write_com(0x0f);
   }
  if(s1num==5)         //光标在日的位置
   {
   TR0=0;
   write_com(0x80+0x09);
   write_com(0x0f);
   }
  if(s1num==6)         //光标在月的位置
   {
   TR0=0;
   write_com(0x80+0x06);
   write_com(0x0f);
   }
  if(s1num==7)         //光标在年的位置
   {
   TR0=0;
   write_com(0x80+0x03);
   write_com(0x0f);
   }
   if(s1num==8)       //按下第8下时接着走时
   {
    s1num=0;
    write_com(0x0c);
    TR0=1;
   }

  }
 }
 if(s1num!=0)
 {
  if(s1num==1)
  
  if(k2==0)            //按k2键秒加1
  {
   delay(5);
  if(k2==0)
  {
   while(!k2);
   delay(5);
   while(!k2);
 
   miao++;
   if(miao==60)
   miao=0;

   write_sfm(0x0c,miao); 
   write_com(0x80+0x4d);
  }
  }
 }


  if(s1num==2)
  {
  if(k2==0)           //分加1
  {
   delay(5);
  if(k2==0)
   {
   while(!k2);
   delay(5);
   while(!k2);
   fen++; 
   if(fen==60)
   fen=0;

   write_sfm(0x09,fen); 
   write_com(0x80+0x4a);
   }
  }
  }
  
  if(s1num==3)
  {
   if(k2==0)           //时加1
  {
   delay(5);
   if(k2==0)
   {

   while(!k2);
   delay(5);
   while(!k2);
   shi++; 
   if(shi==24)
   shi=0;

   write_sfm(0x06,shi); 
   write_com(0x80+0x47);
   }
  }
  }

  if(s1num==4)
  {
   if(k2==0)           //星期加1
  {
   delay(5);
   if(k2==0)
   {

   while(!k2);
   delay(5);
   while(!k2);
   week++; 
   if(week==7)
   week=0;

   write_week(week); 
   write_com(0x80+0x0d);
   }
  }
  }

  if(s1num==5)
  {
   if(k2==0)           //日加1
  {
   delay(5);
   if(k2==0)
   {

   while(!k2);
   delay(5);
   while(!k2);
   ri++; 
   if(ri==31)
   ri=1;

   write_riqi(0x08,ri);
   write_com(0x80+0x09);
   }
  }
  }


  if(s1num==6)
  {
   if(k2==0)           //月加1
  {
   delay(5);
   if(k2==0)
   {

   while(!k2);
   delay(5);
   while(!k2);
   yue++; 
   if(yue==12)
   yue=1;

   write_riqi(0x05,yue);  
   write_com(0x80+0x06);
   }
  }
  }

  if(s1num==7)
  {
   if(k2==0)           //年加1
  {
   delay(5);
   if(k2==0)
   {

   while(!k2);
   delay(5);
   while(!k2);
   nian++; 
   if(nian==100)
   nian=0;
   write_riqi(0x02,nian); 
   write_com(0x80+0x03);
   }
  }
  }

 

 

 if(k4==0)  //判断k4是否被按下
 {
  delay(5);
  if(k4==0)
  {
   while(!k4);
   delay(5);
   while(!k4);
   if(s1num==1)
   {
    miao--;        //秒减1
    if(miao==-1)
    miao=59;
    write_sfm(0x0c,miao); 
    write_com(0x80+0x4d);
   }
   if(s1num==2)
   {
    fen--;         //分减1
    if(fen==-1)
    fen=59;
    write_sfm(0x09,fen); 
    write_com(0x80+0x4a);
   }
   if(s1num==3)
   {
    shi--;         //时减1
    if(shi==-1)
    shi=23;
    write_sfm(0x06,shi); 
    write_com(0x80+0x47);
   }
  if(s1num==4)
   {
    week--;         //星期减1
    if(week==-1)
    week=6;
    write_week(week); 
    write_com(0x80+0x0d);
   }
  if(s1num==5)
   {
    ri--;         //日减1
    if(ri==0)
    ri=30;
    write_riqi(0x08,ri);
    write_com(0x80+0x09);
   }
  if(s1num==6)
   {
    yue--;         //月减1
    if(yue==0)
    yue=12;
    write_riqi(0x05,yue);  
    write_com(0x80+0x06);
   }
  if(s1num==7)
   {
    nian--;         //年减1
    if(nian==-1)
    nian=99;
    write_riqi(0x02,nian); 
    write_com(0x80+0x03);
   }
  }
 }
 }
 if(k8==0)        // 按下k8退出调时  
 {
  delay(5);
  if(k8==0)
  {
   while(!k8);
   delay(5);
   while(!k8);
   s1num=0;
   write_com(0x0c);
   TR0=1; 
  }
 }
}
 
void main()
{
 init();
    while(1)
 {
 keyscan();
 }
}

void timer0() interrupt 1       //中断服务程序
{

 TH0=(65536-50000)/256;         //设定定时器初值
 TL0=(65536-50000)%6;         //12M晶振时50ms数为50000
 t++;
  if(t==20)           //定时器中断20次为1秒
 {
 t=0;
 miao++;
 if(miao==60)
 {
 miao=0;
 fen++;
 if(fen==60)
 {
  fen=0;
  shi++;
  if(shi==24)
  {
   shi=0;
   ri++;
   week++;
   if(week==7)
    week=0;
    write_week(week);                //刷新星期
    if(ri==31)
    {
     ri=1;
     yue++;
     if(yue==13)
      {
       yue=1;
       nian++;
       if(nian==100)
       nian=0;
       write_riqi(0x02,nian);   //刷新年
      }

      write_riqi(0x05,yue);   //刷新月
      }
  write_riqi(0x08,ri);  //刷新日  
  }
 write_sfm(0x06,shi);    //刷新时
 }
 write_sfm(0x09,fen);     //刷新分
 }
 write_sfm(0x0c,miao);     //刷新秒
}
}

 


// 还可以加上整点报时和断电记忆的功能,还可以加上24小时和12小时制转换功能,还可以加上秒表功能,原理都是一样的,但由于51单片机内存有限,只有
//4k,所以没加
//由于单片机晶振不是严格的12MHz,所以要想时钟精确的话还要进行中断时间的调整//其中年只能改变后两位,即从2000到2099年,其实也可实现全调,原理是一样的,但没这个必要

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 用数字电路CD4069制作的万能遥控轻触开关

  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • RS-485基础知识:处理空闲总线条件的两种常见方法

  • 带有短路保护系统的5V直流稳压电源电路图

  • 基于ICL296的大电流开关稳压器电源电路

    相关电子头条文章