我想知道AT89C51单片机电子时钟一个可以任意设定时间的程序

2024年11月16日 08:54
有2个网友回答
网友(1):

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;20h.1半点标示位
  ;20H.2闹钟设置中........标示,为了显示区别用
  ;20H.3闹钟设置时间CHECK到,使能标志位
  ;20H.5开/关闹钟设置中........标示;
  ;20H.6闹钟1开关标志位
  ;20H.7闹钟2开关标志位
  ;psw.5用来做显示开关标志位
  ;21,22,23,24这里设置第一个闹钟的时间
  ;25,26,27,28这里设置第二个闹钟的时间
  ;29H
  ;P0口输出数码管段码,
  ;P2口 输出位选信号
  ;
  ;70H存放P1.0--3按钮值,
  ;71H--78H存放当前系统定时时间;
  ;78H 77H 76H 75H 74H 73H 72H 71H
  ; 星期* 小时 分钟 秒钟
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ts equ 24h ;这里设置`24小时周期制
  trr equ #0bbh ;这个是温度,晶振等的时间补偿值,
  org 0000h ;定时太慢此值调大,定时太快调小;
  jmp main
  ;org 0bh ;定时器0中断入口矢量
  ;jmp bz
  org 1bh ;定时器1中断入口矢量
  jmp t1int
  org 0100h ;主程序
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;主程序
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  main:clr p3.0; ;关继电器
  mov sp,#30h
  mov r3,#20
  mov tmod,#10h
  ;mov tl0,#06h ;定时器1,方式1,定时 50 MS;
  ;mov th0,#06h
  mov tl1,#0b0h
  mov th1,#3ch
  mov ie,#88h ;开定时器1中断
  ;mov 65h,#5
  ; mov 66h,#100
  ;mov 64h,#4
  ;clr psw.5
  clr p3.0
  setb pt1 ;设置T1为高优先级中断
  ;setb tr1
  clr tr1 ;开启T1中断
  acall send ;71h--78h 清零;
  acall send1 ;20h--29h 清零;
  dd: acall daa ;进行十进制调整71H-79H
  ;acall compare ;第一闹钟
  ;acall compare1 ;第二闹钟 设置值
  ;acall sound
  acall disp ;数码管显示,78H--71H分别对应着8个数码管显示
  acall key_scanf ;按钮控制
  acall time_adj ;时间调整
  acall lasttime ;调用上一次的设置值为当前定时值
  ;acall alarm1_set ;设置定时开/关闹钟
  ajmp dd

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;调用上次值为设置时间
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  lasttime:push acc
  mov a,70h
  jnb acc.2,return1
  clr p3.0; 紧急暂停按钮,按下后暂停,并把上次设定值恢复.
  clr tr1
  mov 73h,21h
  mov 74h,22h
  wait7:acall disp
  acall key_scanf
  mov a,70h
  jnb acc.0,wait7
  mov 71h,#0
  mov 72h,#0
  mov 79h,#0
  mov tl1,trr
  mov th1,#3ch
  mov r3,#20
  setb tr1
  setb p3.0
  return1:pop acc
  ret

  daa: push acc ;对当前系统时间进行十进制调整
  mov 71h,79h
  mov r1,#71h
  cjne @r1,#10,s2
  mov 71h,#0h
  mov 79h,#0
  inc 72h
  mov r1,#72h
  cjne @r1,#6,s2
  mov 72h,#0h
  dec 73h
  mov r1,#73h
  cjne @r1,#255,s2
  dec 74h
  mov 73h,#9
  s1: pop acc
  ret
  s2: mov r1,#73h
  cjne @r1,#0,s1
  mov r1,#74h
  cjne @r1,#0,s1
  clr p3.0
  clr tr1
  sjmp s1

  h_half: ;半点CHECK
  mov r1,#73h
  mov a,74h
  swap a
  xchd a,@r1
  cjne a,#29h,o25 ;CHECK 当前时间是否为29分钟
  xchd a,@r1
  mov r1,#71h
  mov a,72h
  swap a
  xchd a,@r1
  cjne a,#59h,o25 ;CHECK 当前时间为59秒?
  setb tr0 ;启动T0
  setb 20h.1 ;enable 半点flag bit
  o25: xchd a,@r1
  ret
  compare: ;闹钟1设置时间与当前时间比较
  push acc
  jnb 20h.6,nequ ;闹钟1开/关标志位
  mov a,73h
  cjne a,21h,nequ ;分低位
  mov a,74h
  cjne a,22h,nequ ;分高位
  mov a,75h
  cjne a,23h,nequ ;小时低位
  mov a,76h
  cjne a,24h,nequ ;小时高位
  setb 20h.3 ;到闹钟设置时间,使能闹钟报警标志位
  nequ:pop acc
  ret

  compare1: ;闹钟2设置时间与当前时间比较
  push acc
  jnb 20h.7,nequ33 ;闹钟2开/关标志位
  mov a,73h
  cjne a,25h,nequ33
  mov a,74h
  cjne a,26h,nequ33
  mov a,75h
  cjne a,27h,nequ33
  mov a,76h
  cjne a,28h,nequ33
  setb 20h.3 ;到闹钟设置时间,使能闹钟报警标志位
  nequ33:
  pop acc
  ret

  sound:
  acall h_half ;check 是否半点?
  jb 20h.1,s23 ;半点则返回
  jb 20h.0,s23
  mov r1,#73h
  mov a,74h
  swap a
  xchd a,@r1
  cjne a,#59h,s25
  xchd a,@r1
  mov r1,#71h
  mov a,72h
  swap a
  xchd a,@r1
  s20: cjne a,#56h,s21
  ajmp s26
  s21: cjne a,#58h,s22
  ajmp s26
  s22: cjne a,#59h,s25
  setb tr0
  ajmp s26
  s25: xchd a,@r1
  s23: ret
  s26: jb 20h.0,s25
  setb tr0
  xchd a,@r1
  ret
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;T0中断服务程序,报时铃音信号输出
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  bz: djnz 64h,rrr
  jb 20h.3,alarmsign;闹钟到点报时有效
  jb 20h.1,next ;半点报时
  mov 64h,#4 ;0.5KHZ
  ajmp justh
  alarmsign:
  mov 64h,#1; 2KHZ信号
  justh:
  djnz 66h,ccc
  mov 66h,#100
  djnz 65h,ccc ;产生1000次中断后关中断
  mov 65h,#5 ;响0.5秒
  setb 20h.0
  clr tr0
  reti

  next:mov 64h,#2 ;1KHZ信号,半点报时音
  ccc: jb 20h.3,cc
  cpl p1.4 ;半点报时输出声音信号
  rrr: reti
  cc: cpl p1.4 ;闹钟报时输出声音信号
  reti

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;T1中断服务程序,定时器主时钟;
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  t1int:
  clr ea
  mov tl1,trr
  mov th1,#3ch
  djnz r3,sd ;20*50MS=1S
  mov r3,#20
  ;cpl p1.4
  inc 79h
  clr 20h.0
  clr 20h.1 ;半点报时标志清零
  jb 20h.3,sdd ;闹钟CHECK有效与否?
  clr tr0 ;关T0
  sd: setb ea
  reti
  sdd: setb tr0 ;开T0,即开闹铃声音
  setb ea
  reti
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;显示子函数
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dispnum1:; 显示
  ajmp disp_num
  disp:
  push acc
  ;jb 20h.5,dispnum1;开/关闹钟设置中界面...........
  ;jb 20h.2,alarmcheck;闹钟设置时间中界面..........
  jb psw.5,closedisp
  mov r2,#01h;位选通信号输出到P2口
  mov r5,#2; 显示的位数循环控制
  mov r0,#73h;分别取出内存76H-71H
  cjne r3,#10,dot1;在小时和分之间闪烁DOT point
  dot1:jnc dsp1
  orl 73h,#10h
  ;dot1:cjne r3,#11,dsp1
  ;anl 73h,#0efh
  dsp1:mov a,r2
  ;cpl a
  mov p2,a
  mov a,@r0
  dsp2:mov dptr,#bcd
  movc a,@a+dptr
  mov p0,a
  acall delay
  mov a,r2
  rl a
  mov r2,a
  inc r0
  djnz r5,dsp1
  anl 73h,#0efh
  pop acc
  ret
  closedisp:; 关显示
  acall delay
  mov p0,#0ffh
  mov p2,#0
  pop acc
  ret

  ;;;;;;;;;;;;;;;;;闹钟的定时设置显示
  alarmcheck:
  mov r2,#01h
  mov r5,#2 ;两位显示22-21H对应定时设置值
  mov r0,#21h
  dsp21:
  mov a,r2
  ;cpl a
  mov p2,a
  mov a,@r0
  mov dptr,#bcd
  movc a,@a+dptr
  mov p0,a
  acall delay
  mov a,r2
  rl a
  mov r2,a
  inc r0
  djnz r5,dsp21
  pop acc
  ret
  bcd:; 共阳接法数码管段码表
  db 0c0h,0f9h,0a4h,0b0h
  db 99h,92h,82h,0f8h
  db 80h,90h,88h,83h
  db 0c6h,0a1h,86h,8eh; 不带小数点七段
  db 40h,79h,24h,30h,19h
  db 12h,02h,78h,00h,10h
  db 0ffh,0bfh,7fh,3fh; 带小数点七段
  delay:mov r6,#4h
  tm: mov r4,#0h
  ee: djnz r4,ee; 延时2048US=2MS
  djnz r6,tm
  ret

  send:mov r7,#9; 初始化设置
  mov r0,#71h
  mov a,#0h
  ss: mov @r0,a
  inc r0
  djnz r7,ss
  mov 78h,#1h
  mov 77h,#01ah
  ;mov 71h,#1
  ;mov 72h,#2
  ;mov 73h,#3
  ;mov 74h,#4
  ret
  send1:; 初始化
  mov r7,#10
  mov r0,#20h
  mov a,#0
  ss1: mov @r0,a
  inc r0
  djnz r7,ss1
  ret

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;;;;;;;;;;开/关闹钟界面显示
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  disp_num:
  mov p2,#0f7h
  mov a,29h ;当前要操作的闹钟号码
  mov dptr,#bcd
  movc a,@a+dptr
  mov p0,a
  acall delay
  pop acc
  ret
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  key_scanf:; 按钮处理
  push acc
  mov 70h,#0
  orl p1,#0fh
  mov a,p1
  cpl a
  anl a,#07h
  jz nokey1
  acall daa
  acall disp
  mov a,p1
  cpl a
  anl a,#07h
  jz nokey1
  mov 70h,a
  key_wait:; 等按钮放下
  acall daa
  acall disp
  mov a,p1
  cpl a
  anl a,#07h
  jnz key_wait
  mov a,70h
  jnb acc.1,nokey1
  cpl psw.5
  nokey1:; 无按钮
  pop acc
  ret

  a_on_off:
  jnb 29h.0,iii
  cpl 20h.6
  iii: jnb 29h.1,out_2
  cpl 20h.7
  out_2:
  ajmp alarmnum
  alarmnum:
  setb 20h.5
  acall daa
  acall disp
  acall key_scanf
  clr 20h.5
  mov a,70h
  jb acc.0,a_on_off
  jb acc.1,alar_adj_1
  jb acc.2,a_num_inc
  acall numb
  ajmp alarmnum
  alarm1_set:
  push acc
  mov a,70h
  jb acc.1,alarmnum
  alarm1_out:
  clr 20h.2
  pop acc
  ret
  a_num_inc:
  inc 29h
  mov a,29h
  anl a,#0fh
  cjne a,#3,alarmnum
  anl 29h,#0
  ajmp alarmnum
  alar_adj_1:
  setb 20h.2
  acall daa
  orl 21h,#10h
  acall disp
  anl 21h,#0fh
  acall key_scanf
  mov a,70h
  jb acc.1,hadj_1
  jb acc.2,minc_1
  ajmp alar_adj_1
  madj_2:
  acall daa
  orl 25h,#10h
  acall disp
  anl 25h,#0fh
  acall key_scanf
  mov a,70h
  jb acc.1,hadj_2
  jb acc.2,minc_2
  ajmp madj_2
  hadj_1:
  acall daa
  orl 23h,#10h
  acall disp
  anl 23h,#0fh
  acall key_scanf
  mov a,70h
  jb acc.1,madj_2
  jb acc.2,hinc_1
  ajmp hadj_1
  hadj_2:acall daa
  orl 27h,#10h
  acall disp
  anl 27h,#0fh
  acall key_scanf
  mov a,70h
  jb acc.1,alarm1_out
  jb acc.2,hinc_2
  ajmp hadj_2
  minc_1:
  inc 21h
  mov r1,#21h
  cjne @r1,#10,alar_adj_1
  mov 21h,#0
  inc 22h
  mov r1,#22h
  cjne @r1,#6,alar_adj_1
  mov 22h,#0h
  ajmp alar_adj_1
  minc_2:
  inc 25h
  mov r1,#25h
  cjne @r1,#10,madj_2
  mov 25h,#0
  inc 26h
  mov r1,#26h
  cjne @r1,#6,madj_2
  mov 26h,#0
  ajmp madj_2
  hinc_1:
  inc 23h
  mov r1,#23h
  cjne @r1,#10,ss14
  mov 23h,#0
  inc 24h
  ss14:
  mov a,24h
  swap a
  xchd a,@r1
  cjne a,#ts,ss15
  mov 23h,#0
  mov 24h,#0
  ajmp hadj_1
  ss15:xchd a,@r1
  ajmp hadj_1
  hinc_2:
  inc 27h
  mov r1,#27h
  cjne @r1,#10,sss14
  mov 27h,#0
  inc 28h
  sss14:
  mov a,28h
  swap a
  xchd a, @r1
  cjne a,#ts,sss15
  mov 27h,#0
  mov 28h,#0
  ajmp hadj_2
  sss15:
  xchd a,@r1
  ajmp hadj_2

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;时间调整程序
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  time_adj:;
  clr psw.5
  push acc
  mov a,70h
  jb acc.0,l1;P1.0调时功能键,每按一次切换一位
  ajmp nokeyout
  adj_out:
  mov 21h,73h
  mov 22h,74h
  setb p3.0 ;闭合继电器
  setb tr1
  nokeyout:
  pop acc
  ret
  QQ: anl 73h,#0fh
  anl 74h,#0fh
  ;anl 78h,#0fh
  ret
  l1: clr tr1;acall dab; 分钟调整
  orl 73h,#10h;点亮分右下角的小数点,当前调整位置
  acall disp
  acall QQ
  acall key_scanf
  clr psw.5
  mov a,70h
  jb acc.0,h_adj;切换到小时调整
  jb acc.1,m_inc;P1.2加1按钮
  ajmp l1
  h_adj:; 小时调整
  ;acall dab
  orl 74h,#10h
  acall disp
  acall QQ
  acall key_scanf
  clr psw.5
  mov a,70h
  jb acc.0,out_adj;切换到星期调整
  jb acc.1,h_inc;小时加1
  ajmp h_adj
  w_adj:
  acall daa
  orl 78h,#10h
  acall disp
  acall QQ
  acall key_scanf
  clr psw.5
  mov a,70h
  jb acc.0,out_adj
  jb acc.2,w_inc
  ajmp w_adj
  out_adj:
  ajmp adj_out
  m_inc:;;;;;;;;;;;;;;; 调整分时,对定时复位,初始化
  clr tr1
  mov 71h,#0
  mov 72h,#0
  mov 79h,#0
  mov tl1,trr
  mov th1,#3ch
  mov r3,#20
  inc 73h
  mov r1,#73h
  cjne @r1,#10,s12
  mov 73h,#0
  inc 74h
  mov r1,#74h
  cjne @r1,#10,s12
  mov 74h,#0
  s12: ajmp l1
  ;;;;;;;;;;;;;;;;;;;;;;调整小时位
  h_inc:
  inc 74h
  mov r1,#74h
  cjne @r1,#10,s14
  mov 74h,#0
  ;inc 76h
  s14: ajmp h_adj
  ;mov a,76h
  ;swap a
  ;xchd a,@r1
  ;cjne a,#ts,s15;;;12进制,24进制设置值决定
  ;mov 75h,#0
  ;mov 76h,#0
  ;ajmp h_adj
  ;s15: ;xchd a,@r1
  ;ajmp h_adj
  ;;;;;;;;;;;;;;;;;;;;;;;调整星期位
  w_inc:
  inc 78h
  mov r1,#78h
  cjne @r1,#8,s16
  mov 78h,#1h
  s16: ajmp w_adj

  ;;;;;;;;;;;;;;;;;;;;;;;当前闹钟开/关情况报告位
  numb:clr 29h.4
  jnb 29h.0,iii1
  jnb 20h.6,iii1
  setb 29h.4
  iii1:jnb 29h.1,out_21
  jnb 20h.7,out_21
  setb 29h.4
  out_21:
  jnb 20h.6,out_12
  jnb 20h.7,out_13
  mov 77h,#1dh
  ajmp out_22
  out_12:
  jnb 20h.7,out_14
  mov 77h,#1bh
  ajmp out_22
  out_13:
  mov 77h,#1ch
  ajmp out_22
  out_14:
  mov 77h,#1ah
  out_22:
  ret
  end

网友(2):

void Key_Set_Clock( uchar * clock_time )
{
clock_time ++ ;
Lcd_Set_Clock( 2 );
Key_Idle();
while(1)
{
uchar minute;
minute = ( ( * clock_time >>4 ) * 10 ) + ( ( * clock_time ) & 0x0f );
switch( Key_Scan() )
{
case Up:
{
minute ++ ;
if( minute == 60 ) minute=0;
( * clock_time ) = minute/10 <<4 ;
( * clock_time ) = ( * clock_time ) | (minute%10);
Lcd_Set_Clock( 2 );
Key_Idle();
}
break;
case Down:
{
if( minute == 0 ) minute = 60;
minute --;
( * clock_time ) = minute/10 <<4 ;
( * clock_time ) = ( * clock_time ) | (minute%10);
Lcd_Set_Clock( 2);
Key_Idle();
}
break;
case Function:
{
clock_time ++;
Lcd_Set_Clock( 3 );
Key_Idle();
while(1)
{
uchar hour;
hour = ( ( * clock_time >>4 ) * 10 ) + ( ( * clock_time ) & 0x0f );
switch( Key_Scan())
{
case Up:
{
hour ++;
if(hour == 24) hour = 0;
( * clock_time ) = hour/10 <<4 ;
( * clock_time ) = ( * clock_time ) | (hour%10);
Lcd_Set_Clock( 3);
Key_Idle();
}
break;
case Down:
{
if(hour == 0) hour = 24;
hour --;
( * clock_time ) = hour/10 <<4 ;
( * clock_time ) = ( * clock_time ) | (hour%10);
Lcd_Set_Clock( 3);
Key_Idle();
}
break;
case Function:
{
clock_time +=2;
Lcd_Set_Clock( 4);
Key_Idle();
while(1)
{
uchar day;
day = ( (*clock_time >>4)*10 ) + ( (*clock_time)&0x0f );
switch(Key_Scan())
{
case Up:
{
day ++; if(day == 32) day = 1;
( * clock_time ) = day/10 <<4 ;
( * clock_time ) = ( * clock_time) | (day%10);
Lcd_Set_Clock( 4);
Key_Idle();
}
break;
case Down:
{
if(day == 0) day= 31; day --;
if(day == 0) day=31;
(*clock_time) = day/10 <<4 ;
(*clock_time) = (*clock_time) | (day%10);
Lcd_Set_Clock( 4 );
Key_Idle();
}
break;
case Function:
{
clock_time ++;
Lcd_Set_Clock( 5);
Key_Idle();
while(1)
{
uchar month;
month = ( ( * clock_time >>4)*10 ) + ( ( * clock_time ) & 0x0f );
switch(Key_Scan())
{
case Up:
{
month ++; if(month == 13) month= 1;
( * clock_time ) = month/10 <<4 ;
( * clock_time ) = ( * clock_time ) | (month%10);
Lcd_Set_Clock( 5);
Key_Idle();
}
break;
case Down:
{
if(month==0) month = 12; month --;
if(month==0) month = 12;
( * clock_time ) = month/10 <<4 ;
( * clock_time ) = ( * clock_time ) | (month%10);
Lcd_Set_Clock( 5);
Key_Idle();
}
break;
case Function:
{
clock_time ++;
Lcd_Set_Clock( 6);
Key_Idle();
while(1)
{
uchar year;
year = ( ( * clock_time >>4 ) * 10 ) + ( ( * clock_time ) & 0x0f );
switch( Key_Scan() )
{
case Up:
{
year ++;
if(year == 100) year= 0;
( * clock_time ) = year / 10 << 4 ;
( * clock_time ) = ( * clock_time ) | (year%10);
Lcd_Set_Clock( 6);
Key_Idle();
}
break;
case Down:
{
if(year==0) year=100 ; year--;
if(year==0) year=100;
( * clock_time ) = year/10 <<4 ;
( * clock_time ) = ( * clock_time ) | (year%10);
Lcd_Set_Clock( 6 );
Key_Idle();
}
break;
case Function:
{
DS12887_Init();
goto loop;
}
break;
default:Lcd_Set_Clock( 6);
}
}
}
default:Lcd_Set_Clock( 5);

}
}
}
default:Lcd_Set_Clock( 4);
}
}
}
default:Lcd_Set_Clock( 3);

}
}
}
default:Lcd_Set_Clock( 2);
}
}
loop: Key_Idle();
}