Problem with Timer0 rollover time -pic16f1503

Thread Starter

hunterage2000

Joined May 2, 2010
487
I tried the below code expecting a Timer rollover every 200us with:

fosc/4 = 1MHz = 1us
prescaler = 256
TMR0 = 256 - 200 = 56

but I'm getting 21.8us and even changing the prescaler to 2 it remains 21.8us. The code is wrong but I can't see where.

Anyone see what could be the problem?

Code:
#include <stdio.h>
#include <pic16f1503.h>
#include <stdlib.h>
#include <xc.h>
// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF        // Watchdog Timer Enable (WDT enabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = ON    // Clock Out Enable (CLKOUT function is enabled on the CLKOUT pin)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = ON      
void delay(void);

void main()
{
    OSCCONbits.SCS = 0b10;
    OSCCONbits.IRCF = 0b1101;
    TRISCbits.TRISC3 = 0;
    OPTION_REGbits.TMR0CS = 0;
    OPTION_REGbits.PSA = 0;
    OPTION_REGbits.PS = 0b000;

    while(1)
    {
        //LATCbits.LATC3 = 0;
      LATCbits.LATC3 = !LATCbits.LATC3;
       delay();
    }
}

void delay()
{
    TMR0 = 56;
    INTCONbits.T0IE = 1;

    while (INTCONbits.T0IF == 0)
    {
        ;
    }
}
 

AlbertHall

Joined Jun 4, 2014
12,347
Having had a longer look:
The TMR0 prescaler is actually set to 2:1, so TMR0 will increment every 2uS.
In the delay routine you enable the TMR0 interrupt but there is no interrupt routine.
In the delay routine you wait until TMR0IF is set but you never reset it so it will be set forever.

To make it work as you want:
Set PSA = 1 - prescaler not assigned to TMR0. The timer will increment every 1uS.
In the delay routine after setting the TMR0 value, reset the TMR0IF flag.
 

Thread Starter

hunterage2000

Joined May 2, 2010
487
Ok so now PSA = 1 and I have cleared the TMR0 flag. I ran it and the oscilloscope is measuring 220us. I tried 256 - 1 = 255 thinking this might make it 1us but it is 1ms. Any ideas why?
 

AlbertHall

Joined Jun 4, 2014
12,347
The uC is executing one instruction in 1uS (jumps take 2uS) so you will not get correct results trying to get 1uS delay. You would get that from a single instruction with no time left to toggle a pin.

The delay for an expected 200uS is longer than expected than expected because the uC is executing other instructions before/after the delay loop - return from delay; toggle the pin; call delay routine...

To get it exact either make the delay shorter to allow for the overhead, or use the TMR0 interrupt.

The delay you have is called a blocking delay because the uC can do nothing during the delay period. Depending on what you use the delay for this may not matter. One advantage of using the interrupt version is that the uC can do other stuff while waiting for the end of the delay period. In this case toggling a pin.
 

dannyf

Joined Sep 13, 2015
2,197
the following generates 50us stops consistently:

Code:
        //alternative #2
        IO_FLP(OUT_PORT, OUT);                //flip the output pin
        tmr0_delay(OUT_DLY);                //waste time
OUT_DLY is defined as 50.
 

AlbertHall

Joined Jun 4, 2014
12,347
BTW As you are apparently using XC8 then there is a built-in accurate delay routines.
At the top of the program:
#define _XTAL_FREQ 4000000 // Tells the delay routines what the clock frequency is.

Then use __delay_us(constant_expression) or __delay_ms(constant_expression)
Note they begin with a double underscore.
 

ci139

Joined Jul 11, 2016
1,898
unit tme2;

interface uses windos,sysx;

function GetLongTime: longint; function MakeTime(tm: longint): String;
function GetSC: double;
function GetOSTime: longint; function MakeOSTime(tm: longint): String;

implementation var ctm : longint absolute 0:$46C; { timer value holder }

function GetLongTime : longint; begin GetLongTime := ctm end;

const SC:double=18.2064815;{ the min interval between timer ticks is ÷ 55ms }

function MakeTime(tm: longint): String; var tst: string; dd,cr: longint;
hh,mm,ss,cc,rr : longint; { ctm receives timer updates SC times per second }
begin dd:=0; tm:=tm*3*3*3*2*2*2*5; { ++ ~ NEW ! ~ ! iNsAnE ~ ~ ~ }
{ when ctm reaches 1573040-1 then next update is resetting it back to zero }
hh:=tm div 70786800; rr:=tm mod 70786800; { updateing and the date value }
mm:=rr div 1179780; rr:=rr mod 1179780;
ss:=rr div 19663; rr:=rr mod 19663; cc:=Round(100*rr/19663);
if cc>99 then begin cr:=cc div 100; cc:=cc mod 100; ss:=ss+cr;
if ss>59 then begin cr:=ss div 60; ss:=ss mod 60; mm:=mm+cr;
if mm>59 then begin cr:=mm div 60; mm:=mm mod 60; hh:=hh+cr;
if hh>23 then begin cr:=hh div 24; cc:=hh mod 24; dd:=dd+cr end end end end;
tst := frm(dcs(hh),2) + ':';
tst := tst + frm(dcs(mm),2) + ':';
tst := tst + frm(dcs(ss),2) + '.';
tst := tst + frm(dcs(cc),2); MakeTime:=tst end;

function GetSC:double; begin GetSC:=SC end;

function GetOSTime:longint; var hh,mm,ss,cc:word; rv,zt:longint;
begin GetTime(hh,mm,ss,cc); rv:=0+hh; zt:=rv shl 6;
rv:=0+mm; zt:=(zt or rv)shl 6; rv:=0+ss; zt:=(zt or rv)shl 7;
rv:=0+cc; zt:=zt or rv; GetOSTime:=zt end;

function MakeOSTime(tm : longint) : String;
var hh,mm,ss,cc,zt: longint; ost: string;
begin
cc:=tm and $7F; tm:=tm shr 7; ss:=tm and $3F; tm:=tm shr 6;
mm:=tm and $3F; tm:=tm shr 6; hh:=tm and $1F;
ost:=frm(dcs(hh),2)+':'; ost:=ost+frm(dcs(mm),2)+':';
ost:=ost+frm(dcs(ss),2)+'.'; ost:=ost+frm(dcs(cc),2); MakeOSTime:=ost end;

begin SC:=1573040/24/3600 end.
 

ErnieM

Joined Apr 24, 2011
8,377
Is there some good reason you are not using Timer2 for this task?

Once configured Timer2 is designed to give you regularly spaced events completely determined and regulated by hardware only.
 
Top