时钟显示时、分、秒,程序和制作较简单,误差每天小于1秒。缺点是断电后不能保存时间。

制作过程:利用现有的电子元器件,参数选择上可能不是最优的,程序和软件来源于互联网,整理后上传主要是为初学者了解单片机。
             在自学单片机C语言程序有问题时,可以利用互联网免费的Chat GPT
             提问“你是单片机C语言专家,再提出编程或解释程序等问题”。
      1、调整时间快慢时,用手机时钟比照,从大往小数值调整,调至个位数时,增加数值1,单片机时钟跑慢;
           减少数值减1,单片机时钟跑快,这时误差能控制在两天差1秒左右。
      2、整机测试耗电5V,90ma左右,建议用5V充电头供电。
      3、按键P1.3确认键,没利用,可用P1.0键代替。
电子元器件:
      1、一寸六个共阳数码管LG10016BH。
      2、P0是8个段脚;P2是6个位脚。
      3、三个按键开关(P1.0调整时间;P1.1调整时间增;P1.2调整时间减)、六个1K电阻、六个S8550三极管和一片STC89C51RC。

附:1、加光敏电阻原理图:利用原程序,加光敏电阻是解决晚上时钟显示太亮。加半可调电阻(因没有现成大的半可调电阻,用5K的半可调电阻
            和10K电阻串联代替)解决光线太暗时,数码管不会全灭,调整半可调电阻显示最低亮度。

制作出来的实物图如下:
image.png

image.png

image.png

单片机源程序如下:
//采用8位数码管动态显示程序
  • //使用AT89C51单片机,12MHz晶振,P0输出字段码,P2口输出位选码
  • //用共阳极LED数码管,key0为调时分位选择键,key1为加1键,key2为减1键,key3为确定键
  • #include  "reg51.h"
  • //包含头文件
  • #define char unsigned char
  • //定义无符号字符型
  • //char code dis_7[12]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0xff};   //共阴极
  • char code dis_7[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};     //共阳极LED数码管"0~9","-"的字段码
  • //char code scan_con[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
  • char code scan_con[8] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f}; // P2口
  • //位选择码
  • char data dis[8]={0x00,0x00,0x0a,0x00,0x00,0x0a,0x00,0x00};                //00-00-00
  • //显示缓冲区,时、分、秒初始为0,0x0a为"-"的编码
  • char data timedata[3]={0x00,0x00,0x00};                //初始化
  • //分别为秒、分和小时的值
  • char data ms50=0x00,con=0x00,con1=0x00,con2=0x00;
  • //定义四个按键
  • sbit  dian=P0^7;
  • sbit  key0=P1^0;
  • sbit  key1=P1^1;
  • sbit  key2=P1^2;
  • sbit  key3=P1^3;
  • //1ms延时函数
  • delay1ms(int t)
  • {
  •         int i,j;
  •         for (i=0;i<t;i++)
  •         {
  •                 for(j=0;j<120;j++);
  •         }
  • }
  • keyscan()//按键处理函数
  • {
  •         EA=0; //关总中断
  •         if (key0==0)//判断第一个按键是否按下
  •         {                            //按键消抖
  •                 delay1ms(10);
  •                 while (key0==0);//再次判断按键是否按下
  •                   con++;
  •                 TR0=0;
  •                 ET0=0; //关定时/计数器,关T0中断
  •                 if (con>=3)  
  •                 {
  •                         con=0;
  •                         TR0=1;
  •                         ET0=1;
  •                 }
  •         }
  •         if (con!=0)
  •         {
  •    if (key1==0)        //如果第二个按键按下
  •                 {
  •               delay1ms(10);
  •               while (key1==0);
  •               timedata[con]++;//加一功能
  •               if (con==2)
  •                 con1=24;
  •                 else con1=60;                        
  •                 if (timedata[con]>=con1)
  •          {timedata[con]=0;}
  •              }
  •         }
  •           if (con!=0)
  •    {
  •    if (key2==0)
  •       //如果第三个按键按下
  •                 {
  •                         delay1ms(10);
  •          while (key2==0);
  •          timedata[con]--;
  •          //减一功能
  •          if (con==2)
  •              con2=23;
  •          else con2=59;                        
  •             if (timedata[con]<=0)
  •                {
  •                                                 timedata[con]=con2;
  •                }
  •        }
  •    }
  •         if(key3==0)//如果第四个按键按下
  •         {      
  •                 delay1ms(10);
  •            while(key3==0);
  •            EA=1;
  •            TR0=1;
  •            ET0=1;        
  •         }
  •         EA=1;//开总中断
  • }
  • //数码管显示函数
  •         scan()
  • {
  •         char k;
  •         dis[0]=timedata[0]%10;
  •    dis[1]=timedata[0]/10;
  •    dis[2]=timedata[1]%10;
  •    dis[3]=timedata[1]/10;
  •         dis[4]=timedata[2]%10;                //【1】显示"分";【2】显示"时";【0】显示"秒"
  •    dis[5]=timedata[2]/10;                //【1】显示"分";【2】显示"时";【0】显示"秒"
  •    for (k=0;k<8;k++)
  •         {
  •                 P0=dis_7[dis[k]];
  •                 if (k==1|k==2|k==3|k==4)
  •                 {
  •                         dian=0;
  •                 }
  •                 else
  •                 {
  •                         dian=1;
  •                 }
  •                 P2=scan_con[k];
  •                 delay1ms(1);
  •                 P2=0x00;    //数码管消隐
  •                 P2=0xff;    //数码管消隐
  •         }
  • }
  •         
  • //主函数
  •         main()
  • {
  • //TH0=0x4c;
  • //TL0=0xb0;
  •         TH0=(65536-52615)/256;                //12M,52615数值越大,走时越慢;数值越小,走时越快。
  •         TL0=(65536-52615)%256;                //12M,52615数值越大,走时越慢;数值越小,走时越快?
  •         TMOD=0x01;
  •         //选择工作方式1
  •         ET0=1;
  •         TR0=1;
  •         EA=1;
  •    while (1)
  •    {
  •                 scan();
  •         //调用数码管显示scan()子函数
  •         keyscan();
  •         //调用按键处理keyscan()子函数
  •         }
  • }
  • //定时器/计数器T0中断服务函数
  • void time_intt0(void) interrupt 1
  • {
  •         ET0=0;
  •         TR0=0;
  •         //TH0=0x4c;         //12M 应该是TH00=0x4c
  •         //TL0=0xb0;        //11.0592M 应该是TL00=0x00
  •         TH0=(65536-52615)/256;                //12M,52615数值越大,走时越慢;数值越小,走时越快?
  •         TL0=(65536-52615)%256;                //12M,52615数值越大,走时越慢;数值越小,走时越快?
  •         TR0=1;
  •         ms50++;
  •         if (ms50==19)
  •    {
  •                 ms50=0x00;
  •                 timedata[0]++;
  •       if (timedata[0]==60)
  •       {
  •                         timedata[0]=0;
  •                         timedata[1]++;
  •                         if (timedata[1]==60)
  •          {
  •                                 timedata[1]=0;
  •                                 timedata[2]++;
  •             if (timedata[2]==24)
  •             {
  •                                         timedata[2]=0;
  •             }
  •          }
  •             }
  •    }
  •     ET0=1;
  •         //开T0中断
  • }
  • 复制代码

    image.png

    image.png

    image.png

    image.png

    image.png

    image.png

    image.png