Timer0 problem with PIC16F1716

Thread Starter

hunterage2000

Joined May 2, 2010
487
Hi all

I want to be able to create a 1ms delay using timer0 and have tried the below code.

Code:
#include <stdio.h>
#include <pic16f1716.h>
#include <xc.h>
#include <stdlib.h>
#pragma config FOSC = INTOSC
#pragma config WDTE = OFF      
#pragma config PWRTE = OFF
#pragma config CLKOUTEN = ON   

void delay();

int main(int argc, char** argv)
{
   PORTB = LATB = ANSELB = TRISB = 0;
   OSCCONbits.SCS = 0b10;
   OSCCONbits.IRCF = 0b1111;
   OPTION_REGbits.PSA = 0;
   OPTION_REGbits.PS = 0b100;
   OPTION_REGbits.nWPUEN = 1;
   OPTION_REGbits.TMR0CS = 0;
   OPTION_REGbits.TMR0SE = 0;
   TMR0 = 131;
   INTCONbits.TMR0IE = 1;
   INTCONbits.GIE = 1;
   INTCONbits.PEIE = 1;

   while(1)
   {
       PORTB = ~PORTB;
       delay();
   }
}

void delay()
{
    if(INTCONbits.TMR0IF == 1)
    {
        TMR0 = 132;
        INTCONbits.TMR0IF = 0;
    }
}

I have used the formula I got from https://proteustutorials.blogspot.com/2018/07/pic-timer-0-programming.html :

TMR0 = 256-(Delay * Fosc)/(Prescalar*4))

so for a 1ms delay, the values:
Delay = 1ms
Fosc = 16MHz
Prescaler = 32
gives a TMR0 value of 131

Looking at the oscilloscope waveform I am getting a pulse width of 2.8us.

Can anyone tell me why this is the case, how do i fix it or has anyone got any code that gives a correct delay please?
 

BobTPH

Joined Jun 5, 2013
8,998
Look at your delay function. What code does it execute when you call it? Does that code create a 1 ms delay?

Bob
 

Thread Starter

hunterage2000

Joined May 2, 2010
487
Hi Bob, the delay should toggle PORTB on and off at 1ms but it shows 2.8us. I have looked at numerous code examples which are all different and none work.

I have used a timer0 calculator to calculate the required parameters but still doesn't work.
 

sagor

Joined Mar 10, 2019
912
Hm, using a PIC timer calculator from MikroElektronica, a 1ms timer for TMR0 for a PIC16F at 16Mhz is:

Code:
//Timer0
//Prescaler 1:16; TMR0 Preload = 6; Actual Interrupt Time : 1 ms
//Place/Copy this part in declaration section
void InitTimer0(){
  OPTION_REG     = 0x83;
  TMR0         = 6;
  INTCON     = 0xA0;
}
void Interrupt(){
  if (TMR0IF_bit){
    TMR0IF_bit     = 0;
    TMR0         = 6;
    //Enter your code here
  }
}
If your pre-scaler is not set right, you may not get proper timing... Add bits as required to INTCON for other interrupts
 
Last edited:

Ian Rogers

Joined Dec 12, 2012
1,136
Remember!! With XC8 yu can still use the _XTAL_FREQ = xxx and then use the delays built in :-- __delay_ms(1); for exact delays..
On Mikroelectronica's web site you can download their timer calc software.. You can use it for all the timers not just timer0.
 

jpanhalt

Joined Jan 18, 2008
11,087
I cannot comment on any errors in the C code, but one question to address is how accurate do you want the 1 ms "ticks?"

A preset of 131 + 1:32 prescale should give 1 ms ticks, ignoring any delays or losses for housekeeping. As sagor points out, a pre-load of 6 and a pre-scale of 1:16 (i.e., OPTION_REG <2..0> = 3) will also give a 1 ms tick, ignoring housekeeping. If you can do with a 24 us error (i.e., 1.024 ms ticks) , just counting TMR0 overflows with no pre-set will also work.
 

sagor

Joined Mar 10, 2019
912
'delay' doesn't wait for TMR0IF to be set, it exits immediately.
Correct, his delay routine exits if the flag is not set, and also exits when it just resets the timer. There is no loop waiting for TMR0IF to be set. That is, if TMR0IF = 0 then loop and wait until it is =1...
 
Top