unable to toggle a led on port pin using interrupt, went through code & can't find the problem

be80be

Joined Jul 5, 2008
2,072
It not work if your code don;t have this in it
OSCCON = 0x7E: //make the osc start up at 8 mhz

You have to set the OSCCON on the 18f2550 if not it will not run at the speed your setting the timer0 for the osc will be way off
 
Last edited:

Thread Starter

chaosenvoy

Joined Aug 6, 2017
54
It not work if your code don;t have this in it
OSCCON = 0x7E: //make the osc start up at 8 mhz

You have to set the OSCCON on the 18f2550 if not it will not run at the speed your setting the timer0 for the osc will be way off
@be80be
thanks a lot i didn't know that will try it later & let you know ,really appreciate the help .
 

jayanthd

Joined Jul 4, 2015
945
Which Compiler are you using ? mikroC PRO PIC ? If yes, then zip and post the complete project files. I have to check the project settings especially oscillator settings.
 

be80be

Joined Jul 5, 2008
2,072
The code posted has tons of errors if the op post the project that be great here one that works it's in xc8

Code:
#define REPEAT_COUNT 10000 // adjust this value to increase/decrease the delaY
void T0Delay(void);
#define IO_RB0_LAT                LATBbits.LATB0
#define IO_RB0_Toggle()             do { LATBbits.LATB0 = ~LATBbits.LATB0; } while(0)

/*
* File:   main.c
* Author: burt
*
* Created on September 22, 2017, 10:27 PM
*/


// 'C' source line config statements

// CONFIG1L
#pragma config PLLDIV = 1       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1       // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)

// CONFIG1H
#pragma config FOSC = INTOSCIO_EC// Oscillator Selection bits (Internal oscillator, port function on RA6, EC used by USB (INTIO))
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOR = ON         // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3         // Brown-out Reset Voltage bits (Minimum setting 2.05V)
#pragma config VREGEN = OFF     // USB Voltage Regulator Enable bit (USB voltage regulator disabled)

// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = ON      // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-001FFFh) is not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) is not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM is not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM is not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) is not protected from table reads executed in other blocks)
#include <xc.h>
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

void main ( void )
{
int cnt,COUNT;
   // PIC_Init();
//TRISA = 0x00; /* make all of PORTA outputs */
    OSCCON = 0x7E; //make the osc start up at 8 mhz
    TRISB = 0b00000000; // make all PORTA pins output
    PORTB = 0; //turn off PORTA pins
    ADCON1 = 0b00001111; //make all analog pins as digital
    CMCON = 0b00000111; //
//for(;;) /* loop forever */
//PORTBbits.RB1=0;//INITIALIZATION

while(1)

    {

IO_RB0_LAT=0;//Toggle the pin1 of port A

for (cnt = REPEAT_COUNT;cnt;cnt--)

    {
     T0Delay(); // or even the actual code of the function
    } // for (cnt = REPEAT_COUNT;cnt;cnt--)


//T0Delay();

IO_RB0_LAT=1;
for (cnt = REPEAT_COUNT;cnt;cnt--)

    {
     T0Delay(); // or even the actual code of the function
    }

/*for (COUNT = REPEAT_COUNTS;COUNT;COUNT--)

    {
     T0Delay(); // or even the actual code of the function
    } // for (cnt = REPEAT_COUNT;cnt;cnt--)*/

// T0Delay();



}
}

void T0Delay()

{

T0CON=0x01;//timer 0,16bit mode,1:4 prescalar(0000 0001)

TMR0H=0xFF; //load TH0(1001 1100) ONLY FOR THE 8 BIT SO ONLY YOU CAN GO FOR THE 256 CALCULATIONS.
TMR0L=0xEE; //LOAD TL0 ()

T0CONbits.TMR0ON=1; //START TIMER

while (INTCONbits.TMR0IF==0); // WAIT FOR TIMER0 TF0 TO ROLL OVER


T0CONbits.TMR0ON=0;//TURN OFF TIMER
INTCONbits.TMR0IF=0;// CLEAR TF0

    }
 

Thread Starter

chaosenvoy

Joined Aug 6, 2017
54
The code posted has tons of errors if the op post the project that be great here one that works it's in xc8

Code:
#define REPEAT_COUNT 10000 // adjust this value to increase/decrease the delaY
void T0Delay(void);
#define IO_RB0_LAT                LATBbits.LATB0
#define IO_RB0_Toggle()             do { LATBbits.LATB0 = ~LATBbits.LATB0; } while(0)

/*
* File:   main.c
* Author: burt
*
* Created on September 22, 2017, 10:27 PM
*/


// 'C' source line config statements

// CONFIG1L
#pragma config PLLDIV = 1       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1       // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)

// CONFIG1H
#pragma config FOSC = INTOSCIO_EC// Oscillator Selection bits (Internal oscillator, port function on RA6, EC used by USB (INTIO))
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOR = ON         // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3         // Brown-out Reset Voltage bits (Minimum setting 2.05V)
#pragma config VREGEN = OFF     // USB Voltage Regulator Enable bit (USB voltage regulator disabled)

// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = ON      // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-001FFFh) is not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) is not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM is not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM is not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) is not protected from table reads executed in other blocks)
#include <xc.h>
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

void main ( void )
{
int cnt,COUNT;
   // PIC_Init();
//TRISA = 0x00; /* make all of PORTA outputs */
    OSCCON = 0x7E; //make the osc start up at 8 mhz
    TRISB = 0b00000000; // make all PORTA pins output
    PORTB = 0; //turn off PORTA pins
    ADCON1 = 0b00001111; //make all analog pins as digital
    CMCON = 0b00000111; //
//for(;;) /* loop forever */
//PORTBbits.RB1=0;//INITIALIZATION

while(1)

    {

IO_RB0_LAT=0;//Toggle the pin1 of port A

for (cnt = REPEAT_COUNT;cnt;cnt--)

    {
     T0Delay(); // or even the actual code of the function
    } // for (cnt = REPEAT_COUNT;cnt;cnt--)


//T0Delay();

IO_RB0_LAT=1;
for (cnt = REPEAT_COUNT;cnt;cnt--)

    {
     T0Delay(); // or even the actual code of the function
    }

/*for (COUNT = REPEAT_COUNTS;COUNT;COUNT--)

    {
     T0Delay(); // or even the actual code of the function
    } // for (cnt = REPEAT_COUNT;cnt;cnt--)*/

// T0Delay();



}
}

void T0Delay()

{

T0CON=0x01;//timer 0,16bit mode,1:4 prescalar(0000 0001)

TMR0H=0xFF; //load TH0(1001 1100) ONLY FOR THE 8 BIT SO ONLY YOU CAN GO FOR THE 256 CALCULATIONS.
TMR0L=0xEE; //LOAD TL0 ()

T0CONbits.TMR0ON=1; //START TIMER

while (INTCONbits.TMR0IF==0); // WAIT FOR TIMER0 TF0 TO ROLL OVER


T0CONbits.TMR0ON=0;//TURN OFF TIMER
INTCONbits.TMR0IF=0;// CLEAR TF0

    }
@be80be
Thank you so much for all the work you did for writing & posting the code
but i'm lost even more so because i'm using MikroC Pro & i was just trying to learn how to create an interrupt on a pic & understand what i'm doing in terms of calculating the speed i can create .
In the beginning i tried the MPlab compiler but got discourage from all the tutorials & getting nowhere, i'm not the sharpest tack in the box but i was able to do all i can now which isn't much but i'm happy with the MikroC Pro compiler.
sorry for being such a bother & i hope i'm not sounding ignorant towards what you are trying to teach me because i ask for the help but i'm hoping to learn as much as i can & i will ending up asking too many questions on the simple things in your code that i should know but i don't . i learn all i know from watching tutorials no help till i'm here.
I've tried painstakingly before to learn to use the Mplab compiler but it's like they don't cater for someone who doesn't know anything just engineers. i will try & see if i can continue using MikroC which i'm very comfortable with to learn all that i can about pics.
i know Mplab & Microchip go hand in hand in terms of compiler & chip but i think i will fry my brains if i try to change .
thank you so much again @be80be
 

be80be

Joined Jul 5, 2008
2,072
You don't have to change the code I posted is C code and should work with mikroC with not a lot of changes I posted it to give you a idea to what should be set if you posted your Main C code I could fix it for you using MikroC.
 

Thread Starter

chaosenvoy

Joined Aug 6, 2017
54
You don't have to change the code I posted is C code and should work with mikroC with not a lot of changes I posted it to give you a idea to what should be set if you posted your Main C code I could fix it for you using MikroC.
@be80be
C:
// pic 18f2550 the pic i'm using
//MickroC Pro compiler
//Pickit 2  programmer

sbit Led at LATA1_bit;
sbit Led_Direction at TRISA1_bit;
unsigned char counter = 0, count = 2;

void InitTimer0 () {
T0CON = 0b11000111; //TMR0 on,at 8 bit,internal clock,low to high transition,1 : 256256 prescaler
TMR0L = 0xE9; //load value
GIE_bit = 1; // enable global interrupt
TMR0IE_bit = 1; // enable interrupt
}
void interrupt() {
if ((TMR0IF_bit)&&(TMR0IE_bit)){ //if both TMR0IF & TMR0IE is true
INTCON.TMR0IF = 0; //reset overflow flag
TMR0L = 0xE9;
if(++counter >=count){ // increment counter
Led = ~Led ; // toggle led
counter = 0; // reset counter
}
}
}
void main() {
TRISA = 0b00000000; // make all PORTA pins output
PORTA = 0; //turn off PORTA pins
ADCON1 = 0b00001111; //make all analog pins as digital
CMCON = 0b00000111; //
InitTimer0 ();
while (1){
}
}
this is my code to generate a 1 second interrupt here is my calculations
i think the internal clock is 48Mhz so
FOSC4 so 48/4 = 12
1/(12Mhz/256 prescaler/256) = 1/(.046875/256) = 1/.000183105 = 5461
1/(12Mhz/256) = 1/.046875 =21
so 1000 x 21 = 21 ms add 2 to 21 = 23
256 - 23 = 233 decimal = 0xE9
so i TMR0L = 0xE9
I don't have a scope or anything like that to check the speed of the blink of the led but from looking at it, it seems to be blinking faster than 1 sec. can you tell me where i went wrong ?
when i write OSCCON = ox7E // do i do it like this in my calculations '' fosc 8/4 & go on from there .
as i said before i'm trying to understand if i'm doing the calculations correctly i got this way of doing the calculation for interrupt form this site
''http://www.best-microcontroller-projects.com/article-pic-timer-calculation.html'' which i was directed to on this forum, the coding was also given to me from this forum, my main issue is learning to do interrupt on the pic 18f2550 in terms of calculation so i can play around with the calculations in the code to get different interrupt times , i have read the data sheet & i'm not sure of the internal timer speed, you told me to use
OSCCON ==ox7E // so that the timer starts up at 8Mhz/ , i don't need an exact interrupt just need to understand if i want to get a 1sec interrupt, how to go about it.
My second issue is how to do the calculations if i'm using an external oscillator at 8Mhz
thank you for your speedy response.

Mod edit: code tags and text box
 
Last edited by a moderator:

Thread Starter

chaosenvoy

Joined Aug 6, 2017
54
@be80be
@JohnInTX
C:
// 18f2550 pic
//MikroC Pro//compiler
// Pickit2 programmer
sbit Led at LATA1_bit;
sbit Led_Direction at TRISA1_bit;
unsigned char counter = 0, count = 1;

void InitTimer0 () {
 T0CON = 0x83; //TMR0 on,at 16 bit,internal clock,low to high transition,1 : 16 prescaler
 TMR0H = 0xB;
 TMR0L = 0xE9;           //load value
 GIE_bit = 1;               // enable global interrupt
 TMR0IE_bit = 1;        // enable interrupt
}

void interrupt() {
if ((TMR0IF_bit)&&(TMR0IE_bit)){  //if both TMR0IF & TMR0IE is true
   INTCON.TMR0IF = 0;             //reset overflow flag
   TMR0H = 0xB;
   TMR0L = 0xE9;
   if(++counter >=count){          // increment counter
     Led = ~Led ;                       // toggle led
     counter = 0;                        // reset counter
    }
  }
}

void main() {
OSCCON = 0b1111110;
TRISA = 0b00000000;            // make all PORTA pins output
PORTA = 0;                          //turn off PORTA pins
ADCON1 = 0b00001111;        //make all analog pins as digital
CMCON = 0b00000111;         //
InitTimer0 ();
while (1); // do nothing
}
these are the setting in the compiler

# PLL prescale selection // no prescale (4Mhz oscillator input drives PLLdirect
# MCLR pin //enable
# CCP2 Mux bit // enable
# WDT //disable
# Brown out reset // emable
# Power up timer // disable
# Int/Ext oscillator switchover // disable
# Fail safe clock monitor // disable
# Oscillator selection // Internal oscillator ,CLKO function, on RA6 , EC used by USB (INTCKO)
# USB clock selection , used in full speed USB MODE only // USB clock source comes directly from the primary oscillator block
# System clock postscale selection // primary oscillator Scr;/1]96Mhz PLLScr/2

i hope this helps in understanding my code ,it is working with a 500ms interrupt i have & can use the timer calculator but i want to learn how to do the calculations on my own correctly.
I've read up on OSCCON & have a better understanding of it, you said when i use OSCCON = ox7E it starts up at 8Mhz , does it run at 8Mhz & can i run it faster.
one of my main issue is being able to do the interrupt calculations using the internal clock & an external crystal i really want to learn this & if you cant give me an example of doing the calculations using the int osc & 1 using an ext osc or can you point me in the right direction.
I've been playing around with the code trying to figure it out but still not accurate with the calculations .
thank you again for all the help .

Mod edit: code tags, indents
 
Last edited by a moderator:

JohnInTX

Joined Jun 26, 2012
4,787
@chaosenvoy
So, it's running right but you want to know how the calculator did it? Well allrighty then!

The timer is just a big counter that counts the input frequency and generates an interrupt when it rolls over from FFFFh to 0000h. The way I do it is like this:

Figure out the input freq. to the counter. Ref. Fig 2-1 in the datasheet. You have
8MHz Fosc and OSCCON 6:4 routes that directly to the MUX where OSCCON 1:0 routes it to the peripheral clock. You are not using the USB clock section.

The peripheral clock is always Fosc / 4 in a PIC so the input to the timer is 2MHz for a period of 500ns.

You want a 500ms tik so just divide 500ms / 500ns = 1E6 counts i.e. it takes 1,000,000 timer ticks to make 500ms.

1E6 counts won't fit into a 16 bit timer (max 65536) so we need an external divider. Do a trial division to see what works. 1E6/65536 = 15.2587....

We pick a timer prescaler that is at least that big. 16 works. So does 32, 64, 128 and 256 but we want the smallest usable prescaler to keep the number of timer counts bigger. That makes each count a smaller time and gives us more resolution - always a good thing.

So with a prescaler of 16, the input period to the timer is 500ns * 16 = 8us.

The number of 8us ticks to make 500ms is 500ms / 8us = 62500. Almost there.

Your postscaler (counter >= count) is always 1 in this example so it does not contribute to the calculated time. Increase the value of 'count' and you get multiples of the interrupt period.

The counter counts UP and interrupts when it rolls over to 0 so we subtract the desired number of counts from the 16 bit timer base (2^16). 65536 - 62500 = 3036 = 0BDCh.
So TMR0H = 0Bh and TMR0L = DCh.

The calculator's answer is a little different - Might want to review the arithmetic but that's pretty much it.

Note that when you have to manually reload a timer, you lose a bit in overhead. Consider what happens when the interrupt happens. It takes some time to get the interrupt serviced and get to the point where you reload the timer BUT! You reload the timer with the value calculated with no overhead allowance so a correctly calculated timer value will result in the timer being a little slow (it times the 500ms PLUS the overhead). If you got the calculated values using MikroC's calculator, they may have adjusted the time to be a bit shorter to compensate for their overhead.

Let's see:
Me: 62500 counts at 8us/count = 500ms on the dot.
Them: 0BE9h = 3049. 65536-3049 = 62487 timer tiks
62487 tiks * 8us/tik = 499.896ms, a difference of 104us. At 500ns/instruction that's 208 Tcycs or about 200 instructions give or take (calls, returns gotos take 2Tcyc to execute). Maybe it takes that many to do the interrupt or we have a different view of 500ms.

Here's another problem with manually reloading a timer. If you have multiple interrupts, you can be servicing one when the timer rolls over, adding to the overhead time.

You can mitigate those problems somewhat by instead of loading the timer with the value, ADD the value to the current timer value (which has been accumulating tiks while the interrupt service routing was getting around to being serviced). That will take into account a lot (but not all) of the overhead.

Because of all that, I usually use TIMER2 / PR2 as a periodic timebase because once it is loaded, you don't have to reload it on each interrupt. The calculation is similar but the prescaler will be bigger because TIMER2 is only 8 bits. With your setup, the longest interrupt period from TMR2/PR2 is on the order of 32ms so you would need that secondary counter to extend the time to 500ms.

I usually use a TIMER2/PR2 system tik of 1ms - 10 ms depending on the system then run a series of derived timers for those extended times. I like to count down to 00 then reload since testing for 00 is usually cheaper than testing for <= some value.

That's about all there is to it.

Good luck.
 
Last edited:

Thread Starter

chaosenvoy

Joined Aug 6, 2017
54
@chaosenvoy
So, it's running right but you want to know how the calculator did it? Well allrighty then!

The timer is just a big counter that counts the input frequency and generates an interrupt when it rolls over from FFFFh to 0000h. The way I do it is like this:

Figure out the input freq. to the counter. Ref. Fig 2-1 in the datasheet. You have
8MHz Fosc and OSCCON 6:4 routes that directly to the MUX where OSCCON 1:0 routes it to the peripheral clock. You are not using the USB clock section.

The peripheral clock is always Fosc / 4 in a PIC so the input to the timer is 2MHz for a period of 500ns.

You want a 500ms tik so just divide 500ms / 500ns = 1E6 counts i.e. it takes 1,000,000 timer ticks to make 500ms.

1E6 counts won't fit into a 16 bit timer (max 65536) so we need an external divider. Do a trial division to see what works. 1E6/65536 = 15.2587....

We pick a timer prescaler that is at least that big. 16 works. So does 32, 64, 128 and 256 but we want the smallest usable prescaler to keep the number of timer counts bigger. That makes each count a smaller time and gives us more resolution - always a good thing.

So with a prescaler of 16, the input period to the timer is 500ns * 16 = 8us.

The number of 8us ticks to make 500ms is 500ms / 8us = 62500. Almost there.

Your postscaler (counter >= count) is always 1 in this example so it does not contribute to the calculated time. Increase the value of 'count' and you get multiples of the interrupt period.

The counter counts UP and interrupts when it rolls over to 0 so we subtract the desired number of counts from the 16 bit timer base (2^16). 65536 - 62500 = 3036 = 0BDCh.
So TMR0H = 0Bh and TMR0L = DCh.

The calculator's answer is a little different - Might want to review the arithmetic but that's pretty much it.

Note that when you have to manually reload a timer, you lose a bit in overhead. Consider what happens when the interrupt happens. It takes some time to get the interrupt serviced and get to the point where you reload the timer BUT! You reload the timer with the value calculated with no overhead allowance so a correctly calculated timer value will result in the timer being a little slow (it times the 500ms PLUS the overhead). If you got the calculated values using MikroC's calculator, they may have adjusted the time to be a bit shorter to compensate for their overhead.

Let's see:
Me: 62500 counts at 8us/count = 500ms on the dot.
Them: 0BE9h = 3049. 65536-3049 = 62487 timer tiks
62487 tiks * 8us/tik = 499.896ms, a difference of 104us. At 500ns/instruction that's 208 Tcycs or about 200 instructions give or take (calls, returns gotos take 2Tcyc to execute). Maybe it takes that many to do the interrupt or we have a different view of 500ms.

Here's another problem with manually reloading a timer. If you have multiple interrupts, you can be servicing one when the timer rolls over, adding to the overhead time.

You can mitigate those problems somewhat by instead of loading the timer with the value, ADD the value to the current timer value (which has been accumulating tiks while the interrupt service routing was getting around to being serviced). That will take into account a lot (but not all) of the overhead.

Because of all that, I usually use TIMER2 / PR2 as a periodic timebase because once it is loaded, you don't have to reload it on each interrupt. The calculation is similar but the prescaler will be bigger because TIMER2 is only 8 bits. With your setup, the longest interrupt period from TMR2/PR2 is on the order of 32ms so you would need that secondary counter to extend the time to 500ms.

I usually use a TIMER2/PR2 system tik of 1ms - 10 ms depending on the system then run a series of derived timers for those extended times. I like to count down to 00 then reload since testing for 00 is usually cheaper than testing for <= some value.

That's about all there is to it.

Good luck.
@JohnInTX
Thank you very much for the explanation & sorry for so much bother, if i understand you correctly i should use TMR2 so i don't have to load it manually to do the interrupt & if so can you give me an example of the code to do an interrupt on TMR2,no particular time just an example .
secondly if im using interrupt i shouldn't use an external oscillator & if i can use an external oscillator when doing the calculations i still have to do FOSC/4 am i right
thank you again for all the help .
 

JohnInTX

Joined Jun 26, 2012
4,787
Sure.
As I said, TMR2 does not have enough bits to get a 500ms time so you'll have to use an additional counter to make a derived timer that counts interrupts generated by TMR2 / PR2.

Unlike timer 1 which interrupts when it rolls over from FFFFh -> 0000h, TMR2 counts up to the value set in PR2 then resets itself to 00h. The post scaler counts each time that happens and raises an interrupt on every nth time where n is the post scaler setting.

The databook has the formulae to determine the setting PR2 with prescaler and post scaler settings known. To get a rough idea of where you are, figure out the max time.
At 8Mhz, Tcyc is 500ns.
500ns * prescaler * PR2 counts* postscaler = 1500ns * 16 * 255 * 16 = 32.64ms max time.
To see how many of those max times you need for 500ms.
500ms / 32.64ms ~=15.2588. Note that 15.2588 is not an integer. Since you are going to drive a counter to count TMR2 interrupts up to 500ms, pick some nice factor of 500ms for the interrupt interval. 10ms is a good one.

So, figure out how to get to 10ms. Set up the prescaler and postscaler first to get the remaining counts in a one byte range for PR2. There may be more than one solution.

At 500ns/Tcyc, the number of counts for a 10ms interrupt is 10ms / 500ns = 20000.
Factor the number of counts into what works with TMR2. Make sure your results stay an integer.

20000/16 prescaler = 1250 left. Still too big for the 8 bit PR2 so factor 1250 to split it up, starting with what the postscaler will provide.
1250 = 10 * 125.
Use postscaler = 10 and PR2 = 125.
The derived counter will be set to 50 (500ms / 10ms)

The setup is:
T2CON = 0b01001010; // Postscaler = 16, Prescaler = 16, Timer OFF (for now)
PR2 = 125;

TMR2IF = 0; // clear any pending IF
TMR2IE = 1; // then enable timer 2 interrupt
PEIE = 1; // and peripheral interrupts
GIE = 1; // and global interrupts
counter = 50;
TMR2ON = 1; // then start timer

//The interrupt routine is the same except you look at TMR2IF and TMR2IE instead of those for timer 0.
// Note that if you never turn TMR2IE off, you don't have to test it in the interrupt routine
if ((TMR2IE) && (TMR2IF){
if(--counter == 0){
counter = 50;
// toggle LED or whatever
}
}
Finally, when modifying I/O on an 18F or 16F1xxx, ALWAYS do your outputs to the LATx registers, never PORTx.

Have fun!
 
Last edited:

Thread Starter

chaosenvoy

Joined Aug 6, 2017
54
Sure.
As I said, TMR2 does not have enough bits to get a 500ms time so you'll have to use an additional counter to make a derived timer that counts interrupts generated by TMR2 / PR2.

Unlike timer 1 which interrupts when it rolls over from FFFFh -> 0000h, TMR2 counts up to the value set in PR2 then resets itself to 00h. The post scaler counts each time that happens and raises an interrupt on every nth time where n is the post scaler setting.

The databook has the formulae to determine the setting PR2 with prescaler and post scaler settings known. To get a rough idea of where you are, figure out the max time.
At 8Mhz, Tcyc is 500ns.
500ns * prescaler * PR2 counts* postscaler = 1500ns * 16 * 255 * 16 = 32.64ms max time.
To see how many of those max times you need for 500ms.
500ms / 32.64ms ~=15.2588. Note that 15.2588 is not an integer. Since you are going to drive a counter to count TMR2 interrupts up to 500ms, pick some nice factor of 500ms for the interrupt interval. 10ms is a good one.

So, figure out how to get to 10ms. Set up the prescaler and postscaler first to get the remaining counts in a one byte range for PR2. There may be more than one solution.

At 500ns/Tcyc, the number of counts for a 10ms interrupt is 10ms / 500ns = 20000.
Factor the number of counts into what works with TMR2. Make sure your results stay an integer.

20000/16 prescaler = 1250 left. Still too big for the 8 bit PR2 so factor 1250 to split it up, starting with what the postscaler will provide.
1250 = 10 * 125.
Use postscaler = 10 and PR2 = 125.
The derived counter will be set to 50 (500ms / 10ms)

The setup is:


Finally, when modifying I/O on an 18F or 16F1xxx, ALWAYS do your outputs to the LATx registers, never PORTx.

Have fun!
@JohnInTX
thank you,
sorry for the long wait to responed i was playing around with the code trying to get it to work , i have read the data sheet & this is the code i came up with, but i keep getting an error on this line
if (--counter = = 0) { saying invalid expression
when i comment it out the led stays on this is my code with the error
C:
// 10/10/2017
// pic 18f2550
// MikroC Pro - compiler
// Pickit2 - programmer


sbit Led at LATA2_bit;
sbit Led_Direction at TRISA2_bit;
unsigned char counter = 20;
void InitTimer2 (){
T2CON = 0b01001010;  // prostscaler set to 16, prescaler set to 10, turn off TMR2
PIR2 = 250;
PIR1 = 0b00000000; // clear all pending interrupt flags
PIE1 = 0b00000010;    //  enable TMR2 interrupt
INTCON = 0b11000000;  // enable global & peripherial interrupts
IPR1 = 0b00000010;     // enable priority enterrupt
counter = 20;
T2CON = 0b00000100;   // start TMR2
}
void interrupt () {
if (( TMR2IE ) && ( TMR2IF )){

if (--counter = = 0) {
counter = 20;
Led = ~ Led;  // toggle Led


}
}

void main () {
OSCCON = 0b1111110;  // start oscillator at 8 Mhz
TRISA = 0b00000000;  // make all PortA pins as output
PORTA = 0;           // turn off all PortA pins
ADCON1 = 0b00001111; // all pins are digital
CMCON = 0b00000111;
InitTimer2 () ;
while (1){
}
}
i know it may seem as a simple problem but i can't figure it out thank you for the help in advance .

Moderators note: Please use code tags for pieces of code
 

Thread Starter

chaosenvoy

Joined Aug 6, 2017
54
@JohnInTX hello sorry i haven't been on for a while,trying to get timer 2 working but no luck, i have been able to get the timer calculations correct without using the timer calculator i'm so happy & played around with it i got the calculation from another site '' http://www.microchip.com/forums/m950385.aspx '' i will post 2 of the calculations & codes i used 1 with 8 bit & 1 with 16 bit, i'm using the 18f2550 pic internal oscillator.
For the 8 bit
i'm looking for a 100ms interrupt so
100 ms (intosc 8Mhz / 4 x prescaler 256)
100ms (8 /1024)
100ms x .0078125
,78125 x 8 bits = .78125 x 256 = 200
after this part of the calculations the number must not exceed 256 so 200 is good
so 256 - 200 = 56 = ox 38
so you load TMR0L = ox 38; & if you need a longer interrupt in multiples of 100ms just adjust counter as you want

pic : 18f2550
compiler : MikroC Pro
programmer : Pickit2

C:
sbit Led at LATA1_bit;
sbit Led_Direction at TRISA1_bit;
unsigned char counter = 0, count = 1;

void InitTimer0 () {
T0CON = 0b11000111;                     // TMR0 on,set at 8 bit,1;256 prescaler
TMR0L = 0x36;                                  //TMR0L  value to be loaded
GIE_bit = 1;                                     // enable global interrupt
TMR0IE_bit = 1;                               // enable interrupt
}
void interrupt() {
if ((TMR0IF_bit)&&(TMR0IE_bit)){
INTCON.TMR0IF = 0;                       // reset interrupt flag
TMR0L = 0x36;
if(++counter >=count){
   Led = ~Led ;                                 // toggle led
   counter = 0;                                  // reset counter
   }
   }
    }
void main() {
TRISA = 0b00000000;            // make all port A pins as output
PORTA = 0;                             // turn off all portA pins
ADCON1 = 0b00001111;        // make all pins digital
CMCON = 0b00000111;    
InitTimer0 ();
while (1){
}
}
The timing may not be exact but this is what i use
i haven't been able to buy the oscilloscope you ask me to buy finances is a bit tight but i will get it in time .
thank you again if i don't get through with timer2 i will post my code for help .

Mod edit: code tags
 
Last edited by a moderator:

Thread Starter

chaosenvoy

Joined Aug 6, 2017
54
@JohnInTX my 16 bit calculations & code

500ms needed
500ms ( intosc 8Mhz/ ( 4 x prescaler )
500ms (8 / (4 x 16)
500ms (8/64)
500 x .125 = 62.5 = 62500
65536 - 62500 = 3036 = ox 0BDC
load value = TMR0H = ox0B
loda value = TIMR0L = oxDC

C:
//pic 18f2550
//Pickit2 programmer
//MikroC Pro compiler


sbit Led at LATA1_bit;
sbit Led_Direction at TRISA1_bit;
unsigned char counter = 0, count = 1;

void InitTimer0 () {
T0CON = 0x83; //TMR0 on,at 16 bit,internal clock,low to high transition,1 : 16prescaler
TMR0H = 0x0B;
TMR0L = 0xDC;           //load value
GIE_bit = 1;               // enable global interrupt
TMR0IE_bit = 1;        // enable interrupt
}
void interrupt() {
if ((TMR0IF_bit)&&(TMR0IE_bit)){  //if both TMR0IF & TMR0IE is true
INTCON.TMR0IF = 0;
TMR0H = 0x0B;              //reset overflow flag  
TMR0L = 0xDC;
if(++counter >=count){          // increment counter
   Led = ~Led ;                       // toggle led
   counter = 0;                        // reset counter
   }
   }
    }
void main() {
OSCCON = 0b1111110;
TRISA = 0b00000000;            // make all PORTA pins output
PORTA = 0;                          //turn off PORTA pins
ADCON1 = 0b00001111;        //make all analog pins as digital
CMCON = 0b00000111;         //
InitTimer0 ();
while (1){
}
both codes & calculations are subjected to corrections thank you in advance for all the help

Mod edit: code tags
 
Last edited by a moderator:

BobaMosfet

Joined Jul 1, 2009
2,110
@JohnlnTX
Thank you for all the help i got a sample code from Jayanthd & i forgot i have the timer calculator ;i'm not just about coping code that's why i ask too many questions i'm not the sharpest tack in the box sometimes minor parts of coding gives me trouble to figure out .
i just want know ( TMR0H = 0x3C & TMR0L=oxB0) in the code what am i doing & why do i need it in the ISR & InitTimer0? i looked at the data sheet trying to figure it out & if you can't explain it to me . where can i read up on it,
still not sure if i'm doing calculations with regards to crystal & prescaler right
8 Mhz crystal HS external
this is my calculation
so 8000000 divide by 1000 = 8000
to count 256 ticks in 8000 = 8000 divide by prescaler = 8000 divide by 32 = 250 which is within the 256 ticks
so interrupt fires every 32ms
You do not have to be the 'sharpest tack in the box' :p . - Persistence, and plodding your way through something until you understand it and can use it has solved more problems and progressed mankind farther than most genius thinking.
 

JohnInTX

Joined Jun 26, 2012
4,787
@chaosenvoy
Your math to generate 500ms tiks looks OK to me.
The write to timer order is correct for the 16 bit timer configuration. Write to H gets buffered then written with L when L is written.

Note that it is difficult to get a perfectly exact tik when using Timer 0 because any accumulated time between the rollover/interrupt and when you write the period value is lost, including ticks in the prescaler. You can't do much about the prescaler in this case. If the interrupt latency is such that you accumulate some tiks in the timer section itself, you can make that a little better by stopping the timer, ADDing the period value to the current timer value then restarting the timer. You also can get a few cycles out of the latency by resetting TMR0IF after you reset the time. Also, if TMR0 is always active, you don't have to test for TMR0IE, that can save cycles. If you do need to test it, consider not using the '&&' operator. I don't know about MicroC but in PICC18, testing with the && operator generated much more code (and lost time) than successive tests i.e.
if(TMR0IE)
if(TMR0IF){
// process interrupt
}
You can find out by examining the code in the Assembler Output window.

If you want to dispense with all of the uncertainty, consider using TMR2 / PR2. It reloads automatically so never loses any counts. Some guys also just run a timer open loop i.e. without loading. The base time might not be exactly what you want but the error is a fraction of the last tik, not accumulated over many tiks.

Other than that, well done! You know how to set up the timers and extend them with a counter. Which one you choose is just application from here.
 

Thread Starter

chaosenvoy

Joined Aug 6, 2017
54
@chaosenvoy
Your math to generate 500ms tiks looks OK to me.
The write to timer order is correct for the 16 bit timer configuration. Write to H gets buffered then written with L when L is written.

Note that it is difficult to get a perfectly exact tik when using Timer 0 because any accumulated time between the rollover/interrupt and when you write the period value is lost, including ticks in the prescaler. You can't do much about the prescaler in this case. If the interrupt latency is such that you accumulate some tiks in the timer section itself, you can make that a little better by stopping the timer, ADDing the period value to the current timer value then restarting the timer. You also can get a few cycles out of the latency by resetting TMR0IF after you reset the time. Also, if TMR0 is always active, you don't have to test for TMR0IE, that can save cycles. If you do need to test it, consider not using the '&&' operator. I don't know about MicroC but in PICC18, testing with the && operator generated much more code (and lost time) than successive tests i.e.
if(TMR0IE)
if(TMR0IF){
// process interrupt
}
You can find out by examining the code in the Assembler Output window.

If you want to dispense with all of the uncertainty, consider using TMR2 / PR2. It reloads automatically so never loses any counts. Some guys also just run a timer open loop i.e. without loading. The base time might not be exactly what you want but the error is a fraction of the last tik, not accumulated over many tiks.

Other than that, well done! You know how to set up the timers and extend them with a counter. Which one you choose is just application from here.
@JohnInTX thank you for all your help i was looking at a post you commented on a few years ago on using TMR2, i will do my best to figure it out i, think i'm a bit confuse with the calculations of TMR2 & PR2 in terms of the postscaler & prescaler .i went through the datasheet on TRM2 a few times & i will go at it again this week, i will post the code i have & the calculations i'm using & the result i get.
Thanks again @JohnInTX & @BobaMosfet .
 

Thread Starter

chaosenvoy

Joined Aug 6, 2017
54
@JohnInTX
hello again i got my code working with TMR2 after a few brains burnout just because of 1 simple mistake in the code for the pass month,still not sure of the calculations but i'm happy its working & i have an idea of the calculations.
i work with your calculations from your post in 2014 but with an 8Mhz internal osc, i will have a go at your post from then & see if i can nail it to an exact time .
still haven't been able to buy the Oscilloscope as yet i know it's very important with regards to electronics & what i'm doing now with timers but i will get it in time .here is my code & i'm thankful for all the help & corrections with it.

C:
// 07/02/2018
// pic 18f2550
// MikroC Pro - compiler
// Pickit2 - programmer

sbit Led at LATA2_bit;
sbit Led_Direction at TRISA2_bit;
unsigned char counter = 20;
void InitTimer2 (){
T2CON = 0b1001010;           // prostscaler set to 16, prescaler set to 10, turn off TMR2
PR2 = 125;
PIR1 = 0b00000000;            // clear all pending interrupt flags
PIE1 = 0b00000010;            //  enable TMR2 interrupt
INTCON = 0b11000000;       // enable global & peripherial interrupts
IPR1 = 0b00000010;           // enable priority enterrupt
T2CON = 0b1001110;         // start TMR2
}
void interrupt () {
if (TMR2IF ) {
PIR1 = 0b00;                   // reset TRM2IF

if (--counter == 0) {        // decrement counter from 20 till 0
Led = ~ Led;                  // toggle led after 20 counts of interrupts
counter = 20;                // reset counter to 20
}
}
}
void main () {
OSCCON = 0b1111110;  // start oscillator at 9 Mhz
TRISA = 0b00000000;  // make all PortA pins as output
PORTA = 0;           // turn off all PortA pins
ADCON1 = 0b00001111; // all pins are digital
CMCON = 0b00000111;
InitTimer2 () ;
while (1){
}
}
the mistake i was making in the code was on this line ( PIR1 = 0b00; i had TRM2IF = 0;) & it was only when i change it to PIR1 = 0b00 the led started to blink, the led was staying on before & i thought it was interrupting too fast for me to see so i kept changing counter to a bigger value, the importance of a scope hhmmm.

ps ; 2 - things
(1) i don't know how to post the code properly i think there is a code editor here to use
(2) my next step is to use interrupts to control the brightness of 1 led then move on to 4 then 8 leds & can you point me in that direction .
thank you again .

Mod edit: code tags
Code tags are available on the toolbar of the edit window. Roll your mouse over until you see 'Insert' then select code tags. You can use the window to copy / paste your code there but it is faster to just drop them into the edit window then paste your code between them. Use code=C for C formatting.
 
Last edited by a moderator:
Top