; Copyright 2005 TMD Innovations, LLC ; ; ; Meter Clock ; ; ; Written by Len Bayles ; ; ; Timer 0 Running Mode 1 ; ; Preload Value 0xEC8A (Xtal = 12 Mhz .01 delay) ; Count goes in R7 for Radio Pulse Delay ; Count goes in R6 For Switch Delay ; ; ; Timer 1 Running Mode 1 as Counter ; ; Preload Value 0xFF/0xFF (Driven as an external counter 1PPS) ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; $NOMOD51 $INCLUDE(89c2051.mcu) SECONDS DATA 30H MINUTES DATA 31H HOURS DATA 32H DAC_DATA BIT P3.0 ; D2A DAC_CLK BIT P3.1 ; D2A DAC_LOAD BIT P3.2 ; D2A RED BIT P1.0 ; LED GREEN BIT P1.1 ; LED MODE_BUTTON BIT P1.2 ; MODE BUTTON SET_BUTTON BIT P1.3 ; SET BUTTON SET_PRE BIT 04H SET_SW BIT 05H MODE_PRE BIT 06H MODE_SW BIT 07H RTC_UPDATE BIT 03H SDA BIT P3.4 ; I2C SCL BIT P3.3 ; I2C DS1307 DATA 0D0H ; DS1307 Slave Address DAC_RANGE EQU 00H STACK EQU 50H TH0_PRELOAD DATA 0ECH ; Timer 0 preload value for 10ms TL0_PRELOAD DATA 08AH ; Timer 0 preload value for 10ms ORG 0000H SJMP INIT ORG 000BH ; Timer 0 Interrupt CLR EA ; Disable Interupts CLR TR0 ; Stop Timer 0 SJMP TIME0 ; Jump to routine ORG 001BH ; Timer 1 Interrupt CLR EA ; Disable Interupts CLR TR1 ; Stop Timer 1 PUSH PSW PUSH ACC MOV TH1, #0FFH ; Set to 0xFF Causes timer 1 Interupt each pps MOV TL1, #0FFH ; Set to 0xFF Causes timer 1 Interupt each pps MOV A, SECONDS ; Move Seconds to A ADD A, #01H ; Increment Seconds DA A ; BCD Adjust CJNE A, #60H, SEC_DONE ; Seconds at 60? MOV SECONDS, #00H ; Clear Seconds MOV A, MINUTES ; Move Minutes to A ADD A, #01H ; Increment Minutes DA A ; BCD Adjust CJNE A, #60H, MIN_DONE ; Minutes at 60? MOV MINUTES, #00H ; Clear Minutes MOV A, HOURS ; Move Hours to A ADD A, #01H ; Increment Hours DA A ; BCD Adjust CJNE A, #24H, HRS_DONE ; Hours at 24? MOV HOURS, #00H ; Clear Hours SJMP TIME1_DONE SEC_DONE: MOV SECONDS, A ; Copy seconds back from A SJMP TIME1_DONE MIN_DONE: MOV MINUTES, A ; Copy Minutes back from A SJMP TIME1_DONE HRS_DONE: MOV HOURS, A ; Copy Hours back from A TIME1_DONE: CJNE R5, #00, TIME1_DONE_ALL ; If we're in setup jump around INC INC 37H ; INCrement "out of mode" count TIME1_DONE_ALL: POP ACC POP PSW SETB EA ; Enable Interupts SETB TR1 ; Start Timer 1 RETI TIME0: ; Timer 0 Interrupt Handler INC R7 ; Increment R7 (10ms count) INC R6 ; Increment R6 (Debounce) NOP NOP ; Nop's used to tune 10ms NOP NOP NOP MOV TL0, #TL0_PRELOAD ; Set T0 Low preload MOV TH0, #TH0_PRELOAD ; Set T0 High preload SETB EA ; Enable Interupts SETB TR0 ; Start Timer 0 RETI INIT: CLR DAC_DATA ; Clear DATA Bit CLR DAC_CLK ; Clear CLOCK Bit SETB DAC_LOAD ; Set LOAD Bit CLR RED ; Turn off RED LED CLR GREEN ; Turn off GREEN LED MOV SP, #STACK ; Set stack pointer MOV R7, #00H ; Clear Register 7 (10 ms count) MOV R6, #00H ; Clear Register 6 (10 ms debounce count) MOV R5, #00H ; Clear Register 5 (MODE) MOV 20H, #00H ; Clear Flag Bits MOV SECONDS, #00H ; Clear Seconds MOV MINUTES, #00H ; Clear Minutes MOV HOURS, #00H ; Clear Hours MOV TL0, #TL0_PRELOAD ; Set T0 Low preload MOV TH0, #TH0_PRELOAD ; Set T0 High preload MOV TL1, #0FFH ; Set to 0xFF Causes timer 1 Interupt each pps MOV TH1, #0FFH ; Set to 0xFF Causes timer 1 Interupt each pps MOV TMOD, #51H ; Set Timer 0 to Mode 1 ; Set Timer 1 to Mode 1 Counter SETB ET0 ; Enable Timer 0 Interupt SETB ET1 ; Enable Timer 1 Interupt SETB EA ; Enable Interupts SETB TR0 ; Start Timer 0 SETB TR1 ; Start Timer 1 JB P3.7, INIT_1 ; Ground P3.7 Pin to Re-init DS1307 ACALL DS1307_SET_STATE ; Sets to known state INIT_1: ACALL DS1307_READ ; Read DS1307 to get current setup ACALL DS1307_CKECK_STATE ; Check to see if DS1307 needs to be init MAIN: ACALL DISPLAY ACALL DISPLAY_MODE ACALL SET_SWITCH ACALL MODE_SWITCH ACALL CHECK_RTC_UPDATE SJMP MAIN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; DISPLAY ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DISPLAY: MOV A, R5 ; Move Mode to A for compare CJNE A, #04H, DISPLAY_RUN ; Jump if not in calabrate mode MOV A, #00H ; DAC A (Seconds) MOV B, #0ECH ACALL SET_DAC MOV A, #01H ; DAC B (Minutes) MOV B, #0ECH ACALL SET_DAC MOV A, #02H ; DAC C (Hours) MOV B, #0E6H ACALL SET_DAC RET DISPLAY_RUN: MOV A, SECONDS ; ANL A, #0FH ; Mask out Low Nibble MOV R0, A ; Store temp in R0 MOV A, SECONDS ; SWAP A ; Swap nibbles ANL A, #0FH ; Mask MOV B, #0AH ; 10 x MUL AB ADD A, R0 ; Add low nibble back in MOV B, #04H ; Scale for DAC MUL AB MOV B, A ; Move data vale to B MOV A, #00H ; DAC A ACALL SET_DAC MOV A, MINUTES ; ANL A, #0FH ; Mask out Low Nibble MOV R0, A ; Store temp in R0 MOV A, MINUTES ; SWAP A ; Swap nibbles ANL A, #0FH ; Mask MOV B, #0AH ; 10 x MUL AB ADD A, R0 ; Add low nibble back in MOV B, #04H ; Scale for DAC MUL AB MOV B, A ; Move data vale to B MOV A, #01H ; DAC B ACALL SET_DAC MOV A, HOURS ; ANL A, #0FH ; Mask out Low Nibble MOV R0, A ; Store temp in R0 MOV A, HOURS ; SWAP A ; Swap nibbles ANL A, #0FH ; Mask MOV B, #0AH ; 10 x MUL AB ADD A, R0 ; Add low nibble back in MOV B, #0AH ; Scale for DAC 10x MUL AB MOV B, A ; Move data vale to B MOV A, #02H ; DAC C ACALL SET_DAC RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; DISPLAY_MODE ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DISPLAY_MODE: MOV A, R5 ; Move Mode to A for compare DSP_M_0: JNZ DSP_M_1 CLR RED ; Clear LEDS for Mode 0 CLR GREEN RET DSP_M_1: CJNE A, #01H, DSP_M_2 SETB RED ; Trun on RED LED for mode 1 CLR GREEN RET DSP_M_2: CJNE A, #02H, DSP_M_3 CLR RED SETB GREEN ; Trun on Green LED for mode 2 RET DSP_M_3: CJNE A, #03H, DSP_M_4 SETB RED ; Turn on both for Orange, Mode 3 SETB GREEN RET DSP_M_4: MOV A, #32H ; Value for 500ms blink CLR C ; Clear carry for subtract SUBB A, R7 ; Subtract 10ms count from A JNC DSP_M_DONE ; If carry == 0 not at end of delay MOV R7, #00H ; Clear R7 for next delay period MOV A, #03H ; Load A with Bit Mask ANL A, R4 ; Mask out upper 6 bits JNZ DSP_M_4_DO ; Only count 1 through 3 MOV A, #01H ; Start again at 1 (After Increment) DSP_M_4_DO: MOV R4, A ; Put count Back in R4 RRC A ; Rotate low bit into C MOV RED, C ; Move C to Red LED RRC A ; Rotate next bit into C MOV GREEN, C ; Move C to Green LED INC R4 ; Increment R4 to change LED colors DSP_M_DONE: RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; SET_DAC - Enter with Address in A and Data in B ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SET_DAC: ANL A, #07H ; Mask out address RL A ; Shift Address Left for DAC Range bit ORL A, #DAC_RANGE ; OR in DAC range bit SWAP A ; Swap Nibbles to get A ready for shift MOV R0, #04H ; 4 bits to send ACALL DAC_LOOP MOV A, B ; Move data byte to A MOV R0, #08H ; 8 bits to send ACALL DAC_LOOP CLR DAC_LOAD ; Lower and then raise LOAD SETB DAC_LOAD ; Bit to update dac RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; DAC_LOOP - A contains DATA, R0 contains loop count ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DAC_LOOP: RLC A ; Rotate a bit through carry JC WRITE_ONE ; Jump if we need to set data bit CLR DAC_DATA ; Otherwise clear data bit SJMP DO_CLOCK ; Then do clock pulse WRITE_ONE: SETB DAC_DATA ; Set data bit DO_CLOCK: SETB DAC_CLK ; Raise clock bit CLR DAC_CLK ; Clear clock bit DJNZ R0, DAC_LOOP ; Loop until all bits sent RET ;############################################################################## ; ; SET_SWITCH Checks Set Switch ; ;############################################################################## SET_SWITCH: JNB MODE_BUTTON, SET_SWITCH_END ; Jump out if Mode switch pushed JB MODE_PRE, SET_SWITCH_END ; Jump out if Mode switch in debounce JB MODE_SW, SET_SWITCH_END ; Jump out if Mode switch in progress MOV A, R5 ; Copy R5 to A for Mode Check JZ SET_SWITCH_END ; Not in Setup Mode if = 0 JNB SET_BUTTON, SET_PUSH ; Set Switch Pushed JNB SET_PRE, SET_UP ; Not In Debounce MOV A, R6 ; Copy Debounce Count to A ADD A, #0FCH ; Add 252 to A Will set carry if 4 or over JNC SET_SWITCH_END ; Jump out and wait, still in Debounce CLR SET_PRE ; Must be noise, clear bit SJMP SET_SWITCH_END SET_UP: CLR SET_SW ; Button up, clear Set bit SJMP SET_SWITCH_END SET_PUSH: JNB SET_SW, SET_DEBOUNCE ; SET_SW Not set, do debounce MOV A, R6 ; Copy Debounce Count to A ADD A, #0CDH ; Add 205 to A Will set carry if 50 or over JNC SET_SWITCH_END ; Jump out and wait MOV R6, #00 ; Zero Out Bounce Timer ACALL DO_SET SJMP SET_SWITCH_END SET_DEBOUNCE: ; Debounce Routine JNB SET_PRE, SET_DEB_START ; If SET_PRE not set Initiliaze Debounce MOV A, R6 ; Copy Debounce Count to A ADD A, #0FDH ; Add 253 to A Will set carry if 3 or over JNC SET_SWITCH_END ; Jump out and wait SET_DEB_DONE: SETB SET_SW CLR SET_PRE MOV R6, #00 ; Zero Out Bounce Timer SETB RTC_UPDATE ; Set flag for RTC Update ACALL DO_SET SJMP SET_SWITCH_END SET_DEB_START: SETB SET_PRE ; Set "Set" Pre Bit (Delay For Bounce) MOV R6, #00 ; Zero Out Bounce Timer SET_SWITCH_END: RET ;############################################################################## ; ; MODE_SWITCH Checks Mode Switch ; ;############################################################################## MODE_SWITCH: JNB MODE_BUTTON, MODE_PUSH ; Mode Switch Pushed JNB MODE_PRE, MODE_UP ; Not In Debounce MOV A, R6 ; Copy Debounce Count to A ADD A, #0FCH ; Add 252 to A Will set carry if 4 or over JNC MODE_SWITCH_END ; Jump out and wait, still in Debounce CLR MODE_PRE ; Must be noise, clear bit SJMP MODE_SWITCH_END MODE_UP: CLR MODE_SW ; Button up, clear Mode bit SJMP MODE_SWITCH_END MODE_PUSH: JNB MODE_SW, MODE_DEBOUNCE ; MODE_SW Not set, do debounce MOV A, R6 ; Copy Debounce Count to A ADD A, #0CDH ; Add 205 to A Will set carry if 50 or over JNC MODE_SWITCH_END ; Jump out and wait MOV R6, #00 ; Zero Out Bounce Timer INC R5 ; Increment Mode CJNE R5, #05H, MODE_SWITCH_END ; Only allow mode 0 through 4 MOV R5, #00H ; Set mode to 0 SJMP MODE_SWITCH_END MODE_DEBOUNCE: ; Debounce Routine JNB MODE_PRE, MODE_DEB_START ; If MODE_PRE not set Initiliaze Debounce MOV A, R6 ; Copy Debounce Count to A ADD A, #0FDH ; Add 253 to A Will set carry if 3 or over JNC MODE_SWITCH_END ; Jump out and wait MODE_DEB_DONE: SETB MODE_SW CLR MODE_PRE MOV R6, #00 ; Zero Out Bounce Timer MOV 37H, #00H ; Clear count on "end of setup mode" INC R5 ; Increment Mode CJNE R5, #05H, MODE_SWITCH_END ; Only allow mode 0 through 4 MOV R5, #00H ; Set mode to 0 SJMP MODE_SWITCH_END MODE_DEB_START: SETB MODE_PRE ; Set Mode Pre Bit (Delay For Bounce) MOV R6, #00 ; Zero Out Bounce Timer MODE_SWITCH_END: RET ;############################################################################## ; ; DO_SET Looks at Mode and Increments settings ; ; Set Modes ; ; 1. Hour Set ; 2. Minute Set ; 3. Seconds Zero ; 4. Meter Calabrate ; ;############################################################################## DO_SET: MOV A, R5 ; Move Mode to A for compare DO_SET_1: CJNE A, #01H, DO_SET_2 ACALL SET_HOUR RET DO_SET_2: CJNE A, #02H, DO_SET_3 ACALL SET_MIN RET DO_SET_3: CJNE A, #03H, DO_SET_4 ACALL SET_SEC RET DO_SET_4: MOV R7, #00H ; Clear Register 7 (10 ms count) For Blink LED MOV R4, #01H ; Start with RED LED RET ;############################################################################## ; ; SET_HOUR Set Hour ; ;############################################################################## SET_HOUR: MOV A, HOURS ; Move Hours to A ADD A, #01H ; Increment Hours DA A ; BCD Adjust CJNE A, #24H, SET_HOUR_DONE ; Hours at 24? MOV A, #00H ; Clear Hours SET_HOUR_DONE: MOV HOURS, A RET ;############################################################################## ; ; SET_MIN Set Minutes ; ;############################################################################## SET_MIN: MOV A, MINUTES ; Move Minutes to A ADD A, #01H ; Increment Minutes DA A ; BCD Adjust CJNE A, #60H, SET_MIN_DONE ; Minutes at 60? MOV A, #00H ; Clear Minutes SET_MIN_DONE: MOV MINUTES, A ; Move A to Minutes RET ;############################################################################## ; ; SET_SEC Zero Seconds Count ; ;############################################################################## SET_SEC: MOV SECONDS, #00H RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; CHECK_RTC_UPDATE - See if the RTC needs updating ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; CODE_CHECK CHECK_RTC_UPDATE: JNB RTC_UPDATE, CHECK_RTC_UPDATE_END ; Jump out if Update flag 0 MOV A, 37H ; Seconds out of "setup mode" CLR C ; Clear carry flag for sub SUBB A, #0AH ; Subtract 10 JC CHECK_RTC_UPDATE_END ; Not been 10 seconds yet CLR RTC_UPDATE ; Move Time and config data ro I2C Scratchpad, then update MOV 22H, 30H ; Copy Running Sec to RTC Scratchpad MOV 23H, 31H ; Copy Running Min to RTC Scratchpad MOV 24H, 32H ; Copy Running Hrs to RTC Scratchpad MOV 2CH, #00H ; Copy Config Bts to RTC Scratchpad MOV 2DH, #00H ; Copy Running TZ to RTC Scratchpad ACALL DS1307_WRITE ; Update The RTC CHECK_RTC_UPDATE_END: RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; DS1307_CKECK_STATE - Check to see if the DS1307 has been Initilized ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DS1307_CKECK_STATE: MOV A, 2AH ; Signature Byte Should be 0xAA CJNE A, #0AAH, DS1307_SET_STATE MOV A, 2BH ; Signature Byte Should be 0x55 CJNE A, #055H, DS1307_SET_STATE SJMP DS1307_CKECK_STATE_UPDATE DS1307_SET_STATE: MOV 22H, #000H MOV 23H, #000H MOV 24H, #000H MOV 25H, #007H MOV 26H, #001H MOV 27H, #001H MOV 28H, #005H MOV 29H, #010H MOV 2AH, #0AAH MOV 2BH, #055H MOV 2CH, #000H MOV 2DH, #000H ACALL DS1307_WRITE DS1307_CKECK_STATE_UPDATE: MOV 30H, 22H ; Copy RTC Scratchpad Running Sec MOV 31H, 23H ; Copy RTC Scratchpad Running Min MOV 32H, 24H ; Copy RTC Scratchpad Running Hrs RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; DS1307_READ ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DS1307_READ: ; Setup the DS1307's memory ptr to read at address 0 ACALL I2C_START ; Send I2C Start MOV A, #DS1307 ; Move the "slave address" to A ACALL I2C_WRITE ; Write Byte JNZ DS1307_READ_ERROR ; If A = 1 we didn't get an ack MOV A, #00H ; Move 0x00 "memory read address" to A ACALL I2C_WRITE ; Write Byte JNZ DS1307_READ_ERROR ; If A = 1 we didn't get an ack ACALL I2C_STOP ; Send I2C Stop ; Now read the DS1307 were the memory address ptr is set ACALL I2C_START ; Send I2C Start MOV A, #DS1307 ; Move the "slave address" to A SETB ACC.0 ; Set read bit in "slave address" ACALL I2C_WRITE ; Write Byte JNZ DS1307_READ_ERROR ; If A = 1 we didn't get an ack MOV R0, #22H ; Ptr to Memory Address 0x22 MOV R1, #0CH ; We're going to read 12 bytes DS1307_READ_LOOP: ACALL I2C_READ ; Read a byte INC R0 ; Increment our memory ptr DJNZ R1, DS1307_READ_LOOP ; Got all 12 bytes? ACALL I2C_STOP ; Send I2C Stop RET DS1307_READ_ERROR: RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; DS1307_WRITE ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DS1307_WRITE: ACALL I2C_START ; Send I2C Start MOV A, #DS1307 ; Move the "slave address" to A ACALL I2C_WRITE ; Write Byte JNZ DS1307_WRITE_ERROR ; If A = 1 we didn't get an ack MOV A, #00H ; Move 0x00 "memory read address" to A ACALL I2C_WRITE ; Write Byte JNZ DS1307_WRITE_ERROR ; If A = 1 we didn't get an ack MOV R0, #22H ; Ptr to Memory Address 0x22 MOV R1, #0CH ; We're going to read 12 bytes DS1307_WRITE_LOOP: MOV A, @R0 ACALL I2C_WRITE ; Write a byte JNZ DS1307_WRITE_ERROR ; If A = 1 we didn't get an ack INC R0 ; Increment our memory ptr DJNZ R1, DS1307_WRITE_LOOP ; Wrote all 12 bytes? ACALL I2C_STOP ; Send I2C Stop RET DS1307_WRITE_ERROR: RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; I2C_WRITE - Byte in A gets sent (R2 Loop counter) ; ; Return Value in A (0 Good) (1 Fail) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; I2C_WRITE: MOV R2, #08H ; We're going to do this for 8 bits I2C_WRITE_LOOP: JB ACC.7, I2C_WRITE_ONE ; If A bit 7 one - set SDA to one CLR SDA ; Otherwise clear bit SJMP I2C_WRITE_NOW I2C_WRITE_ONE: SETB SDA ; It's high I2C_WRITE_NOW: ACALL I2C_DELAY ; Settle delay ACALL I2C_STROBE ; Strobe RL A ; Shift left through byte DJNZ R2, I2C_WRITE_LOOP ; Do 8 times SETB SDA ; Raise SDA for read ACALL I2C_DELAY ; Settle delay ACALL I2C_READ_BIT ; Read Ack from Slave RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; I2C_READ ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; I2C_READ: SETB SDA ; Set SDA high for Read MOV A, #00H ; Clear A MOV R2, #08H ; Read 8 Bits I2C_READ_LOOP: PUSH ACC ; Save A, return will be in A ACALL I2C_READ_BIT ; Read Bit from Slave JZ I2C_READ_ZERO POP ACC ; Get A back from stack SETB ACC.0 ; Set low bit RL A ; Rotate left SJMP I2C_READ_DONE I2C_READ_ZERO: POP ACC ; Get A back from stack RL A ; Read 0 just rotate I2C_READ_DONE: DJNZ R2, I2C_READ_LOOP ; Read all 8 bits yet? RR A ; Undo last rotate MOV @R0, A ; Put received byte in add pointed to by R0 CJNE R1, #01H, I2C_READ_ACK ; Is this our last byte to read? SETB SDA ; Do a NOT ACK SJMP I2C_READ_ACK_STROBE I2C_READ_ACK: CLR SDA ; Lower SDA for ACK I2C_READ_ACK_STROBE: ACALL I2C_DELAY ACALL I2C_STROBE RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; I2C_START ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; I2C_START: CLR SDA ; Lower Data Line (SDA) ACALL I2C_DELAY CLR SCL ; Lower Clock Line (SCL) ACALL I2C_DELAY RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; I2C_STOP ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; I2C_STOP: CLR SDA ; Lower Data Line (SDA) ACALL I2C_DELAY SETB SCL ; Raise Clock Line (SCL) ACALL I2C_DELAY SETB SDA ; Raise Data Line (SDA) ACALL I2C_DELAY RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; I2C_STROBE ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; I2C_STROBE: SETB SCL ; Raise Clock Line (SCL) ACALL I2C_DELAY CLR SCL ; Lower Clock Line (SCL) ACALL I2C_DELAY RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; I2C_READ_BIT ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; I2C_READ_BIT: SETB SCL ; Raise Clock Line (SCL) ACALL I2C_DELAY JB SDA, I2C_READ_BIT_ONE ; Test SDA - Jump if one MOV A, #00H ; SDA Low, set A = 0 SJMP I2C_READ_BIT_DONE I2C_READ_BIT_ONE: MOV A, #01H ; SDA high, set A = 1 I2C_READ_BIT_DONE: CLR SCL ; Lower Clock Line (SCL) ACALL I2C_DELAY RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; I2C_DELAY ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; I2C_DELAY: NOP RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; END