INCLUDE Clock2.Hd ;╒══════════════════════════════════════════════════════════════════════════╕ ;│ System Clock │ ;│ This program shows the RTC. It reads the RTC with a polling │ ;│ approach. │ ;╘══════════════════════════════════════════════════════════════════════════╛ COMSEG SEGMENT BYTE PUBLIC ASSUME CS:COMSEG, DS:COMSEG, ES:COMSEG, SS:COMSEG ORG 100H ;──────────────────────────────────────────────────────────────────────────── ComStart: jmp RealStart ;╒══════════════════════════════════════════════════════════════════════════╕ ;│ VARIABLES │ ;╘══════════════════════════════════════════════════════════════════════════╛ CurrentSeconds db 00 ; Seconds in BCD CurrentMinutes db 00 ; Minutes in BCD CurrentHours db 00 ; Hours in BCD PreviousSeconds db 00 StatusA db 00 UpdateScreen db FALSE ;╒══════════════════════════════════════════════════════════════════════════╕ ;│ CODE │ ;╘══════════════════════════════════════════════════════════════════════════╛ RealStart: Call BlastUserMessage ; Display user message Call InstallRTCInterruptHandler ; Install our INT 70h ; handler to catch clock ; update interrupts Call EnableRTCUpdateInts ; Allow RTC system interrupts ;-------------------------------------------------------------------------- DisplayTime: Call DisplayCurrentTime ; Blast the time onto the ; template Call CheckForTermination ; Check for ESC character jnc DisplayTime ; If we didn't terminate, do ; it again. ;-------------------------------------------------------------------------- Goodbye: Call DisableRTCUpdateInts ; Disable RTC system interrupts Call RemoveRTCInterruptHandler ; Remove our INT 70h ; handler Call ClearScreen ; Clear off the clock mov ah, EXE_TERMINATE ; Exit back to DOS int DOS_FUNCTION ;╒══════════════════════════════════════════════════════════════════════════╕ ;│ SUBROUTINES │ ;╘══════════════════════════════════════════════════════════════════════════╛ ;┌──────────────────────────────────────────────────────────────────────────┐ ;│ Clear Screen │ ;│ This routine will clear the screen by writing spaces to every │ ;│ location. │ ;│ Call With : Nothing │ ;│ Alters : AX, BX, CX, DX │ ;│ Returns : Nothing │ ;│ Calls : SetCursorLoc │ ;└──────────────────────────────────────────────────────────────────────────┘ ClearScreen: xor dx, dx ; Move cursor to the Call SetCursorLoc ; top of the screen ;-------------------------------------------------------------------------- mov al, SPACE_CHARACTER ; Fill the screen xor bh, bh ; with bright white mov bl, BR_WHT_ON_BLK ; on black spaces mov cx, ONE_SCREEN_OF_CHARS mov ah, WRITE_CHAR_AND_ATTRIB int VIDEO_IO ret ;┌──────────────────────────────────────────────────────────────────────────┐ ;│ Blast Clock Template │ ;│ This routine will write the clock template to the screen. │ ;│ Call With : Nothing │ ;│ Alters : AX, DX │ ;│ Returns : Nothing │ ;│ Calls : ClearScreen │ ;└──────────────────────────────────────────────────────────────────────────┘ BlastClockTemplate: Call ClearScreen ; Clear screen and move ; cursor to top of screen ;-------------------------------------------------------------------------- mov dx, OFFSET ClockTemplate ; Use DOS to write clock mov ah, DOS_PRINTSTRING ; onto screen int DOS_FUNCTION ret ;┌──────────────────────────────────────────────────────────────────────────┐ ;│ Blast User Message │ ;│ This routine will write the user message onto the screen and wait │ ;│ for a keystroke. │ ;│ Call With : Nothing │ ;│ Alters : AX, DX │ ;│ Returns : Nothing │ ;│ Calls : ClearScreen │ ;└──────────────────────────────────────────────────────────────────────────┘ BlastUserMessage: Call ClearScreen ; Clear screen and move ; cursor to top of screen ;-------------------------------------------------------------------------- mov dx, OFFSET ClockMessage ; Use DOS to write clock mov ah, DOS_PRINTSTRING ; message onto screen int DOS_FUNCTION Call WaitForKeystroke ret ;┌──────────────────────────────────────────────────────────────────────────┐ ;│ Check For Termination │ ;│ This routine checks to see if the ESC key was hit. If it wasn't, we │ ;│ leave. │ ;│ Call With : Nothing │ ;│ Alters : AX │ ;│ Returns : CY set if termination set │ ;│ Calls : CheckForKeystroke │ ;│ WaitForKeystroke │ ;└──────────────────────────────────────────────────────────────────────────┘ CheckForTermination: Call CheckForKeystroke clc jz FinishedTerminationCheck Call WaitForKeystroke cmp ah, ESC_SCAN_CODE jne CheckForTermination stc FinishedTerminationCheck: ret ;┌──────────────────────────────────────────────────────────────────────────┐ ;│ Get RTC Reading │ ;│ This routine is responsible for reading the seconds, minutes, and │ ;│ hours from the RTC. │ ;│ Call With : DS pointing to data │ ;│ Alters : AX, DI │ ;│ Returns : Hours:Minutes:Seconds in data region │ ;│ Calls : ReadCMOSByte │ ;└──────────────────────────────────────────────────────────────────────────┘ GetRTCReading: push ds ; Save current data seg push cs ; Then make it point to pop ds ; the current segment mov di, OFFSET CurrentSeconds ; Point destination pointer ; to data area ;────────────────────────────────────────────────────────────────────────── cli ; Turn off system interrupts ;-------------------------------------------------------------------------- mov al, RTC_SECONDS ; Read in current RTC Call ReadCMOSByte ; seconds and store it stosb ; to a local variable ;-------------------------------------------------------------------------- mov al, RTC_MINUTES ; Read in current RTC Call ReadCMOSByte ; minutes and store it to stosb ; a local variable ;-------------------------------------------------------------------------- mov al, RTC_HOURS ; Read in current RTC Call ReadCMOSByte ; hours and store it to stosb ; a local variable ;-------------------------------------------------------------------------- sti ; Restore system interrupts pop ds ; Restore data segment ret ; Return to caller ;┌──────────────────────────────────────────────────────────────────────────┐ ;│ Display Current Time │ ;│ This routine will convert the BCD time to text and blast it onto the │ ;│ screen. │ ;│ Call With : New Time in data region │ ;│ Alters : AX, DI │ ;│ Returns : Nothing │ ;│ Calls : ConvertByteToText │ ;└──────────────────────────────────────────────────────────────────────────┘ DisplayCurrentTime: cmp UpdateScreen, TRUE jne FinishedScreenUpdate mov UpdateScreen, FALSE ;-------------------------------------------------------------------------- xor ah, ah ; Convert the seconds mov al, CurrentSeconds ; into text format mov di, OFFSET SecondsText ; and place into the Call ConvertByteToText ; clock template ;-------------------------------------------------------------------------- xor ah, ah ; Now convert the mov al, CurrentMinutes ; minutes mov di, OFFSET MinutesText Call ConvertByteToText ;-------------------------------------------------------------------------- xor ah, ah ; Now convert the mov al, CurrentHours ; hours mov di, OFFSET HoursText Call ConvertByteToText ;-------------------------------------------------------------------------- mov dx, OFFSET ClockTemplate ; Copy the entire mov ah, DOS_PRINTSTRING ; clock onto the Call BlastClockTemplate ; screen FinishedScreenUpdate: ret ;┌──────────────────────────────────────────────────────────────────────────┐ ;│ Convert Byte To Text │ ;│ This routine will take a two digit BCD number and store it to the │ ;│ location pointed to by DI. │ ;│ Call With : AL = BCD number │ ;│ DI pointing to location to write text │ ;│ Alters : AX, BX, DI │ ;│ Returns : Nothing │ ;│ Calls : Nothing │ ;└──────────────────────────────────────────────────────────────────────────┘ ConvertByteToText: mov bl, 16 ; Divide by 16 since it's div bl ; BCD and not binary add ah, NUMBER_ZERO ; AH will have lower digit mov [di], ah ; Add Character 0 and store dec di ; Point to next digit add al, NUMBER_ZERO ; AL will have upper digit mov [di], al ; Add character 0 and store ret ;┌──────────────────────────────────────────────────────────────────────────┐ ;│ Set Cursor Location │ ;│ This routine will set the cursor position to the value in DX │ ;│ Call With : DX = New Cursor Position │ ;│ Returns : Nothing │ ;│ Alters : AX, BX, DX │ ;│ Calls : Nothing │ ;└──────────────────────────────────────────────────────────────────────────┘ SetCursorLoc: mov ah, SET_CURSOR_POSITION xor bh, bh int VIDEO_IO ret ;┌──────────────────────────────────────────────────────────────────────────┐ ;│ Check For Keystroke │ ;│ This routine will check to see if there are any keystrokes waiting │ ;│ in the keyboard buffer. │ ;│ Call With : Nothing │ ;│ Alters : AX │ ;│ Returns : NZ if key is waiting │ ;│ Calls : Nothing │ ;└──────────────────────────────────────────────────────────────────────────┘ CheckForKeystroke: mov ah, NO_WAIT_FOR_KEY int KEYBOARD_IO ret ;┌──────────────────────────────────────────────────────────────────────────┐ ;│ Wait For Keystroke │ ;│ This routine will wait until a key is in the buffer. │ ;│ Call With : Nothing │ ;│ Alters : AX │ ;│ Returns : Nothing │ ;│ Calls : Nothing │ ;└──────────────────────────────────────────────────────────────────────────┘ WaitForKeystroke: mov ah, WAIT_FOR_KEYSTROKE int KEYBOARD_IO ret ;╒══════════════════════════════════════════════════════════════════════════╕ ;│ INCLUDE FILES │ ;╘══════════════════════════════════════════════════════════════════════════╛ INCLUDE PcMag2.Asm ;╒══════════════════════════════════════════════════════════════════════════╕ ;│ DATA, SCREENS, BUFFERS │ ;╘══════════════════════════════════════════════════════════════════════════╛ CLOCK_WIDTH equ 12 CLOCK_LENGTH equ 03 ClockTemplate: db"╔══ TIME ══╗",CR, LF db"║ 0" HoursText: db"0:0" MinutesText: db"0:0" SecondsText: db"0 ║", CR, LF db"╚══════════╝", "$" ;-------------------------------------------------------------------------- ClockMessage: db"█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█" db"█ █" db"█ Clock 2 █" db"█ █" db"█ █" db"█ This short program will display an Hour:Minute:Second clock in the upper █" db"█ left hand corner of the screen. The current time is acquired from the █" db"█ CMOS Real Time Clock. In this particular program, the time is checked █" db"█ after each RTC update interrupt. This will result in the time being █" db"█ updated once a second. After each interrupt, the program will read in █" db"█ the current time and set a flag indicating the time has changed. The █" db"█ main loop simply waits for this flag to change. As soon as the time has █" db"█ been altered, the main loop will drop into the routines to display the █" db"█ clock. By writing faster code to display the clock and moving that code █" db"█ into the interrupt handler, a clock can be displayed while other code is █" db"█ running. This example uses that extra processing power in a useless loop, █" db"█ but with a little thought, this time can be put to better use. █" db"█ █" db"█ █" db"█ In order to return to DOS, press the ESC key. █" db"█ █" db"█ █" db"█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█" db" " db" Press Any Key To Begin ","$" ;──────────────────────────────────────────────────────────────────────────── COMSEG ENDS END ComStart