Name:  K640_cooking-timers.JPG
Views: 423
Size:  43.9 KB

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".

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

Code:
 '****************************************************************
'*  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,95,78,45,108,111,103,105,99,95,114,101,115,111,95,49,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