破解project 发表于 2018-5-25 21:52

51单片机的时钟源码和PowerShell一键时间设置串口通讯脚本

本帖最后由 破解project 于 2018-5-26 20:07 编辑

接上文 https://www.52pojie.cn/thread-741982-1-1.html

对源代码进行了修改

更新记录:
1:走时准确率提升,之前7小时偏差9秒,现在一天偏差不到一秒。完全可以作为日用钟表
2:增加秒钟显示,并可以直接取消设置模式而不将秒针置零
3:增加PowerShell一键设置时间脚本。在有电脑的情况下可以直接将时间设置为系统时钟

更新源码
(由于这论坛代码高亮插件的bug,去掉了所有注释,想获得完整注释的代码和PowerShell脚本的可以下载附件)
#include <reg52.h>
#define lsd_seg P0
#define ledx P1
#define lsd_pos P2
#define adjust_offset 2789
sbit key2=P3^4;
sbit key3=P3^5;
sbit key4=P3^6;
sbit key5=P3^7;
sbit led1=P1^0;
sbit led4=P1^3;
sbit led5=P1^4;
sbit led7=P1^6;
sbit beep=P2^3;
int fiftyms_count=0,pendulum,flash,set_mode,hour_alarm,adjust=0;
int hour,min,sec;
unsigned char code lsd_list[]= {0x8f,0x4f,0x2f,0x1f};
unsigned char code charset[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
void delay(int i)
{
    int j,k;
    for(j=i; j>0; j--)
      for(k=124; k>0; k--);
}
void lsd_display(int which,int body)
{
    lsd_seg=0x00;
    lsd_pos|=0xf0;
    lsd_pos=lsd_pos&lsd_list;
    switch(set_mode)
    {
    case 0:
      if(which==2&&pendulum)
            lsd_seg=charset+0x80;
      else
            lsd_seg=charset;
      break;
    case 1:
      if((which==2||which==3)&&pendulum)
            lsd_seg=charset;
      else
            lsd_seg=0x00;
      break;
    case 2:
      if((which==0||which==1)&&pendulum)
            lsd_seg=charset;
      else
            lsd_seg=0x00;
    }
    delay(1);
}
void lsd_show_all(int a,int b,int c,int d)
{
    lsd_display(3,a);
    lsd_display(2,b);
    lsd_display(1,c);
    lsd_display(0,d);
}
void set_timer_para()
{
    TH0=76;
    TL0=0;
}
void serial_init()
{
    SCON=0x50;
    TMOD|=0x20;
    PCON=0x00;
    TH1=0xfd;
    TL1=0xfd;
    ES=1;
    TR1=1;
}
void main()
{
    EA=1;
    TMOD=0x01;
    set_timer_para();
    serial_init();
    hour=11;
    min=59;
    sec=57;
    ET0=1;
    TR0=1;
    while(1)
    {
      lsd_show_all(hour/10,hour%10,min/10,min%10);
      if(key2==0)
      {
            delay(10);
            if(key2==0)
            {
                set_mode++;
                if(set_mode==3)
                {
                  set_mode=0;
                  sec=0;
                  fiftyms_count=0;
                  adjust=0;
                }
            }
            while(key2==0);
      }
      if(key3==0)
      {
            delay(10);
            if(key3==0)
            {
                switch(set_mode)
                {
                case 1:
                  hour++;
                  if(hour==24)
                        hour=0;
                  break;
                case 2:
                  min++;
                  if(min==60)
                        min=0;
                }
            }
            while(key3==0)
            {
                if(!set_mode)
                {
                  lsd_show_all(min/10,min%10,sec/10,sec%10);
                  led7=0;
                }
            }
            led7=1;
      }
      if(key4==0)
      {
            delay(10);
            if(key4==0)
            {
                switch(set_mode)
                {
                case 1:
                  hour--;
                  if(hour==-1)
                        hour=23;
                  break;
                case 2:
                  min--;
                  if(min==-1)
                        min=59;
                }
            }
            while(key4==0)
            {
                if(!set_mode)
                {
                  unsigned char percent=adjust/(adjust_offset/100);
                  lsd_show_all(7,5,percent/10,percent%10);
                }
            }
      }
      if(key5==0)
      {
            delay(10);
            if(key5==0)
            {
                if(set_mode)
                  set_mode=0;
                else
                  if(min!=0||(sec!=0&&sec!=1))
                  {
                        hour_alarm=!hour_alarm;
                        led5=!hour_alarm;
                  }
                while(key5==0);
            }
      }
    }
}
void timer0() interrupt 1 using 1
{
    set_timer_para();
    fiftyms_count++;
    if(fiftyms_count==20)
    {
      sec++;
      adjust++;
      if(adjust==adjust_offset)
      {
            led4=0;
            adjust=0;
            sec++;
      }
      else
            led4=1;
      pendulum=!pendulum;
      fiftyms_count=0;
      if(sec==60)
      {
            min++;
            sec=0;
      }
      if(min==60)
      {
            hour++;
            min=0;
      }
      if(hour==24)
            hour=0;
      if(hour_alarm&&!set_mode)
            if(min==0&&(sec==0||sec==1))
            {
                beep=~beep;
                ledx=~ledx;
            }
    }
    if(led1==0)
      led1=1;
    if(pendulum!=flash)
    {
      led1=~led1;
      flash=pendulum;
    }
}
void serial_io() interrupt 4 using 2
{
    unsigned char dat;
    dat=SBUF;
    RI=0;
    switch(dat)
    {
    case 0:
      SBUF=hour;
      break;
    case 1:
      SBUF=min;
      break;
    case 2:
      SBUF=sec;
      break;
    case 3:
      SBUF=pendulum;
      break;
    case 4:
      SBUF=flash;
      break;
    case 5:
      SBUF=set_mode;
      break;
    case 6:
      SBUF=hour_alarm;
      break;
    case 7:
      SBUF=adjust/(adjust_offset/255);
      break;
    default:
      if(dat<152)
      {
            if(dat<32)
                hour=dat-8;
            else if(dat<92)
                min=dat-32;
            else
            {
                sec=dat-92;
                adjust=0;
                fiftyms_count=0;
            }
            SBUF='!';
      }
      else
            SBUF='?';
    }
    while(!TI);
    TI=0;
}
//在附件中有此代码的更新版本


如果代码有帮助的话,请给我免费评分,谢谢

PowerShell更新
等到整秒才设置,使之几乎完全同步

linuxprobe 发表于 2018-5-25 21:58

很好的一个脚本,能给我带来方便快捷。

DDOSS 发表于 2018-5-26 08:45

感谢分享,可以看看。
页: [1]
查看完整版本: 51单片机的时钟源码和PowerShell一键时间设置串口通讯脚本