1 Attachment(s)
Clock and Dual Termometer
Hi everyone !
I try to build for my use , in home, one clock with dual termometer, using 16F628A, 2x16 LCD and 2 x DS18B20. I wrote the code, but... at every minute I have a few seconds more...I don't have a clue where it's the mistake. Can help me, please ? Thanks in advance :) !
Code:
@ DEVICE pic16F628A, XT_osc, WDT_OFF, PWRT_OFF, BOD_OFF, MCLR_ON, LVP_OFF
TRISA= %11111000 ' RA0..3=Outputs RA4=Input
TRISB= %00001111 ' RB0..RB2=Inputs, RB3..RB7=Outputs
CMCON=7 ' Disable comparators
OPTION_REG=%00000111
DEFINE LCD_DREG PORTB ' LCD on port B
DEFINE LCD_DBIT 4 ' Data bits B4..B7
DEFINE LCD_RSREG PORTA ' RS on PORTA
DEFINE LCD_RSBIT 1 ' RS on A1
DEFINE LCD_EREG PORTA ' E on PORTA
DEFINE LCD_EBIT 0 ' E on A0
DEFINE LCD_BITS 4 ' LCD 4 bit mode
DEFINE LCD_LINES 2 ' 2 line LCD display
TempC var word
Float var word
Sign var bit ' +/- sign
DQ var PORTA.4 ' One-wire data pin
TempC2 var word
Float2 var word
Sign2 var BIT ' +/- sign
DQ2 var PORTA.3 ' One-wire data pin
Delay var byte
Mode var byte
semn var word
semn2 var word
DS18B20_1_12bit CON %01111111 ; 750ms, 0.0625°C (default)
DS18B20_2_12bit CON %01111111 ; 750ms, 0.0625°C (default)
Ticks var byte ; Tick count (61 ticks=1 sec)
Hour var byte ; Hour variable
Minute var byte ; Minute variable
Second var byte ; Second variable
ZIUA var byte
LUNA var byte
Disp var byte ; Disp=1 to update display
PAUSE 500 ; Wait 0.5sec for LCD to initialize
Hour=0 : Minute=0 : Second=0
Ticks=0 : ZIUA=01 : LUNA=01
OPTION_REG=$05 ; Set prescaler
ON INTERRUPT GOTO ISR ; ISR routine
INTCON=$A0 ; Enable TMR
LCDOUT $FE, 1 ; Clear LCD
' Init Sensor 1
OWOUT DQ, 1, [$CC, $4E, 0, 0, DS18B20_1_12bit]
OWOut DQ, 1, [$CC, $48]
OWOut DQ, 1, [$CC, $B8]
OWOut DQ, 1, [$CC, $BE]
Pause 50
OWIn DQ, 2, [TempC.byte0, TempC.byte1]
Pause 50
' Init Sensor 2
OWOUT DQ2, 1, [$CC, $4E, 0, 0, DS18B20_2_12bit]
OWOut DQ2, 1, [$CC, $48]
OWOut DQ2, 1, [$CC, $B8]
OWOut DQ2, 1, [$CC, $BE]
Pause 50
OWIn DQ2, 2, [TempC2.byte0, TempC2.byte1]
Pause 50
LOOP:
If PORTB.0=0 then ' Mode switch preSeconded
Pause 50 ' Debounce
LcdOut $FE, 1
LcdOut $FE, $C0, " SETTING" ' Show that coMinuteand is accepted
PAUSE 500
LcdOut $FE, 1
If PORTB.0=0 then Loop ' Wait until button is released
Mode=Mode+1 ' Increment mode
ENDIF
If Mode=1 then ' SET HOUR
LcdOut $FE, $80, dec2 Hour
LcdOut $FE, $C0, "HOUR SETTING"
if portb.1=0 then
Hour=Hour+1
IF Hour=24 then
Hour=0
ENDIF
Gosub Debounce
endif
if portb.2=0 then
IF Hour = 0 then
Hour=24
ENDIF
Hour=Hour-1
Gosub Debounce
endif
EndIf
If Mode=2 then ' SET MINUTES
LcdOut $FE, $80, dec2 Hour,":",dec2 Minute
LcdOut $FE, $C0, "MINUTES SETTING"
if portb.1=0 then
Second=0
Minute=Minute+1
IF Minute=60 THEN
Minute=0
ENDIF
Gosub Debounce
endif
if portb.2=0 then
Second=0
IF Minute =<0 THEN
Minute=60
ENDIF
Minute=Minute-1
Gosub Debounce
endif
EndIf
If Mode=3 then ' SET DAY
LcdOut $FE, $80, dec2 Hour,":",dec2 Minute,":",dec2 Second," ",DEC2 ZIUA,"/"
LcdOut $FE, $C0, "DAY SETTING"
if portb.1=0 then
ziua=ziua+1
IF LUNA=2 THEN
IF ZIUA > 28 THEN
ZIUA=1
ENDIF
ENDIF
IF LUNA=4 OR LUNA=6 OR LUNA=9 OR LUNA=11 THEN
IF ZIUA > 30 THEN ZIUA=1
ELSE
IF ZIUA > 31 THEN ZIUA=1
ENDIF
Gosub Debounce
endif
if portb.2=0 then
ZIUA=ZIUA-1
IF ZIUA = 0 THEN ZIUA=31
Gosub Debounce
endif
EndIf
If Mode=4 then ' SET MONTH
LcdOut $FE, $80, dec2 Hour,":",dec2 Minute,":",dec2 Second," ",DEC2 ZIUA,"/",DEC2 LUNA
LcdOut $FE, $C0, "MONTH SETTING"
if portb.1=0 then
luna=luna+1
if luna>12 then
luna=1
endif
Gosub Debounce
endif
if portb.2=0 then
luna=luna-1
if luna<1 then
luna=12
endif
Gosub Debounce
endif
EndIf
If Mode > 4 then
LCDOUT $FE, $C0, "END SETTING"
PAUSE 1000
LCDOUT $FE, 1, $FE, $0C
mode=0
EndIf
If Mode > 0 then Loop
IF Disp=1 THEN
LcdOut $FE, $80, DEC2 Hour, ":",DEC2 Minute, ":",DEC2 Second," ",DEC2 ZIUA,"/",DEC2 LUNA
LCDOUT $FE, $C0, semn,DEC ABS TempC/100,".", DEC1 ABS TempC/10, 223,"C ", $FE, $C0 + 9, semn2,DEC ABS TempC2/100,".", DEC1 ABS TempC2/10, 223,"C "
Disp=0
ENDIF
GOTO LOOP
DISABLE
ISR:
Ticks=Ticks + 1
IF Ticks < 61 THEN NoUpdate
Ticks=0
Second=Second + 1 ; Update second
IF Second=60 THEN
Second=0
Minute=Minute + 1 ; Update Minute
IF Minute=60 THEN
Minute=0
Hour=Hour + 1 ; Update Hour
IF Hour=24 THEN
Hour=0
ZIUA=ZIUA+1
IF LUNA=2 THEN
IF ZIUA > 28 THEN
ZIUA=1
LUNA=3
ENDIF
ENDIF
IF LUNA=4 OR LUNA=6 OR LUNA=9 OR LUNA=11 THEN
IF ZIUA > 30 THEN
ZIUA=1
LUNA=LUNA+1
ENDIF
ENDIF
IF LUNA=1 OR LUNA=3 OR LUNA=5 OR LUNA=7 OR LUNA=8 OR LUNA=10 THEN
IF ZIUA > 31 THEN
ZIUA=1
LUNA=LUNA+1
ENDIF
ENDIF
IF LUNA=12 THEN
IF ZIUA > 31 THEN
ZIUA=1
LUNA=1
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
Disp=1 ; Set to update display
Gosub Read_temp
NoUpdate:
INTCON.2=0 ; Re-enable TMR0 interrupts
Resume
ENABLE ; Re-enable interrupts
END
;=================================
;Subrutine
Debounce:
FOR Delay=1 To 200
Pause 1 ; Delay 1ms inside a loop. This way,
NEXT Delay ; timer interrupts are not stopped
Disp=1 ; Set display flag to 1
RETURN
;==================================
Read_Temp:
OWOut DQ, 1, [$CC, $44]
OWOut DQ, 1, [$CC, $BE]
OWIn DQ, 2, [TempC.byte0, TempC.byte1]
Sign = TempC.15
TempC = ABS(TempC)
TempC = ((TempC >> 4)*100) + ((TempC & $F)*100 >> 4)
IF Sign THEN TempC = -TempC
IF TempC.15 THEN
Semn="-"
else
Semn="+"
endif
OWOut DQ2, 1, [$CC, $44]
OWOut DQ2, 1, [$CC, $BE]
OWIn DQ2, 2, [TempC2.byte0, TempC2.byte1]
Sign2 = TempC2.15
TempC2 = ABS(TempC2)
TempC2 = ((TempC2 >> 4)*100) + ((TempC2 & $F)*100 >> 4)
IF Sign2 THEN TempC2 = -TempC2
IF TempC2.15 THEN
Semn2="-"
else
Semn2="+"
endif
Return
;=====================================
END ; End of program
1 Attachment(s)
If You see one crazy man, it's me !
I re-re-re-read all the topics on this forum (searching for "timer") and I found one code (Josepino's code) for HIGH-accuracy clock.
I try to compile them, but I have errors. What I do wrong ?
Code:
DEFINE NO_CLRWDT
Define OSC 4
DEFINE LCD_DREG PORTB ' LCD Data Port
DEFINE LCD_DBIT 4 ' Starting Data Bit
DEFINE LCD_RSREG PORTA ' Register Select Port
DEFINE LCD_RSBIT 1 ' Register Select Bit
DEFINE LCD_EREG PORTA ' Enable Port
DEFINE LCD_EBIT 0 ' Enable Bit
DEFINE LCD_BITS 4 ' Data Bus Size
DEFINE LCD_LINES 2 ' Number of Lines on LCD
DEFINE LCD_COMMANDUS 2000
DEFINE LCD_DATAUS 50
TRISA= %11111000 ' RA0..3=Outputs RA4=Input
TRISB= %00001111 ' RB0..RB2=Inputs, RB3..RB7=Outputs
CMCON = 7
pushButton1 var portb.0 'switch
pushButton2 var portb.1
pushButton3 Var portb.2
pushButton4 Var portb.3
pressed con 0 ;value of button pressed
notPressed con 1 ;value of button not pressed
dhour var byte ' Define display hour variable
i var byte ' Debounce loop variable
ticks var byte ' Define pieces of seconds variable
Seconds var byte
Minutes var byte
Hours var byte
Days var byte
Months var BYTE
TempC var word
Float var word
Sign var bit ' +/- sign
DQ var PORTA.4 ' One-wire data pin
TempC2 var word
Float2 var word
Sign2 var bit ' +/- sign
DQ2 var PORTA.3 ' One-wire data pin
semn var word
semn2 var word
DS18B20_1 CON %01011111
DS18B20_2 CON %01011111
;DS18B20_9bit CON %00011111 ; 93.75ms, 0.5°C
;DS18B20_10bit CON %00111111 ; 187.5ms, 0.25°C
;DS18B20_11bit CON %01011111 ; 375ms, 0.125°C
SecondsChanged var bit
MinutesChanged var bit
HoursChanged var bit
DaysChanged var bit
SecondsChanged = 1
MinutesChanged = 1
Seconds = 0
Minutes = 0
Hours = 12
Days = 1
Months = 1
SecondsChanged = 1
MinutesChanged = 1
HoursChanged = 1
DaysChanged = 1
include "timp.pbp.txt"
Pause 200 ' Wait for LCD to Initialize
' Init Sensor 1
OWOUT DQ, 1, [$CC, $4E, 0, 0, DS18B20_1]
OWOut DQ, 1, [$CC, $48]
OWOut DQ, 1, [$CC, $B8]
OWOut DQ, 1, [$CC, $BE]
Pause 50
OWIn DQ, 2, [TempC.byte0, TempC.byte1]
Pause 50
' Init Sensor 2
OWOUT DQ2, 1, [$CC, $4E, 0, 0, DS18B20_2]
OWOut DQ2, 1, [$CC, $48]
OWOut DQ2, 1, [$CC, $B8]
OWOut DQ2, 1, [$CC, $BE]
Pause 50
OWIn DQ2, 2, [TempC2.byte0, TempC2.byte1]
Pause 50
mainloop:
if tick.0=1 then
tick.0=0
Seconds = Seconds + 1
SecondsChanged = 1
if Seconds = 60 then
Minutes = Minutes + 1
MinutesChanged = 1
Seconds = 0
endif
if Minutes = 60 then
Hours = Hours + 1
HoursChanged = 1
Minutes = 0
endif
if Hours = 24 then
Days = Days + 1
DaysChanged = 1
Hours = 0
endif
if Days = 32 then
Months = Months + 1
Days = 1
endif
if months = 13 then
months = 1
endif
endif
' Check button pressed to set time
if pushbutton1 = pressed Then
gosub set_minutes
endif
if pushbutton2 = pressed then
gosub set_hours
endif
if pushbutton4 = pressed then
gosub set_days
endif
if pushbutton3 = pressed then
gosub set_Months
endif
' Check for time to update screen
If SecondsChanged = 1 Then
SecondsChanged = 0 ' Display time as hh:mm:ss
LCDout $FE, $80, dec2 Hours,":",dec2 Minutes,":",dec2 Seconds," ",DEC2 Days,"/",DEC2 Months
LCDOUT $FE, $C0, semn,DEC ABS TempC/100,".", DEC1 ABS TempC/10, 223,"C ", $FE, $C0 + 9, semn2,DEC ABS TempC2/100,".", DEC1 ABS TempC2/10, 223,"C "
' pauseus 1386
Endif
Goto mainloop ' Do it all forever
set_minutes:
Minutes = Minutes + 1
if Minutes = 60 then
Minutes = 0
endif
gosub debounce
return
set_hours:
Hours = Hours + 1
if Hours = 24 then
Hours = 0
endif
gosub debounce
return
set_days:
Days = Days + 1
if Days = 32 then
Days = 1
endif
gosub debounce
return
set_months:
Months = Months +1
if Months = 13 then
Months = 1
endif
gosub debounce
return
debounce:
For i = 1 To 100 ' Debounce and delay for 100ms
Pause 1 ' 1ms at a time so no interrupts are lost
Next i
SecondsChanged = 1
return
;===================================================
Read_Temp:
' Skip ROM search & do temp conversion
OWOut DQ, 1, [$CC, $BE]
OWIn DQ, 2, [TempC.byte0, TempC.byte1]
Sign = TempC.15
TempC = ABS(TempC)
TempC = ((TempC >> 4)*100) + ((TempC & $F)*100 >> 4)
IF Sign THEN TempC = -TempC
IF TempC.15 THEN
Semn="-"
else
Semn="+"
endif
OWOut DQ2, 1, [$CC, $BE]
OWIn DQ2, 2, [TempC2.byte0, TempC2.byte1]
Sign2 = TempC2.15
TempC2 = ABS(TempC2)
TempC2 = ((TempC2 >> 4)*100) + ((TempC2 & $F)*100 >> 4)
IF Sign2 THEN TempC2 = -TempC2
IF TempC2.15 THEN
Semn2="-"
else
Semn2="+"
endif
Return
;===================================================
End
and timp.pbp.txt
Code:
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, int_handler, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
INT_ENABLE TMR0_INT ; Enable Timer 1 Interrupts
ENDASM
OPTION_REG = %00001000 ' Set TMR0 configuration
INTCON = %10100000 ' Enable TMR0 interrupts
bres_hi VAR BYTE bank0 system ' hi byte of our 24bit variable
bres_mid VAR BYTE bank0 system ' ; mid byte
bres_lo VAR BYTE bank0 system '; lo byte
'; (we only need 3 bytes for this system)
bres_hi = $0F
bres_mid= $42
bres_lo= $40
tick VAR BYTE bank0 system
ASM
;******************************************************************************
; INTERRUPT HANDLER (runs this code each timer0 interrupt)
;******************************************************************************
;
;------------------
int_handler ;
;------------------
;-------------------------------------------------
;-------------------------------------------------
; Note! we get here every 256 instructions, we
; can now do our special one second timing system.
; This consists of three main steps;
; * subtract 256 counts from our 24bit variable
; * test if we reached the setpoint
; * if so, add 1,000,000 counts to 24bit variable and generate event.
;-------------------------------------------------
; * optimised 24 bit subtract here
; This is done with the minimum instructions.
; We subtract 256 from the 24bit variable
; by just decrementing the mid byte.
tstf bres_mid ; first test for mid==0
skpnz ; nz = no underflow needed
decf bres_hi,f ; z, so is underflow, so dec the msb
decfsz bres_mid,f ; dec the mid byte (subtract 256)
; now the full 24bit optimised subtract is done!
; this is about 4 times faster than a "proper"
; 24bit subtract.
goto int_exit ; nz, so definitely not one second yet.
; in most cases the entire 'fake" int takes
; only 9 instructions.
;------------------------
; * test if we have reached one second.
; only gets here when mid==0, it MAY be one second.
; only gets to here 1 in every 256 times.
; (this is our best optimised test)
; it gets here when bres_mid ==0.
tstf bres_hi ; test hi for zero too
skpz ; z = both hi and mid are zero, is one second!
goto int_exit ; nz, so not one second yet.
;-------------------------------------------------
; Only gets to here if we have reached one second.
; now we can generate our one second event, like add
; one second to our clock or whatever.
; (in this example we toggle a led)
; The other thing we need to do is add 1,000,000 counts
; to our 24bit variable and start all over again.
;-------------------------------------------------
; Add the 1,000,000 counts first.
; One second = 1,000,000 = 0F 42 40 (in hex)
; As we know hi==0 and mid==0 this makes it very fast.
; This is an optimised 24bit add, because we can
; just load the top two bytes and only need to do
; a real add on the bottom byte. This is much quicker
; than a "proper" 24bit add.
movlw 0x0F ; get msb value
movwf bres_hi ; load in msb
movlw 0x42 ; get mid value
movwf bres_mid ; load in mid
movlw 0x40 ; lsb value to add
addwf bres_lo,f ; add it to the remainder already in lsb
skpnc ; nc = no overflow, so mid is still ok
incf bres_mid,f ; c, so lsb overflowed, so inc mid
; this is optimised and relies on mid being known
; and that mid won't overflow from one inc.
; that's it! Our optimised 24bit add is done,
; this is roughly twice as quick as a "proper"
; 24bit add.
;-------------------------
; now we do the "event" that we do every one second.
; Note! for this example we toggle a led, which
; will give a flashing led which is on for a second
; and off for a second.
; Add your own code here for your one second event.
; Note! My led is on porta,3
; your led may be on a different pin.
movlw b'00000001' ; mask for bit 3
xorwf tick,f ; toggle PORTA,bit3 (toggle the led)
;-------------------------------------------------
; now our one second event is all done, we can exit the
; interrupt handler.
;-------------------------------------------------
; finally we restore w and status registers.
; also clears TMRO int flag now we are finished.
int_exit
INT_RETURN
ENDASM