Amoque
- 25th October 2013, 16:30
I hope this day finds you well.
Armed with the information I gained in my last post (thank you again), I set about putting it to use in the following code. I think that it is a good beginner project - a clock that uses the popular DS series I2C chip and is very simple in hardware by displaying to the debug window rather than some complicated interface. Unlike many I have seen posted, the complete code for buttons is included and to the best of my ability it is commented and tested to function in every regard - except one: It doesn't work.
Enjoy your laugh at my chagrin, as I have! Then, wipe the tear from your eye and consider my problem, if you please.
The clock starts by displaying the special and status registers, writes to them and reads back the values without flaw.
It then initialized each day and date register with it's hex value ($00 is written to seconds, $01 to minutes, $02 to hours...). This also works well and displays as expected.
Clock display outputs as it should.
Each of the three buttons work as I intended: Press "1" to enter the adjustment routines, "2" to advance though the registers, and "3" to advance through valid values. "1" again writes the new register value to the clock chip and, in a few seconds without input, at any point, the routines abort appropriately.
Almost perfect, except the clock value never advances - stubbornly remaining precisely as set. I believe that in my fumbling attempts to "pull up" the heartbeat signal I may have damaged the clock chip. I haven't another and so expose my ineptitude in hopes of avoiding the delay of ordering another (or at least verifying such a delay is unavoidable) by asking for help - either by hardware test or simulation to determine I have not a code error. Is that possible? If so, thank you.
'************************************************* ***************
'* Name : 3 BTN CLOCK.BAS *
'* Author : [AMOQUE] *
'* Notice : Copyright (c) 2013 [PBP 2.6] *
'* : All Rights Reserved *
'* Date : 10/21/2013 *
'* Version : 1.0 *
'* Notes : 16F88, DS1337 or equivalent, *
'* : 3 BUTTONS - ACTIVE HIGH *
'************************************************* ***************
#CONFIG
__config _CONFIG1, _INTRC_IO & _WDT_OFF & _PWRTE_OFF & _MCLR_ON & _BODEN_OFF & _LVP_OFF & _CPD_OFF & _WRT_PROTECT_OFF & _DEBUG_OFF
__config _CONFIG2, _FCMEN_OFF & _IESO_OFF
#ENDCONFIG
DEFINE OSC 8
'-----DEBUG (SERIAL) SETUP----------------------------------------
DEFINE DEBUG_REG PORTB
DEFINE DEBUG_BIT 5
DEFINE DEBUG_BAUD 2400
DEFINE DEBUG_MODE 0
'-----CHIP REGISTER SET-UP----------------------------------------
TRISA = %00000000 ' Set PORTA output
TRISB = %00001101
OSCCON = %01110000
CCP1CON = %00001100
T2CON = %00000101
'ADCON0 = %11000000 ' Configure and turn on A/D Module
'ADCON1 = %10000000 ' Set PORTA analog and LEFT justify result
'ANSEL = %00000011
'-----PORT SET-UP-------------------------------------------------
SDA VAR PORTB.1
SCL VAR PORTB.4
BTN1 VAR PORTB.0
BTN2 VAR PORTB.2
BTN3 VAR PORTB.3
'-----CLOCK SET-UP------------------------------------------------
RTC_ADD CON %11010000
REG_TIM CON $00
REG_AL1 CON $07 ' Not implemented
REG_AL2 CON $0B ' Not implemented
REG_SPC con $0E
REG_STS CON $0F
'-----TIME/ CLOCK VARIABLES----------------------------------------
REG_MIN VAR BYTE[7] ' Minimum register values
REG_VAL VAR Byte[7] ' Seconds, minutes, hours, day of week, date, month, year
REG_MAX VAR BYTE[7] ' Maximum register values
ACT_REG VAR BYTE ' Active register (setting)
'-----GENERAL USE VARIABLES---------------------------------------
LP VAR BYTE ' For/ Next value
D0 VAR BYTE
D1 VAR BYTE
D2 VAR BYTE
'-----INITIALIZE CLOCK--------------------------------------------
'CHECK STATUS
debug "---STABALIZE---", 10
pause 250
D0 = $00 : D1 = $00
gosub SPCL_READ
D0 = $00 : D1 = $00 ' Assign 'special' registers
gosub SPCL_WRITE ' Write 'special' registers
gosub SPCL_READ ' Verify
'SET INITIAL TIME
FOR lp = 0 TO 6 ' For each register
REG_VAL[LP] = LP ' Set value to address
NEXT LP ' Loop
'----------------------' Alarm set-up
GOSUB CLK_WRITE ' Write initial values and start clock
'LOAD REGISTER MIN/ MAX VALUES
REG_MIN[0] = 00: REG_MIN[1] = 00: REG_MIN[2] = 00: REG_MIN[3] = 1: REG_MIN[4] = 01: REG_MIN[5] = 01: REG_MIN[6] = 00
REG_MAX[0] = 59: REG_MAX[1] = 59: REG_MAX[2] = 23: REG_MAX[3] = 6: REG_MAX[4] = 31: REG_MAX[5] = 12: REG_MAX[6] = 99
'+++++MAIN LOOP++++++++++++++++++++++++++++++++++++++++++++++ +++++
MAIN:
if BTN1 then goto CLK_SET ' Button 1 = Enter set mode
GOSUB CLK_READ: ' Read clock
PAUSE 500 ' Pause
GOTO MAIN ' Loop til the end of time (lol)
'-----SUB-ROUTINES------------------------------------------------
'READ TIME, CONVERT TO DECIMAL VALUES, DISPLAY
CLK_READ:
I2CRead SDA, SCL, RTC_ADD, REG_TIM, [REG_VAL[0], REG_VAL[1], REG_VAL[2], REG_VAL[3], REG_VAL[4], REG_VAL[5], REG_VAL[6]]
FOR LP = 0 TO 6 ' For each register
D0 = (REG_VAL[LP] >> 4) * 10 ' Decode 10's digit
D1 = REG_VAL[LP] & %0001111 ' Blank 10's, get 1's
REG_VAL[LP] = D0 + D1 ' Write Decimal value to register
NEXT LP ' Next register
DEBUG "TIME:[", dec1 REG_VAL[3], "] ", dec2 REG_VAL[5], "/", dec2 REG_VAL[4], "/", dec2 REG_VAL[6], " ", dec2 REG_VAL[2], ":", dec2 REG_VAL[1], ":",
dec2 REG_VAL[0], 10
Return
'CONVERT TO BCD VALUES, WRITE TO CLOCK REGISTERS
CLK_WRITE:
FOR LP = 0 TO 6 ' For each register
D0 = REG_VAL[LP] / 10 ' Get decimal 10's digit
D1 = REG_VAL[LP] // 10 ' Get decimal 1's
REG_VAL[LP] = (D0 << 4) + d1 ' Shift BCD 10's in, add 1's
NEXT LP ' Next register
I2CWrite SDA, SCL, RTC_ADD, REG_TIM, [REG_VAL[0], REG_VAL[1], REG_VAL[2], REG_VAL[3], REG_VAL[4], REG_VAL[5], REG_VAL[6]]
GOSUB CLK_READ ' Update display
Return
'SPECIAL REGISTERS--------------------------------------------------------------
SPCL_WRITE:
I2CWrite SDA, SCL, RTC_ADD, REG_SPC, [D0, D1]
Return
SPCL_READ:
I2CRead SDA, SCL, RTC_ADD, REG_SPC, [D0, D1]
debug "SPCL: [", bin8 D0, "] STATUS: [", BIN8 D1, "]", 10, 10
pause 1000
Return
'BEGIN SET ROUTINE--------------------------------------------------------------
CLK_SET:
debug "SET TIME", 10 ' Announce in debug window
For LP = 0 to 100 ' Start timer loop
IF BTN2 Then Goto SELECT_REG ' Button 2 = select register
Pause 100 ' Advance time
NEXT LP ' Loop
GOTO MAIN ' Time expired, drop out
'SELECT REGISTER
SELECT_REG:
debug "SELECT REGISTER" , 10
ACT_REG = 0 : D2 = 0 ' Reset active register
For LP = 0 to 100 ' Start timer loop
IF BTN2 Then ' Button 2 press
ACT_REG = ACT_REG + 1 ' Advance active register
LP = 0 ' Restart time loop
IF ACT_REG > 6 THEN ACT_REG = 0 ' Keep register number in bounds
DEBUG "EDIT=", DEC1 ACT_REG, " MAX=" ' Announce register and max value to debug
debug DEC2 REG_MAX[ACT_REG], 10
Endif
If BTN3 Then ' Button 3 press
debug "SET REGISTER VALUE" , 10 ' Announce to debug
LP = 0 ' Restart time loop
Goto ADV_VALUE ' Goto advance register value routine
Endif ' End button 3 loop
Pause 100 ' Advance time
NEXT LP ' Loop
GOTO MAIN ' Time expired, drop out
'ADVANCE REGISTER VALUE
ADV_VALUE:
debug "ADVANCE REGISTER VALUE" , 10
for LP = 0 to 100 ' Announce to debug
IF Btn3 Then ' Button 3 press
LP = 0 ' Restart time loop
D2 = D2 + 1 ' Advance register value
IF D2 > REG_MAX[ACT_REG] THEN D2 = REG_MIN[ACT_REG] ' Keep register value in bounds
debug "REG=", DEC2 ACT_REG, " NEW VALUE=", DEC2 D2 , 10 ' Announce to debug
ENDIF ' End button 3 press
IF BTN1 Then ' Button 1 press
debug "WRITE VALUE TO CLOCK" , 10 ' Announce to debug
LP = 0 ' Restart timer
GOSUB CLK_READ ' Read fresh clock values
REG_VAL[ACT_REG] = D2 ' Insert new value
GOSUB CLK_WRITE ' Write to chip
GOTO SELECT_REG ' Goto 'select register'
EndIF ' End button 1 press
Pause 100 ' Advance timer
Next LP ' Loop
GOTO MAIN ' Time expired, drop out
END
Armed with the information I gained in my last post (thank you again), I set about putting it to use in the following code. I think that it is a good beginner project - a clock that uses the popular DS series I2C chip and is very simple in hardware by displaying to the debug window rather than some complicated interface. Unlike many I have seen posted, the complete code for buttons is included and to the best of my ability it is commented and tested to function in every regard - except one: It doesn't work.
Enjoy your laugh at my chagrin, as I have! Then, wipe the tear from your eye and consider my problem, if you please.
The clock starts by displaying the special and status registers, writes to them and reads back the values without flaw.
It then initialized each day and date register with it's hex value ($00 is written to seconds, $01 to minutes, $02 to hours...). This also works well and displays as expected.
Clock display outputs as it should.
Each of the three buttons work as I intended: Press "1" to enter the adjustment routines, "2" to advance though the registers, and "3" to advance through valid values. "1" again writes the new register value to the clock chip and, in a few seconds without input, at any point, the routines abort appropriately.
Almost perfect, except the clock value never advances - stubbornly remaining precisely as set. I believe that in my fumbling attempts to "pull up" the heartbeat signal I may have damaged the clock chip. I haven't another and so expose my ineptitude in hopes of avoiding the delay of ordering another (or at least verifying such a delay is unavoidable) by asking for help - either by hardware test or simulation to determine I have not a code error. Is that possible? If so, thank you.
'************************************************* ***************
'* Name : 3 BTN CLOCK.BAS *
'* Author : [AMOQUE] *
'* Notice : Copyright (c) 2013 [PBP 2.6] *
'* : All Rights Reserved *
'* Date : 10/21/2013 *
'* Version : 1.0 *
'* Notes : 16F88, DS1337 or equivalent, *
'* : 3 BUTTONS - ACTIVE HIGH *
'************************************************* ***************
#CONFIG
__config _CONFIG1, _INTRC_IO & _WDT_OFF & _PWRTE_OFF & _MCLR_ON & _BODEN_OFF & _LVP_OFF & _CPD_OFF & _WRT_PROTECT_OFF & _DEBUG_OFF
__config _CONFIG2, _FCMEN_OFF & _IESO_OFF
#ENDCONFIG
DEFINE OSC 8
'-----DEBUG (SERIAL) SETUP----------------------------------------
DEFINE DEBUG_REG PORTB
DEFINE DEBUG_BIT 5
DEFINE DEBUG_BAUD 2400
DEFINE DEBUG_MODE 0
'-----CHIP REGISTER SET-UP----------------------------------------
TRISA = %00000000 ' Set PORTA output
TRISB = %00001101
OSCCON = %01110000
CCP1CON = %00001100
T2CON = %00000101
'ADCON0 = %11000000 ' Configure and turn on A/D Module
'ADCON1 = %10000000 ' Set PORTA analog and LEFT justify result
'ANSEL = %00000011
'-----PORT SET-UP-------------------------------------------------
SDA VAR PORTB.1
SCL VAR PORTB.4
BTN1 VAR PORTB.0
BTN2 VAR PORTB.2
BTN3 VAR PORTB.3
'-----CLOCK SET-UP------------------------------------------------
RTC_ADD CON %11010000
REG_TIM CON $00
REG_AL1 CON $07 ' Not implemented
REG_AL2 CON $0B ' Not implemented
REG_SPC con $0E
REG_STS CON $0F
'-----TIME/ CLOCK VARIABLES----------------------------------------
REG_MIN VAR BYTE[7] ' Minimum register values
REG_VAL VAR Byte[7] ' Seconds, minutes, hours, day of week, date, month, year
REG_MAX VAR BYTE[7] ' Maximum register values
ACT_REG VAR BYTE ' Active register (setting)
'-----GENERAL USE VARIABLES---------------------------------------
LP VAR BYTE ' For/ Next value
D0 VAR BYTE
D1 VAR BYTE
D2 VAR BYTE
'-----INITIALIZE CLOCK--------------------------------------------
'CHECK STATUS
debug "---STABALIZE---", 10
pause 250
D0 = $00 : D1 = $00
gosub SPCL_READ
D0 = $00 : D1 = $00 ' Assign 'special' registers
gosub SPCL_WRITE ' Write 'special' registers
gosub SPCL_READ ' Verify
'SET INITIAL TIME
FOR lp = 0 TO 6 ' For each register
REG_VAL[LP] = LP ' Set value to address
NEXT LP ' Loop
'----------------------' Alarm set-up
GOSUB CLK_WRITE ' Write initial values and start clock
'LOAD REGISTER MIN/ MAX VALUES
REG_MIN[0] = 00: REG_MIN[1] = 00: REG_MIN[2] = 00: REG_MIN[3] = 1: REG_MIN[4] = 01: REG_MIN[5] = 01: REG_MIN[6] = 00
REG_MAX[0] = 59: REG_MAX[1] = 59: REG_MAX[2] = 23: REG_MAX[3] = 6: REG_MAX[4] = 31: REG_MAX[5] = 12: REG_MAX[6] = 99
'+++++MAIN LOOP++++++++++++++++++++++++++++++++++++++++++++++ +++++
MAIN:
if BTN1 then goto CLK_SET ' Button 1 = Enter set mode
GOSUB CLK_READ: ' Read clock
PAUSE 500 ' Pause
GOTO MAIN ' Loop til the end of time (lol)
'-----SUB-ROUTINES------------------------------------------------
'READ TIME, CONVERT TO DECIMAL VALUES, DISPLAY
CLK_READ:
I2CRead SDA, SCL, RTC_ADD, REG_TIM, [REG_VAL[0], REG_VAL[1], REG_VAL[2], REG_VAL[3], REG_VAL[4], REG_VAL[5], REG_VAL[6]]
FOR LP = 0 TO 6 ' For each register
D0 = (REG_VAL[LP] >> 4) * 10 ' Decode 10's digit
D1 = REG_VAL[LP] & %0001111 ' Blank 10's, get 1's
REG_VAL[LP] = D0 + D1 ' Write Decimal value to register
NEXT LP ' Next register
DEBUG "TIME:[", dec1 REG_VAL[3], "] ", dec2 REG_VAL[5], "/", dec2 REG_VAL[4], "/", dec2 REG_VAL[6], " ", dec2 REG_VAL[2], ":", dec2 REG_VAL[1], ":",
dec2 REG_VAL[0], 10
Return
'CONVERT TO BCD VALUES, WRITE TO CLOCK REGISTERS
CLK_WRITE:
FOR LP = 0 TO 6 ' For each register
D0 = REG_VAL[LP] / 10 ' Get decimal 10's digit
D1 = REG_VAL[LP] // 10 ' Get decimal 1's
REG_VAL[LP] = (D0 << 4) + d1 ' Shift BCD 10's in, add 1's
NEXT LP ' Next register
I2CWrite SDA, SCL, RTC_ADD, REG_TIM, [REG_VAL[0], REG_VAL[1], REG_VAL[2], REG_VAL[3], REG_VAL[4], REG_VAL[5], REG_VAL[6]]
GOSUB CLK_READ ' Update display
Return
'SPECIAL REGISTERS--------------------------------------------------------------
SPCL_WRITE:
I2CWrite SDA, SCL, RTC_ADD, REG_SPC, [D0, D1]
Return
SPCL_READ:
I2CRead SDA, SCL, RTC_ADD, REG_SPC, [D0, D1]
debug "SPCL: [", bin8 D0, "] STATUS: [", BIN8 D1, "]", 10, 10
pause 1000
Return
'BEGIN SET ROUTINE--------------------------------------------------------------
CLK_SET:
debug "SET TIME", 10 ' Announce in debug window
For LP = 0 to 100 ' Start timer loop
IF BTN2 Then Goto SELECT_REG ' Button 2 = select register
Pause 100 ' Advance time
NEXT LP ' Loop
GOTO MAIN ' Time expired, drop out
'SELECT REGISTER
SELECT_REG:
debug "SELECT REGISTER" , 10
ACT_REG = 0 : D2 = 0 ' Reset active register
For LP = 0 to 100 ' Start timer loop
IF BTN2 Then ' Button 2 press
ACT_REG = ACT_REG + 1 ' Advance active register
LP = 0 ' Restart time loop
IF ACT_REG > 6 THEN ACT_REG = 0 ' Keep register number in bounds
DEBUG "EDIT=", DEC1 ACT_REG, " MAX=" ' Announce register and max value to debug
debug DEC2 REG_MAX[ACT_REG], 10
Endif
If BTN3 Then ' Button 3 press
debug "SET REGISTER VALUE" , 10 ' Announce to debug
LP = 0 ' Restart time loop
Goto ADV_VALUE ' Goto advance register value routine
Endif ' End button 3 loop
Pause 100 ' Advance time
NEXT LP ' Loop
GOTO MAIN ' Time expired, drop out
'ADVANCE REGISTER VALUE
ADV_VALUE:
debug "ADVANCE REGISTER VALUE" , 10
for LP = 0 to 100 ' Announce to debug
IF Btn3 Then ' Button 3 press
LP = 0 ' Restart time loop
D2 = D2 + 1 ' Advance register value
IF D2 > REG_MAX[ACT_REG] THEN D2 = REG_MIN[ACT_REG] ' Keep register value in bounds
debug "REG=", DEC2 ACT_REG, " NEW VALUE=", DEC2 D2 , 10 ' Announce to debug
ENDIF ' End button 3 press
IF BTN1 Then ' Button 1 press
debug "WRITE VALUE TO CLOCK" , 10 ' Announce to debug
LP = 0 ' Restart timer
GOSUB CLK_READ ' Read fresh clock values
REG_VAL[ACT_REG] = D2 ' Insert new value
GOSUB CLK_WRITE ' Write to chip
GOTO SELECT_REG ' Goto 'select register'
EndIF ' End button 1 press
Pause 100 ' Advance timer
Next LP ' Loop
GOTO MAIN ' Time expired, drop out
END