Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

TMR0 gives incorrect timing

Status
Not open for further replies.
blueroomelectronics said:
Just noticed (yes I'm just finishing my morning coffee)
You're running the timer asynchronously (you're reloading it), this is not the way to do it.
https://www.romanblack.com/one_sec.htm
The method you linked to gives you a "one second" interval that has zero error when averaged over many intervals. But any single "one second" interval can be off by as much as 255 microseconds (assuming you run with a 1:1 prescaler).

With the 16F628, it would be much better to use TMR2. Using TMR2 you can get an exact 1 second interval (well as precise as the oscillator being used). Using the 4MHz internal osciallator and by setting the TMR2 prescaler to 1:16, the postscaler to 1:10 and the PR2 register to 124 you get an interrupt every 20 milliseconds. After his CNT variable reaches 50 this gives exactly one second.

It is surprising that the internal oscillator is off by 5%, Microchip claims that it is accurate to 1%.

Mike
 
To be 5% out is unusual. Have you tried a different chip. They are supposed to be accurate to 1%.

I just had another look at your code and noticed you don't have a parameter after cblock. This results in CNT getting the value zero which will give unpredictable results. Try changing it to cblock 0x20 and see it that helps.

Mike.
 
I know it shouldn't be as much as 5%, that's why I worried if this is just a case of broken PIC..

but anyway, i think i'll try the TMR2 method to get a correct timing rather than bet on TMR0.. let me try to change the code and see if it works.
 
Either method just counts 1,000,000 clock cycles and so will give the same time. Did you change the cblock directive?

Mike.
 
yes. cblock 0x20 is there.. just missed it out when i added in the code here..

so, that means I should use prescaller 1:1 and count 1,000,000 times to get an accurate time rather than using my current setting?
 
No it means you should either use a different timer like TMR2 (which is very flexible) or mode 14 of the CCP1 module. Did you read the Roman Black article (which includes code)
 
Both methods count 1,000,000 cycles.

Timer 0 = 78*64*200=998400.
Timer 2 = 16*125*10*50 = 1,000,000

With a 1% clock the missing bit in the timer 0 calculation is irrelevant.

You could set timer 0 free running and do,
64 * 256 * 61 = 999424

You have to use some extra multipliers to get to 1 million as the timers can only count to 256.

Mike.
 
blueroomelectronics said:
No it means you should either use a different timer like TMR2 (which is very flexible) or mode 14 of the CCP1 module. Did you read the Roman Black article (which includes code)

i've read the roman's.. still figuring how it works.
 
Try this, put your LED code where the comment is. I made it for a 16F628A, but just remove the first two lines in MAIN for a 16F628 (turns off the comparator)
Code:
    LIST    p=16F628A  ;tell assembler what chip we are using
     include "P16F628A.inc"  ;include the defaults for the chip
     ERRORLEVEL 0, -302 ;suppress bank selection messages
     __config _WDT_OFF & _INTOSC_OSC_NOCLKOUT & _LVP_OFF

        cblock 0x20
        Jiffy           ; 
        endc
        ORG 0x00
        goto MAIN
        ORG 0x04
IRQ     decfsz  Jiffy   ; 500ms interval
        goto    Pop
; one second code goes here
        movlw   .2      ; reload the Jiffy timer
        movwf   Jiffy   ; 
Pop     bcf     PIE1, CCP1IE
        retfie

MAIN    movlw    0x07
        movfw    CMCON
        bsf     STATUS, RP0      
        clrf    TRISB           ;b1 Sets up PORTB all OUTPUT
        bsf     PIE1, CCP1IE    ;b1 CCP1 IRQ enable
        bcf     STATUS, RP0
        clrf    PORTB 
        movlw   high(.62500)
        movwf   CCPR1H          
        movlw   low(.62500)
        movwf   CCPR1L
        movlw   0x0B            ; compare trigger special event
        movwf   CCP1CON
        movlw   b'00110001'     ; TMR1 on, 1/8 prescale
        movwf   T1CON  
        movlw   b'11000000'
        movwf   INTCON

LOOP    goto    $     ; loop forever                                           

        END
 
skyrock said:
I know it shouldn't be as much as 5%, that's why I worried if this is just a case of broken PIC..

The internal oscillator of the PIC16F628 is not calibrated to 1% IIRC, that's been a new feature of the A-version. You can check the Electrical Specifications of the two devices.
 
eng1 said:
The internal oscillator of the PIC16F628 is not calibrated to 1% IIRC, that's been a new feature of the A-version. You can check the Electrical Specifications of the two devices.

Nice catch. Guess it's possible to tune it with OSCTUNE

I've not used the non A in years.
 
blueroomelectronics said:
Try this, put your LED code where the comment is. I made it for a 16F628A, but just remove the first two lines in MAIN for a 16F628 (turns off the comparator)

I've tried putting this code in, but it didn't bring me to the interrupt.. can you please check again the code?

I'll also attach the code which I modified.. it's a really long code but i'll just post the relevant initialising part. The code compiled but it stayed in the loop without getting to INTERRUPT.

EDIT: OK, i've tried again and it actually went to INTERRUPT.. it just takes a little longer than I had expected(in SIMULATION).. Now that if I want to start and stop the interrupt, what should I add? Just turn bit 0 of T1CON on and off?

Code:
		list P=16F628a
		include "p16f628a.inc"
		__config 0x3D18

ISR    decfsz  Jiffy  	; 500ms interval
        goto    Pop		
        bsf      CHECK_TIME,4    ; one second code goes here
        movlw   .2      		; reload the Jiffy timer
        movwf   Jiffy   		; 
Pop     bcf     PIE1, CCP1IE
        retfie

init	bsf 	STATUS, RP0
		movlw 	b'11100000'
		movwf 	TRISA
		movlw	b'00000000'
		movwf	TRISB
		movlw	b'10000101'
		movwf	OPTION_REG
		bsf     PIE1, CCP1IE   		 ;b1 CCP1 IRQ enable
		bcf		STATUS, RP0
		movlw	b'00000111'			;turn off comparator
		movwf	CMCON
		movlw   high(.62500)
                          movwf   CCPR1H          
                          movlw   low(.62500)
                          movwf   CCPR1L
                          movlw   0x0B            ; compare trigger special event
                          movwf   CCP1CON
                          movlw   b'00110001'     ; TMR1 on, 1/8 prescale
                          movwf   T1CON  
                          movlw   b'11000000'
                          movwf   INTCON 
		clrf	PORTB
		movlw	0x01
		movwf	LEDCOUNT
 
Last edited:
Hi,
You don't save the registers in the ISR. Check the datasheet page 109 for saving the registers. Also, I've noticed in your ISR, bcf PIE1, CCP1IE which is incorrect.

Note that 'E' is to enable. For the flag bit, it is in the PIR1 register, and the flag bit is CCP1IF
 
bananasiong said:
Hi,
You don't save the registers in the ISR. Check the datasheet page 109 for saving the registers. Also, I've noticed in your ISR, bcf PIE1, CCP1IE which is incorrect.

Note that 'E' is to enable. For the flag bit, it is in the PIR1 register, and the flag bit is CCP1IF

i've checked the manual.. it seems so as explained.. but when I simulate the code, it seems both are working. i.e. BCF PIE1, CCP1IE and BCF PIR1, CCP1IF both works..

Bill, can you confirm?
 
ok, I've changed my code and start/stop timer by changing T1CON BIT0. And it worked.

so, the result is that TMR1 gives me faster timing than a real world clock.. it gives 1 extra second by the 25th second. that's about 1/25 second faster. I've changed the prescaller to 1:1 and makes it runing 20 times @ 50,000 CCPR1.. still getting same results.
 
Last edited:
Saving the registers is only needed if your main program is actually doing something. goto $ won't care what happens to the W,STATUS,FSR registers.
That said it's normally a must for your program but was unnessary for the scope of the question.
You can fine tune the OSCILLATOR with the OSCTUNE register. But realistically the 16F628 (the non A version) is not all that accurate without a crystal. If you need accuracy there's no way to beat a crystal timebase on a PIC. The A version is calibrated to 1%.

PS in hindsight I should have used TMR2, no need for the CCP stuff.
Timer 2 has a PR2 register that allows for a compare and reset mode.

As for stopping the clock there are at least two ways.
Stop (clear the TMR2 on bit, or clear the TMR2IE bit) although this would stop it from keeping correct time.
 
I think i'll try using the internal oscillator in the 16f628a. Seems like it is the only way to get accurate result..
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top