;* FILENAME: DS1307.ASM ;* DISPLAY: 16X2 LCD 4-BIT OPERATION ;* MICRO: DS89C450 FLASH BASED MICRO ;* PROJECT: ALARM CLOCK ;* DATE: 09/07/20 ;* TIMEKEEPER: DS1307 SERIAL TIMEKEEPER I.C. ; ; ; $MOD51 SCL BIT P1.7 SDA BIT P1.6 DS1307W EQU 0D0H ; SLAVE ADDRESS 1101 000 + 0 TO WRITE DS1307R EQU 0D1H ; SLAVE ADDRESS 1101 000 + 1 TO READ FLAGS DATA 20H LASTREAD BIT FLAGS.0 ACK BIT FLAGS.5 BUS_FLT BIT FLAGS.6 _2W_BUSY BIT FLAGS.7 BITCNT DATA 21H BYTECNT DATA 22H SECS DATA 24H ; ' SECONDS STORAGE RAM MINS DATA 25H ; ' MINUTES ' ' HRS DATA 26H ; ' HOURS ' ' DAY DATA 27H ; ' DAY ' ' DATE DATA 28H ; ' DATE ' ' MONTH DATA 29H ; ' MONTH ' ' YEAR DATA 2AH ; ' YEAR ' ' CONTROL DATA 2BH ; FOR STORAGE OF CONTROL REGISTER WHEN READ. ALM_HOUR DATA 2CH ; INTERNAL (ALARM HOURS) STORAGE. ALM_MIN DATA 2DH ; INTERNAL (ALARM MINUTES) STORAGE. ALM_CNTRL DATA 2EH ; INTERNAL STORAGE FOR ALARM (ON) TIME. ALM_STORE EQU 08H ; DS1307 RAM, ALARM STORAGE, BEGINNING. ; ***LCD CONTROL*** LCD_DATA EQU 080H LCD_DB4 EQU 084H ; P0.4 HIGH NIBBLE OF PORT 0 IS USED FOR DATA LCD_DB5 EQU 085H ; P0.5 HIGH NIBBLE OF PORT 0 IS USED FOR DATA LCD_DB6 EQU 086H ; P0.6 HIGH NIBBLE OF PORT 0 IS USED FOR DATA LCD_DB7 EQU 087H ; P0.7 HIGH NIBBLE OF PORT 0 IS USED FOR DATA LCD_RS EQU 0B3H ; P3.3 LCD REGISTER SELECT LINE LCD_RW EQU 0B4H ; P3.4 LCD READ / WRITE LINE LCD_E EQU 0B5H ; P3.5 LCD ENABLE LINE ; ***USER INPUT KEYS*** UP_BTTN BIT 090H ; P1.0 UP DOWN_BTTN BIT 091H ; P1.1 DOWN ENTER BIT 092H ; P1.2 ENTER ALARM_SET BIT 093H ; P1.3 ALARM TIME SET SELECT ; ***SYSTEM INSTRUCTIONS*** CONFIG EQU 28H ; 4-BIT DATA,2 LINES,5X7 MATRIX LCD ENTRYMODE EQU 6 ; INCREMENT CURSOR DON'T SHIFT DISPLAY ; ***CURSOR CONTROL INSTRUCTIONS*** OFFCUR EQU 0CH BLINKCUR EQU 0DH ; ***DISPLAY CONTROL INSTRUCTIONS*** CLRDSP EQU 01H ONDSP EQU 0EH ; ***MACRO'S*** SCL_HIGH MACRO SETB SCL ; SET SCL HIGH JNB SCL,$ ; LOOP UNTIL STRONG 1 ON SCL ENDM CSEG AT 0 ; RESET VECTOR JNB ENTER,INIT_YEAR AJMP START INIT_YEAR: JNB ENTER,INIT_YEAR MOV YEAR,#97H; INITIALIZE YEAR IF NEW 1307 TO 1997 ACALL SET_CLOCK; ELSE GO ON. ; ********************************************************** ; RESET GOES HERE TO START PROGRAM ; ********************************************************** START: MOV YEAR,#97H ; SET YEAR TO 1997 ON BOOT ACALL OFF ; ALARM OFF ON BOOT MOV SP,#2FH ; POSITION STACK ABOVE BUFFER MOV IE,#0 ; DISABLE INTERUPTS SETB SDA ; ENSURE SDA HIGH SCL_HIGH ; ENSURE SCL HIGH CLR ACK ; CLEAR STATUS FLAGS CLR BUS_FLT CLR _2W_BUSY ; ********************************************************** ; SUB SETS THE DS1307 OSCILLATOR ; ********************************************************** OSC_CONTROL: ACALL SEND_START ; GENERATE START CONDITION MOV A,#DS1307W ; 1101 0000 ADDRESS + WRITE-BIT ACALL SEND_BYTE ; SEND BYTE TO 1307 MOV A,#00H ; ADDRESS BYTE TO REGISTER 00H ACALL SEND_BYTE ; SECONDS REGISTER, ALWAYS LEAVE SETB LASTREAD ; REG 00H-BIT #7 = 0 (LOW) ACALL SEND_STOP ; IF REG 00H-BIT #7 = 1 CLOCK ACALL SEND_START ; OSCILLATOR IS OFF. MOV A,#DS1307R ; 1101 0001 ADDRESS + READ-BIT ACALL SEND_BYTE ; ACALL READ_BYTE ; READ A BYTE FROM THE 1307 CLR ACC.7 ; CLEAR REG 00H-BIT #7 TO ENABLE OSC_SET: ; OSCILLATOR. PUSH ACC ; SAVE ON STACK ACALL SEND_STOP ; ACALL SEND_START ; MOV A,#DS1307W ; SETUP TO WRITE ACALL SEND_BYTE ; MOV A,#00H ; REGISTER 00H ADDRESS ACALL SEND_BYTE ; POP ACC ; GET DATA TO START OSCILLATOR ACALL SEND_BYTE ; SEND IT ACALL SEND_STOP ACALL BEGIN ; ********************************************************** ; TIME AND DATE ROUTINE, GET & DISPLAY MONTH/DATE/YEAR ; ********************************************************** GET_TIME: ACALL READ_CLOCK ; GET TIME,DATE,ALARM DATA JNB ENTER,SET_TIME ; GOTO SET TIME IF PUSHED JNB ALARM_SET,SET_ALARMS ; GOTO SET ALARMS ELSE SHOW TIME MOV A,#1 ; LINE #1 MOV B,#1 ; COLUMN #1 ACALL PLACECUR4 ; PLACE CURSOR FOR DAY MOV A,DAY ; GET DAY ACALL GET_DAY ; SHOW DAY OF WEEK MOV A,#1 MOV B,#7 ACALL PLACECUR4 ; PLACE CURSOR FOR MONTH MOV A,MONTH ; LOAD MONTH DATA ACALL WRITE_BCD MOV A,#1 MOV B,#10 ; PLACE CURSOR FOR DATE ACALL PLACECUR4 MOV A,DATE ACALL WRITE_BCD MOV A,#1 MOV B,#13 ACALL PLACECUR4 MOV A,YEAR ACALL WRITE_BCD ; ********************************************************** ; NOW GET & DISPLAY TIME ; ********************************************************** MOV A,#2 MOV B,#4 ACALL PLACECUR4 MOV A,HRS ACALL WRITE_BCD MOV A,#2 MOV B,#7 ACALL PLACECUR4 MOV A,MINS ACALL WRITE_BCD MOV A,#2 MOV B,#10 ACALL PLACECUR4 MOV A,SECS ACALL WRITE_BCD ACALL CHECK_ALARM_TIME SJMP GET_TIME SET_ALARMS: JNB ALARM_SET,SET_ALARMS ACALL MDELAY AJMP ALARMS SET_TIME: JNB ENTER,SET_TIME; HOLDS HERE UNTIL BUTTON IS RELEASED ACALL MDELAY SET_DAY: MOV A,#1 MOV B,#0 ACALL PLACECUR4 ACALL PRTLCD4 DB '*',0 ; PRINT '*' BY DAY WAIT_DAY: ; WAIT HERE FOR BUTTON PRESS JNB UP_BTTN,UP_DAY JNB DOWN_BTTN,DOWN_DAY JNB ENTER,ENTER_DAY ACALL UPDATE SJMP WAIT_DAY REDO_DAY: ; RESETS DAY TO SUN MOV A,#1 MOV DAY,A AJMP WAIT_DAY REDO_DAY_DOWN: ; RESETS DAY TO SAT MOV A,#7H MOV DAY,A AJMP WAIT_DAY OK_DAY: ; PLACES NEW DAY DATA INTO REGISTER MOV DAY,A AJMP WAIT_DAY UP_DAY: ; CHANGES DAY DATA UP BY 1 JNB UP_BTTN,UP_DAY ACALL MDELAY MOV R1,#DAY MOV A,@R1 INC A CJNE A,#8H,OK_DAY AJMP REDO_DAY DOWN_DAY: ; CHANGES MONTH DATA DOWN BY 1 JNB DOWN_BTTN,DOWN_DAY ACALL MDELAY MOV R1,#DAY MOV A,@R1 DEC A CJNE A,#0,OK_DAY AJMP REDO_DAY_DOWN ENTER_DAY: ; DONE WITH DAY GO ON TO MONTH JNB ENTER,ENTER_DAY ACALL MDELAY SET_MONTH: MOV A,#1 MOV B,#0 ACALL PLACECUR4 ACALL PRTLCD4 DB ' ',0 ; PRINT '*' FOR MONTH MOV A,#1 MOV B,#6 ACALL PLACECUR4 ACALL PRTLCD4 DB '*',0 WAIT_MONTH: ; WAIT HERE FOR BUTTON PRESS JNB UP_BTTN,UP_MONTH JNB DOWN_BTTN,DOWN_MONTH JNB ENTER,ENTER_MONTH ACALL UPDATE SJMP WAIT_MONTH REDO_MONTH: ; RESETS MONTH TO 1 MOV A,#1 MOV MONTH,A AJMP WAIT_MONTH REDO_MONTH_DOWN: ; RESETS MONTH TO 12 MOV A,#12H MOV MONTH,A AJMP WAIT_MONTH OK_MONTH: ; PLACES NEW MONTH DATA INTO REGISTER MOV MONTH,A AJMP WAIT_MONTH UP_MONTH: ; CHANGES MONTH DATA UP BY 1 JNB UP_BTTN,UP_MONTH ACALL MDELAY MOV R1,#MONTH MOV A,@R1 MOV R4,A ACALL CHECK_BCD CJNE A,#13H,OK_MONTH AJMP REDO_MONTH DOWN_MONTH: ; CHANGES MONTH DATA DOWN BY 1 JNB DOWN_BTTN,DOWN_MONTH ACALL MDELAY MOV R1,#MONTH MOV A,@R1 MOV R4,A ACALL CHECK_BCD_DOWN DEC A CJNE A,#0,OK_MONTH AJMP REDO_MONTH_DOWN ENTER_MONTH: ; DONE WITH MONTH GO ON TO DATE JNB ENTER,ENTER_MONTH ACALL MDELAY SET_DATE: MOV A,#1 MOV B,#6 ACALL PLACECUR4 ACALL PRTLCD4 DB ' ',0 ; ERASE '*' BY MONTH MOV A,#1 MOV B,#9 ACALL PLACECUR4 ACALL PRTLCD4 DB '*',0 ; PRINT '*' BY DATE WAIT_DATE: ; WAIT HERE UNTIL BUTTON PRESS JNB UP_BTTN,UP_DATE JNB DOWN_BTTN,DOWN_DATE JNB ENTER,ENTER_DATE ACALL UPDATE SJMP WAIT_DATE REDO_DATE: ; RESETS DATE TO 1 MOV A,#1 MOV DATE,A AJMP WAIT_DATE REDO_DATE_DOWN: ; RESETS DATE TO 31 MOV A,#31H MOV DATE,A AJMP WAIT_DATE OK_DATE: ; PLACES NEW DATE DATA INTO REGISTER MOV DATE,A AJMP WAIT_DATE UP_DATE: ; CHANGES DATE DATA UP BY 1 JNB UP_BTTN,UP_DATE ACALL MDELAY MOV R1,#DATE MOV A,@R1 MOV R4,A ACALL CHECK_BCD CJNE A,#32H,OK_DATE AJMP REDO_DATE DOWN_DATE: ; CHANGES DATE DATA DOWN BY 1 JNB DOWN_BTTN,DOWN_DATE ACALL MDELAY MOV R1,#DATE MOV A,@R1 MOV R4,A ACALL CHECK_BCD_DOWN DEC A CJNE A,#0,OK_DATE AJMP REDO_DATE_DOWN ENTER_DATE: ; DONE WITH DATE GO ON TO YEAR JNB ENTER,ENTER_DATE ACALL MDELAY SET_YEAR: MOV A,#1 MOV B,#9 ACALL PLACECUR4 ACALL PRTLCD4 DB '-',0 ; PRINT '-' BESIDE DATE MOV A,#1 MOV B,#12 ACALL PLACECUR4 ACALL PRTLCD4 DB '*',0 ; PRINT '*' BESIDE YEAR WAIT_YEAR: ; WAIT HERE FOR BUTTON PRESS JNB UP_BTTN,UP_YEAR JNB DOWN_BTTN,DOWN_YEAR JNB ENTER,ENTER_YEAR ACALL UPDATE SJMP WAIT_YEAR REDO_YEAR: ; RESETS YEAR TO 1 MOV A,#97H MOV YEAR,A SJMP WAIT_YEAR REDO_YEAR_DOWN: ; RESETS YEAR TO 99 MOV A,#99H MOV YEAR,A AJMP WAIT_YEAR OK_YEAR: ; PLACES NEW YEAR DATA INTO REGISTER MOV YEAR,A AJMP WAIT_YEAR UP_YEAR: ; CHANGES YEAR DATA UP BY 1 JNB UP_BTTN,UP_YEAR ACALL MDELAY MOV R1,#YEAR MOV A,@R1 INC A CJNE A,#9AH,OK_YEAR AJMP REDO_YEAR DOWN_YEAR: ; CHANGES YEAR DATA DOWN BY 1 JNB DOWN_BTTN,DOWN_YEAR ACALL MDELAY MOV R1,#YEAR MOV A,@R1 DEC A CJNE A,#96H,OK_YEAR AJMP REDO_YEAR_DOWN ENTER_YEAR: ; DONE WITH YEAR GO ON TO HOUR JNB ENTER,ENTER_YEAR ACALL MDELAY SET_HOUR: MOV A,#1 MOV B,#12 ACALL PLACECUR4 ACALL PRTLCD4 DB '-',0 ; PRINT '-' BESIDE YEAR MOV A,#2 MOV B,#3 ACALL PLACECUR4 ACALL PRTLCD4 DB '*',0 ; PRINT '*' BESIDE HOUR AJMP WAIT_HOUR WAIT_HOUR: ; WAIT HERE UNTIL BUTTON PRESS JNB UP_BTTN,UP_HOUR JNB DOWN_BTTN,DOWN_HOUR JNB ENTER,ENTER_HOUR ACALL UPDATE SJMP WAIT_HOUR REDO_HOUR: ; RESET HOUR TO 00 MOV A,#0 MOV HRS,A AJMP WAIT_HOUR REDO_HOUR_DOWN: ; RESET HOUR TO 23 MOV A,#23H MOV HRS,A AJMP WAIT_HOUR OK_HOUR: ; PLACE NEW HOUR DATA INTO REGISTER MOV HRS,A AJMP WAIT_HOUR UP_HOUR: ; CHANGES HOUR DATA UP BY 1 JNB UP_BTTN,UP_HOUR ACALL MDELAY MOV R1,#HRS MOV A,@R1 MOV R4,A ACALL CHECK_BCD CJNE A,#24H,OK_HOUR AJMP REDO_HOUR DOWN_HOUR: ; CHANGES HOUR DATA DOWN BY ONE JNB DOWN_BTTN,DOWN_HOUR ACALL MDELAY MOV R1,#HRS MOV A,@R1 MOV R4,A ACALL CHECK_BCD_DOWN DEC A CJNE A,#0F9H,OK_HOUR AJMP REDO_HOUR_DOWN ENTER_HOUR: ; DONE WITH HOUR GO ON TO MINUTES JNB ENTER,ENTER_HOUR ACALL MDELAY SET_MIN: MOV A,#2 MOV B,#3 ACALL PLACECUR4 ACALL PRTLCD4 DB ' ',0 ; ERASE '*' BESIDE HOUR MOV A,#2 MOV B,#6 ACALL PLACECUR4 ACALL PRTLCD4 DB '*',0 ; PRINT '*' BESIDE MINUTES WAIT_MIN: ; WAIT HERE UNTIL BUTTON PRESS JNB UP_BTTN,UP_MIN JNB DOWN_BTTN,DOWN_MIN JNB ENTER,ENTER_MIN ACALL UPDATE SJMP WAIT_MIN REDO_MIN: ; RESET MINUTES TO 00 MOV A,#0 MOV MINS,A AJMP WAIT_MIN REDO_MIN_DOWN: ; RESETS MINUTES TO 59 MOV A,#59H MOV MINS,A AJMP WAIT_MIN OK_MIN: ; PLACE NEW MINUTE DATA INTO REGISTER MOV MINS,A AJMP WAIT_MIN UP_MIN: ; CHANGES MINUTES DATA UP BY 1 JNB UP_BTTN,UP_MIN ACALL MDELAY MOV R1,#MINS MOV A,@R1 MOV R4,A ACALL CHECK_BCD CJNE A,#60H,OK_MIN AJMP REDO_MIN DOWN_MIN: ; CHANGES MINUTES DATA DOWN BY 1 JNB DOWN_BTTN,DOWN_MIN ACALL MDELAY MOV R1,#MINS MOV A,@R1 MOV R4,A ACALL CHECK_BCD_DOWN DEC A CJNE A,#0F9H,OK_MIN AJMP REDO_MIN_DOWN ENTER_MIN: ; DONE WITH MINUTES GO ON TO SECONDS JNB ENTER,ENTER_MIN ACALL MDELAY SET_SECONDS: MOV A,#2 MOV B,#6 ACALL PLACECUR4 ACALL PRTLCD4 DB ':',0 ; PRINT ':' BESIDE MINUTES ACALL MDELAY MOV A,#00000000B ; SECONDS ARE SET TO 00 MOV SECS,A ACALL SET_CLOCK AJMP GET_TIME ; RETURN TO MAIN LOOP ALARMS: ACALL RESETLCD4 ACALL INITLCD4 MOV A,#1 MOV B,#0 ACALL PLACECUR4 ACALL PRTLCD4 DB '-SET ALARM TIME-',0 ACALL BEGIN3 ; PRINT HOUR & MINUTE SEPERATORS ACALL UPDATE3 ; DISPLAY ALARM TIME AJMP ALM_A ; GO TO SET HOURS & MINUTES ROUTINE ; FOR ALARM TIME. UPDATE: MOV A,#1 ; LINE #1 MOV B,#1 ; COLUMN #1 ACALL PLACECUR4 ; PLACE CURSOR FOR DAY MOV A,DAY ; GET DAY DATA ACALL GET_DAY ; CONVERT BCD TO ASCII FOR LCD MOV A,#1 MOV B,#7 ACALL PLACECUR4 ; PLACE CURSOR FOR MONTH MOV A,MONTH ; LOAD DATE MONTH ACALL WRITE_BCD MOV A,#1 MOV B,#10 ; PLACE CURSOR FOR DATE ACALL PLACECUR4 MOV A,DATE ; LOAD DATE DATA ACALL WRITE_BCD MOV A,#1 MOV B,#13 ACALL PLACECUR4 MOV A,YEAR ACALL WRITE_BCD ; ********************************************************** ; NOW GET & DISPLAY TIME ; ********************************************************** UPDATE2: MOV A,#2 MOV B,#4 ACALL PLACECUR4 MOV A,HRS ACALL WRITE_BCD MOV A,#2 MOV B,#7 ACALL PLACECUR4 MOV A,MINS ACALL WRITE_BCD MOV A,#2 MOV B,#10 ACALL PLACECUR4 MOV A,SECS ACALL WRITE_BCD MOV R4,#OFFCUR ACALL WRLCDCOM4 ; TURN OFF CURSOR ACALL BIG_DELAY RET UPDATE3: MOV A,#2 MOV B,#6 ACALL PLACECUR4 MOV A,ALM_HOUR ACALL WRITE_BCD MOV A,#2 MOV B,#9 ACALL PLACECUR4 MOV A,ALM_MIN ACALL WRITE_BCD MOV R4,#OFFCUR ACALL WRLCDCOM4 ACALL BIG_DELAY RET CHECK_ALARM_TIME: MOV A,MINS CJNE A,ALM_MIN,OFF MOV A,HRS CJNE A,ALM_HOUR,OFF MOV ALM_CNTRL,#10H ; LOAD VALUE TO TURN ON SQW OUT & ALARM ACALL ALARM_CONTROL RET OFF: MOV ALM_CNTRL,#00H ACALL ALARM_CONTROL ; LOAD VALUE TO TURN OFF ALARM & SQW OUT. RET ALM_A: MOV A,#2 MOV B,#5 ACALL PLACECUR4 ACALL PRTLCD4 DB '*',0 ; PRINT '*' BESIDE HOUR WAIT_HOUR1: ; WAIT HERE UNTIL BUTTON PRESS JNB UP_BTTN,UP_HOUR1 JNB DOWN_BTTN,DOWN_HOUR1 JNB ENTER,ENTER_HOUR1 ACALL UPDATE3 SJMP WAIT_HOUR1 REDO_HOUR1: ; RESET HOUR TO 00 MOV A,#0 MOV ALM_HOUR,A AJMP WAIT_HOUR1 REDO_HOUR_DOWN1: ; RESET HOUR TO 23 MOV A,#23H MOV ALM_HOUR,A AJMP WAIT_HOUR1 OK_HOUR1: ; PLACE NEW HOUR DATA INTO REGISTER MOV ALM_HOUR,A AJMP WAIT_HOUR1 UP_HOUR1: ; CHANGES HOUR DATA UP BY 1 JNB UP_BTTN,UP_HOUR1 ACALL MDELAY MOV R1,#ALM_HOUR MOV A,@R1 MOV R4,A ACALL CHECK_BCD CJNE A,#24H,OK_HOUR1 AJMP REDO_HOUR1 DOWN_HOUR1: ; CHANGES HOUR DATA DOWN BY ONE JNB DOWN_BTTN,DOWN_HOUR1 ACALL MDELAY MOV R1,#ALM_HOUR MOV A,@R1 MOV R4,A ACALL CHECK_BCD_DOWN DEC A CJNE A,#0F9H,OK_HOUR1 AJMP REDO_HOUR_DOWN1 ENTER_HOUR1: ; DONE WITH HOUR GO ON TO MINUTES JNB ENTER,ENTER_HOUR1 ACALL MDELAY SET_MIN1: MOV A,#2 MOV B,#5 ACALL PLACECUR4 ACALL PRTLCD4 DB ' ',0 ; ERASE '*' BESIDE HOUR MOV A,#2 MOV B,#8 ACALL PLACECUR4 ACALL PRTLCD4 DB '*',0 ; PRINT '*' BESIDE MINUTES WAIT_MIN1: ; WAIT HERE UNTIL BUTTON PRESS JNB UP_BTTN,UP_MIN1 JNB DOWN_BTTN,DOWN_MIN1 JNB ENTER,ENTER_MIN1 ACALL UPDATE3 SJMP WAIT_MIN1 REDO_MIN1: ; RESET MINUTES TO 00 MOV A,#0 MOV ALM_MIN,A AJMP WAIT_MIN1 REDO_MIN_DOWN1: ; RESETS MINUTES TO 59 MOV A,#59H MOV ALM_MIN,A AJMP WAIT_MIN1 OK_MIN1: ; PLACE NEW MINUTE DATA INTO REGISTER MOV ALM_MIN,A AJMP WAIT_MIN1 UP_MIN1: ; CHANGES MINUTES DATA UP BY 1 JNB UP_BTTN,UP_MIN1 ACALL MDELAY MOV R1,#ALM_MIN MOV A,@R1 MOV R4,A ACALL CHECK_BCD CJNE A,#60H,OK_MIN1 AJMP REDO_MIN1 DOWN_MIN1: ; CHANGES MINUTES DATA DOWN BY 1 JNB DOWN_BTTN,DOWN_MIN1 ACALL MDELAY MOV R1,#ALM_MIN MOV A,@R1 MOV R4,A ACALL CHECK_BCD_DOWN DEC A CJNE A,#0F9H,OK_MIN1 AJMP REDO_MIN_DOWN1 ENTER_MIN1: ; DONE WITH MINUTES GO ON TO SECONDS JNB ENTER,ENTER_MIN1 ACALL MDELAY SET_SECONDS1: MOV A,#2 MOV B,#8 ACALL PLACECUR4 ACALL PRTLCD4 DB ':',0 ; PRINT ':' BESIDE MINUTES ACALL MDELAY STORE_ALARMS: ACALL SEND_START ; SEND 2-WIRE START CONDITION MOV A,#DS1307W ; SEND 1307 WRITE COMMAND ACALL SEND_BYTE MOV A,#ALM_STORE; POINT TO REGISTER ; 08H ON THE DS1307 ACALL SEND_BYTE MOV R1,#ALM_HOUR; START WITH HOURS REGISTER ; IN INTERNAL RAM SEND_LOOP2: MOV A,@R1 ; LOAD HOURS DATA FOR ALARM ACALL SEND_BYTE ; SET HOURS MOV R1,#ALM_MIN MOV A,@R1 ; LOAD MINUTES DATA FOR ALARM ACALL SEND_BYTE ; SET MINUTES ACALL SEND_STOP ; SEND 2-WIRE STOP CONDITION ACALL BEGIN ; SETUP DISPLAY AGAIN BEFORE RETURNING. AJMP GET_TIME ; GO BACK TO SHOWING TIME AFTER ; SETTING ALARM ; ********************************************************** ; BCD CONVERSION ROUTINE ; ACC CONTAINS TIME DATA FROM RAM WHEN ROUTINE IS CALLED. ; ********************************************************** WRITE_BCD: PUSH ACC ; DECODE HIGH DIGIT SWAP A ANL A,#0FH ACALL FIND ; LOOK IT UP & THEN PRINT IT. POP ACC ; DECODE LOW DIGIT ANL A,#0FH ACALL FIND RET ; ********************************************************** ; SUB CONTROLS THE ALARM OUTPUT ; THE DS1307 SQW OUTPUT DRIVES THE ALARM BUZZER @ 1Hz ; ********************************************************** ALARM_CONTROL: ACALL SEND_START MOV A,#DS1307W ACALL SEND_BYTE MOV A,#07H ACALL SEND_BYTE MOV R1,#ALM_CNTRL MOV A,@R1 ; 10H = ALARM ON AT 1HZ ACALL SEND_BYTE ; 00H = ALARM OFF & SQW OUT = GND ACALL SEND_STOP RET ; ********************************************************** ; SET UP DISPLAY ON BOOT, AND REDO DISPLAY AFTER CHANGE ; ********************************************************** BEGIN: ACALL RESETLCD4 ACALL INITLCD4 MOV A,#1 MOV B,#7 ACALL PLACECUR4 ACALL PRTLCD4 DB ' - - ',0 MOV A,#2 MOV B,#0 ACALL PLACECUR4 ACALL PRTLCD4 DB '* : : *',0 MOV R4,#OFFCUR ; TURN OFF CURSOR ACALL WRLCDCOM4 RET BEGIN3: MOV A,#2 MOV B,#0 ACALL PLACECUR4 ACALL PRTLCD4 DB '* : *',0 MOV R4,#OFFCUR ; TURN OFF CURSOR ACALL WRLCDCOM4 RET ; ********************************************************** ; LOOKUP TABLE USED BY WRITE_BCD. ; ********************************************************** FIND: SJMP LOOK_UP ST: RET LOOK_UP: CJNE A,#0000000B,m1 LCALL PRTLCD4 DB '0',0 LJMP ST m1: CJNE A,#00000001B,m2 LCALL PRTLCD4 DB '1',0 LJMP ST m2: CJNE A,#00000010B,m3 LCALL PRTLCD4 DB '2',0 LJMP ST m3: CJNE A,#00000011B,m4 LCALL PRTLCD4 DB '3',0 LJMP ST m4: CJNE A,#00000100B,m5 LCALL PRTLCD4 DB '4',0 LJMP ST m5: CJNE A,#00000101B,m6 LCALL PRTLCD4 DB '5',0 LJMP ST m6: CJNE A,#00000110B,m7 LCALL PRTLCD4 DB '6',0 LJMP ST m7: CJNE A,#00000111B,m8 LCALL PRTLCD4 DB '7',0 LJMP ST m8: CJNE A,#00001000B,m9 LCALL PRTLCD4 DB '8',0 LJMP ST m9: CJNE A,#00001001B,m10 LCALL PRTLCD4 DB '9',0 LJMP ST m10: LJMP ST ; ********************************************************** ; LOOKUP TABLE FOR DAY ; ********************************************************** GET_DAY: CJNE A,#00000001B,MON LCALL PRTLCD4 DB 'DIM',0 RET MON: CJNE A,#00000010B,TUE LCALL PRTLCD4 DB 'LUN',0 RET TUE: CJNE A,#00000011B,WED LCALL PRTLCD4 DB 'MAR',0 RET WED: CJNE A,#00000100B,THU LCALL PRTLCD4 DB 'MER',0 RET THU: CJNE A,#00000101B,FRI LCALL PRTLCD4 DB 'JEU',0 RET FRI: CJNE A,#00000110B,SAT LCALL PRTLCD4 DB 'VEN',0 RET SAT: CJNE A,#00000111B,WHAT LCALL PRTLCD4 DB 'SAM',0 RET WHAT: RET ; ********************************************************** ; SUB SETS THE CLOCK ; ********************************************************** SET_CLOCK: ACALL SEND_START ; SEND 2-WIRE START CONDITION MOV A,#DS1307W ; SEND 1307 WRITE COMMAND ACALL SEND_BYTE MOV A,#00H ; SET DATA POINTER TO REGISTER ; 00H ON THE DS1307 ACALL SEND_BYTE MOV R1,#24H ; START WITH SECONDS REGISTER ; IN INTERNAL RAM SEND_LOOP: MOV A,@R1 ; MOVE FIRST BYTE OF DATA TO ACC ACALL SEND_BYTE ; SEND DATA ON 2-WIRE BUT INC R1 ; LOOP UNTIL CLOCK DATA SENT CJNE R1,#2BH,SEND_LOOP ACALL SEND_STOP ; SEND 2-WIRE STOP CONDITION RET ; ********************************************************** ; INITIALIZE THE LCD 4-BIT MODE ; ********************************************************** INITLCD4: CLR LCD_RS ; LCD REGISTER SELECT LINE CLR LCD_RW ; READ / WRITE LINE CLR LCD_E ; ENABLE LINE MOV R4, #CONFIG; FUNCTION SET - DATA BITS, ; LINES, FONTS ACALL WRLCDCOM4 MOV R4, #ONDSP ; DISPLAY ON ACALL WRLCDCOM4 MOV R4, #ENTRYMODE ; SET ENTRY MODE ACALL WRLCDCOM4 ; INCREMENT CURSOR RIGHT, NO SHIFT MOV R4, #CLRDSP; CLEAR DISPLAY, HOME CURSOR ACALL WRLCDCOM4 RET ; ********************************************************** ; SOFTWARE VERSION OF THE POWER ON RESET ; ********************************************************** RESETLCD4: CLR LCD_RS ; LCD REGISTER SELECT LINE CLR LCD_RW ; READ / WRITE LINE CLR LCD_E ; ENABLE LINE CLR LCD_DB7 ; SET BIT PATTERN FOR... CLR LCD_DB6 ; ... POWER-ON-RESET SETB LCD_DB5 SETB LCD_DB4 SETB LCD_E ; START ENABLE PULSE CLR LCD_E ; END ENABLE PULSE MOV A, #4 ; DELAY 4 MILLISECONDS ACALL MDELAY SETB LCD_E ; START ENABLE PULSE CLR LCD_E ; END ENABLE PULSE MOV A, #1 ; DELAY 1 MILLISECOND ACALL MDELAY SETB LCD_E ; START ENABLE PULSE CLR LCD_E ; END ENABLE PULSE MOV A, #1 ; DELAY 1 MILLISECOND ACALL MDELAY CLR LCD_DB4 ; SPECIFY 4-BIT OPERATION SETB LCD_E ; START ENABLE PULSE CLR LCD_E ; END ENABLE PULSE MOV A, #1 ; DELAY 1 MILLISECOND ACALL MDELAY MOV R4, #CONFIG; FUNCTION SET ACALL WRLCDCOM4 MOV R4, #08H ; DISPLAY OFF ACALL WRLCDCOM4 MOV R4, #1 ; CLEAR DISPLAY, HOME CURSOR ACALL WRLCDCOM4 MOV R4, #ENTRYMODE ; SET ENTRY MODE ACALL WRLCDCOM4 AJMP INITLCD4 ; ********************************************************** ; SUB WRITES A COMMAND WORD TO THE LCD ; COMMAND MUST BE PLACED IN R4 BY CALLING PROGRAM ; ********************************************************** WRLCDCOM4: CLR LCD_E CLR LCD_RS ; SELECT SEND COMMAND CLR LCD_RW ; SELECT WRITE OPERATION PUSH ACC ; SAVE ACCUMULATOR MOV A, R4 ; PUT DATA BYTE IN ACC MOV C, ACC.4 ; LOAD HIGH NIBBLE ON DATA BUS MOV LCD_DB4, C ; ONE BIT AT A TIME USING... MOV C, ACC.5 ; BIT MOVE OPERATOINS MOV LCD_DB5, C MOV C, ACC.6 MOV LCD_DB6, C MOV C, ACC.7 MOV LCD_DB7, C SETB LCD_E ; PULSE THE ENABLE LINE CLR LCD_E MOV C, ACC.0 ; SIMILARLY, LOAD LOW NIBBLE MOV LCD_DB4, C MOV C, ACC.1 MOV LCD_DB5, C MOV C, ACC.2 MOV LCD_DB6, C MOV C, ACC.3 MOV LCD_DB7, C ACALL PULSEEWAIT4; PULSE THE ENABLE LINE... ; AND WAIT FOR BUSY FLAG TO CLEAR POP ACC RET ; ********************************************************** ; SUB TO WRITE A DATA WORD TO THE LCD ; DATA MUST BE PLACED IN R4 BY CALLING PROGRAM ; ********************************************************** WRLCDDATA: CLR LCD_E SETB LCD_RS ; SELECT SEND DATA CLR LCD_RW ; SELECT WRITE OPERATION PUSH ACC ; SAVE ACCUMULATOR MOV A, R4 ; PUT DATA BYTE IN ACC MOV C, ACC.4 ; LOAD HIGH NIBBLE ON DATA BUS MOV LCD_DB4, C ; ONE BIT AT A TIME USING... MOV C, ACC.5 ; BIT MOVE OPERATOINS MOV LCD_DB5, C MOV C, ACC.6 MOV LCD_DB6, C MOV C, ACC.7 MOV LCD_DB7, C SETB LCD_E ; PULSE THE ENABLE LINE CLR LCD_E MOV C, ACC.0 ; SIMILARLY, LOAD LOW NIBBLE MOV LCD_DB4, C MOV C, ACC.1 MOV LCD_DB5, C MOV C, ACC.2 MOV LCD_DB6, C MOV C, ACC.3 MOV LCD_DB7, C ACALL PULSEEWAIT4; PULSE THE ENABLE LINE... ; AND WAIT FOR BUSY FLAG TO CLEAR POP ACC RET ; ********************************************************** ; GENERATES A POSITIVE PULSE ON THE LCD ENABLE LINE. ; WAITS FOR THE BUSY FLAG TO CLEAR BEFORE RETURNING. ; ********************************************************** PULSEEWAIT4: CLR LCD_E SETB LCD_E ; PULSE THE ENABLE LINE CLR LCD_E MOV LCD_DATA, #0FFH ; PREPARE PORT FOR INPUT SETB LCD_RW ; PREPARE R/W FOR READ OPERATION PUSH ACC ; SAVE ACCUMULATOR CONTENTS PEW: SETB LCD_E ; START THE ENABLE PULSE MOV A, LCD_DATA; READ STATUS NIBBLE CLR LCD_E ; END ENABLE PULSE SETB LCD_E ; PRETEND READING STATUS LOW NIBBLE CLR LCD_E JB ACC.7, PEW ; LOOP WHILE BUSY FLAG IS SET POP ACC ; RESTORE ACCUMULATOR RET ; ********************************************************** ; SUB TAKES THE STRING IMMEDIATELY FOLLOWING THE CALL AND ; DISPLAYS ON THE LCD. STRING MUST BE TERMINATED WITH A ; NULL (0). ; ********************************************************** PRTLCD4: POP DPH ; POP RETURN ADDRESS INTO DPTR POP DPL PRTNEXT: CLR A ; SET OFFSET = 0 MOVC A, @A+DPTR ; GET CHR FROM CODE MEMORY CJNE A, #0, CHROK; IF CHR = 0 THEN RETURN SJMP RETPRTLCD CHROK: MOV R4, A ACALL WRLCDDATA ; SEND CHARACTER INC DPTR ; POINT AT NEXT CHARACTER AJMP PRTNEXT ; LOOP TILL END OF STRING RETPRTLCD: MOV A, #1H ; POINT TO INSTRUCTION AFTER STRING JMP @A+DPTR ; RETURN WITH A JUMP INSTRUCTION ; ********************************************************** ; SUB SETS THE CURSOR POSITION. ; ********************************************************** PLACECUR4: DEC ACC ; ACC=0 FOR LINE=1 JNZ LINE2 ; IF ACC=0 THEN FIRST LINE MOV A, B ADD A, #080H ; CONSTRUCT CONTROL WORD FOR LINE 1 SJMP SETCUR LINE2: MOV A, B ADD A, #0C0H ; CONSTRUCT CONTROL WORD FOR LINE 2 SETCUR: MOV R4, A ; PLACE CONTROL WORD ACALL WRLCDCOM4 ; ISSUE COMMAND RET SETCGRAM: PUSH B MOV B, #8 MUL AB ; multiply character number by 8 POP B ; b holds row number ADD A,B ; a holds CGRAM address ADD A,#40h ; convert to instruction MOV R4,A ; place instruction ACALL WRLCDCOM4 ; issue command RET ;MDELAY: ; MOV R5,#02DH ;here1: MOV R4,#0F2H ;here2: MOV R3,#0FFH ;here3: DJNZ R3,here3 ; DJNZ R4,here2 ; DJNZ R5,here1 ; RET ; ********************************************************** ; 1 MILLISECOND DELAY ROUTINE ; ********************************************************** MDELAY: PUSH ACC MOV A,#0A6H MD_OLP: INC A NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP JNZ MD_OLP NOP POP ACC RET BIG_DELAY: MOV R3,#0CH ; DELAY ROUTINE. X0B: MOV R2,#0FFH X1B: MOV R5,#0FFH X2B: DJNZ R5,X2B DJNZ R2,X1B DJNZ R3,X0B RET ; ********************************************************** ; THIS SUB READS ONE BYTE OF DATA FROM THE DS1307 ; ********************************************************** READ_BYTE: MOV BITCNT,#08H; SET COUNTER FOR 8-BITS DATA MOV A,#00H SETB SDA ; SET SDA HIGH TO ENSURE LINE ; FREE READ_BITS: SCL_HIGH ; TRANSITION SCL LOW-TO-HIGH MOV C,SDA ; MOVE DATA BIT INTO CARRY RLC A ; ROTATE CARRY-BIT INTO ACC.0 CLR SCL ; TRANSITION SCL HIGH-TO-LOW DJNZ BITCNT,READ_BITS ; LOOP FOR 8-BITS JB LASTREAD,ACKN ; CHECK TO SEE IF THIS IS ; THE LAST READ CLR SDA ; IF NOT LAST READ SEND ACK-BIT ACKN: SCL_HIGH ; PULSE SCL TO TRANSMIT ACKNOWLEDGE CLR SCL ; OR NOT ACKNOWLEDGE BIT RET ; ********************************************************** ; SUB SENDS START CONDITION ; ********************************************************** SEND_START: SETB _2W_BUSY ; INDICATE THAT 2-WIRE CLR ACK ; OPERATION IS IN PROGRESS CLR BUS_FLT ; CLEAR STATUS FLAGS JNB SCL,FAULT JNB SDA,FAULT SETB SDA ; BEGIN START CODITION SCL_HIGH CLR SDA ACALL DELAY CLR SCL RET FAULT: SETB BUS_FLT RET ; ********************************************************** ; SUB SENDS STOP CONDITION ; ********************************************************** SEND_STOP: CLR SDA SCL_HIGH SETB SDA CLR _2W_BUSY RET ; ********************************************************** ; SUB DELAYS THE BUS ; ********************************************************** DELAY: NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP ; DELAY FOR BUS TIMING RET ; ********************************************************** ; THIS SUB SENDS 1 BYTE OF DATA TO THE DS1307 ; CALL THIS FOR EACH REGISTER SECONDS TO YEAR ; ACC MUST CONTAIN DATA TO BE SENT TO CLOCK ; ********************************************************** SEND_BYTE: MOV BITCNT,#08H; SET COUNTER FOR 8-BITS SB_LOOP: JNB ACC.7,NOTONE; CHECK TO SEE IF BIT-7 OF SETB SDA ; ACC IS A 1, AND SET SDA HIGH JMP ONE NOTONE: CLR SDA ; CLR SDA LOW ONE: SCL_HIGH ; TRANSITION SCL LOW-TO-HIGH RL A ; ROTATE ACC LEFT 1-BIT CLR SCL ; TRANSITION SCL LOW-TO-HIGH DJNZ BITCNT,SB_LOOP; LOOP FOR 8-BITS SETB SDA ; SET SDA HIGH TO LOOK FOR SCL_HIGH ; ACKNOWLEDGE PULSE CLR ACK JNB SDA,SB_EX ; CHECK FOR ACK OR NOT ACK SETB ACK ; SET ACKNOWLEDGE FLAG FOR ; NOT ACK SB_EX: ACALL DELAY ; DELAY FOR AN OPERATION CLR SCL ; TRANSITION SCL HIGH-TO-LOW ACALL DELAY ; DELAY FOR AN OPERATION RET ; ********************************************************** ; SUB READS THE CLOCK AND WRITES IT TO THE SCRATCHPAD MEMORY ; ON RETURN FROM HERE DATE & TIME DATA WILL BE STORED IN THE ; DATE & TIME REGISTERS FROM 24H (SECS) TO 2AH (YEAR) ; ALARM SETTINGS IN REGISTERS 2CH(HRS) AND 2DH(MINUTES). ; ********************************************************** READ_CLOCK: MOV R1,#24H ; SECONDS STORAGE LOCATION MOV BYTECNT,#00H CLR LASTREAD ACALL SEND_START MOV A,#DS1307W ACALL SEND_BYTE MOV A,#00H ACALL SEND_BYTE ACALL SEND_STOP ACALL SEND_START MOV A,#DS1307R ACALL SEND_BYTE READ_LOOP: MOV A,BYTECNT CJNE A,#09H,NOT_LAST SETB LASTREAD NOT_LAST: ACALL READ_BYTE MOV @R1,A MOV A,BYTECNT CJNE A,#00H,NOT_FIRST MOV A,@R1 CLR ACC.7 ; ENSURE OSC BIT=0 (ENABLED) MOV @R1,A NOT_FIRST: INC R1 INC BYTECNT MOV A,BYTECNT CJNE A,#0AH,READ_LOOP ACALL SEND_STOP RET ; ********************************************************** ; MOST OF THE REAL WORK IS DONE IN THE ADJUST ROUTINE ; THIS ROUTINE SIMPLY CHECKS TO SEE IF THE NUMBER IS ; ZERO OR ENDS IN NINE. ; ********************************************************** CHECK_BCD: MOV A,R4 ; SAVES THE NUMBER TO R4 CLR C ; CLEARS CARRY BIT ADD A,#67H ; CHECKS TO SEE IF EQUAL 99 JC ZERO ; IF EQUAL THEN BECOMES 0 MOV A,R4 ; GETS ORIGINAL NUMBER ANL A,#0FH ; GETS RID OF UPPER 4 BITS CLR C ; CLEARS CARRY BIT ADD A,#0F7H ; CHECKS TO SEE IF NUMBER ENDS IN 9 JC ADJUST ; IF LARGER ADJUST IT MOV A,R4 ; GET ORIGINAL NUMBER INC A ; ITS UNDER 9 AND NOT 0 SO INCREASE RET ; BY 1 AND GO BACK. ; ********************************************************** ; BCD CONVERSION ROUTINE. ; ********************************************************** ADJUST: MOV A,R4 ; GET ORIGINAL NUMBER SWAP A ; CHANGE UPPER BITS TO LOWER BITS ANL A,#0FH ; GET RID OF WHAT WAS LOWER BITS INC A ; INCREASE BY ONE SWAP A ; SWITCH THE UPPER AND LOWER BITS BACK RET ; GO BACK WITH NEW NUMBER ZERO: ; IF NUMBER IS ZERO SEND BACK A ZERO MOV A,#00000000B RET ; ********************************************************** ; THIS ROUTINE CHECKS TO SEE IF THE LOWER 4 BITS ARE ; EQUAL TO ZERO. IF THEY ARE THEN A STRAIGHT DECREASE ; CAN BE DONE. IF NOT THEN CONVERT. ; ********************************************************** CHECK_BCD_DOWN: MOV A,R4 ; SAVE ORIGINAL NUMBER ANL A,#0FH ; GET RID OF UPPER FOUR BITS CJNE A,#00000000B,GO_ON_BACK ;DO LOWER BITS =0 ? MOV A,R4 ; GET ORIGINAL NUMBER SUBB A,#06H ; CONVERT IT TO A BINARY NUMBER RET ; ********************************************************** ; IF THE NUMBER ENDS IN NUMBER LESS THAN 9 THEN ; GO BACK AND, DO A NORMAL DECREMENT. ; ********************************************************** GO_ON_BACK: MOV A,R4 ; GET ORIGINAL NUMBER RET ; GO BACK ; ********************************************************** ; END OF PROGRAM ; ********************************************************** END