nobody968
Newbie level 3
Hello all:
This is my first post on this board, I was looking for a 7 digit clock project to built as a hobby project I found one at this board along the code, originally the project was for Common Cathode, but the author also provided alternate code for common anode. I did build the common anode version as common cathode 7 digits are not available in my country. However I am having a strange problem that during the AM hours the clock shows digits from 1 - 9 while hour ten digit is blanc, however during PM timings instead the the hour 10 digit goes blanc it shows 8, I have been looking into the code but couldnt seem to find the problem.
I am posting the code here, and would really appreciate any help, to me it seems that there is only one line of code which is causing the problem, as during the AM the hour ten digit is blanc.
This is my first post on this board, I was looking for a 7 digit clock project to built as a hobby project I found one at this board along the code, originally the project was for Common Cathode, but the author also provided alternate code for common anode. I did build the common anode version as common cathode 7 digits are not available in my country. However I am having a strange problem that during the AM hours the clock shows digits from 1 - 9 while hour ten digit is blanc, however during PM timings instead the the hour 10 digit goes blanc it shows 8, I have been looking into the code but couldnt seem to find the problem.
I am posting the code here, and would really appreciate any help, to me it seems that there is only one line of code which is causing the problem, as during the AM the hour ten digit is blanc.
Code:
; Adding AM/PM -ok (11-Aug-2009
; fixed with this - ok (23-July-2009)
; Common Cathode ( For Common Anode Change Table And Search And Change (bsf PORTC,7) to (bcf PORTC,7)
; Blanking First Digit If Zero (AM/PM Indicator Will Be Done Later)
; Shrinking - Phase1 - ok
; Adding Keys To Adjust Time - ok
; Added Hour + And Hour - And Min+ And Min- (from 4 keys 1=setup 2=+ 3=- 4=Done)
; Update From RTC only Done Hourly After Time Tics xx:59:59 -> xx:00:00 (to Avoide Flicker) Using 4Mhz
;########################################################################################################
;########################################################################################################
;################################# Wish To Do List #########################################
;
;
;
;########################################################################################################
;########################################################################################################
LIST p=16F877a ;tell assembler what chip we are using
include "P16F877a.inc" ;include the defaults for the chip
ERRORLEVEL 0, -302 ;suppress bank selection messages
; __config 0x3939 ;sets the configuration settings (oscillator type etc.)for 16F87x
__config 0x3F39
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;rtc Read Write Address
I2C_PORT Equ PORTB
I2C_TRIS Equ TRISB
Chip_Read Equ 0xD1 ;DS1307 address values
Chip_Write Equ 0xD0
Buf_Size Equ 0x03 ;buffer 3 bytes long
ErrFlag Equ 0x00
StartFlag Equ 0x01 ;flags used for received bit
One Equ 0x02
Zero Equ 0x03
Time Equ 0x04 ;flag for setting time, line1 or line2
#define SCL 1
#define SDA 2
CBLOCK 0x20
Secs
Mins
Hrs
DisplayPosition ; Store Location Here - should Find Another Way
DispStatus ;bit0 - colon 2- Update Time 3-Am/Pm
tempcount
tempcount1
; For Delay
count1 ;used in delay routine
counta ;used in delay routine
countb ;used in delay routine
; I2C Temps
count ;used in looping routines
DAT_VAL
_N ; Store Bits Sended I2C
N ; Buff Size N Number Of Time 2 Read Or Write
I2C_Address ; DS1307 memory address to be accessed
Data_Page ; DS1307 page, 0-7
InputByte ; byte read from DS1307 is stored in this register
OutputByte ; used for holding byte to be output to DS1307
I2Cflags ; flag bit register
HourTen
HourOne
MinOne
MinTen
SecsTen
SecsOne
; Store W and Status Register, In Time Of interrupt
STATUS_TMP ;
W_TMP ;
ENDC
Reset ORG 0x00
GoTo Start
org 0x04 ;
GoTo INTRUPT ;
;########################################################################################################
;########################################################################################################
;-- Table
;########################################################################################################
;########################################################################################################
TABLA ADDWF PCL,F
; Dp G F E D C B A (RC7-0) 0-On 1-Off
;Common Cathode Also Have To Change (bcf PORTC,7) to (bsf PORTC,7)
; dig1pm (bcf PORTC,7) to (bsf PORTC,7)
; RETLW B'00111111' ; == 0
; RETLW B'00000110' ; == 1
; RETLW B'01011011' ; == 2
; RETLW B'01001111' ; == 3
; RETLW B'01100110' ; == 4
; RETLW B'01101101' ; == 5
; RETLW B'01111101' ; == 6
; RETLW B'00000111' ; == 7
; RETLW B'01111111' ; == 8
; RETLW B'01101111' ; == 9
; RETLW B'01000000' ; - 0x0A
; RETLW B'01110100' ; h 0x0B
; RETLW B'01010100' ; n 0x0C
; RETLW 0x00
; Common Anode Also Have To Change (bsf PORTC,7) to (bcf PORTC,7)
; dig1pm (bsf PORTC,7) to (bcf PORTC,7)
RETLW B'11000000' ; == 0
RETLW B'11111001' ; == 1
RETLW B'10100100' ; == 2
RETLW B'10110000' ; == 3
RETLW B'10011001' ; == 4
RETLW B'10010010' ; == 5
RETLW B'10000010' ; == 6
RETLW B'11111000' ; == 7
RETLW B'10000000' ; == 8
RETLW B'10010000' ; == 9
RETLW B'10111111' ; - 0x0A
RETLW B'10001011' ; h 0x0B
RETLW B'10101011' ; n 0x0C
RETLW 0x00
;########################################################################################################
;########################################################################################################
;-- End Of Table
;########################################################################################################
;########################################################################################################
; start interrupt by saving w and status registers before altered by interrupt routine
;########################################################################################################
;########################################################################################################
INTRUPT movwf W_TMP ; w to w_tmp storage
swapf STATUS,w ; status to w
movwf STATUS_TMP ; status in status_tmp
bcf STATUS,RP0 ; select memory bank 0
btfss INTCON,T0IF ; TMRO overflow interrupt flag
GoTo RECLAIM
;---------------------------------------------
;-- Digits To Display
;---------------------------------------------
movf TMR0,w ; timer value
; freq is 4MHz/4/4/(256(-8+2))=1kHz
nop
nop ; synchronise counter read with divide by 4 ie add two cycles
addlw 0x8 ; add to timer register and takes 2 cycles to start counting
movwf TMR0 ; place in timer (the two cycles plus 2-cycle delay = 4cycles)
bcf INTCON,T0IF ; clear TMRO interrupt flag
; 1000 ms = 1 sec So 500 ms to Clear Colon And The Next To Update Colon and Time
incfsz tempcount,f ;
GoTo CHK_UPD ;
incf tempcount1,f ;
CHK_UPD movf tempcount1,w ; 500 milli Second Check And Add Colon
xorlw 0x01 ;
btfss STATUS,Z ;
GoTo MPX_DSP ; Not Yet So Multiplex Display
movf tempcount,w ;
xorlw 0xF4 ;
;
btfss STATUS,Z ;
GoTo MPX_DSP ;
clrf tempcount ;
clrf tempcount1 ;
incf tempcount,f ;
btfsc DispStatus,0 ;
GoTo COL_CR ; If Already On Then Clear Colon
bsf DispStatus,0 ;
bsf DispStatus,2 ; Time For Clock Update
GoTo MPX_DSP
COL_CR bcf DispStatus,0 ;
;########################################################################################################
;########################################################################################################
;-- Time To Multiplex Display
;########################################################################################################
;########################################################################################################
MPX_DSP BTFSC DisplayPosition,0 ; See Which Digit's On And Switch Accordingly
GoTo Dig2 ;If digit 1 On GoTo Digit 2
BTFSC DisplayPosition,1
GoTo Dig3 ;If digit 2 On GoTo Digit 3
BTFSC DisplayPosition,2
GoTo Dig4 ;If digit 3 On GoTo Digit 4
BTFSC DisplayPosition,3
GoTo Dig5 ;If digit 4 On GoTo Digit 5
BTFSC DisplayPosition,4
GoTo Dig6 ;If digit 5 On GoTo Digit 6 If 6 Then Digit 1
; Show Digit 1 Now
Dig1 Clrf PORTA ; Display Digit 1 That Is Hour Tens
movf HourTen,W
btfsc STATUS,Z
GoTo digcheck_A_P
btfss DispStatus,3
goto dig1am
dig1pm movf HourTen,W
CALL TABLA
MOVWF PORTC ;
bcf PORTC,7
bsf PORTA,0 ;
goto dig1exit
dig1am movf HourTen,W
CALL TABLA
MOVWF PORTC ;
; bcf PORTC,7 ; added on 18-02-2013 to see if there is no 8
bsf PORTA,0 ;
goto dig1exit
digcheck_A_P btfss DispStatus,3
goto dig1exit
dig1pm2 clrf PORTC ;
bcf PORTC,7 ;
bsf PORTA,0 ;
goto dig1exit
dig1exit Movlw b'00000001'
movwf DisplayPosition
GoTo RECLAIM
; Show Digit 2 Now
Dig2 Clrf PORTA ; Display Digit 2 That Is Hour Ones
MOVF HourOne,W
CALL TABLA
MOVWF PORTC ;
Btfsc DispStatus,0 ; Check If Time For Displaying Colon
bcf PORTC,7
bsf PORTA,1 ;
Movlw b'00000010'
movwf DisplayPosition
GoTo RECLAIM
; Show Digit 3 Now
Dig3 Clrf PORTA ; Display Digit 3 That Is Minutes Tens
MOVF MinTen,W
CALL TABLA
MOVWF PORTC ;
Btfsc DispStatus,0 ; Check If Time For Displaying Colon
bcf PORTC,7
bsf PORTA,2 ;
Movlw b'00000100'
movwf DisplayPosition
GoTo RECLAIM
; Show Digit 4 Now
Dig4 Clrf PORTA ; Display Digit 4 That Is Minutes Ones
MOVF MinOne,W
CALL TABLA
MOVWF PORTC
bsf PORTA,3 ;
Movlw b'00001000'
movwf DisplayPosition
GoTo RECLAIM
; Show Digit 5 Now
Dig5 Clrf PORTA ; Display Digit 5 That Is Seconds Tens
movf SecsTen,W
CALL TABLA
MOVWF PORTC ;
bsf PORTA,4 ;
Movlw b'00010000'
movwf DisplayPosition
GoTo RECLAIM
; Show Digit 6 Now
Dig6 Clrf PORTA ; Display Digit 6 That Is Seconds Ones
MOVF SecsOne,W
CALL TABLA
MOVWF PORTC
bsf PORTA,5 ;
Movlw b'00100000'
movwf DisplayPosition
; End Of Digits To Display
; Time To Exit interrupt
RECLAIM swapf STATUS_TMP,w ; status temp storage to w
movwf STATUS ; w to status register
swapf W_TMP,f ; swap upper and lower 4-bits in w_tmp
swapf W_TMP,w ; swap bits and into w register
retfie ; return from interrupt
;########################################################################################################
;########################################################################################################
;--------- Start From Reset Or Power On ------
;---------------------------------------------
;########################################################################################################
;########################################################################################################
Start
BANKSEL ADCON1 ;disable analogue inputs
movlw 0x06
movwf ADCON1
movlw b'00000000' ;Set port data directions, data output
movwf TRISC
movwf TRISA
movlw b'11111111'
movwf TRISB
movlw B'00000001' ; TMRO prescaler 4 division, PORTB pullups enabled
movwf OPTION_REG ;
BANKSEL PORTA ; select bank 0
;
clrf tempcount ; Clear Temprory Registers
clrf tempcount1 ; "
clrf DispStatus ; '
;
movlw B'11111111' ; Display All Digits And All Segments (Display Test)
movwf PORTC
movlw B'11111111'
movwf PORTA
;
Call Delay255 ; Give 1 Sec Delay For PowerUp
Call Delay255
Call Delay255
Call Delay255
;
clrf PORTC
movlw 0xff
movwf PORTA
;
Call seq_out ; Check If RTC Intialized And Setup Time IfNot
clrf I2C_Address ; Clear DS1307 Address
Call Seq_Read_EEPROM ; Read From RTC
call rtc2hours ; RTC Format To Digits
Movlw b'00100000' ; Set Display Position
movwf DisplayPosition
movlw b'10100000' ; TMRO Interupt ON
movwf INTCON
MainLoop nop ; MainLoop
nop
btfss PORTB,5 ; See If Setup Key Pressed
GoTo Set_key ; Then GoTo
nop
nop
btfss DispStatus,2 ; see update time flag set
GoTo MainLoop ; No so loop
call TimeUp ; yes so update time
nop
nop
GoTo MainLoop
;########################################################################################################
;########################################################################################################
Set_key ; Time To Setup Clock
btfss PORTB,5
GoTo $-1
movlw 0x0A
movwf SecsTen
movlw 0x0B
movwf SecsOne
loopkeyHour btfss PORTB,4 ; Finished
GoTo EditDone
btfss PORTB,5
GoTo SetMin ; set mins
btfss PORTB,6
GoTo Hourplus ; set Hour +
btfss PORTB,7
GoTo HourMinus ; set Hour -
call Delay10
GoTo loopkeyHour
;########################################
SetMin
btfss PORTB,5
GoTo $-1
movlw 0x0A
movwf SecsTen
movlw 0x0C
movwf SecsOne
loopkeyMin btfss PORTB,4
GoTo EditDone ; Finished
btfss PORTB,5
GoTo Set_key ; set Hours
btfss PORTB,6
GoTo Minplus ; set mins +
btfss PORTB,7
GoTo MinMinus
call Delay10 ; set mins -
GoTo loopkeyMin
;######################################## hour error look between here
Hourplus
btfss PORTB,6 ; Wait For Key Release
GoTo $-1
btfss HourTen,0 ; HourTen skip if bit0 = 1
GoTo h10_0
h10_1 incf HourOne,f ; Increment HourOne +1
movf HourOne,w
xorlw 0x02
btfsc STATUS,Z ; skip if hour1 = 3
GoTo H_AP ; If <3 return to keys loop
movf HourOne,W
xorlw 0x03
btfss STATUS,Z ; skip if hour1 more than 3 then Set Time to h10=0 h1=1
goto okhr
movlw 0x01 ; If 3 Then Clear HourTen & set HourOne=1 [so hour is 01]
movwf HourOne
clrf HourTen
GoTo okhr
H_AP btfss DispStatus,3 ; Time Is 12 so set AM/PM;
goto $+3
bcf DispStatus,3
goto $+2
bsf DispStatus,3
goto okhr
h10_0 incf HourOne,f ; If HourTen =0 Then Inc HourOne
movf HourOne,w
xorlw 0x0A
btfss STATUS,Z ; skip if HourOne =10 Otherwise Finish
GoTo okhr
clrf HourOne ; If HourOne 10 Then Clear HourOne Ans Set HourTen=1 [so Hour Is 10]
movlw 0x01
movwf HourTen
okhr call Delay255
GoTo loopkeyHour ;Return to keys
;########################################
HourMinus
btfss PORTB,7 ; Wait For Key Release
GoTo $-1
btfss HourTen,0 ; skip if HourTen = 1
GoTo h10_0_minus
movf HourOne,w ; if HourTen = 0 and see If HourOne is 0
btfsc STATUS,Z ; Then Skip to ---> h10_1_mi
GoTo h10_1_mi
h10_1_minus decf HourOne,f ; If HourOne Not 0 Then decrement HourOne And Return
GoTo okhr_minus
h10_1_mi movlw 0x09 ; If HourTen And HourOne is 0 then -
movwf HourOne ; Clear HourTen and 9 -> HourOne [so hour is 09]
clrf HourTen
GoTo okhr_minus
h10_0_minus decfsz HourOne,f ; if HourTen = 1 then decrement HourOne And Skip If Zero
GoTo okhr_minus ; If Else return to keys
movlw 0x02 ; If HourOne 0 Then Move 2 -> HourOne & 1 -> HourTen -
movwf HourOne ; [so hour is 12] And Return
movlw 0x01
movwf HourTen
btfss DispStatus,3
goto $+3
bcf DispStatus,3
goto $+2
bsf DispStatus,3
okhr_minus call Delay255
GoTo loopkeyHour ;Return to keys
;######################################## and here
Minplus
btfss PORTB,6 ; Wait For Key Release
GoTo $-1
incf MinOne,f ; Increment MinOne and check if 10
movf MinOne,w
xorlw 0x0A
btfss STATUS,Z ; skip if MinOne = 10 If Else return to keys
GoTo okmin
clrf MinOne ; if MinOne=10 the clear MinOne And Inc MinTen
incf MinTen,f
movf MinTen,w
xorlw 0x06
btfss STATUS,Z ; skip if MinTen = 6 If Else Return to keys
GoTo okmin
clrf MinTen ; If MinTen=6 The Clear MinTen and return
okmin call Delay255
GoTo loopkeyMin ;Return to keys
;########################################
MinMinus
btfss PORTB,7 ; Wait For Key Release
GoTo $-1
movf MinOne,w ; Check If MinOne = 0
btfss STATUS,Z ; If 0 Then Skip
GoTo MinusMin2 ; If Not 0 Then GoTo ---> MinusMin2
movf MinTen,w ; Check If MinTen = 0 (Already Checked MinOne = 0)
btfsc STATUS,Z
GoTo MinusMin3
MinusMin4 movlw 0x09 ; If MinOne = 0 & MinTen Not 0 Then Set 9 ->MinOne And -
movwf MinOne ; decrement MinTen And Return
decf MinTen,f
GoTo okminMinus
MinusMin3 movlw 0x05 ; If MinOne And MinTen = 0 Then Set 5 ->MinTen & 9 ->MinOne
movwf MinTen ; [so Mins is 59]
movlw 0x09
movwf MinOne
GoTo okminMinus
MinusMin2 decf MinOne,f
okminMinus call Delay255
GoTo loopkeyMin ;Return to keys
;########################################
EditDone
btfss PORTB,5 ; Wait For Key Release
GoTo $-1
clrf SecsTen ; Clear Seconds Before Exiting Setup
clrf SecsOne ; Clear Seconds Before Exiting Setup
call WriteRtc ; Update The Changed Values To DS1307
GoTo MainLoop ; And Return To MainLoop
;########################################################################################################
;########################################################################################################
; Time Update
;########################################################################################################
;########################################################################################################
TimeUp bcf DispStatus,2
incf SecsOne,f
movf SecsOne,w
xorlw 0x0A
btfss STATUS,Z ;skip if SecsOne = 10
return
clrf SecsOne
incf SecsTen,f
movf SecsTen,w
xorlw 0x06
btfss STATUS,Z ;skip if SecsTen = 6
return
clrf SecsTen
MinP incf MinOne,f
movf MinOne,w
xorlw 0x0A
btfss STATUS,Z ;skip if MinOne = 10
return
clrf MinOne
incf MinTen,f
movf MinTen,w
xorlw 0x06
btfss STATUS,Z ;skip if MinTen = 6
return
clrf MinTen
call Readrtc ; Update Time From RTC (only Done Hourly After Time Tics xx:59:59)
return
;########################################################################################################
;########################################################################################################
;Start of I2C Services
;########################################################################################################
;########################################################################################################
seq_out clrf Data_Page ;check if ds1307 already initialized
movlw 0x07
movwf I2C_Address ;
call Read_EEPROM
movwf count1
btfsc count1,4 ; Just Temprery
return ; if yes return
clrf Data_Page
movlw 0x02
movwf I2C_Address ;
movlw 0x72
call Write_EEPROM ; am/pm set hour 12:00:00
clrf Data_Page ;
movlw 0x07
movwf I2C_Address ;
movlw 0x10
call Write_EEPROM ; Square Wave Enable. _|-|_|-|_|-|_|-|_|-|_
clrf Data_Page ;
movlw 0x01
movwf I2C_Address ;
movlw 0x00
call Write_EEPROM ; Minutes xx:00:xx
movlw 0x00
movwf I2C_Address ;
movlw 0x00
call Write_EEPROM ; Seconds xx:xx:00
return
;
; SubRoutine "ds1307_Read" ;------------------------------------------------------
Readrtc
bcf INTCON,GIE
clrf I2C_Address ;set DS1307 address
call Seq_Read_EEPROM ;read data in to buffer
call rtc2hours
bsf INTCON,GIE
Return
rtc2hours swapf Hrs,w
andlw 0x01
movwf HourTen
movf Hrs,w
andlw 0x0F
btfss Hrs,5
goto $+3
bsf DispStatus,3
goto $+2
bcf DispStatus,3
rtc2mins movwf HourOne
swapf Mins,w
andlw 0x0F
movwf MinTen
movf Mins,w
andlw 0x0F
movwf MinOne
rtc2secs swapf Secs,w
andlw 0x0F
movwf SecsTen
movf Secs,w
andlw 0x0F
movwf SecsOne
Return
; SubRoutine "ds1307_Write" ;------------------------------------------------------
WriteRtc bcf INTCON,GIE
swapf SecsTen,w
iorwf SecsOne,w
movwf Secs
swapf MinTen,w
iorwf MinOne,w
movwf Mins
swapf HourTen,w
iorwf HourOne,w
movwf Hrs
btfsc DispStatus,3
goto $+4
movlw 0x40 ; AM
addwf Hrs,F
goto $+3
movlw 0x60 ; PM
addwf Hrs,F
clrf Data_Page ;set DS1307 page
clrf I2C_Address ;set DS1307 address
Call Seq_Write_EEPROM
bsf INTCON,GIE
Return
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
;Start of I2C routines
Write_EEPROM ; write W register to address I2C_Address
movwf DAT_VAL ; save W
call I2C_STARTa
call I2C_Set_Write
; If ACK error display 'e'
btfsc I2Cflags, 0
call Error_Routine
call I2C_Lo_Adr
; If ACK error display 'f'
btfsc I2Cflags, 0
call Error_Routine1
movf DAT_VAL, W ; send the actual data
movwf OutputByte
call I2C_Out
call I2C_NAK
; If ACK error display 'g'
btfsc I2Cflags, 0
call Error_Routine2
call I2C_STOPa
call WaitForWrite
return
Read_EEPROM ; reads data at location specified in I2C_Address
; and page specified in Data_Page
; returns result in W
call I2C_STARTa
call I2C_Set_Write
; If ACK error display 'e'
btfsc I2Cflags, 0
call Error_Routine
call I2C_Lo_Adr
; If ACK error display 'f'
btfsc I2Cflags, 0
call Error_Routine1
call I2C_STARTa ; note there is no STOP
call I2C_Set_Read
; If ACK error display 'g'
btfsc I2Cflags, 0
call Error_Routine2
call I2C_READa ; fetch the byte
call I2C_Send_NAK ; send no acknowledgement
call I2C_STOPa
movf InputByte, W ; return the byte in W
return
Seq_Write_EEPROM ; write buffer to address I2C_Address
movwf DAT_VAL ; save W
call I2C_STARTa
call I2C_Set_Write
; If ACK error display 'e'
btfsc I2Cflags, 0
call Error_Routine
call I2C_Lo_Adr
; If ACK error display 'f'
btfsc I2Cflags, 0
call Error_Routine1
movlw Secs ; now write Buff_Size bytes to DS1307
movwf FSR
movlw Buf_Size
movwf N
SEQ_WRITE_1:
movf INDF, w ; fetch the data byte from the buffer
movwf OutputByte
call I2C_Out
call I2C_NAK
; If ACK error display 'g'
btfsc I2Cflags, 0
call Error_Routine2
incf FSR, f
decfsz N, f
GoTo SEQ_WRITE_1
call I2C_STOPa
call WaitForWrite
return
Seq_Read_EEPROM ; reads data at location specified in I2C_Address
; and page specified in Data_Page
; ; returns 4 byte result in secs
call I2C_STARTa
call I2C_Set_Write
; If ACK error display 'e'
btfsc I2Cflags, 0
call Error_Routine
call I2C_Lo_Adr
; If ACK error display 'f'
btfsc I2Cflags, 0
call Error_Routine1
call I2C_STARTa ; note there is no STOP
call I2C_Set_Read
; If ACK error display 'g'
btfsc I2Cflags, 0
call Error_Routine2
movlw Secs ; now sequentially read bytes from DS1307
movwf FSR
movlw Buf_Size
movwf N
SEQ_READ_1:
call I2C_READa ; fetch each byte from DS1307
movf InputByte, w
movwf INDF ; and save in data buffer
incf FSR, f
decfsz N, f
GoTo SEQ_READ_2 ; not done
GoTo SEQ_READ_3
SEQ_READ_2:
call I2C_ACK ; if not done, send an ACK and continue
GoTo SEQ_READ_1
SEQ_READ_3:
call I2C_Send_NAK ; send no acknowledgement
call I2C_STOPa
movf InputByte, w ; return the byte in W
return
; The following routines are low level I2C routines applicable to most
; interfaces with I2C devices.
I2C_READa ; read byte on i2c bus
clrf InputByte
movlw 0x08
movwf _N ; set index to 8
call HIGH_SDA ; be sure SDA is configured as input
In_Bit
call HIGH_SCL ; clock high
btfss I2C_PORT, SDA ; test SDA bit
GoTo In_Zero
GoTo In_One
In_Zero
bcf STATUS, C ; clear carry
rlf InputByte, f ; i_byte = i_byte << 1 | 0
GoTo Cont_In
In_One
bsf STATUS, C ; set carry
rlf InputByte, f
Cont_In
call LOW_SCL ; bring clock low
decfsz _N, F ; decrement index
GoTo In_Bit
return
I2C_Out: ; send w register on I2C bus
movwf OutputByte
movlw 0x08
movwf _N
Out_Bit:
bcf STATUS, C ; clear carry
rlf OutputByte, f ; left shift, most sig bit is now in carry
btfss STATUS, C ; if one, send a one
GoTo Out_Zero
GoTo Out_One
Out_Zero:
call LOW_SDA ; SDA at zero
call Clock_Pulse
call HIGH_SDA
GoTo Out_Cont
Out_One:
call HIGH_SDA ; SDA at logic one
call Clock_Pulse
Out_Cont:
decfsz _N, F ; decrement index
GoTo Out_Bit
return
;;;;;;
I2C_NAK: ; bring SDA high and clock
call HIGH_SDA
call HIGH_SCL
clrf count ; wait for ACK
WaitForACK incf count, f ; increase timeout counter each time ACK is not received
btfsc STATUS, Z
GoTo No_ACK_Rec
btfsc I2C_PORT, SDA ; test pin. If clear, DS1307 is pulling SDA low for ACK
GoTo WaitForACK ; ...otherwise, continue to wait
bcf I2Cflags, 0 ; clear flag bit (ACK received)
call LOW_SCL
return
I2C_Send_NAK: ; bring SDA high and clock
call HIGH_SDA
call Clock_Pulse
return
WaitForWrite ; poll ACK for write timing
call I2C_STARTa
call I2C_Set_Write
btfsc I2Cflags, 0
GoTo WaitForWrite
return
;------ No ACK received from slave (must use "return" from here)
;; Typically, set a flag bit to indicate failed write and check for it upon return.
No_ACK_Rec
bsf I2Cflags, 0 ; set flag bit
retlw 0x00
;------ No ACK received from slave. This is the error handler.
Error_Routine
; Output error message, etc. here
movlw 'e'
retlw 0x00 ; returns to INITIAL calling routine
Error_Routine1
; Output error message, etc. here
movlw 'f'
retlw 0x00
Error_Routine2
; Output error message, etc. here
movlw 'g'
retlw 0x00
I2C_ACK:
call LOW_SDA
call Clock_Pulse
return
I2C_STARTa:
; call LOW_SCL ;;
; call HIGH_SDA ;;
call HIGH_SCL
call LOW_SDA ; bring SDA low while SCL is high
call LOW_SCL
return
I2C_STOPa:
call LOW_SCL
call LOW_SDA
call HIGH_SCL
call HIGH_SDA ; bring SDA high while SCL is high
; call LOW_SCL ;;
return
I2C_Set_Write rlf Data_Page, W ; shift device page
andlw b'00001110' ; AND to make sure in range
iorlw Chip_Write
call I2C_Out
call I2C_NAK
return
I2C_Set_Read rlf Data_Page, W ; shift device page
andlw b'00001110' ; AND to make sure in range
iorlw Chip_Read
call I2C_Out
call I2C_NAK
return
I2C_Lo_Adr movf I2C_Address, W ; send low byte of address
call I2C_Out
call I2C_NAK
return
Clock_Pulse: ; SCL momentarily to logic one
call HIGH_SCL
call LOW_SCL
return
HIGH_SDA: ; high impedance by making SDA an input
bsf STATUS, RP0 ; bank 1
bsf I2C_TRIS, SDA ; make SDA pin an input
bcf STATUS, RP0 ; back to bank 0
return
LOW_SDA:
bcf I2C_PORT, SDA
bsf STATUS, RP0 ; bank 1
bcf I2C_TRIS, SDA ; make SDA pin an output
bcf STATUS, RP0 ; back to bank 0
return
HIGH_SCL:
bsf STATUS, RP0 ; bank 1
bsf I2C_TRIS, SCL ; make SCL pin an input
bcf STATUS, RP0 ; back to bank 0
return
LOW_SCL:
bcf I2C_PORT, SCL
bsf STATUS, RP0 ; bank 1
bcf I2C_TRIS, SCL ; make SCL pin an output
bcf STATUS, RP0 ; back to bank 0
return
; End of I2C routines
;########################################################################################################
;########################################################################################################
;########################################################################################################
;########################################################################################################
; Delay routines
;
;
Delay255 movlw 0xff ;delay 255 mS
GoTo d0
Delay100 movlw d'100' ;delay 100mS
GoTo d0
Delay50 movlw d'50' ;delay 50mS
GoTo d0
Delay20 movlw d'20' ;delay 20mS
GoTo d0
Delay10 movlw d'10' ;delay 10mS
GoTo d0
Delay5 movlw 0x05 ;delay 5.000 ms (4 MHz clock)
d0 movwf count1
d1 movlw 0xC7
movwf counta
movlw 0x01
movwf countb
Delay_0 decfsz counta, f
GoTo $+2
decfsz countb, f
GoTo Delay_0
decfsz count1 ,f
GoTo d1
retlw 0x00
;end of Delay routines
End