KEY1 BIT P3.2
KEY2 BIT P3.3
KEY3 BIT P3.5
DISPRAM DATA 30H ;显示数字的暂存
HOUR_REG DATA 38H
MINU_REG DATA 39H
SECO_REG DATA 3AH
T0_COUNT DATA 3BH
DISP_COUNT DATA 3CH
ORG 0000H ;主程序的入口
LJMP MAIN
ORG 000BH ; 定时//器T0中断程序入口
LJMP T0_TIME
ORG 0030H
MAIN: MOV SP, #3FH ;//堆栈指针设置堆栈地址存放
MOV HOUR_REG, #0
MOV MINU_REG, #0
MOV SECO_REG, #0
MOV TMOD, #11H; //选择工作方式1
MOV IE, #82H; // EA=1,CPU开放中断 ET0=1,使能定时器T0溢出中断
SETB TR0 // 开定时计数器
MAIN1: LCALL TIME2STR // 调用时间数据显示
MOV R0, #DISPRAM
LCALL DISPLAY
JB KEY1, MAIN1
LCALL TIME_SET
SJMP MAIN1
;---------------------------------------
;时间数据显示字符串功能
;---------------------------------------
TIME2STR: MOV R0, #DISPRAM //时间数据显示
MOV A, HOUR_REG
MOV B, #10
DIV AB
MOV @R0, A
MOV A, B
INC R0
MOV @R0, A
MOV A, MINU_REG
MOV B, #10
DIV AB
INC R0
MOV @R0, A
MOV A, B
INC R0
MOV @R0, A
MOV A, SECO_REG
MOV B, #10
DIV AB
INC R0
MOV @R0, A
MOV A, B
INC R0
MOV @R0, A
RET
;
;---------------------------------------
;设定的时间功能
;---------------------------------------
TIME_SET: CLR TR0 //关定时计数器
MOV SECO_REG, #0 //把秒清零
LCALL TIME2STR
TIME_S1: MOV R0, #DISPRAM
LCALL DISPLAY
JNB KEY1, TIME_S1
MOV R2, #2
TIME_S2: MOV A, R2
JZ TIME_S3
LCALL TIME2STR
CJNE R2, #2, TIME_S21
ORL DISPRAM, #80H
ORL DISPRAM+1, #80H
SJMP TIME_S22
TIME_S21: ORL DISPRAM+2, #80H
ORL DISPRAM+3, #80H
TIME_S22: MOV R0, #DISPRAM
LCALL DISPLAY
JB KEY1, TIME_S23
DEC R2
TIME_S221:MOV R0, #DISPRAM
LCALL DISPLAY
JNB KEY1, TIME_S221
TIME_S23: JB KEY2, TIME_S2
CJNE R2, #2, TIME_S231
INC HOUR_REG
MOV A, HOUR_REG
CJNE A, #24, TIME_S232
MOV HOUR_REG, #0
SJMP TIME_S232
TIME_S231:INC MINU_REG
MOV A, MINU_REG
CJNE A, #60, TIME_S232
MOV MINU_REG, #0
TIME_S232:MOV R3, #20
TIME_S233:MOV R0, #DISPRAM
LCALL DISPLAY
DJNZ R3, TIME_S233
SJMP TIME_S2
TIME_S3: SETB TR0
RET
;
;---------------------------------------
; 显示功能
;6个LED数码管
;---------------------------------------
DISPLAY: PUSH ACC // 把ACC(累加器)中的数字压入堆栈
PUSH DPH // 把16位指针高8位压入堆栈
PUSH DPL
PUSH PSW // 状态字入栈保护【保护现场】
MOV A, R4
PUSH ACC // 保存寄存器的数字R4、R5、R6、R7
MOV A, R5
PUSH ACC
MOV A, R6
PUSH ACC
MOV A, R7
PUSH ACC
INC DISP_COUNT
ANL DISP_COUNT, #7FH //相与,闪烁,让灯可以由亮转为灭
MOV R5, #8
MOV R4, #01H
MOV DPTR, #DISPTABLE
DISPL1: MOV A, @R0
PUSH ACC
MOV P2, R4
ANL A, #80H
JZ DISPL11
MOV A, DISP_COUNT
SUBB A, #32
JNC DISPL11
MOV P2, #0
DISPL11: POP ACC
ANL A, #7FH
MOVC A, @A+DPTR
MOV P0, A
MOV R6, #00H
MOV R7, #01H
LCALL DELAY
MOV P0, #0FFH
INC R0
MOV A, R4
RL A
MOV R4, A
DJNZ R5, DISPL1
POP ACC
MOV R7, A
POP ACC
MOV R6, A
POP ACC
MOV R5, A
POP ACC
MOV R4, A
POP PSW
POP DPL
POP DPH
POP ACC
RET
DISPTABLE:DB 0C0H,0F9H,0A4H,0B0H, 99H, 92H, 82H,0F8H, 80H, 90H, 88H, 83H,0C6H,0A1H, 86H, 8EH,0BFH, 89H,0C7H, 8CH,0FFH
; "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "-", "H", "L", "P", " "
;
;--------------------------------------
延迟功能。
;延迟时间=(R6R7)(ms)
;--------------------------------------
DELAY: PUSH ACC
MOV A, R4
PUSH ACC
MOV A, R5
PUSH ACC
MOV A, R7
JZ DELAY01
INC R6
DELAY01: MOV R4, #02H
MOV R5, #0F4H
DELAY02: DJNZ R5, $
DJNZ R4, DELAY02
DJNZ R7, DELAY01
DJNZ R6, DELAY01
POP ACC
MOV R5, A
POP ACC
MOV R4, A
POP ACC
RET
;
;--------------------------------------
;用T0的中断功能
;--------------------------------------
T0_TIME: MOV TL0, #0B0H
MOV TH0, #3CH
PUSH PSW
PUSH ACC
INC T0_COUNT
MOV A, T0_COUNT
SUBB A, #20
JC T0_OUT
MOV T0_COUNT, #0
INC SECO_REG
MOV A, SECO_REG
SUBB A, #60
JC T0_OUT
MOV SECO_REG, #0
INC MINU_REG
MOV A, MINU_REG
SUBB A, #60
JC T0_OUT
MOV MINU_REG, #0
INC HOUR_REG
MOV A, HOUR_REG
SUBB A, #24
JC T0_OUT
MOV HOUR_REG, #0
T0_OUT: POP ACC
POP PSW
RETI
;
END
2.7.2. C语言程序编译
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
sbit BUZZ=P3^7;
sbit KEY1=P1^0;
sbit KEY2=P1^1;
uchar hour_reg,minute_reg,second_reg;
void delay(uint);
void display(uchar*);
void time2str(uchar*);
void time_set(void);
void main(void)
{
uchar dispram[8];
TMOD=0x11; 选择工作方式1
IE=0x82; EA=1,CPU开放中断 ET0=1,使能定时器T0溢出中断
TR0=1; 开定时计数器
while(1)
{
time2str(dispram);
display(dispram);
if(KEY1==0) time_set();
}
}
void time2str(uchar*ch)
{
ch[0]=hour_reg/10; 显示小时的高位
ch[1]=hour_reg%10; 显示小时的低位
ch[2]=minute_reg/10; 显示分钟的高位
ch[3]=minute_reg%10; 显示分钟的低位
ch[4]=second_reg/10; 显示秒的高位
ch[5]=second_reg%10; 显示秒的低位
}
void time_set(void)
{
uchar ch[6];
uchar i,c;
TR0=0; 关定时计数器
second_reg=0; 秒钟清零
time2str(ch);
do
{ display(ch);}
while(KEY1==0);
c=2;
while(c)
{
time2str(ch);
if(c==2) {ch[0]|=0x80;ch[1]|=0x80;} 最高位补1
else { ch[2]|=0x80;ch[3]|=0x80;}
display(ch);
if(KEY1==0)
{
c--;
do{ display(ch);
}
while(KEY1==0);
}
if(KEY2==0)
{
if(c==2) hour_reg=(hour_reg+1)%24; 恢复显示小时
else minute_reg=(minute_reg+1)%60; 恢复显示分钟
for(i=0;i<50;i++) display(ch);
}
}
TR0=1; 开定时计数器
}
void delay_ms(unsigned int dt)
{
register unsigned char bt ,ct;
for(;dt;dt--)
for(ct=2;ct;ct--)
for(bt=250;--bt;); 延时2*2*250=1ms
}
void display(uchar*disp_ram)
{
static uchar disp_count;
unsigned char i,j;
unsigned char code table[]=
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf,0xff};
disp_count=(disp_count+1)&0x7f;
for(i=0;i<6;i++)
{
j=disp_ram[i];
if(j&0x80) P0=(disp_count>32)? table[j&0x7f]:0xff; 32/128=1/4,1/4的时间灯灭
else P0=table[j];
P2=0x01<<i;
delay_ms(1);
P0=0xff;
P2=0;
}
}
void T0_time(void) interrupt 1
{
static uchar T0_count=0;
TL0=0xb0; 2^16-15536=50000us=50ms
TH0=0x3c;
T0_count++;
if(T0_count>=20) 循环20次延时1s
{
T0_count=0; 当1s延时到,秒钟数字加1
second_reg++;
if(second_reg>=60)
{
second_reg=0; 秒清零,分加1
minute_reg++;
if(minute_reg>=60)
{
minute_reg=0;
hour_reg=(hour_reg+1)%24; 24小时的记数
}
}
|