;Timekeeping Example, using Timer 0 with interrupts ;http://www.pjrc.com/tech/8051/board4/timers.html ;This examples demonstrates how to use Timer 0 to keep track ;of time. Timer 0 is used in mode 0, which produces 225 ;overflows per second (22.1184 MHz crystal). .equ cout, 0x0030 ;Send Acc to serial port .equ cin, 0x0032 ;Get Acc from serial port .equ phex, 0x0034 ;Print Hex value of Acc .equ pstr, 0x0038 ;Print string pointed to by DPTR, .equ esc, 0x003E ;Check for ESC key .equ newline, 0x0048 ;print CR/LF (13 and 10) ;internal RAM memory usage .equ flags, 0x20 .equ time_changed_flag, 0 ;first bit in "flags" byte .equ hours, 0x21 .equ minutes, 0x22 .equ seconds, 0x23 .equ ov_countdown, 0x24 .equ stack, 0x25 ;begin stack after last data in internal RAM .org 0x2000 ljmp begin .org 0x200B ljmp timer0_isr begin: mov ie, #0 ;turn off all interrupts mov sp, #stack-1 mov hours, #0 ;zero hours, minutes, seconds mov minutes, #0 mov seconds, #0 mov ov_countdown, #225 clr tr0 ;make sure timer 0 is stopped clr tf0 ;clear the overflow flag anl tmod, #0xF0 ;set to mode 0 (without touching timer 1) mov th0, #0 ;clear the timer 0 value mov tl0, #0 mov dptr, #msg_begin lcall pstr clr time_changed_flag setb tr0 ;start the timing mov ip, #0 ;set interrupt priorities (all low) mov ie, #0x82 ;enable timer0 interrupt lcall print_time timekeeping_loop: lcall esc jc abort jnb time_changed_flag, timekeeping_loop clr time_changed_flag lcall print_time sjmp timekeeping_loop abort: mov dptr, #msg_end lcall pstr lcall cin ljmp 0 ;this interrupt service routine will run every time timer0 sets ;the TF0 flag. The 8051 hardware automatically clears TF0 for ;us. As with all interrupts, we must be very careful to save ;any registers that get changed. timer0_isr: djnz ov_countdown, timer0_end ;have 225 interrupts (1 second) elapsed? mov ov_countdown, #225 push psw ;save psw (cjne changes status bits) push acc ;save accumulator, used inside inc_time acall inc_time ;actually increment the time setb time_changed_flag ;set a flag to alert the main program to change pop acc pop psw timer0_end: reti inc_time: inc seconds ;increment seconds mov a, seconds cjne a, #60, inc_time_end mov seconds, #0 inc minutes ;increment minutes mov a, minutes cjne a, #60, inc_time_end mov minutes, #0 inc hours ;increment hours mov a, hours cjne a, #24, inc_time_end mov hours, #0 inc_time_end: ret print_time: clr et0 ;temporarily disable the timer0 interrupt while mov r7, hours ;reading the time data. If we simply used the mov r6, minutes ;three variables below, each read between 3 bytes mov r5, seconds ;of output, the time might change while printint it! setb et0 ;reenable interupt as soon as possible mov a, r7 ;hours lcall print_2digit_int mov a, #':' lcall cout mov a, r6 ;minutes lcall print_2digit_int mov a, #':' lcall cout mov a, r5 ;seconds lcall print_2digit_int lcall newline ret print_2digit_int: mov b, #10 ;divide by 10... div ab add a, #'0' ;quotient is tens digit lcall cout mov a, b ;remainder is ones digit add a, #'0' lcall cout ret msg_begin: .db 13,10,13,10,13,10 .db "Timekeeping Example (Interrupts)",13,10 .db "Press ESC to stop...",13,10,13,10,0 msg_end: .db 13,10,13,10,"Stopped. Press a key to reboot",0