Timing external interrupts using TMR1

General discussion on mikroC.
Post Reply
Author
Message
Jimbotnik
Posts: 42
Joined: 20 Jan 2010 14:27

Timing external interrupts using TMR1

#1 Post by Jimbotnik » 01 Jul 2010 13:05

Hello,

I have written some code to calculate the time/frequency of a series of evenly space pulses received in pin RB4. I am using the EasyPic5 dev board with a 16F887 chip.

Every time a pulse is received the current value of the 16bit timer1 is displayed across PORTC and PORTD LEDs (PORTC displaying the highest 8 bits, PORTD displaying the lowest 8 bits)

I am using a burst generator to produce 4 square waves at a frequency of 100Hz.

When I convert the value of timer1 into a frequency I get a result of 50Hz.

Here is my code:

Code: Select all

unsigned short temp;

void interrupt()
{
    if (INTCON.RBIF==1)
    {
        temp = PORTB;  //clear mismatch
        INTCON.RBIF = 0; // clear flag
        if (Button(&PORTB, 4, 20, 1))
        {
             PORTD = TMR1L;
             PORTC = TMR1H;
        }
    }
    PIR1.TMR1IF = 0;            // clear TMR1IF
    TMR1H = 0;
    TMR1L = 0;
}

void main() 
{
    ANSEL  = 0;                 // Configure AN pins as digital I/O
    ANSELH = 0;
    PORTD = 0;               
    TRISD =0;
    PORTC = 0;
    TRISC = 0;
    PORTB = 0;

    T1CON = 1;                  // Timer1 settings
    PIR1.TMR1IF = 0;            // clear TMR1IF
    TMR1H = 0;               // Initialize Timer1 register
    TMR1L = 0;

    PIE1.TMR1IE  = 1;           // enable Timer1 interrupt

    TRISB = 0b00110000;
    IOCB = 0b00110000;    
    INTCON = 0xC8;
    
    T1CON = 0x45;
    
    do
    {
    
    }
  } while (1);

}

The result left on the PORTC and PORTD LEDs is:

1001110111001000 which equals 40392

The chip runs at 8Mhz, divided by 4 = 2Mhz

1 / 2000000 = 0.0000005 seconds per count

40392 * 0.0000005 = 0.020196

Freq = 1 / 0.02 = 50Hz

Where am I going wrong?

After writing this I notice that I am using the Button function to pick up on the pin interrupt and have a debounce of 20 - maybe this is affecting it?

Thanks for any guidance,

Jimbo

Sparky1039
Posts: 1179
Joined: 24 Nov 2005 20:07
Location: Colorado, USA

Re: Timing external interrupts using TMR1

#2 Post by Sparky1039 » 01 Jul 2010 23:49

After writing this I notice that I am using the Button function to pick up on the pin interrupt and have a debounce of 20 - maybe this is affecting it?
Yep. Your code specifies 20mS as the debounce period so basically it's measuring how accurate the button debounce routine is triggered by the 100Hz signal edge. :wink:
In actuality there is no reason to use the button command in your routine, especially within an interrupt. Unless of course you were anticipating the 100Hz signal to be very noisy.
A far better solution for measuring the period is to use the capture/compare module in the PIC.
See this app note for guidance.
http://ww1.microchip.com/downloads/en/D ... 41214a.pdf

Jimbotnik
Posts: 42
Joined: 20 Jan 2010 14:27

Re: Timing external interrupts using TMR1

#3 Post by Jimbotnik » 02 Jul 2010 12:13

Thanks Sparky1039!

That capture/compare stuff looks interesting - I'll look at incorporating it

User avatar
ranko.rankovic
Posts: 433
Joined: 11 Jun 2010 09:22

Re: Timing external interrupts using TMR1

#4 Post by ranko.rankovic » 05 Jul 2010 08:06

Hello Jimbotnik,

I suggest you to look at this project.
It will give you another approach and maybe you'll get some new idea in solving your problem.

Best regards
Ranko Rankovic
mikroElektronika [Support Department]

Jimbotnik
Posts: 42
Joined: 20 Jan 2010 14:27

Re: Timing external interrupts using TMR1

#5 Post by Jimbotnik » 06 Jul 2010 22:43

Hello,

Thanks for the help.

I've been trying to use the CCP1 capture feature but am not having much luck. Here is how my code looks:

Code: Select all


void interrupt()
{
    PORTD = CCPR1L;
    PORTB = CCPR1H;
    
    PIR1.CCP1IF = 0;            // clear CCP1IF
}

void main()
{
    ANSEL  = 0;                 // Configure AN pins as digital I/O
    ANSELH = 0;

    PORTB = 0;               // Initialize PORTB
    TRISB = 0;                // PORTB is output
    
    TRISC = 1;               // PORTC is input
    
    PORTD = 0;               // Initialize PORTD
    TRISD = 0;                  // PORTD is output
    
    T1CON = 1;                  // Timer1 settings
    PIR1.TMR1IF = 0;            // clear TMR1IF
    TMR1H = 0x0;               // Initialize Timer1 register
    TMR1L = 0x0;
    
    PIE1.CCP1IE  = 1;           // enable CCP1 interrupt

    INTCON = 0xD0;              // Set GIE, PEIE
    CCP1CON = 0x5;              // Set to trigger on every rising edge

    do
    {

    } while (1);
}

When I send my burst of 4 square waves at a frequency of 100Hz I see no change on the PORTB or PORTD LEDs

What am I missing?

Thanks for any help,

Jimbo

User avatar
ranko.rankovic
Posts: 433
Joined: 11 Jun 2010 09:22

Re: Timing external interrupts using TMR1

#6 Post by ranko.rankovic » 07 Jul 2010 14:25

Hello Jimbotnik,

In attachment I send you project of working frequency meter. It uses 2x16 LCD to show current frequency. It runs great till 1kHz, after that it has some measuring error.
At 2kHz we measured error of 1.5-2%. It's because PIC uses too much time for frequency calculation. On some faster MCU it would be more accurate.

Hope this helps.

Best regards
Attachments
Interrupt freq meter for PIC16F887.rar
(44.89 KiB) Downloaded 178 times
Ranko Rankovic
mikroElektronika [Support Department]

Jimbotnik
Posts: 42
Joined: 20 Jan 2010 14:27

Re: Timing external interrupts using TMR1

#7 Post by Jimbotnik » 07 Jul 2010 23:59

Thanks for the help.

I've worked out what was wrong with my code - I had set pin RC0 as an input (TRISC = 1) but I needed to set RC2 as the input for CCP1 (TRISC = 4)

Also I think picking up on which interrupt had triggered was important too. I was just picking up on any interrupt but I should have been checking that it was the CCP1 interrupt flag.

Jimbo

Post Reply

Return to “mikroC General”