找回密码
 立即注册

QQ登录

只需一步,快速开始

帖子
查看: 2095|回复: 0
打印 上一主题 下一主题
收起左侧

数字电子钟元理图及代码

[复制链接]
跳转到指定楼层
楼主
ID:114676 发表于 2016-4-17 09:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
file:///D:/Temp/msohtmlclip1/01/clip_image002.jpgfile:///D:/Temp/msohtmlclip1/01/clip_image002.jpg


/********************************************************************
*  描述*                                                                     *                 电子时钟,LED数码管显示,晶振使用12MHz         *
*                   K1---时调整                                    *
  K2---分调整                                          *                   K3---秒调整                                                     K4---时间暂停                                    K5---12小时制和24小时制切换
*                    上电时初始化显示:12-00-00                                   *
*********************************************************************#include<reg51.h>
#include<intrins.h>
unsignedchar data dis_digit;
unsignedchar key_s, key_v;
unsignedchar code dis_code[11]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00   
              };//0,1,2,3 4, 5, 6, 7, 8, 9, off   //共阴数码管
unsignedchar data dis_buf[8];
unsignedchar data dis_index;
unsignedchar hour,min,sec;
unsignedchar sec100;
unsignedchar flag,flag1,flag2;    //falg用于时间停止和启动标志,falg1为12小时和24小时的切换标志,falg2为12小时的上午和下午的切换标志
sbitK1 = P1^0;      //用于时的调整
sbitK2 = P1^1;      //用于分的调整
sbitK3 = P1^2;      //用于秒的调整
sbitK4 = P1^3;      //用于时间调整的开关,按下一次暂停时间,再按一次时则开始计时
sbitK5 = P1^4;      //用于24小时制和12小时制的切换
bitscan_key();
voidproc_key();
voidinc_sec();
voidinc_min();
voidinc_hour();
voidinc_hour1();
voiddelayms(unsigned char ms);
voidmain(void)
{
P0 = 0xff;
P2 = 0xff;
TMOD = 0x11; // 定时器0, 1工作模式1, 16位定时方式
TH1 = 0xd8;  //使用12MHz的晶振,定时时间为:10ms
TL1 = 0xf0;
TH0 = 0xf8;  //定时时间为2ms,用于数码管的动态扫描
TL0 = 0x30;
hour = 12;
min = 00;
sec = 00;
sec100 = 0;
flag = 0;
flag1 = 0;
dis_buf[0] = dis_code[hour / 10];  // 时十位
dis_buf[1] = dis_code[hour % 10];  // 时个位
dis_buf[2] = dis_code[min / 10];  // 分十位   
dis_buf[3] = dis_code[min % 10];  // 分个位
dis_buf[4] = dis_code[sec / 10];  // 秒十位
dis_buf[5] = dis_code[sec % 10];  // 秒个位   
dis_buf[6] = 0x00;   // 关闭该位数码管
dis_buf[7] = 0x7f;   // 显示 B 表示下午
   
dis_digit = 0xfe;
dis_index = 0;
TCON = 0x01; //T1:TF1TR1    T0:TF0 TR0    定时中断:IE1 IT1 IE0 IT0 //外部中断0的触发方式为下降沿触发
IE = 0x8a;    // 使能timer0,1 中断,控制IE寄存器的格式:EA - -ES ET1 EX1 ET0 EX0
              //                                  1 0 0  0 1   0   1 0
TR0 = 1;     //开定时器0
TR1 = 1;     //开定时器1
key_v = 0x1f;    //定义为K1,K2,K3,K4,K5相应的按键,当没有按下时则为,K1,K2,K3,K4,K5,都为高电平,0x1f
while(1)
{
  if(scan_key())  //先扫描一次是否有按键按下
  {
   delayms(10);         //延时
   if(scan_key())    //再次扫描一次是否有按键 按下
   {
    key_v = key_s;       //将key_s的值传给key_v
    proc_key();
   }
  }
  
}
}
bitscan_key()
{
key_s = 0x00;         //设置key_s先为0
key_s |=K5;
key_s <<= 1;
key_s |= K4;
key_s <<= 1;
key_s |= K3;
key_s <<= 1;
key_s |= K2;       //K2 -> P1.1,若K2按下则为0,当K2按下时key_s与K2或的结果会使得key_s为0x00,未按下时K2则为1,key_s与K2或的结果会使得key_s为0x01
key_s <<= 1;       //将key_s左移一位,
key_s |= K1;        //K1-> P1.0,若K1按下则为0,当K1按下时key_s与K1或的结果会使得key_s为0x00或是0x02,没有按下时则得到的结果为0x01或是0x03
return(key_s ^ key_v);     //进行逻辑异或运算,相同为0,不同为1.  已经定义了变量:key_v = 0x1f;  如果两个按键都没有按下则是得到0x03,异或的结果是为0
}
voidproc_key()
{
     if(K4==0)    //K4是否按下
     {
        flag++;  //关闭定时器
        TR1=0;       //关闭定时器1
        dis_buf[6] = 0x76;   // 显示 H,用于表示设定时间的标志
     }
     if(K5==0)
     {
     flag1++;      //flag1的初始值是0,falg1为12小时和24小时的切换标志
      if(flag1==1)         //24小时制
       {
         if(dis_buf[7]==0x7f)    //判断是不是下午
           {
               hour=hour+12;
              dis_buf[7]=0x00;
           }
           dis_buf[7] =  0x00;    // 关闭显示
           if(hour >23)
           {
                hour = 0;
           }
           if(hour > 9)
               dis_buf[0] = dis_code[hour / 10];  // 时十位
           else
               dis_buf[0] = 0x00;     // 当小时的十位为0时不显示
               dis_buf[1] = dis_code[hour % 10];  // 时个位
       }
       if(flag1==2)   //12小时制
       {
           flag1=0;
           if(hour>12||hour==0)    //判断是不是下午,并用于处理24小时制的大于13和等于0的处理
           {   
              if(hour>12)
               hour=hour-12;
              if(hour==0)
              hour=12;
              dis_buf[7]=0x7f;  //显示下午  B
           }
           else
              dis_buf[7] =  0x77;    // 显示 A 表示上午
           if(hour > 9)
               dis_buf[0] = dis_code[hour / 10];  // 时十位
           else
               dis_buf[0] = 0x00;     // 当小时的十位为0时不显示
               dis_buf[1] = dis_code[hour % 10];  // 时个位         
       }
       }
     if((key_v & 0x01) == 0)   // K1,当只有K1按下时,则key_s为0x02,没有按下时key_s则为0x03
     {
     if(flag1==0)
        inc_hour();
     if(flag1==1)
         inc_hour1();
     }
     elseif((key_v & 0x02) == 0) // K2, 当只有K2按下时,则key_s为0x01,没有按下时key_s则为0x03
     {
     min++;
     if(min > 59)
      {
       min= 0;
      }
     dis_buf[2] = dis_code[min / 10]; // 分十位
     dis_buf[3] = dis_code[min % 10]; // 分个位
     }
    else if((key_v & 0x04) == 0) // K3是否按下
     {
     sec++;
     if(sec > 59)
      {
       sec= 0;
      }
     dis_buf[4] = dis_code[sec / 10]; // 秒十位
     dis_buf[5] = dis_code[sec % 10]; // 秒个位
     }
     if(flag==2)
     {
        flag=0;
       TR1=1;
       dis_buf[6] =  0x00;
       if(flag1==0)
       {
           if(flag2)
               dis_buf[7] =  0x77;    // 显示 A 表示上午
           else
               dis_buf[7] =  0x7f;    // 显示 B 表示下午
       }
     }
}
voidtimer0() interrupt 1
// 定时器0中断服务程序, 用于数码管的动态扫描
//dis_index --- 显示索引, 用于标识当前显示的数码管和缓冲区的偏移量
//dis_digit --- 位选通值, 传送到P0口用于选通当前数码管的数值,如等于0xfe时,
//    选通P2.0口数码管
//dis_buf   --- 显于缓冲区基地址
{
TH0 = 0xf8;  //定时时间为2ms
TL0 = 0x30;
P2 = 0xff;       // 先关闭所有数码管
P0 = dis_buf[dis_index];   // 显示代码传送到P0口
P2 = dis_digit;      //
dis_digit = _crol_(dis_digit,1); // 位选通值左移, 下次中断时选通下一位数码管
dis_index++;      //
     
dis_index &= 0x07;   // 8个数码管全部扫描完一遍之后,再回到第一个开始下一次扫描 ,限定了只扫描8位,当为超过8位时则开始清零.
}                   //0x07=0000 0111  dis_index在一个个加一时,则为加到8次。
//定时器1的定时时间为10ms
voidtimer1() interrupt 3
{
TH1 = 0xd8;
TL1 = 0xf0;
sec100++;
if(sec100 >= 100) //定时1秒的时间
{
  sec100 = 0;
  inc_sec();
}
}
voidinc_sec()
{
sec++;
if(sec > 59)
{
  sec = 0;
  inc_min();
}
dis_buf[4] = dis_code[sec / 10];  // 秒十位
dis_buf[5] = dis_code[sec % 10];  // 秒个位
}
voidinc_min()
{
min++;
if(min > 59)
{
  min = 0;
  if(flag1==0)
    inc_hour();
  if(flag1==1)
    inc_hour1();
  
}
dis_buf[2] = dis_code[min / 10];  // 分十位
dis_buf[3] = dis_code[min % 10];  // 分个位
}
voidinc_hour()        //12小时制
{
     hour++;
     if(hour > 12)
     {
     flag2=~flag2;
      hour= 1;
     }
     if(hour> 9)
     dis_buf[0] = dis_code[hour / 10]; // 时十位
     else
     dis_buf[0] = 0x00;                // 当小时的十位为0时不显示
     dis_buf[1] = dis_code[hour % 10]; // 时个位
     if(flag2)
        dis_buf[7] = 0x77;           //显示 A 表示上午
     else
        dis_buf[7] = 0x7f;          // 显示 B 表示下午
}  
voidinc_hour1()                  //24小时制时间
{   
hour++;
if(hour >23)
{
  hour = 0;
}
if(hour > 9)
  dis_buf[0] = dis_code[hour / 10];   // 时十位
else
  dis_buf[0] = 0x00;                 // 当小时的十位为0时不显示
dis_buf[1] = dis_code[hour % 10];  // 时个位
}   
voiddelayms(unsigned char ms)
// 延时子程序
{      
unsigned char i;
while(ms--)
{
  for(i = 0; i < 120; i++);
}
}

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表