Timer 0 not accurate


+ Reply to Thread
Results 1 to 6 of 6
  1. #1
    Join Date
    Mar 2024
    Posts
    2

    Default Timer 0 not accurate

    Hello, I am new to to this forum and am looking for help regarding timer issue. I am using a 18F4523 with a 4Mhz clock. Timer 0 is configured for 8 bit 1/64 prescaler (16.384ms/tick) which I am displaying hour:min:sec to LCD display. The problem is that the time is 52 seconds faster every minute. I have gone over the code umpteen times and do not no why it is acting as it is. The object of the program is to condition a device at a certain temperature for 3 days then test the device and continue for the next 5 days testing every day. See code for possible error.

    Code:
    'Define LCD registers and bits 
    DEFINE	LCD_DREG	PORTD
    DEFINE	LCD_DBIT	4
    DEFINE	LCD_RSREG	PORTE
    DEFINE	LCD_RSBIT	0
    DEFINE	LCD_EREG	PORTE
    DEFINE	LCD_EBIT	1
    
    
    low PORTE.2
    pause 100
    
    
    TRISB.0 = 1             ' Set PORTB bit 0 as input external pullups
    TRISB.1 = 1             ' Set PORTB bit 1 as input external pullups
    TRISB.2 = 1             ' Set PORTB bit 2 as input external pullups
    TRISB.3 = 0             ' Set PORTB bit 3 as output
    TRISB.4 = 0             ' Set PORTB bit 4 as output
    TRISB.5 = 0             ' Set PORTB bit 5 as output
    
    
    ' Set TMR0 to interrupt every 16.384 milliseconds
    INTCON = $E0            ' Enable TMR0 interrupts
    TMR0IF  var INTCON.2    ' Timer0 interrupt flag
    T0CON = $45             ' Set timer0 register - timer off, 
                            ' internal instruction clock, 1:64 prescale
    TMR0ON  var T0CON.7     ' Timer0 on bit
    
    
    
    
    ' Timer 1 used to blink LEDs
    ' Set TMR1 to interrupt every 500 milliseconds
    T1CON = $31         ' Set prescaler to 1:8 and timer1 on 
    TMR1IF  var PIR1.0  ' Timer1 interrupt flag
    TMR1ON  var T1CON.0 ' Timer1 on bit
    PIE1.0 = 1          ' Timer1 enabled
    TMR1H = $0B         ' preset for timer1 MSB register
    TMR1L = $DC         ' preset for timer1 LSB register
    TMR1IF = 0          ' Clear timer1 interrupt flag
    ADCON1 = $0F        ' Set channels all digital
    
    
    
    
    
    
    '---------------------------Declare Variables-----------------------------------
    
    
    reset_pb    var PORTB.0 ' 4.7K external pullup resistor Reset button
    cycle_pb    var PORTB.1 ' 4.7K external pullup resistor Inc Cycle button 
    alarm_in    var PORTB.2 ' 4.7K external pullup resistor Alarm indication
    done_LED    var PORTB.3 ' Done indication LED
    cond_LED    var PORTB.4 ' Condition LED
    alrm_LED    var PORTB.5 ' Alarm from temperature controller LED
    hour        Var byte    ' Define hour variable
    minute      Var byte    ' Define minute variable
    second      Var byte    ' Define second variable
    ticks       Var byte    ' Define pieces of seconds variable for timer0
    ticks1      var byte    ' Define pieces of seconds variable for timer1
    update      Var bit     ' Define variable to indicate update of LCD
    i           Var byte    ' Debounce loop variable
    cond_days   var byte    ' Days of conditioning = 60
    cycles      var byte    ' Test cycles = 10
    do_once     var bit     ' Only do one time flag
    do_once1    var bit     ' Only do one time flag
    ready       var bit     ' Flag for cycles push button ready
    counts      var byte    ' Counter for alarms
    hr          var bit     ' Flag to indicate 24hrs has passed
    timer1      var bit     ' Flag to blink LED's
    
    
    
    
    hour = 0                ' Reset hour
    minute = 0              ' Reset minute
    second = 0              ' Reset second
    low done_LED            ' Turn off LED
    low cond_LED            ' Turn off LED
    low alrm_LED            ' Turn off LED
    update = 1              ' Set to update LCD display
    do_once = 0             ' Reset flag
    do_once1 = 0            ' Reset flag
    counts = 0              ' Reset flag
    
    
    read 100, cond_days     ' Load condition days from memory
    read 101, cycles        ' Load cycles from memory
    
    
    On Interrupt Goto ISR   ' Jump to interrupt service routine
    
    
    main:
        if reset_pb = 0 then        ' Reset button pressed
            cond_days = 0
            cycles = 0
            second = 0
            minute = 0
            hour = 0
            low done_LED
            low cond_LED
            low alrm_LED 
            do_once = 0     ' Flag for temp in range
            do_once1 = 0    ' Flag for temp out of range
            update = 1
        endif    
        
        If update = 1 Then      ' Check for time to update screen
            INTCON = $00        ' No interrupts during lcdout write
            lcdout,$FE,1
            lcdout,$FE,$C0,"      ",dec2 hour, ":",dec2 minute,":",dec2 second
            lcdout,$FE,$94," CONDITION DAYS: ",dec cond_days
            lcdout,$FE,$D4," TEST CYCLES: ", dec cycles        
            update = 0          ' Screen updated
            INTCON = $E0        ' Enable interrupts
        Endif    
    
    
         
        if cycles = 5 and cond_days = 8 then    ' Condition for 3 days and 
            TMR0ON = 0                            ' cycle for 5 = 8 total days
            TMR1ON = 0
            INTCON = $00
            low cond_led
            high done_led
            goto main
        endif
        
        if alarm_in = 0 then
            if do_once1 = 0 then    ' Temperature out of range
                TMR0ON = 0          ' Turn off timer0
                TMR1ON = 0          ' Turn off timer1
                high alrm_LED
                low done_LED
                low cond_LED
                do_once = 0
                do_once1 = 1            
            endif    
        endif
        
        if alarm_in = 1 then        ' Temperature in range       
            if do_once = 0 then  
                T0CON = $C5         ' Turn on timer 0, 8 bit, 1/64 prescaler 
                TMR1ON = 1          ' Turn on timer 0
                TMR1IF = 0          ' Clear timer 0 interrupt flag           
                low alrm_LED
                do_once = 1
                do_once1 = 0
            endif   
        endif    
        
        if hr = 1 then
            if do_once = 1 then            
                T0CON = $25
                cond_days = cond_days + 1
                write 100,cond_days
                second = 0
                minute = 0
                hour = 0
                do_once = 0
                if cond_days > 3 then ready = 1 ' change according to test requirement                              
            endif
            hr = 0
        endif 
        
        if cond_days > 3 and cycles < 6  then  ' Change according to test requirements
            if ready = 1 then           ' 24 hours passed ready for cycle
                T0CON = $25             ' Set timer0 register - timer off, internal instruction clock, 1/64 prescale        
                if cycles < 6 then      ' Change according to test requirements
                    if cycle_pb = 0 then
                        gosub Debounce
                        cycles = cycles + 1
                        write 101, cycles
                        second = 0
                        minute = 0
                        hour = 0
                        low done_LED
                        do_once = 0
                        ready = 0
                        update = 1
                    endif                
                endif
            endif    
        endif    
    
    
        if timer1 = 1 then
            if cond_days < 9 then  ' Change according to test requirements
                if ready = 1 then
                    low cond_led
                else
                    toggle cond_LED
                endif
            endif
            if cond_days > 3 and cycles < 6 then   ' Change according to test requirements
                if ready = 1 then
                    toggle done_LED
                endif
            endif
            timer1 = 0
        endif
        
        goto main
    
    
    
    
       ' Interrupt routine to handle each timer tick
       Disable            ' Disable interrupts during interrupt handler
    ISR:
    
    
        if TMR0IF = 1 then
            ticks = ticks + 1  ' Count pieces of seconds
            If ticks < 61 Then tiexit ' 61 ticks per second (16.384ms per tick)
     
            ticks = 0
    
    
            ' One second elasped - update time
            second = second + 1
            If second > 59 Then
                minute = minute + 1
                second = 0
                If minute > 59 Then
                    minute = 0
                    hour = hour + 1
                    if hour >= 24 then hr = 1   ' Set flag 24hrs passed
                endif
            endif
            update = 1      ' Set to update LCD    
        endif
    
    
    
    
    
    
        if TMR1IF = 1 then                 
            timer1 = 1
            TMR1H = $0B         ' preset for timer1 MSB register
            TMR1L = $DC         ' preset for timer1 LSB register    
            TMR1IF = 0 
        endif
        resume
    
    
    tiexit: 
        TMR0IF = 0    ' Reset timer interrupt flag
        TMR0H = $00
        TMR0L = $00
        resume
    
    
    debounce: 
        For i = 1 to 25
            Pause 10        ' 10ms at a time so no interrupts are lost
        Next i
        Resume
    
    
    end
    Thanks mfsparky

  2. #2
    Join Date
    May 2013
    Location
    australia
    Posts
    2,389


    Did you find this post helpful? Yes | No

    Default Re: Timer 0 not accurate

    how have you set FOSC for the pic.
    there is no OSCCON REGISTER setting in your code , the CONFIG settings are not shown, unless you have a 4mz Xtal setup
    how sure are you that FOSC is the 4mhz you think it is
    Warning I'm not a teacher

  3. #3
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,807


    Did you find this post helpful? Yes | No

    Default Re: Timer 0 not accurate

    One second in the ISR is counted as 16.384*62=1.015808

    Every minute is 60*1.015808=60.94848 so it is indeed about 50-56 seconds faster.

    Why not use the TMR0 as 16 bit timer, no prescaler. After 10000 counts you will have 1 second.

    And if you need it to be more accurate you can either use a XTAL 4MHz with a trimmer to adjust it on spot or use the Timer 1 with external xtal at 32.768KHz, divide by 32768 and get 1Hz pulse.

    Ioannis

  4. #4
    Join Date
    Mar 2024
    Posts
    2


    Did you find this post helpful? Yes | No

    Default Re: Timer 0 not accurate

    I'm sorry I meant that it was 52sec faster every hour not minute. @Richard No I have not defined oscillator but thought it defaulted to 4Mhz. Thanks to you both for your speedy reply. I will define osc and give it ago.

  5. #5
    Join Date
    May 2013
    Location
    australia
    Posts
    2,389


    Did you find this post helpful? Yes | No

    Default Re: Timer 0 not accurate

    I will define osc and give it ago.
    that won't help at all, you need to ensure that the config is correct and that osccon reg is set appropriately
    define OSC just tells compiler what freq you think you are running at, it does nothing to configure the chip in any way.
    and note the OSC bit is case sensitive
    Warning I'm not a teacher

  6. #6
    Join Date
    May 2004
    Location
    NW France
    Posts
    3,614


    Did you find this post helpful? Yes | No

    Default Re: Timer 0 not accurate

    you also can play with the OSCTUNE register ... ( datasheet DS39631E-page 27 )

    most of time it's enough to get usable precision without tuning the OSC Crystal ...

    Alain
    ************************************************** ***********************
    Why insist on using 32 Bits when you're not even able to deal with the first 8 ones ??? ehhhhhh ...
    ************************************************** ***********************
    IF there is the word "Problem" in your question ...
    certainly the answer is " RTFM " or " RTFDataSheet " !!!
    *****************************************

Similar Threads

  1. A REALLY accurate clock.
    By Charles Linquis in forum Code Examples
    Replies: 24
    Last Post: - 16th January 2012, 17:41
  2. How accurate is the internal oscillator ?
    By lilimike in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 13th May 2010, 05:06
  3. Accurate serin usage?
    By sccoupe in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 10th July 2009, 08:36
  4. Using Pic as a digital clock/timer. How accurate?
    By rocky79 in forum mel PIC BASIC Pro
    Replies: 18
    Last Post: - 15th February 2007, 03:02
  5. More accurate resolution from the A/d converters
    By pjsmith in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 5th August 2004, 22:49

Members who have read this thread : 11

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts