CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Interrupts, Interaction Between CCP1 and TIMER0

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

Interrupts, Interaction Between CCP1 and TIMER0
PostPosted: Mon Jan 03, 2011 10:56 am     Reply with quote

3.249
18LF6627
3.3V
Normal Run Mode
10Mhz (w/ HS 40Mhz)

Hardware: Custom board specifically for this project.

I'm trying to measure the period between rising edges of a clean square wave of 0 - 70hz. I've read many of the posts about measuring long periods and the need to 'extend' timers. I was hoping to do something simpler.

My approach is to load a countdown ticker in the CCP_INT on each rising edge and decrement the ticker in the TIMER0_INT.

The general flow is:

CCP_INT - Read the current ticks and reload.

TIMER0_INT - Decrement the ticks if they're not 0, if they are 0 update the global variable. (This allows for incomplete periods or 0hz.)

The problem that I'm seeing is...

The 'COUNTS' display on the LCD when I trigger the rising edge is always the TMR0_TICK_LOAD value on the first display after the trigger. I have a hard time believing that no time ever passes from the rising edge to the LCD display of the 'COUNTS'.

Any ideas or suggestions of where to look?



Code:
#case

#include <18F6627.h>

#define   XTAL_FREQ   40000000
#device adc=10
#fuses NOWDT,WDT128, H4, NOPROTECT, NOIESO, BROWNOUT, BORV25, PUT, STVREN
#fuses NOLVP, NOWRT, NOWRTD, NOWRTB, NOWRTC, NOCPD, NOCPB, NOEBTR, NOEBTRB //DEBUG,
#use delay(clock=XTAL_FREQ ,RESTART_WDT)
   
#define LED_GREEN   PIN_D0 
#define LED_YELLOW  PIN_D1 
#define LCD_POWER   PIN_F0
#define LCD_DATA    PIN_F1
#define PERI_PWR_SW PIN_F2

#define false 0
#define true  1

#include "SerLCD_V2_5.C"

// define constants to derive the 1ms system clock.
#define C_TMR0_1ms   256 - (XTAL_FREQ/(64*4*1000))
#define CTMR_Activity 2      // number of 100mS increments for LED flash

//////////////////////////////////////////////////////////////////////////
//    timer control flags and counters
//////////////////////////////////////////////////////////////////////////
BYTE   TMR_Short;      // Short Timer Counter - used for general purpose timing functions with TMR0 interrupts
long   TMR_Long;      // Long Timer Counter - used for general purpose timing functions with TMR0 interrupts
BYTE   TMR_100ms;      // 100ms timer counter
BYTE   TMR_Activity;   // LED flash timer for activity - number of 100ms increments
short   TF_Short;      // short timer done flag
short   TF_Long;      // long timer done flag

// period length of utility timers (in mS)
#define TMR_LONG_LOAD    1000
#define TMR_SHORT_LOAD     32

#define    CStatusLEDCount      5   // number of 100ms timer rollovers to toggle the Status LED
BYTE       StatusLEDCount;         // used for toggling the Status LED

#byte   TMR0L = 0x0FD6

#define TMR0_TICK_LOAD 1200
int16   gTimer0_Ticks  = TMR0_TICK_LOAD;
int16   gTotal_Counts  = 0;

#INT_TIMER0
void timer0_isr()
{
    TMR0L += C_TMR0_1ms;
    clear_interrupt(INT_TIMER0);
   
    // If gTimer0_Ticks is not 0, then decrement
    if(gTimer0_Ticks)
    {
        --gTimer0_Ticks;
    }
    // If gTimer0_Ticks has reached zero, pass value to total
    //  (This ensures gTotal_Counts is updated if another
    //  rising isn't encountered after gTimer0_Ticks
    //  reaches 0.)
    else   
    {
        gTotal_Counts = 0;
    }

   // service the short timer
   if(!--TMR_Short)
      TF_Short = TRUE;

   // service the long timer
   if(!--TMR_Long)
      TF_Long = TRUE;

   // service the 100ms timer
   if(!--TMR_100ms)
   {
      TMR_100ms = 100;
      if (TMR_Activity)
         if(!--TMR_Activity)
            output_low(LED_YELLOW);
      if (!--StatusLEDCount)
      {
         StatusLEDCount = CStatusLEDCount;
         output_toggle(LED_GREEN);
      }
   }
}
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
int1    gFirst_Rising_Edge_flg = true;

#INT_CCP1
void ccp1_isr(void)
{
    gTotal_Counts = gTimer0_Ticks;
    gTimer0_Ticks = TMR0_TICK_LOAD;

    /*
    if(gFirst_Rising_Edge_flg)
    {
        gFirst_Rising_Edge_flg = false;
        gTimer0_Ticks = TMR0_TICK_LOAD;
    }
    else
    {
        gFirst_Rising_Edge_flg = true;
        gTotal_Counts = gTimer0_Ticks;
    }
    */
   
}
//////////////////////////////////////////////////////////////////////
   
//////////////////////////////////////////////////////////////////////
int16    gPeriod = 0;

void Calculate_Period(void)
{
    if(gTotal_Counts)
    {
        gPeriod = 2 *  gTotal_Counts;  //670
    }
}
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void main()
{
    int8 i = 0;
   
    // Ensure unused modules are configured off
    setup_adc_ports(NO_ANALOGS);
    setup_adc(ADC_OFF);
    setup_psp(PSP_DISABLED);
    setup_spi(FALSE);
    setup_wdt(WDT_OFF);
    port_b_pullups(false);
   
    // Enable CCP1 to interrupt on rising edges
    setup_ccp1(CCP_CAPTURE_RE);
    clear_interrupt(INT_CCP1);
    enable_interrupts(INT_CCP1);
   
    // setup the system timer - Timer0
    setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_64 | RTCC_8_BIT);
    set_timer0 (C_TMR0_1ms);
    clear_interrupt(INT_TIMER0);
    enable_interrupts(INT_TIMER0);
   
    // Don't enable the LCD_DATA pin until after power has been applied
    output_low(LCD_DATA);
   
    // Enable Interrupts
    enable_interrupts(GLOBAL);
    delay_ms(10);
   
    // setup Status LED Toggle counter
    StatusLEDCount = CStatusLEDCount;
    output_low(LED_GREEN);
    TMR_Activity = CTMR_Activity;
   
    // Flash LED to indicate startup
    for (i =0; i<6; i++)
    {
        output_toggle(LED_GREEN);
        delay_ms(200);
    }
   output_low(LED_GREEN);
   
    // Powerup LCD module
    output_high(LCD_POWER);
    delay_ms(100);
    output_low(LCD_DATA);
    delay_ms(500);
    Set_LCD_Backlight(135);
    delay_ms(500);
    Send_CMD(CLR_DISP);
    delay_ms(10);
    Send_CMD(SET_CURSOR + 0);
    delay_ms(10);
    fprintf(LCD,"%s",__DATE__);
    delay_ms(10);
    Send_CMD(SET_CURSOR + 64);
    delay_ms(10);
    fprintf(LCD,"%s",__TIME__);
    delay_ms(2000);
   
    // initialize the countdown timer values
    TMR_Long  = TMR_LONG_LOAD;
    TMR_Short = TMR_SHORT_LOAD;
   
    // Turn on power to peripherals
    output_high(PERI_PWR_SW);
   
   /////////////////////////////////////////////////////////////////////////////
   /////////////////////////////////////////////////////////////////////////////
   //ExecLoop
   for (;;)
   {      
      if (TF_Long)
      {
            ///////////////////////////////////////////////////////////////////////
            //events
            //---------------------------------------------------------------------
            Calculate_Period();
            Send_CMD(CLR_DISP);
            delay_ms(10);
            Send_CMD(SET_CURSOR + 0);
            delay_ms(10);
            //fprintf(LCD,"PERIOD: %LU",gPeriod);
            fprintf(LCD,"COUNTS: %LU",gTotal_Counts);
            Send_CMD(SET_CURSOR + 64);
            delay_ms(10);
            fprintf(LCD," TICKS: %LU",gTimer0_Ticks);           
            //---------------------------------------------------------------------
            ///////////////////////////////////////////////////////////////////////
            TF_Long = FALSE;
            TMR_Long += TMR_LONG_LOAD;
      }
      //////////////////////////////////////////////////////////////////
      
      //////////////////////////////////////////////////////////////////
      if (TF_Short)
      {
         ///////////////////////////////////////////////////////////////////////
         //events
         //---------------------------------------------------------------------
         output_low(LED_YELLOW);
           
         //---------------------------------------------------------------------
         ///////////////////////////////////////////////////////////////////////
         TF_Short = FALSE;
         TMR_Short += TMR_SHORT_LOAD;
      }
      //////////////////////////////////////////////////////////////////
   }
}
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Fri Jan 07, 2011 9:32 pm     Reply with quote

Well, I haven't made any progress on this and have started to try to make the transition to PCM programmer's code that extends TIMER1 to 24 bits.

By extending the TIMER1 from 16 to 24 bits, is this correct:

10MHz crystal w/ PLL

40MHZ Clock

10MHz per timer tick (or 0.0000001 seconds)

Increase prescaler: T1_DIV_BY_8 (now 0.0000008 seconds)

Multiply by 24 bits to get maximum period of time to measure-

~13.42 seconds?



Thanks,

John
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jan 07, 2011 9:38 pm     Reply with quote

The math is correct.
customvinyl22



Joined: 07 Jan 2011
Posts: 1

View user's profile Send private message

hi
PostPosted: Fri Jan 07, 2011 10:20 pm     Reply with quote

nice .. good day
_________________
custom vinyl banner - personalized vinyl banners - vinyl banner
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Fri Jan 07, 2011 10:39 pm     Reply with quote

PCM programmer wrote:
The math is correct.



Thanks for the confirmation. I will test it on hardware in the morning.

John
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Sat Jan 08, 2011 9:02 am     Reply with quote

Well, I should have looked at the edges of the signal a week ago. I knew when PCM programmer's code wasn't working as expected, it had to be something else.




I guess early on, when I saw the rising edge was nice and clean I just assumed the falling edge was as well.

So, do I debounce in hardware or software? Any easy way to do it in software since it's an interrupt?



EDIT:

First thoughts are to hold in the CCP1 ISR for 100uS.

But, that raises these questions:

When in the ISR is the INT bit cleared? (Looking at the LST file it looks like at the end of the ISR.)

How many counts in a loop do I need for a 100uS delay at 40MHz?

EDIT2:

Or, duh, I guess I can just use a simple:

Code:

delay_us(100);
clear_interrupt(CCP1);



EDIT3:

On further thought, to debounce the falling edge in the ISR, I'll need to change the CCP from RE to FE, no?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jan 09, 2011 5:57 pm     Reply with quote

I don't know how many of those pulses are considered to be valid.
Is it just the big pulses ? Or all of them ?

Maybe you need to use an external low-pass filter circuit and then
pass it through a schmitt-trigger circuit to square it up.

Also, the Vih is about 4.0v as shown on your scope image. That's right at
the borderline for the PIC's specification for the CCP pin (for a +5v Vdd).
Ideally it should be a little higher, to provide some margin.
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Mon Jan 10, 2011 1:41 pm     Reply with quote

The first FE at about 16uS from the left is the end of the valid signal. All of the spikes after that are bounce.

Luckily, the required resolution allows for debouncing in software. But, I think if I revise the hardware I'll do that.

The part is LF and running at 3.3V.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group