#include<reg51h>
#define uchar unsigned char
#define uint unsigned int
#define u8 unsigned char
#define u16 unsigned int
sbit k1=P3^1; //第一个按键,选择设置
uchar code distab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};//共阴数码管段码表
uchar disbuf[8]; //声明显示缓冲区8个单元
uchar hour=12; //声明小时变量,初值为12
uchar minute=59; //声明分变量,初值为59
uchar second; //声明秒变量
uchar t0n; //定时器T0中断计数,定时50ms,中断20次为1秒
uchar dis; //调时状态下,显示小数点位
void delay() //延时子程序,用于显示子程序
{
uint j;
for(j=300;j>0;j--);
}
//显示子程序,参数dis为显示小数点位
void display(uchar dis)
{
uchar j,disbit=0x01; //位码
for(j=0;j<8;j++)
{
P2=~disbit; //P2口输出位码
if(dis>0&&dis==j) //调时状态下,显示小数点
P0=distab[disbuf[j]]+0x80; //在小时,分,秒位上显示小数点
else
P0=distab[disbuf[j]]; //其它位正常显示
disbit<<=1; //取下一个位码
delay(); //延时
}
}
#define RxBUFSIZE 10
u8 RxBuf[RxBUFSIZE];
u8 Rxcount=0;
u8 Rxtime=0;
void UartInit(){
SCON=0x50;
TMOD&=0x0f;
TMOD|=0x20;
TH1=TL1=0xfd;//1105926 9600
TR1=1;
ES=1;
EA=1;
}
//格式 Txx:xx:xx
//解析时间
void JX1(){
u8 a;
a=(RxBuf[1]-'0')10+(RxBuf[2]-'0');
if(a>23)return;
hour=a; //时
a=(RxBuf[4]-'0')10+(RxBuf[5]-'0');
if(a>59)return;
minute=a; //分
a=(RxBuf[7]-'0')10+(RxBuf[8]-'0');
if(a>59)return;
second=a; //秒
}
void UartCl(){
if((Rxtime>4)&&(Rxcount>=9)){
if(RxBuf[0]=='T'){
JX1();
}
Rxcount=0;
}
}
void UartInterrupt() interrupt 4
{
if(RI){
RI=0;
Rxtime=0;
if(Rxcount<RxBUFSIZE){
RxBuf[Rxcount++]=SBUF;
}
}
}
void main()
{
disbuf[2]=disbuf[5]=10;//数码管第3,6位显示-
TMOD=0x01;
TH0 =0x3C; //单片机晶振频率=12M,定时50ms,时间常数=3CB0
TL0 =0xB0;
IE =0x82; //开定时器T0中断
TR0 =1; //启动定时器T0
IT0 =1; //设置外部中断为下降沿有效
IT1 =1;
UartInit();
while(1)
{
display(dis); //调显示子程序
UartCl();
if(k1==0) //选择设置
{
dis++; //停止计时,进入调时状态
EX0=1; //调时状态下,允许外部INT0,INT1中断
EX1=1; //用来调小时,分,秒
if(dis>7) //调小时,在小时位显示小数点
{
dis=0; //灭小数点
t0n=0; //调时结束,开始计时
TR0=1;
EX0=0; //关外部中断
EX1=0;
}
else if(dis==2)dis=4; //调分,在分位显示小数点
else if(dis==5)dis=7; //调秒,在秒位显示小数点
while(k1==0)display(dis); //等待按键释放
}
if(t0n>=20&&dis==0) //中断20次,1秒到,计时状态下时钟计时
{
t0n=0;
second++; //秒加1
if(second>=60) //到60秒
{
second=0;
minute++; //分加1
if(minute>=60) //到60分
{
minute=0;
hour++; //小时加1
if(hour>=24)
hour=0;
}
}
}
disbuf[0]=hour/10; //显示小时十位
disbuf[1]=hour%10; //显示小时个位
disbuf[3]=minute/10; //显示分十位
disbuf[4]=minute%10; //显示分个位
disbuf[6]=second/10; //显示秒十位
disbuf[7]=second%10; //显示秒个位
}
}
//定时器T0中断服务子程序
void T0_isr() interrupt 1
{
TH0=0x3C; //重写时间常数
TL0=0xb0;
t0n++; //中断次加1
if(++Rxtime>(205)){//超时处理
Rxtime=0;
Rxcount=0;
}
}
//外部中断INT0服务程序,调时状态下,加1
void INT0_ISR() interrupt 0
{
if(dis==1) //调小时
{
hour++; //小时加1
if(hour>=24)
hour=0;
}
if(dis==4) //调分
{
minute++; //分加1
if(minute>=60)
minute=0;
}
if(dis==7) //调秒
{
second++; //秒加1
if(second>=60)
second=0;
}
}
//外部中断INT1服务程序,调时状态下,减1
void INT1_ISR() interrupt 2
{
if(dis==1) //调小时
{
hour--; //小时减1
if(hour==0xff)
hour=23;
}
if(dis==4) //调分
{
minute--; //分减1
if(minute==0xff)
minute=59;
}
if(dis==7) //调秒
{
second--;//秒减1
if(second==0xff)
second=59;
}
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;20h1半点标示位
;20H2闹钟设置中标示,为了显示区别用
;20H3闹钟设置时间CHECK到,使能标志位
;20H5开/关闹钟设置中标示;
;20H6闹钟1开关标志位
;20H7闹钟2开关标志位
;psw5用来做显示开关标志位
;21,22,23,24这里设置第一个闹钟的时间
;25,26,27,28这里设置第二个闹钟的时间
;29H
;P0口输出数码管段码,
;P2口 输出位选信号
;
;70H存放P10--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 p30; ;关继电器
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 psw5
clr p30
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 acc2,return1
clr p30; 紧急暂停按钮,按下后暂停,并把上次设定值恢复
clr tr1
mov 73h,21h
mov 74h,22h
wait7:acall disp
acall key_scanf
mov a,70h
jnb acc0,wait7
mov 71h,#0
mov 72h,#0
mov 79h,#0
mov tl1,trr
mov th1,#3ch
mov r3,#20
setb tr1
setb p30
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 p30
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 20h1 ;enable 半点flag bit
o25: xchd a,@r1
ret
compare: ;闹钟1设置时间与当前时间比较
push acc
jnb 20h6,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 20h3 ;到闹钟设置时间,使能闹钟报警标志位
nequ:pop acc
ret
compare1: ;闹钟2设置时间与当前时间比较
push acc
jnb 20h7,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 20h3 ;到闹钟设置时间,使能闹钟报警标志位
nequ33:
pop acc
ret
sound:
acall h_half ;check 是否半点
jb 20h1,s23 ;半点则返回
jb 20h0,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 20h0,s25
setb tr0
xchd a,@r1
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;T0中断服务程序,报时铃音信号输出
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
bz: djnz 64h,rrr
jb 20h3,alarmsign;闹钟到点报时有效
jb 20h1,next ;半点报时
mov 64h,#4 ;05KHZ
ajmp justh
alarmsign:
mov 64h,#1; 2KHZ信号
justh:
djnz 66h,ccc
mov 66h,#100
djnz 65h,ccc ;产生1000次中断后关中断
mov 65h,#5 ;响05秒
setb 20h0
clr tr0
reti
next:mov 64h,#2 ;1KHZ信号,半点报时音
ccc: jb 20h3,cc
cpl p14 ;半点报时输出声音信号
rrr: reti
cc: cpl p14 ;闹钟报时输出声音信号
reti
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;T1中断服务程序,定时器主时钟;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
t1int:
clr ea
mov tl1,trr
mov th1,#3ch
djnz r3,sd ;2050MS=1S
mov r3,#20
;cpl p14
inc 79h
clr 20h0
clr 20h1 ;半点报时标志清零
jb 20h3,sdd ;闹钟CHECK有效与否
clr tr0 ;关T0
sd: setb ea
reti
sdd: setb tr0 ;开T0,即开闹铃声音
setb ea
reti
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;显示子函数
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dispnum1:; 显示
ajmp disp_num
disp:
push acc
;jb 20h5,dispnum1;开/关闹钟设置中界面
;jb 20h2,alarmcheck;闹钟设置时间中界面
jb psw5,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 acc1,nokey1
cpl psw5
nokey1:; 无按钮
pop acc
ret
a_on_off:
jnb 29h0,iii
cpl 20h6
iii: jnb 29h1,out_2
cpl 20h7
out_2:
ajmp alarmnum
alarmnum:
setb 20h5
acall daa
acall disp
acall key_scanf
clr 20h5
mov a,70h
jb acc0,a_on_off
jb acc1,alar_adj_1
jb acc2,a_num_inc
acall numb
ajmp alarmnum
alarm1_set:
push acc
mov a,70h
jb acc1,alarmnum
alarm1_out:
clr 20h2
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 20h2
acall daa
orl 21h,#10h
acall disp
anl 21h,#0fh
acall key_scanf
mov a,70h
jb acc1,hadj_1
jb acc2,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 acc1,hadj_2
jb acc2,minc_2
ajmp madj_2
hadj_1:
acall daa
orl 23h,#10h
acall disp
anl 23h,#0fh
acall key_scanf
mov a,70h
jb acc1,madj_2
jb acc2,hinc_1
ajmp hadj_1
hadj_2:acall daa
orl 27h,#10h
acall disp
anl 27h,#0fh
acall key_scanf
mov a,70h
jb acc1,alarm1_out
jb acc2,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 psw5
push acc
mov a,70h
jb acc0,l1;P10调时功能键,每按一次切换一位
ajmp nokeyout
adj_out:
mov 21h,73h
mov 22h,74h
setb p30 ;闭合继电器
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 psw5
mov a,70h
jb acc0,h_adj;切换到小时调整
jb acc1,m_inc;P12加1按钮
ajmp l1
h_adj:; 小时调整
;acall dab
orl 74h,#10h
acall disp
acall QQ
acall key_scanf
clr psw5
mov a,70h
jb acc0,out_adj;切换到星期调整
jb acc1,h_inc;小时加1
ajmp h_adj
w_adj:
acall daa
orl 78h,#10h
acall disp
acall QQ
acall key_scanf
clr psw5
mov a,70h
jb acc0,out_adj
jb acc2,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 29h4
jnb 29h0,iii1
jnb 20h6,iii1
setb 29h4
iii1:jnb 29h1,out_21
jnb 20h7,out_21
setb 29h4
out_21:
jnb 20h6,out_12
jnb 20h7,out_13
mov 77h,#1dh
ajmp out_22
out_12:
jnb 20h7,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
1 例如当时间达到09年6月3日20点31分20秒的时候,CPU转到停止,前提是CPU有硬件时钟,并且正确设置了时间。
LD SM05
EU
TODR VB0 //读取时间
LDB>= VB0, 16#09 //读取的时间是BCD码,这样用省去格式转换
AB>= VB1, 16#06
AB>= VB2, 16#03
AB>= VB3, 16#20
AB>= VB4, 16#31
AB>= VB5, 16#20
STOP
2 如果定时开启关闭外部设备,那PLC可以轻松完成。
例如每天早上6点到晚上8点开机
LD SM05
EU
TODR VB0
LDB>= VB3, 16#06
AB= Q00
3 PLC运行一段时间停止
LD SM04
EU
INCD MD0 //每分钟累加一次,
LDD= MD0, 4320 //3天后CPU停止,4320=3天24小时60分钟
STOP //在系统块里将MD0设置为断电保持,那么计时不受停**响,停电自动保存计时时间。
关键是如何读系统时钟:
S7-200的硬件实时时钟可以提供年、月、时、分、秒的日期/时间数据。
CPU221、CPU222没有内置的实时时钟,需要外插“时钟/电池卡”才能获得此功能。CPU224、CPU226和CPU226 XM都有内置的实时时钟。
为了提高运算效率,应当避免每个程序周期都读取实时时钟。实际上可读取的最小时间单位是1秒,可每秒读取一次(使用SM05上升沿触发读取指令)。
使用程序读取的实时时钟数据为BCD格式,可在状态图中使用十六进制格式查看。
CPU靠内置超级电容(+外插电池卡)在失去供电后为实时时钟提供电源缓冲;缓冲电源放电完毕后,再次上电后时钟将停止在缺省值,并不开始走动。
要设置日期、时间值,使之开始走动,可以:
用编程软件(Micro/WIN)的菜单命令PLC > Time of Day Clock,通过与CPU的在线连接设置,完成后时钟开始走动
编用户程序使用Set_RTC(设置时钟)指令设置
Micro/WIN可以通过任何编程连接实现实时时钟的设置。
使用 S7-200 的 READ_RTC(读取实时时钟)和 SET_RTC(设置实时时钟)指令时, 读取和设置的数据格式都是 BCD 码的。如果觉得不便计算、处理,可使用 Clock Integer 指令库。
if(T0IF&&T0IE) //定时器T0中断类型判别
{
int i;
TMR0=TMR0+11;
T0IF=0;
asm("clrwdt");
count+=1;
if(count==5) //计数基数58250=001s
{
count=0;
i=0;
do{
s[i]+=1;
i++;
}while(i<3); //3个计数基数累加
}
} //Tmr0_int服务子程序3
#include<reg51h>
#define uchar unsigned char
uchar code ledtab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//0-9
unsigned char sec=0,min=0,hour=12,scanled;
unsigned char key,flashbit,mode,time;
unsigned char disdat[6];
sbit led=P1^0;
void delay(unsigned int x)
{
unsigned int i,j;
for(i=0;i<x;i++)
for(j=0;j<120;j++);
}
void dischg()
{
disdat[0]=sec%10;
disdat[1]=sec/10;
disdat[2]=min%10;
disdat[3]=min/10;
disdat[4]=hour%10;
disdat[5]=hour/10;
}
void flash()
{
switch(flashbit)
{
case 0:break;
case 1:
disdat[4]=0x10;
disdat[5]=0x10;
delay(50);
dischg();
delay(80);
break;
case 2:
disdat[2]=0x10;
disdat[3]=0x10;
delay(50);
dischg();
delay(80);
break;
case 3:
disdat[0]=0x10;
disdat[1]=0x10;
delay(50);
dischg();
delay(80);
break;
default:break;
}
}
void t0isr() interrupt 1 //秒计时
{
TH0=0x3c;
TL0=0xb0;
time++;
switch(mode)
{
case 0:
if(time==20)
{
time=0;
sec++;
if(sec>59)
{
sec=0;
min++;
if(min>59)
{
hour++;
if(hour>23)hour=0;
}
}
}
break;
case 1:
if(time==20)
{
time=0;
if(sec>0)sec--;
else if(min>0){sec=59;min--;}
else if(hour>0){sec=59;min=59;hour--;}
else {hour=0;min=0;sec=0;}
}
break;
}
dischg();
}
void t1isr() interrupt 3 //显示
{
TH1=0xec;
TL1=0x78;
switch(scanled)
{
case 0:
P2=0x01;
P0=~ledtab[disdat[5]];
break;
case 1:
P2=0x02;
P0=~ledtab[disdat[4]];
break;
case 2:
P2=0x04;
P0=~ledtab[disdat[3]];
break;
case 3:
P2=0x08;
P0=~ledtab[disdat[2]];
break;
case 4:
P2=0x10;
P0=~ledtab[disdat[1]];
break;
case 5:
P2=0x20;
P0=~ledtab[disdat[0]];
break;
default:break;
}
scanled++;
scanled%=6;
}
main()
{
TMOD=0x11;
TH0=0x3c;
TL0=0xb0;
TH1=0xec;
TL1=0x78;
EA=1;
TR1=1;
ET0=1;
ET1=1;
sec=0;
min=0;
hour=12;
flashbit=0;
scanled=0;
time=0;
mode=0;
dischg();
while(1)
{
flash();//闪烁
// led=1;
if((P3&0x0f)!=0x0f){
key=P3&0x0f;
while((P3&0x0f)!=0x0f);
led=0;
delay(10);
key|=0xf0;
switch(~key)
{
case 0x01: //p31选择调时、分、秒
TR0=0;
flashbit+=1;
if(flashbit>3){flashbit=0;TR0=1;}
break;
case 0x02: //p32调数
if(flashbit==0)break;
if(flashbit==1)
{
hour++;
if(hour>23)hour=0;
}
if(flashbit==2)
{
min++;
if(min>59)min=0;
}
if(flashbit==3)
{
sec++;
if(sec>59)sec=0;
}
break;
case 0x04: //选择正/倒
TR0=0;
mode++;
mode&=0x01;
if(mode==0){sec=0;min=0;hour=0;}
dischg();
break;
case 0x08: //启动/暂停
TR0=~TR0;
break;
default:break;
}
}
}
}
自己写了一个时钟程序,用来模拟时间类型软件的破解,先从基础的运行时间开始,程序运行界面如图:十秒后程序自动退出
十秒后程序自动退出
破解思路:查看程序导入表函数(有N多个程序可以查看,以PETOOLS为例),如图所示:输入表目录
只找到一个和时间有关的函数GetSystemTimeAsFileTime。我们可以通过od自带的api断点,去断下GetSystemTimeAsFileTime这个函数,
Enter进入,在系统领空下段,运行程序,会断在这个函数的系统领空,之后ctrl+F9执行到返回到,call GetSystemTimeAsFileTime的调用,再ctrl+F9执行到返回,来到如下关键代码处:
可见通过上面call函数clock的调用,返回值去和10比较,来判断程序运行的时间,修改跳转或者修改A的值即可实现破解。
以上就是关于单片机电子时钟直接设置定时时间,并实时显示剩余时间全部的内容,包括:单片机电子时钟直接设置定时时间,并实时显示剩余时间、我想知道AT89C51单片机电子时钟一个可以任意设定时间的程序、S7-200设备每天特定时间定时启停怎么实现等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)