PDA

View Full Version : Cooking (kitchen) Timer - Xtal or Resonator both too "slow"



flotulopex
- 28th November 2015, 16:34
8108

Hi All,

I've finished a cooking-timer (or kitchen-timer, as you like...) program and circuit.

I made two prototypes up to now; the first equipped with a Xtal and the second with a resonator.

Unfortunately, both circuits are "slow" in timing. After 1 hour internet time reference, the timer has still 24 to 25 seconds to go before its countdown is finished.

I changed Xtal and capacitors (15pF), tried a ceramic resonator but nothing does.

BTW, my circuit is using Melanie NEWMAN's "Olympic Timer" (http://www.picbasic.co.uk/forum/content.php?r=176-Olympic-Timer).

How can I tune things without having to bit bang the timer interrupt routine?


'************************************************* ***************
'* Name : CookingTimer_N-logic_reso_16F690.pbp
'* Author : FLOTUL
'* Notice : Copyright (c) 2015 Flotulopex & Co.
'* : All Rights Reserved
'* Date : 22.11.2015
'* Version : 2.0
'* Notes :
'* :
'************************************************* ***************

' For use with 8MHz resonator and EAGLE board *reso*

' DESCRIPTION - Cooking (kitchen) Timer VERSION 2 (countdown) program using TMR0 Interrupt
' - ELECTRONIC ASSEMBLY DOGM081 (1x8) LCD display
' - TWO buttons ONLY
' - Each buttons's incremental time is programmable from 1' to 9'
' - Timer from 1 to 255 minutes (4 hours 15 minutes)
' - Buttons are Power-ON Soft-Switches
' - Buttons are not logic inverted because of "soft-switch" function (=> ON = 1, OFF = 0)
' - After two seconds no-press, countdown starts
' - Any press pauses countdown; any press resumes countdown
' - Any press stops alarm
' - 4kHz Piezo sounder steered by PWM /(Half-Bridge P1A & P1B)
' - Circuit does switch-OFF automatically after 255 seconds by alarm or 10 seconds in idle mode
' - Battery level is checked evey 10 seconds
' - Program hierarchy is special to quickly capture the switch-ON button
' - Circuit consumes 3,15mA (0,2mA for ADC)

' USAGE
' - To start timer, press either button to increment time; after 2 seconds no press, countdown starts.
' - Pressing buttons simultaneously any time will RESET the timer.
' - Keeping both button pressed (=RESET!) over 5 seconds will allow to toggle display "00:00" to "00m00s"
' - While incrementing time, keeping a button pressed for more than 5 seconds will
' initate the button's incremental time programming mode.
' - Any press stops alarm.
' - When timer is running, any button will pause countdown; press again to resume.
' - While "paused", sounder bips every 5 seconds.

' OPTION_REG & INTCON TMR0 settings
'----------------------------------
' OSC set to 8MHz : 4(operations per cycle) = 2'000'000 cycles per second
' Cycle duration is: 1s(second) / 2'000'000 = 0,5µs
' TMR0 increments from 0 to 255 = 256 steps
' Choosen TMR0 prescaler rate = 1:128
' One Tick (interrupt) happens every: 256 x 128 x 0,5µs = 16'384µs = 16,384ms
' So, in one second, there are: 1'000ms / 16,384ms = 61 Ticks

'Identify HW-SW
data 48,48,50,48 '0,0,2,0

'Filename
DATA @8,67,111,111,107,105,110,103,84,105,109,101,114,9 5,78,45,108,111,103,105,99,95,114,101,115,111,95,4 9,54,70,54,57,48

' Set inital values for buttons and display format
DATA @5,1,5,0

'Version history
'0-0-2-0:

'-------------------------------------------------------------------------------
' PIC 16F690 Fuses (MPASM)
@ __config _FCMEN_OFF &_IESO_OFF &_CPD_OFF &_WDT_OFF &_XT_OSC &_BOR_OFF &_CP_OFF &_PWRTE_OFF &_MCLRE_OFF
'_INTRC_OSC_NOCLKOUT

'-------------------------------------------------------------------------------
' Registers 76543210
OPTION_REG = %10000110 ' Pull-Ups OFF, Prescaler TMR0 1:128
ANSEL = %00000000 ' Select analog inputs Channels 0 to 7
ANSELH = %00000000 ' Select analog inputs Channels 8 to 11
WPUA = %00000000 ' Select weak pull-ups
WPUB = %00000000 ' Select weak pull-ups
ADCON0 = %10110101 ' Select the VP6 channel as ADC input bits5:2 (xx1101xx)
ADCON1 = %00110000 ' Set FRC
VRCON = %00010000 ' Enable the VP6 reference
CM1CON0 = %00000000 ' Comparator1 Module
CM2CON0 = %00000000 ' Comparator2 Module
INTCON = %10100000 ' INTerrupts CONtrol; GIE=1, T0IE=1
TRISA = %00000000 ' Select Input/Output (0 to 5)
PORTA = %00000100 ' Set High/Low (0 to 5)
TRISB = %00000000 ' Select Input/Output (4 to 7)
PORTB = %00000000 ' Set High/Low (4 to 7)
TRISC = %00000011 ' Select Input/Output (0 to 7)
PORTC = %00000000 ' Set High/Low (0 to 7)

' HPWM registers
T2CON = %00000101 ' Timer2 = ON (bit2), prescaler (bits1:0) 00=1, 01=4, 1x=16
CCP1CON = %00000000 ' Select PWM Mode (%00001100 = PWM module ON)
CCPR1L = 62 ' Dutycycle = proportional to PR2 (here = 50%)
PR2 = 124 ' Freq 4kHz (specific to used piezo sounder)

'-------------------------------------------------------------------------------
' Defines
define OSC 8
DEFINE ADC_BITS 10 'Number of bits in ADCIN result

'-------------------------------------------------------------------------------
' Variables

' Declare minimum var to speed-up switch-ON process
Btn1Val var BYTE
Btn2Val var BYTE
Dsp_Format var bit ' Display format: 0 = "00:00", 1 = "00m00s"
READ 5,Btn1Val,Btn2Val,Dsp_Format
Minutes var byte
minutes = 0
Btn1 var PORTC.1
Btn2 var PORTC.0
IF Btn1 = 1 then Minutes = Btn1Val
IF Btn2 = 1 then Minutes = Btn2Val
while Btn1 = 1 : WEND
while Btn2 = 1 : WEND

' Declare vars normally from here
Alarm var bit
Alarm = 0
Bat_Level var byte ' for LCD character selection (3:7)
Bat_Level = 7
Bat_Value var word ' holds ADC value
Bat_Value = 0
Cnt_A var word
Cnt_a = 0
DataPin var PORTA.0 ' for DEBUG - serial data OUT

Dsp_Upd var bit ' Display Update Allowance
DSP_Upd = 1
IdleCounter var byte ' counter that increments while timer is 00:00
IdleCounter = 0
Mode Var word ' for DEBUG
Mode = 32 ' PICKit DTN 84=9600,32=19200 : SerialCom DIN 16468=9600,16416=19200
Paused var bit
paused = 0
Run var bit ' timer's running flag
RUN = 0
Seconds var byte
Seconds = 0
SoftSwitch var PORTA.2
SoftSwitch = 1
StatusSym var byte ' shows alarm or pause symbol on LCD
StatusSym = " "
Ticks var byte
Ticks = 0

'-------------------------------------------------------------------------------
' Init display

DEFINE LCD_DREG PORTB ' LCD data port
DEFINE LCD_DBIT 4 ' LCD data starting PORT.bit (0 or 4)
DEFINE LCD_RSREG PORTC ' LCD register select port
DEFINE LCD_RSBIT 7 ' LCD register select bit
DEFINE LCD_EREG PORTC ' LCD enable port
DEFINE LCD_EBIT 6 ' LCD enable bit
DEFINE LCD_BITS 4 ' LCD bus size 4 or 8

' ELECTRONIC ASSEMBLY DOGM081 LCD display Mandatory settings
' See datasheet for circuitry changes by 5V or 3,3V operation
pause 100 ' Time to settle Vdd, normally 1000ms (THIS IS CRUCIAL!!!)
lcdout $FE, $29 ' Function Set: 4 bits bus mode
lcdout $FE, $1C ' Bias set
lcdout $FE, $52 ' Power control + Contrast (HiByte)(for 5V=$52 or 3,3V=55)
lcdout $FE, $69 ' Follower control (5V=$69/3,3V=6D)
Lcdout $FE, $75 ' Contrast (LowByte)

' Custom Characters
lcdout $FE,$28 'Function Set change - ONLY valid for ST7036 controller based LCDs
LCDOUT $FE,$40,$02,$06,$1A,$1A,$1A,$06,$02,$00 'Char 0 = Speaker
'LCDOUT $FE,$48,$00,$08,$0C,$0E,$0C,$08,$00,$00 'Char 1 = Run symbol
LCDOUT $FE,$50,$00,00,$1B,$1B,$1B,$1B,$00,$00 ' Char 2 = pause symbol
LCDOUT $FE,$58,$00,$1F,$11,$11,$11,$1F,$00,$00 ' Char 3 = big square
LCDOUT $FE,$60,$00,$00,$0E,$0A,$0E,$00,$00,$00 ' Char 4 = small square
LCDOUT $FE,$68,14,27,17,17,31,31,31,00 'Char 5 = Battery 3/5 full
LCDOUT $FE,$70,$04,$04,$04,$04,$04,$1F,$0E,$04 ' Char 6 = Down arrow
LCDOUT $FE,$78,14,31,31,31,31,31,31,00 'Char 7 = Battery 5/5 full
lcdout $FE,$29 'Function Set change


'-------------------------------------------------------------------------------
' Start program

On Interrupt Goto TICK_INT

MAIN:

if RUN = 0 then ' Timer is stopped (idle)
' Add minutes to timer
IF Alarm = 0 THEN
StatusSym = " "
' Switch PWM OFF and pull piezo's ports down
GOSUB SOUNDER_OFF
' Add Btn1 minutes and allow RESET if both buttons are pressed simultaneously
If Btn1 = 1 Then
Minutes = minutes + Btn1Val
GOSUB UPDATE_DISPLAY
IdleCounter = 0
Ticks = 0
WHILE Btn1 = 1
if IdleCounter > 4 then ' after 3 secs, goto set btn value
Btn1Val = Btn1Val - 1
if Btn1Val < 1 then Btn1Val = 9
while Btn1 = 1 ' increment btn value as long as btn is pressed
Btn1Val = Btn1Val + 1
if Btn1Val > 9 then Btn1Val = 1
Lcdout $FE,2,4," Time:", dec1 Btn1Val
pause 1000
WEND
write 5, Btn1Val
idlecounter = 0
ENDIF
IF Btn2 = 1 then GOSUB RESET
WEND ' does also act as debounce
endif
' Add Btn2 minutes and allow RESET if both buttons are pressed simultaneously
If Btn2 = 1 Then
MINUTEs = MINUTEs + Btn2Val
GOSUB UPDATE_DISPLAY
IdleCounter = 0
Ticks = 0
WHILE Btn2 = 1
if IdleCounter > 4 then ' after 5 secs, goto set btn value
Btn2Val = Btn2Val - 1
if Btn2Val < 1 then Btn2Val = 9
while Btn2 = 1 ' increment btn value as long as btn is pressed
Btn2Val = Btn2Val + 1
if Btn2Val > 9 then Btn2Val = 1
Lcdout $FE,2,3," Time:", dec1 Btn2Val
pause 1000
WEND
write 6, Btn2Val
idlecounter = 0
ENDIF
IF Btn1 = 1 then GOSUB RESET
WEND ' does also act as debounce
endif
' Switch-OFF circuit after 10 seconds
IF IdleCounter > 9 then '**** = 5
alarm = 0
SoftSwitch = 0
endif
' Start the countdown timer after 2 seconds no press (=> RUN = 1)
if minutes > 0 THEN
if IdleCounter > 0 then
if Ticks = 60 then ' allow change until last moment before start
RUN = 1
Alarm = 0
ENDIF
ENDIF
ENDIF
endif ' Alarm = 0
if Alarm = 1 THEN
StatusSym = 0
' Stop alarm by any button press
while Btn1 = 1
idlecounter = 0
Alarm = 0
WEND
WHILE Btn2 = 1
idlecounter = 0
Alarm = 0
WEND
' Switch-OFF circuit after 255 seconds by alarm
IF IdleCounter = 255 then
alarm = 0
SoftSwitch = 0
endif
' Alarm - Piezo sounder activation (PWM)
IF idlecounter // 2 = 0 then
CCP1CON = %10001100 ' enable half-bridge PWM
ELSE
GOSUB SOUNDER_OFF
ENDIF
endif ' Alarm = 1
endif ' RUN = 0

IF RUN = 1 THEN ' Timer is running
' Countdown timer has ended = enable alarm
if minutes = 0 THEN
IF seconds = 0 THEN
RUN = 0
IdleCounter = 0
Alarm = 1
StatusSym = 0
GOSUB UPDATE_DISPLAY
ENDIF
endif
' Stop and GO! ("Paused") Allow to stop countdown and resume
IF paused = 0 then
StatusSym = " "
' Activate "Paused" mode or RESET
IF Btn1 = 1 THEN
PAused = 1
IdleCounter = 1
Dsp_Upd = 1
WHILE Btn1 = 1
IF Btn2 = 1 then GOSUB RESET
WEND
ENDIF
IF Btn2 = 1 THEN
PAused = 1
IdleCounter = 1
Dsp_Upd = 1
WHILE Btn2 = 1
IF Btn1 = 1 then GOSUB RESET
WEND
ENDIF
endif ' "Paused = 0"
IF Paused = 1 then
StatusSym = 2 ' pause symbol
' Alarm - Piezo sounder activation (PWM)
IF idlecounter // 5 = 0 then
CCP1CON = %10001100 ' enable half-bridge PWM
ELSE
GOSUB SOUNDER_OFF
ENDIF
' Deactivate "Paused" mode or RESET
IF Btn1 = 1 THEN
PAused = 0
GOSUB SOUNDER_OFF
IdleCounter = 1
Dsp_Upd = 1
WHILE Btn1 = 1
IF Btn2 = 1 then GOSUB RESET
WEND
ENDIF
IF Btn2 = 1 THEN
PAused = 0
GOSUB SOUNDER_OFF
IdleCounter = 1
Dsp_Upd = 1
WHILE Btn2 = 1
IF Btn1 = 1 then GOSUB RESET
WEND
ENDIF
ENDIF ' "Paused = 1"
ENDIF ' "RUN = 1"

' Battery check every 10 seconds
IF idlecounter // 10 = 0 then gosub BATTERY_CHECK

' Update display each second
if Dsp_Upd = 1 then GOSUB UPDATE_DISPLAY

GOTO MAIN
END


'================================================= ==============================
' SUBROUTINES

RESET:
Lcdout $FE,2," Reset! "
RUN = 0
Alarm = 0
StatusSym = " "
Minutes = 0
Paused = 0
seconds = 0
IdleCounter = 0
CCP1CON = %00000000
PORTC.4 = 0
PORTC.5 = 0
Dsp_Upd = 1
WHILE Btn1 = 1
IF Btn2 = 1 then
IF IdleCounter > 4 then '..if both buttons are still pressed after 5 seconds then
IF Dsp_format = 1 then
Dsp_format = 0
Lcdout $FE,2, " 00:00"
pause 2000
goto LEAVE2
ENDIF
IF Dsp_format = 0 then
Dsp_format = 1
Lcdout $FE,2, " 00m00s"
pause 2000
GOTO LEAVE2
ENDIF
ENDIF
LEAVE2:
write 7, dsp_format
endif
WEND
IdleCounter = 0
PAUSE 300
RETURN

SOUNDER_OFF:
CCP1CON = %00000000
PORTC.4 = 0 ' pull port down because piezo doesn't like DC
PORTC.5 = 0 ' " " " " " " " "
RETURN

UPDATE_DISPLAY:
' Update display every elapsed second and adapt (# of "Minutes" digits) display
Dsp_Upd = 0
if minutes > 99 then
if dsp_format = 0 then
Lcdout $FE,2," ", dec3 minutes,":",dec2 Seconds
ELSE
Lcdout $FE,2," ", dec3 minutes,"m",dec2 Seconds,"s"
ENDIF
'Serout2 DataPin,Mode,[dec1 minutes,"m ",dec2 Seconds,"s",13,10]
GOTO LEAVE1
ENDIF
if minutes > 9 then
if dsp_format = 0 then
Lcdout $FE,2," ", dec2 minutes,":",dec2 Seconds
ELSE
Lcdout $FE,2," ", dec2 minutes,"m",dec2 Seconds,"s"
ENDIF
'Serout2 DataPin,Mode,[dec1 minutes,"m ",dec2 Seconds,"s",13,10]
GOTO LEAVE1
ENDIF
if minutes >= 0 then
if dsp_format = 0 then
Lcdout $FE,2," ",dec1 minutes,":",dec2 Seconds
ELSE
Lcdout $FE,2," ", dec1 minutes,"m",dec2 Seconds,"s"
ENDIF
'Serout2 DataPin,Mode,[dec1 minutes,"m ",dec2 Seconds,"s",13,10]
ENDIF
LEAVE1:
' Alarm symbol blinker
IF idlecounter // 2 = 0 then
Lcdout $FE,$80,StatusSym
ELSE
Lcdout $FE,$80," "
ENDIF
RETURN

' Check battery level using PIC's internal 0,6V reference
' Battery monitoring system according to MICROCHIP's AN1072
BATTERY_CHECK:
disable
' Following 3 registers set on top of program - only here as reminder - DO NOT UNCOMMENT
'ADCON0 = %10110101 ' Select the VP6 channel (13) to select 0,6V reference
'ADCON1 = %00110000 ' Set FRC (Frequency)
'VRCON = %00010000 ' Enable the VP6 reference
ADCON0.1 = 1 ' Start ADC
while ADCON0.1 : wend
Bat_Value.HighByte = ADRESH : Bat_Value.LOWByte = ADRESL
IF Bat_Value >= 120 then Bat_Level = 5
IF Bat_Value < 119 then Bat_Level = 7
resume
enable
RETURN

' Interrupt routine to handle each timer tick
disable
TICK_INT:
Ticks = Ticks + 1 'Count pieces of seconds
If Ticks < 61 Then TICK_FLAG_RESET '61 ticks per second (16.384ms per tick)
' One second has elasped
Ticks = 0
IdleCounter = IdleCounter + 1
Dsp_Upd = 1 'one second has elapsed, update is allowed
IF RUN = 1 THEN
if paused = 0 then
Seconds = Seconds - 1
If Seconds = 255 then '= Second is "smaller" than 0
seconds = 59
minutes = minutes -1
Endif
endif
ENDIF
TICK_FLAG_RESET:
INTCON.2 = 0 'reset T0IF flag
Resume
enable

'================================================= ==============================
' [PIC] - (LCD) EA-8081-A3N 4-bits circuitry

' (LCD) EA DOG-Mxxx-A 4-bits circuitry
'(27,38) Vss - GND
'(23,24,26,27,32,33,32,35,40) Vdd / Vcc +5V or 3,3V
'(38) LCD-R/W -> to Vss

' [PIC] (LCD)
'PORTA.0[19] ICSPDAT
'PORTA.1[18] ICSPCLK
'PORTA.2[17] Soft-Switch
'PORTA.3[04] MCLR
'PORTA.4[03] OSC2 - Xtal
'PORTA.5[02] OSC1 - Xtal

'PORTB.4[13] (31) LCD-D4
'PORTB.5[12] (30) LCD-D5
'PORTB.6[11] (29) LCD-D6
'PORTB.7[10] (28) LCD-D7

'PORTC.0[16] R Button
'PORTC.1[15] L Button
'PORTC.2[14]
'PORTC.3[07]
'PORTC.4[06] CCP1/PWM piezo sounder on P1B
'PORTC.5[05] CCP1/PWM piezo sounder on P1A
'PORTC.6[08] (36) LCD-E
'PORTC.7[09] (39) LCD-RS

flotulopex
- 28th November 2015, 18:26
...well, I just tried to roughly adjust the oscillator's settings via the OSCTUNE register and it looks to make some effect.

Until now, I was assuming OSCTUNE was only effective while using the internal oscillator.

Am I wrong?

flotulopex
- 28th November 2015, 19:55
No, something else is affecting the oscillator's accuracy. But what is it?

I can't see "real" changes by setting the OSCTUNE register. Still believe it doesn't work when using an external oscillator.

Acetronics2
- 28th November 2015, 20:15
No, something else is affecting the oscillator's accuracy. But what is it?





On Interrupt Goto TICK_INT


How many times an Hour ???

BTW ... THIS


CalibrationLoop:
LCDOut $FE,$8B
If TMR1Cal=0 then
LCDOut " "
else
If TMR1CalAR=0 then
LCDOut "+"
else
LCDOut "-"
endif
endif
LCDOut #TMR1Cal," "
' ----------------------------------------------------------
' Press Start Button to ADVANCE (speed-up) Clock
' Press STOP Button to RETARD (slow-down) Clock
' Press RESET Button to SAVE new Calibration Setting
' ----------------------------------------------------------
' Remember each Calibration 'tick' will advance or
' retard the Timing by 1uS in every 10mS period - that's
' 360mS/Hour per setting. Example: A setting of +8 will
' SPEED-UP the Timer by 2.88 Seconds (8 x 360mS) in an Hour.
' ----------------------------------------------------------
If TMR1CalAR=0 then
If ButStart=0 then Gosub CalAdvance
If ButStop=0 then Gosub CalRetard
else
If ButStart=0 then Gosub CalRetard
If ButStop=0 then Gosub CalAdvance
endif
If ButReset=0 then
Write 0,TMR1CalAR
Write 1,TMR1Cal
LCDOut $FE,1,"Have a Nice Day"
Pause 1000
Goto DisplayReset
endif
SetupTimeout=SetupTimeout+1
If SetupTimeout>200 then goto DisplayReset
Pause 100
Goto CalibrationLoop


has mysteriously disappeared from your code ... :rolleyes::rolleyes::rolleyes:

Alain

flotulopex
- 28th November 2015, 21:34
Wow, good notice about the calibration code! ;-)

Going back to my desk and count the ticks in one hour...

Merci Alain