;********************************************************************** ;* 8052.com Single Board Computer -- SBCMON Demonstration Program * ;* ---> CLOCK DEMONSTRATION PROGRAM <--- * ;* For 8052.com SBC, hardware rev 1.3 * ;*--------------------------------------------------------------------* ;* This program is offered as-is with no warranty or guarantee of any * ;* kind. Its purpose is to serve as an educational aid in mastering * ;* the topics and concepts covered by the program. You are free to * ;* use this code for any purpose you see fit--including commercial-- * ;* but the exclusive responsibility for its use is the user of this * ;* code. This code is offered completely free of charge and VIS' and * ;* 8052.com's liability will be limited to the amount paid: zero. * ;*--------------------------------------------------------------------* ;* This program was coded to be compatible with the Pinnacle 52 IDE. * ;* Pinnacle 52 is available at http://www.vaultbbs.com/pinnacle. The * ;* program may require minor modifications in order to assemble with * ;* other assemblers. * ;*--------------------------------------------------------------------* ;* NOTE: This program was designed to be loaded into SBCMON's XRAM * ;* and executed as an SBCMON external program. It depends on one or * ;* more SBCMON library routines and, as such, will not work without * ;* SBCMON. This program is not intended to be loaded via in-system * ;* programming, only loaded within SBCMON. Should you wish to load * ;* this program via ISP as a stand-alone program, the SBCMON library * ;* entry point equates should be removed and the respective routines * ;* should be copied from SBCMON into this program. The source code * ;* for SBCMON may be found at http://www.8052.com/sbc/sbcmon. * ;*====================================================================* ;* Filename: CLOCK.ASM * ;* Description: This is a simple digital clock. The program will * ;* constantly read the current date/time from the DS1307 RTC and * ;* display the day of week, date, and time on the LCD. Press any * ;* key on the PC terminal to exit the program and return to SBCMON. * ;********************************************************************** ;========================================================== ; SBCMON LIBRARY ROUTINE ENTRY POINT EQUATES ; ;If you wish to make this a stand-alone program, remove ;these equates and copy the source code for the named ;routines from the SBCMON source code. SBCMON source code ;may be found at http://www.8052.com/sbc/sbcmon. ;=========================================================== SendSerial EQU 0041h SendLCDCommand EQU 0053h SendLCDText EQU 0050h InitializeLCD EQU 008Ch ByteToBCD EQU 006Bh I2C_ReadByte EQU 0056h I2C_SendByte EQU 0059h I2C_Reset EQU 005Ch I2C_Start EQU 005Fh I2C_Stop EQU 0062h ;========================================================== ; PROGRAM LOCATION ; ;The program is located at 8000h since this is where the ;8052.com SBC's XRAM/code memory is in the memory map. ;Programs loaded into this RAM area can be accessed as both ;data and executed as a program. If you are going to make ;this a stand-alone program the following ORG should be ;modified to 0000h rather than 8000h. ;=========================================================== ORG 8000h ;========================================================== ; PROGRAM CODE ; ;This is the actual guts of the demonstration code. ;=========================================================== LCALL SendSerial DB "Initializing LCD",13,0 LCALL InitializeLCD ;Make sure the LCD is initialized MOV A,#0Ch ;Send command to turn cursor off LCALL SendLCDCommand ;Send cursor off command MOV A,#01h ;Clear LCD screen LCALL SendLCDCommand ;Send clear screen command ;The screen is now clear and cursor is in upper left hand ;corner and the cursor itself has been turned off so it ;won't look ugly. We send a welcome message to the serial ;port/PC terminal program. LCALL SendSerial DB "Digital clock being displayed on LCD",13 DB "Clock should first be set with 'C' command",13 DB "Day of week: 1=Monday, 7=Sunday",13 DB "Press any key to exit", 13,0 CLR RI ;Clear RI initially ClockLoop: JNB RI,ClockContinue ;No key pressed, keep running clock ;If we get here that means a key was pressed, so turn the ;LCD cursor back on and exit. MOV A,#0Eh ;Turn cursor on LCALL SendLCDCommand ;Send cursor on command RET ;Exit to SBCMON ClockContinue: ;The first thing we do is read the current date and time from ;the DS1307 RTC. We read the first 7 bytes of the RTC into ;R7 (seconds), R6 (minutes), R5 (hours), R4 (day of week), ;R3 (day of month), R2 (month), R1 (year). Once we have the ;time/date LCALL I2C_Reset ;Reset I2C Bus LCALL I2C_Start ;Send I2C start MOV A,#0D0h ;DS1307 RTC Write address = D0h CLR C ;Clear carry for I2C transmission LCALL I2C_SendByte ;Send command to DS1307 JC RRNoAck ;If no ack then communication failed MOV A,#00h ;Set address pointer to first byte CLR C ;Clear carry for I2C transmission LCALL I2C_SendByte ;Send address pointer to RTC ;RTCRead: LCALL I2C_Start ;Resend I2C start, new I2C conversation MOV A,#0D1h ;DS1307 Read address = A3h CLR C ;Clear carry for I2C transmission LCALL I2C_SendByte ;Send read command JC RRNoAck ;If no ack then communication failed CLR C ;Clear carry for I2C transmission LCALL I2C_ReadByte ;Read seconds from the RTC ANL A,#7Fh ;Only interested in low 7 bits MOV R7,A ;R7 holds seconds CLR C ;Clear carry for I2C transmission LCALL I2C_ReadByte ;Read minutes from the RTC ANL A,#7Fh ;Only interested in low 7 bits MOV R6,A ;R6 holds minutes CLR C ;Clear carry for I2C transmission LCALL I2C_ReadByte ;Read hours from the RTC ANL A,#3Fh ;Only interested in low 6 bits MOV R5,A ;R5 holds hours CLR C ;Clear carry for I2C transmission LCALL I2C_ReadByte ;Read day of week from the RTC MOV R4,A ;R4 holds day of week CLR C ;Clear carry for I2C transmission LCALL I2C_ReadByte ;Read day of month from the RTC ANL A,#3Fh ;Only interested in low 6 bits MOV R3,A ;R3 holds day of month CLR C ;Clear carry for I2C transmission LCALL I2C_ReadByte ;Get month from the RTC ANL A,#1Fh ;Only interested in low 5 bits MOV R2,A ;R2 holds month SETB C ;Clear carry for I2C transmission LCALL I2C_ReadByte ;Get year from the RTC MOV R1,A ;R1 holds year LCALL I2C_Stop ;Send I2C stop condition SJMP DisplayClock ;Jump over following error code segment RRNoAck: ;This code is executed if there's a communication problem with ;the RTC. Displays an error message on the screen instead of ;the date/time. MOV A,#01h ;Clear screen code LCALL SendLCDCommand ;Send the clear screen command MOV DPTR,#ErrorLine1 ;Point to the address of first line of error message LCALL SendLCDString ;Send it to the LCD MOV A,#0C0h ;Cursor position code for line 2 character 1 LCALL SendLCDCommand ;Send the cursor position command to the LCD MOV DPTR,#ErrorLine2 ;Point to the address of second line of error message LCALL SendLCDString ;Send it to the LCD LJMP ClockLoop ;Go back to the clock loop and try again ErrorLine1: ;Error line 1 DB "Error reading",0 ErrorLine2: ;Error line 2 DB "RTC!",0 DisplayClock: MOV A,#01h ;Clear screen code LCALL SendLCDCommand ;Send the clear screen command ;Display day of week (Mon, Tue, etc.). MOV DPTR,#WeekdayNames ;Point to weekday table MOV A,R4 ;Get day of week (1-7) DEC A ;Now day of week is (0-6) CLR C ;Make sure carry is clear RLC A ;Multiply by 2 RLC A ;Multiply by 4 ADD A,DPL ;Add low byte of DPL MOV DPL,A ;Update value of DPL MOV A,DPH ;Get value of DPH ADDC A,#00h ;Add high byte MOV DPH,A ;Update value of DPH LCALL SendLCDString ;Display "Mon", "Tue", etc. on LCD MOV A,#' ' ;Send a space LCALL SendLCDText ;Send the space ;Display Month MOV DPTR,#MonthNames ;Point to the month name table MOV A,R2 ;Get month (1-12) DEC A ;Now month is (0-11) CLR C ;Make sure carry is clear RLC A ;Multiply by 2 RLC A ;Multiply by 4 ADD A,DPL ;Add low byte of DPL MOV DPL,A ;Update value of DPL MOV A,DPH ;Get value of DPH ADDC A,#00h ;Add high byte MOV DPH,A ;Update value of DPH LCALL SendLCDString ;Display "Jan", "Feb", etc. on LCD MOV A,#' ' ;Send a space LCALL SendLCDText ;Send the space ;Display day of month MOV A,R3 ;Get day of month (1-31) LCALL DisplayValue ;Display day on the screen MOV DPTR,#YearString ;Point to ", 20" strin LCALL SendLCDString ;Display it on the LCD MOV A,R1 ;Get year (00-99) LCALL DisplayValue ;Display year on the screen MOV A,#0C4h ;Cursor command to line 2 character 1 LCALL SendLCDCommand ;Send the cursor positioning command ;Display hour MOV A,R5 ;Get hour (0-23) LCALL DisplayValue ;Display hour on the screen MOV A,#':' ;The ":" separating hour and minute LCALL SendLCDText ;Send it to the LCD ;Display minute MOV A,R6 ;Get minute (0-59) LCALL DisplayValue ;Display minute on the screen MOV A,#':' ;The ":" separating minute and second LCALL SendLCDText ;Send it to the LCD ;Display second MOV A,R7 ;Get second (0-59) LCALL DisplayValue ;Display on the screen LJMP ClockLoop ;Process done, go back and repeat DisplayValue: LCALL ByteToBCD ;Convert BCD accumulator to two ASCII digits LCALL SendLCDText ;Send first ASCII digit to the LCD MOV A,R0 ;Move second ASCII digit from R0 to accumulator LCALL SendLCDText ;Send second ASCII digit to the LCD RET ;Done! SendLCDString: CLR A ;Make sure there is no offset for next instruction MOVC A,@A+DPTR ;Get byte from code memory pointed to by DPTR INC DPTR ;Increment to DPTR to point to next character JZ SendLCDStringExit ;If value we got was zero, then end of string--we're done LCALL SendLCDText ;Otherwise, send the character to the LCD for display SJMP SendLCDString ;Repeat for next character SendLCDStringExit: RET ;Done! WeekdayNames: DB "Mon", 0 DB "Tue", 0 DB "Wed", 0 DB "Thr", 0 DB "Fri", 0 DB "Sat", 0 DB "Sun", 0 MonthNames: DB "Jan", 0 DB "Feb", 0 DB "Mar", 0 DB "Apr", 0 DB "May", 0 DB "Jun", 0 DB "Jul", 0 DB "Aug", 0 DB "Sep", 0 DB "Oct", 0 DB "Nov", 0 DB "Dec", 0 YearString: DB ", 20", 0