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

CCP / 24 bit timer / 1hz to 150 hz range
Goto page Previous  1, 2, 3, 4, 5, 6  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jan 06, 2008 3:36 pm     Reply with quote

The following code works. I orginally had the fuses set for a 20 MHz
crystal, but I changed it to a 12 MHz crystal since that's what you're using.
I don't have an 18F2550, but I do have a 18F4550, which is similar.
I used a B&K Function Generator, with a 5v p/p square wave going into
pin C2. The PIC is running at 5v. I put the B&K on the 5 Hz scale and
it worked OK at the very low input frequencies:

Quote:
4 Hz
4 Hz
4 Hz
4 Hz
3 Hz
3 Hz
3 Hz
3 Hz
2 Hz
2 Hz
2 Hz
1 Hz
1 Hz
1 Hz
1 Hz


Then setting it for the 50 Hz range setting and
turning the knob:
Quote:

4 Hz
4 Hz
4 Hz
4 Hz
6 Hz
10 Hz
14 Hz
17 Hz
19 Hz
21 Hz
23 Hz
25 Hz
28 Hz
29 Hz
31 Hz
33 Hz
38 Hz
41 Hz
51 Hz
51 Hz
51 Hz


I also set it for about 86 Hz and let it sit there. It doesn't ever display
"0 Hz". It works.
Quote:

87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz
87 Hz

This program was tested with vs. 4.064:
Code:

#include <18F4550.H>
#fuses HSPLL, PLL3, CPUDIV1, NOWDT, PUT, BROWNOUT, NOLVP   // 12 MHz xtal
//#fuses HSPLL, PLL5, CPUDIV1, NOWDT, PUT, BROWNOUT, NOLVP // 20 MHz xtal
#use delay(clock=48000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#priority CCP1, TIMER1

#define BytePtr(var, offset)   (char *)(&(char *)var + offset)

#byte PIR1 = 0xF9E
#bit  TMR1IF = PIR1.0

int8  gc_timer1_extension = 0;
int8  gc_capture_flag = FALSE;
int32 g32_ccp_delta;

//------------------------------------------------------
#int_timer1
void timer1_isr(void)
{
gc_timer1_extension++;
}

//------------------------------------------------------

#int_ccp1
void ccp1_isr(void)
{
char timer_ext_copy;
int32 current_ccp;
static int32 old_ccp = 0;

gc_capture_flag = TRUE;       

current_ccp = (int32)CCP_1;   

// Get local copy of the timer ext.
timer_ext_copy = gc_timer1_extension; 


if(TMR1IF)
  {
   if(*BytePtr(current_ccp, 1) < 2)  // Was CCP captured after Timer1 wrapped?
      timer_ext_copy++;  // If so, inc the copy of the timer ext.

   // Since we know a timer interrupt is pending, let's just
   // handle it here and now.  That saves a little load off
   // the processor.
   gc_timer1_extension++;  // Increment the real timer extension
   TMR1IF = 0;     // Then clear the Timer1 interrupt
  }

// Insert the timer extension into the proper place in the 32-bit
// CCP value.
// ie.,  Insert it into location "EE" as follows: 0x00EEnnnn
// (nnnn = the CCP).
*BytePtr(current_ccp, 2) = timer_ext_copy;

g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);

// Save the current ccp value for next time.
old_ccp = current_ccp;

}

//=======================
void main()
{
int16 frequency;
int32 current_ccp_delta;

set_timer1(0);           
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);   

setup_ccp1(CCP_CAPTURE_RE);   

// Enable interrupts.
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);

clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);

enable_interrupts(GLOBAL);


while(1)
  {
   disable_interrupts(GLOBAL);
   current_ccp_delta = g32_ccp_delta;;
   enable_interrupts(GLOBAL);

   if(gc_capture_flag == TRUE)
     {
      frequency = (int16)((12000000L + (current_ccp_delta >> 1)) / current_ccp_delta);

      printf("%lu Hz\n\r", frequency);
//      printf("%lu Hz, delta = %lx \n\r", frequency, current_ccp_delta);

      gc_capture_flag = FALSE;
    }
  else
    {
     printf("No signal\n\r");
    }

  delay_ms(500);
 }

}
ELCouz



Joined: 18 Jul 2007
Posts: 427
Location: Montreal,Quebec

View user's profile Send private message

PostPosted: Sun Jan 06, 2008 9:46 pm     Reply with quote

Dear PCM Programmer,


Gave me this with my pic18f2553...in less than 10 sec...
http://pages.infinit.net/ironz/capture.txt


but now with the 4550 i have a perfect working CCP function wow thanks !!

Maybe your code is pic dependant (some register are missing in the pic18f2553 or 2550?)

Anyway, you solve my problem!

I owe you one ! Smile Mr. Green
You should setup a paypal account, so we can all donate you some money for solving our problems hehe

Laurent

Mtl,Quebec[/url]
deepakomanna



Joined: 06 Mar 2007
Posts: 92
Location: Pune,India

View user's profile Send private message AIM Address Yahoo Messenger

getting incorrect frequency...
PostPosted: Mon Jan 07, 2008 5:24 am     Reply with quote

Dear Sir,
here i am using 16f913, MPLAB 7.5 Ver. & CCS PCM C Compiler, Version 3.249, 34534.Also i am testing this using ICD 2.

in my application external crystal is 32.768khz for timer1(Div by 1 prescalar) & 8 Mhz is used for internal
clock.As per previous threads i checked everything but still now
i am not getting exact freq. I calculate freq. as,

Quote:
isr_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x100000 - old_ccp);
frequency = (int16)((32768L + (isr_ccp_delta >> 1)) / isr_ccp_delta);

So my timer 1 is running at 1 count= 30.52 usec &
consider current i/p frequency is 360 Hz then count == 91(2.78 msec) &
previous frequency count is 93 (350 Hz = 2.86 msec).
then,
isr_ccp_delta = 91 + (0x1000000 - 93);
it will be FF FFFE =>(16777214);
Then,
frequency = (32768+(16777214/2))/16777214;
it will be "0 Hz";
But it should be 360 Hz

_________________
Thank You,
With Best Regards,
Deepak.


Last edited by deepakomanna on Wed Jan 09, 2008 7:36 am; edited 1 time in total
deepakomanna



Joined: 06 Mar 2007
Posts: 92
Location: Pune,India

View user's profile Send private message AIM Address Yahoo Messenger

getting incorrect frequency...
PostPosted: Tue Jan 08, 2008 6:05 am     Reply with quote

can anybody tell me how to calculate frequency by using 16f913 with external crystal for timer1 using CCP1 interrupt & internal oscillator for internal processing.
_________________
Thank You,
With Best Regards,
Deepak.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: getting incorrect frequency...
PostPosted: Tue Jan 08, 2008 1:15 pm     Reply with quote

deepakomanna wrote:

..my timer 1 is running at 1 count= 30.52 usec &
consider current i/p frequency is 360 Hz then count == 91(2.78 msec) &
previous frequency count is 93 (350 Hz = 2.86 msec).
then,
isr_ccp_delta = 91 + (0x1000000 - 93);
it will be FF FFFE =>(16777214);
Then,
frequency = (32768+(16777214/2))/16777214;
it will be "0 Hz";
But it should be 91 Hz


If your input frequency is in the range of 10 Hz to 700 Hz, then the period of one cycle of the input will range from 3276 Timer 1 counts to 47 Timer 1 counts. I don't know if you are resetting Timer 1 on every input cycle or if you are letting it run free. The subtraction implied by your calculation would indicate that it is running free. Then the problem is subtracting two 24-bit numbers so that the result works across a wrap-around at 0x??ffffff. Several solutions to that have been proposed, including mine of just doing:

delta_ccp = (current_ccp - old_ccp) & 0xffffff;

This assumes that immediately after doing this calculation you will then set:

old_ccp = current_ccp;

in preparation for the next cycle. If all that is done properly, then the calculation for frequency is:

freq = 32768 / delta_ccp;

Robert Scott
Real-Time Specialties
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Tue Jan 08, 2008 1:20 pm     Reply with quote

ELCouz wrote:

Does my problem (0hz reading) because my timer is not syncronised with the input?

It may be due to incorrectly handling 24-bit wrap-around, which will give a very large (incorrect) period, which would calculate out to 0 Hz.
Quote:
Code:

delta_ccp = current_ccp - old_ccp;

if(bit_test(delta_ccp,23))
    delta_ccp |= 0xff000000;
else
    delta_ccp &= 0x00ffffff;
   
old_ccp = current_ccp;



then declare delta_ccp as a int32 in the header ?


Not only delta_ccp, but also current_ccp and old_ccp must be 32 bits.

Robert Scott
Real-Time Specialties
deepakomanna



Joined: 06 Mar 2007
Posts: 92
Location: Pune,India

View user's profile Send private message AIM Address Yahoo Messenger

getting incorrect frequency...
PostPosted: Wed Jan 09, 2008 9:22 pm     Reply with quote

RLScott wrote:
Then the problem is subtracting two 24-bit numbers so that the result works across a wrap-around at 0x??ffffff. Several solutions to that have been proposed, including mine of just doing:

delta_ccp = (current_ccp - old_ccp) & 0xffffff;

This assumes that immediately after doing this calculation you will then set:

old_ccp = current_ccp;

in preparation for the next cycle. If all that is done properly, then the calculation for frequency is:

freq = 32768 / delta_ccp;

I gone through your reply,but this solution also gives "0 Hz" output.
Look this,
isr_ccp_delta = 0x000091 - 0x000093;
isr_ccp_delta &= 0xffffff;
it will be FFFFFE =>(16777214);

so, freq = 32768 / 16777214;
And this will gives "0 Hz" insted of "360 Hz"
Below is the my code for your kind reference,
Code:
#include<16F913.h>
#fuses INTRC_IO,NOWDT,PUT,NOMCLR,PROTECT,NOCPD,BROWNOUT,NOIESO,NOFCMEN   //external MCLR bcz of MPLAB ICD2
#use delay(clock=8000000)
/////////////////////////////////////////////////////////////////////////////////////////
//                                 LCD Configuration                                   //
/////////////////////////////////////////////////////////////////////////////////////////
// Digit segments    A              B              C              D              E              F              G           DP
//                         b7             b6             b5             b4             b3             b2            b1             b0
#define DIGIT1  COM0+0,   COM0+1,   COM2+1,   COM3+0,   COM2+0,   COM1+0,   COM1+1,   COM3+3      // DISPALYS FROM RIGHT SIDE
#define DIGIT2  COM0+2,   COM0+3,   COM2+3,   COM3+2,   COM2+2,   COM1+2,   COM1+3               // DISPALYS FROM RIGHT SIDE
#define DIGIT3  COM0+4,   COM0+5,   COM2+5,   COM3+4,   COM2+4,   COM1+4,   COM1+5               // DISPALYS FROM RIGHT SIDE
#define DIGIT4  COM0+6,   COM0+7,   COM2+7,   COM3+6,   COM2+6,   COM1+6,   COM1+7                  // DISPALYS FROM RIGHT SIDE
#define DIGIT5  COM0+8,   COM0+9,   COM2+9,   COM3+8,   COM2+8,   COM1+8,   COM1+9                  // DISPALYS FROM RIGHT SIDE
#define DIGIT6 COM0+13,   COM0+11,   COM2+11,   COM3+13,   COM2+13,   COM1+13,   COM1+11                  // DISPALYS FROM RIGHT SIDE
#define DIGIT7 COM0+12,   COM0+14,   COM2+14,   COM3+12,   COM2+12,   COM1+12,   COM1+14                  // DISPALYS FROM RIGHT SIDE#define VLCD_ENABLE 0x10
#define DUMBEL COM3+14
#define VLCD_ENABLE 0x10

#define eeprom_minute_address 0
#define eeprom_number_address 253
#define store_min_address 254
#define store_number_address 255
#BYTE OSCCON = 0x8F
#BYTE LCDDATA10 = 0X11A
//character                     0         1        2         3        4        5        6         7       8        9      
byte const Digit_Map[10] = {0xFD,0x61,0xDB,0xF3,0x67,0xB7,0xBF,0xE1,0xFF,0xF7};
byte lcd_pos;
byte segments;


void init_CPU();
void ee_write32(int8,int32,int8);
void ee_write16(int8,int16,int8);
int32 ee_read32(int8,int8);
int16 ee_read16(int8,int8);
int8 inc_min_address;
int8 dec_number_address;
int8 wr_inc_dec_addr;
int32 number ;
int16 min_count;
int1 BLINK_DUMBEL= 0;      // this flag for blinking the decimal point
int1 stop_min_wr;
int8 no_freq;

#int_ccp1
void ccp1_isr(void)
{

int32 current_ccp;    
static int32 old_ccp = 0;
int16 frequency;
int32 isr_ccp_delta;
static int16 sec_counter =0;
int16 TIMER1_VALUE;
no_freq = 0;
if(stop_min_wr== 0)
   {
      stop_min_wr = 1;
      clear_interrupt(INT_TIMER0);
      ENABLE_INTERRUPTS(INT_TIMER0);
      SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_256);
   }

current_ccp = (int32)CCP_1;
isr_ccp_delta = (current_ccp - old_ccp) ;
isr_ccp_delta &= 0xFFFFFF;
old_ccp = current_ccp;
frequency = 32768 / isr_ccp_delta;
//if(isr_ccp_delta <= 111)   // if freq >=297 Hz ==(<= 111 count)
if(frequency >= 297)   // if freq >=297 Hz ==(<= 111 count)
   {   
      sec_counter++;
      if(sec_counter >=297)   // 1sec == 298 count
         {   
            sec_counter = 0;
            min_count++;
            BLINK_DUMBEL =~BLINK_DUMBEL;      // compliment flag for decimal point.                                           
            
         }
         
   }
   
else
   {               
      SETUP_TIMER_1(T1_DISABLED);      // TIMER_1 count OFF
      TIMER1_VALUE = GET_TIMER1();
      if(TIMER1_VALUE >= 32766)      // (65536/2)=32766   1SEC timer1 count
      {   
         min_count++;
         set_timer1(0);   
         BLINK_DUMBEL =~BLINK_DUMBEL;      // compliment flag for decimal point.                                           
      }
      setup_timer_1(T1_EXTERNAL_SYNC|T1_DIV_BY_1|T1_CLK_OUT);
   }

}

int32 ee_read32(int8 base_address,int8 RW_cycle)
{
int8 j;
int32 data_read=0;
for(j=0; j<=RW_cycle; j++)
   *((int8 *)&data_read+j) = read_eeprom(base_address - j);
return (data_read);

}

void ee_write32(int8 base_address ,int32 data,int8 WR_cycle)
{
int8 j;
for(j=0; j<WR_cycle; j++)
   write_eeprom(base_address - j,*((int8 *)&data+j));
}

int16 ee_read16(int8 base_address,int8 RW_cycle)
{
int8 j;
int16 data_read=0;
for(j=0; j< RW_cycle; j++)
   *((int8 *)&data_read+j) = read_eeprom(base_address + j);
return (data_read);

}
void ee_write16(int8 base_address,int16 data,int8 WR_cycle)
{
int8 j;
for(j=0; j<WR_cycle; j++)
   write_eeprom(base_address + j,*((int8 *)&data+j));
}

#INT_TIMER0
void timer0_isr(void)
{

int16 stored_minute;

static int16 sec_count = 0;

// TIMER0 overflows after every 30.464 msec


sec_count++;
no_freq++;
if(sec_count >= 197)
   {               //write data every 6 sec to eeprom.
      sec_count = 0;            
                  
write_min_again :
ee_write16((eeprom_minute_address + inc_min_address), min_count,2); //write data to EEPROM loc 0x00
stored_minute=ee_read16((eeprom_minute_address + inc_min_address),2);      

      if(stored_minute != min_count)
         {
            inc_min_address++;   
            wr_inc_dec_addr = 1;
            if(inc_min_address == 144)
               inc_min_address = 0;
            goto write_min_again;
         }
   
   }
   
   
if(no_freq >=16)   //1 SEC =16
   {
      no_freq = 0;
      
      DISABLE_INTERRUPTS(INT_TIMER0);
      stop_min_wr = 0;
      
   }   

}

void lcd_putc(char c)
{
 if(c=='\f')
     lcd_pos=0;
else {
           if((c>='0')&&(c<='9'))
               {
                  segments=Digit_Map[c-'0'];
               }
            else
               segments=0;
            
      switch(lcd_pos)
       {          
          case 1:  lcd_symbol(segments,DIGIT7); break;     // fill 1s place
          case 2:  lcd_symbol(segments,DIGIT6); break;     // fill 1s place
         case 3:  lcd_symbol(segments,DIGIT5); break;      // fill 10s place
              case 4:  lcd_symbol(segments,DIGIT4); break;     // fill 100s place
             case 5 : lcd_symbol(segments,DIGIT3); break;     // fill  1000s place
              case 6 :
                     if(number<10)
                           segments = Digit_Map[0];
                        lcd_symbol(segments,DIGIT2); break;      // fill  10000splace
                case 7 :
                      lcd_symbol(segments,DIGIT1);    // fill  100000s place
                                
                   switch(BLINK_DUMBEL)
                      {
                         case 1 :    #asm
                                BSF      LCDDATA10,6
                                #endasm
                             break;
                       case 0 :   #asm
                                BCF      LCDDATA10,6
                                #endasm   
                                
                      }
                   
                                    
            }
   }
 lcd_pos++;
 
}

void  init_CPU()
{

setup_oscillator(OSC_8MHZ | OSC_INTRC);

/**************  PORT SETTINGS ****************/
   PORT_B_PULLUPS(0X00);      // RB7 & RB6 i/p for programming devices.
   SET_TRIS_A(0XC0);         // i/p OSC1 & OSC2
   SET_TRIS_B(0X00);
   SET_TRIS_C(0X27);         //VLCD 1,2,3 i/p,FREQ i/p.
   SET_TRIS_E(0X08);         // RE3 i/p for RESETING the device EEPROM.
/*************** LCD SETTINGS ********************/
   SETUP_LCD( LCD_MUX14 |LCD_INTRC|VLCD_ENABLE, 2);   
/****************  COMPARATOR SETTINGS  ***************/
   SETUP_COMPARATOR(NC_NC_NC_NC);
/****************  INTERRUPT SETTINGS  *****************/
   ENABLE_INTERRUPTS(GLOBAL);

   clear_interrupt(INT_TIMER0);
   ENABLE_INTERRUPTS(INT_TIMER0);      //enable timer1 interrupt
   
   SET_TIMER0(18);                     // timer0 interrupt for 30.464 msec.
                                 // 1 Count=128 Usec,So 256 - 238 ==18.
   
set_timer1(0);           
setup_ccp1(CCP_CAPTURE_RE);       //Capture on rising edge
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
setup_timer_1(T1_EXTERNAL_SYNC|T1_DIV_BY_1|T1_CLK_OUT);

}
 

void main()
{
int32 stored_number;
int8 wr_rw_cycle;
int8 read_erase;
int16 clear_ee = 0;
init_CPU();
OSCCON = 0x70;
BLINK_DUMBEL = 0;
wr_inc_dec_addr = 0;
stop_min_wr = 0;
inc_min_address = read_eeprom(store_min_address);
dec_number_address = read_eeprom(store_number_address);

min_count = ee_read16((eeprom_minute_address + inc_min_address),2);      
number = ee_read32((eeprom_number_address - dec_number_address),4);
 
while(TRUE)
     {   
        
   printf(lcd_putc,"\f%7lu",number);
   
   if(INPUT_STATE(PIN_E3) == 0)
      {   
         for(clear_ee = 0; clear_ee<= 255;clear_ee++)
            {   
               read_erase = read_eeprom(clear_ee);
               if(read_erase != 0)
                  write_eeprom(clear_ee,0x00);
                  
            }
                           
            }
            
            
     if(min_count >= 360)//360   // if frequency is 297 Hz, min_count == 360, becomes after 6 min.
         {               // so number is incremented once after 6min.
            
            number++;
            
            min_count = 0;
            if(number <= 255)
               wr_rw_cycle = 1;
            else if((number >255) &&(number < 65025))
               wr_rw_cycle = 2;
            else
               wr_rw_cycle = 3;
write_number_again:
            ee_write32((eeprom_number_address - dec_number_address), number,wr_rw_cycle); //write data to EEPROM loc 0x00
            stored_number = ee_read32((eeprom_number_address - dec_number_address),wr_rw_cycle);
            if(stored_number != number)
               {
                  dec_number_address++;   
                  wr_inc_dec_addr = 2;
                  if(dec_number_address == 150)
                     dec_number_address = 0;
                  goto write_number_again;
                }   
            no_freq = 0;   
            if(number == 999999)
               number = 0;            
         }
      switch(wr_inc_dec_addr)
               {
                  case 1 :  write_eeprom(store_min_address,inc_min_address);
                                  wr_inc_dec_addr = 0;
                          break;
                  case 2 : write_eeprom(store_number_address,dec_number_address);
                         wr_inc_dec_addr = 0;
                         break;   
               }
   
      
        }
     
}


Plz helped me i stucked only in this point....
_________________
Thank You,
With Best Regards,
Deepak.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: getting incorrect frequency...
PostPosted: Thu Jan 10, 2008 6:10 am     Reply with quote

deepakomanna wrote:
RLScott wrote:
Then the problem is subtracting two 24-bit numbers so that the result works across a wrap-around at 0x??ffffff. Several solutions to that have been proposed, including mine of just doing:

delta_ccp = (current_ccp - old_ccp) & 0xffffff;

This assumes that immediately after doing this calculation you will then set:

old_ccp = current_ccp;

in preparation for the next cycle. If all that is done properly, then the calculation for frequency is:

freq = 32768 / delta_ccp;

I gone through your reply,but this solution also gives "0 Hz" output.
Look this,
isr_ccp_delta = 0x000091 - 0x000093;
isr_ccp_delta &= 0xffffff;
it will be FFFFFE =>(16777214);

so, freq = 32768 / 16777214;
And this will gives "0 Hz" insted of "360 Hz"....


How do you know that old_ccp = 0x93 and current_ccp = 0x91? You code does not show how you could know this. I think that is the basic problem. It does not make sense that CCP_1 is 0x93 at one time and then it is 0x91 a short time later. CCP_1 is supposed to capture the value of Timer 1 on the rising edge of your signal. Timer 1 is counting up, right? It might appear that Timer 1 is counting down if it actually did count up 16777214 times. This might happen if the signal frequency is very low, but I don't think so. Put in some code to check what CCP_1 is reading on each capture event. Perhaps you actually have ccp_old and ccp_current reversed?

Robert Scott
Real-Time Specialties
Embedded Systems Consulting
deepakomanna



Joined: 06 Mar 2007
Posts: 92
Location: Pune,India

View user's profile Send private message AIM Address Yahoo Messenger

getting incorrect frequency...
PostPosted: Thu Jan 10, 2008 7:33 am     Reply with quote

After your reply i made one pin (RA0) toggle at fixed 480 Hz freq. in the following routine in my code (see earlist my thread)
Quote:

if(frequency >= 297) // if freq >=297 Hz ==(<= 111 count)
{
output_toggle(pin_a0);
sec_counter++;
if(sec_counter >=297) // 1sec == 298 count
{
sec_counter = 0;
min_count++;
BLINK_DUMBEL =~BLINK_DUMBEL; // compliment flag for decimal point.

}

}

then i observed on the oscilloscope that some times it misses to toggle the pin, this means that the sometimes control is not comming inside the loop. & follwoing the else statement. this is not meaning that it is giving 0 Hz, but i want to say is if freq is fixed 480 Hz then why it misses to toggle the pin.
_________________
Thank You,
With Best Regards,
Deepak.
SET



Joined: 15 Nov 2005
Posts: 161
Location: Glasgow, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri Jan 11, 2008 9:55 am     Reply with quote

As PCM posted, you have to handle the case where the current capture is smaller than the last capture:

Quote:
Code:
g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);


So your code:
Code:
current_ccp = (int32)CCP_1;
isr_ccp_delta = (current_ccp - old_ccp) ;
isr_ccp_delta &= 0xFFFFFF;
old_ccp = current_ccp;
frequency = 32768 / isr_ccp_delta;


Should be changed to:
Code:

current_ccp = (int32)CCP_1;
if (current_ccp > old_ccp)
    isr_ccp_delta = (current_ccp - old_ccp) ;
else
    isr_ccp_delta = current_ccp + (0x1000000 - old_ccp); 
old_ccp = current_ccp;
frequency = 32768 / isr_ccp_delta;


PS I changed from the ? operator to explicit 'if' in case peeps here arent familiar with it.
Kenny



Joined: 07 Sep 2003
Posts: 173
Location: Australia

View user's profile Send private message

PostPosted: Fri Jan 11, 2008 2:14 pm     Reply with quote

Deepakomanna:
The 24 bit code is not being used. Also, if you want to use the timer 1 oscillator rather than use a crystal on the main oscillator, then could get a more precise result counting over more cycles of the input using either
setup_ccp1(CCP_CAPTURE_DIV_4);
or
setup_ccp1(CCP_CAPTURE_DIV_16);
The tradeoff is that the update rate will be lower.


RLScott:
I think that the method that tests bit 23 limits the range to 0x7FFFF, which I guess is not a problem for a tachometer application.
I thought about testing bit 31, and if it is set clear the top byte of the int32, with PCM's macro for example.

Your other method
delta_ccp = (current_ccp - old_ccp) & 0xffffff;
works over the full range and is much more efficient than what I was using.

It's two instructions shorter this way ( the scratch area is not needed for the intermediate value):
delta_ccp = current_ccp - old_ccp;
delta_ccp &= 0xffffff;

I shall use that from now on.

Thanks
Ken
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Sat Jan 12, 2008 8:10 am     Reply with quote

SET wrote:

So your code:
Code:
current_ccp = (int32)CCP_1;
isr_ccp_delta = (current_ccp - old_ccp) ;
isr_ccp_delta &= 0xFFFFFF;
old_ccp = current_ccp;
frequency = 32768 / isr_ccp_delta;


Should be changed to:
Code:

current_ccp = (int32)CCP_1;
if (current_ccp > old_ccp)
    isr_ccp_delta = (current_ccp - old_ccp) ;
else
    isr_ccp_delta = current_ccp + (0x1000000 - old_ccp); 
old_ccp = current_ccp;
frequency = 32768 / isr_ccp_delta;



Can you give one example of when the first code gives different results from the second code? It seems to me that for 24-bit values of CCP_1, these two code blocks give the same result, and the first one is smaller and faster.

Robert Scott
Real-Time Specialties
Embedded Systems Consulting
SET



Joined: 15 Nov 2005
Posts: 161
Location: Glasgow, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Mon Jan 14, 2008 6:08 am     Reply with quote

Quote:
Can you give one example of when the first code gives different results from the second code? It seems to me that for 24-bit values of CCP_1, these two code blocks give the same result, and the first one is smaller and faster.


Yes your right, for 2-s complement subtraction this works. Mind you, the efficiency gains are moot compared to the following division! Smile
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Thu Jun 11, 2009 11:10 am     Reply with quote

Hi,

compiler version : 4.057

I read this thread and tested the code above with a 16f628 running at 10Mhz. The input signal, about 1.4 Hz, is generated from a PIC 16f877 using the following code:
Code:

void main()
{

while(1)
 {
 output_high(PIN_E1);
 delay_ms(100);
 output_low(PIN_E1) ;
 delay_ms(600);
 }

}


I connected the 16F877's pin RE2 to the CCP1 pin of 16F628 (RB3) through a pull-down resistance. and here is what I got in the terminal :
Code:


....

53512 Hz
53512 Hz

53512 Hz
0 Hz
53512 Hz

53512 Hz
48100 Hz
53512 Hz


53512 Hz
53512 Hz

53512 Hz
53512 Hz
53512 Hz

53512 Hz
53512 Hz
53512 Hz

...


I was expecting to get 1 or 2 Hz Shocked

here is my code :
Code:

#include <16F628.h>

#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 10000000)
#use rs232 (baud=9600,parity=N,xmit=PIN_B2,rcv=PIN_B1,bits=8)


#priority CCP1, TIMER1
#byte  PortB = 6         // Address of PortB for 16F-series PICs
#byte  PIR1  = 0x0C      // PIR1 : REGISTERS ASSOCIATED WITH TIMER1 (contains TMR1IF in bit0)
#byte CCPR1_REG = 0x15   // Adress of CCPR1L
#bit   TMR1IF  = PIR1.0      // TMR1IF
#define BytePtr(var, offset) (char *)(&var + offset)

int8 gc_timer1_extension = 0;
int8 gc_capture_flag = FALSE;
int32 g32_ccp_delta;

//------------------------------------------------------------
// MACROS
// This macro allows us to insert a byte into the specified
// offset of a 16 or 32 bit variable. Example:
// *BytePtr(temp_long, 2) = 0x55;
// If temp_long is 0, the above line will make it become:
// 0x00550000

// The Timer1 interrupt increments an 8-bit variable which
// extends the timer to 24 bits. We need this so we can
// avoid having to switch the Timer pre-scaler between "low"
// and "high" rpm ranges.

#int_timer1
void timer1_isr(void)
{
gc_timer1_extension++;
}

//------------------------------------------------------
// When we get a CCP interrupt, read the CCP register and
// save it in a global variable.

#int_ccp1
void ccp1_isr(void)
{
char timer_ext_copy;
int32 current_ccp;
static int32 old_ccp = 0;

// Set flag to indicate that we did a capture.
gc_capture_flag = TRUE;

current_ccp = (int32)CCPR1_REG; // Read the current CCP

// Get local copy of the timer ext.
timer_ext_copy = gc_timer1_extension;

// Check if a Timer1 interrupt is pending. If so, check if
// the CCP capture occurred before or after the Timer rolled
// over. We can tell if it occurred after it rolled over, if
// the CCP's MSB is zero. ie., if the CCP is somewhere between
// 0x0000 and 0x00FF.
// We know that we can just check if the MSB = 0x00, because
// it takes about 30 us to get into this ISR. (Using a 4 Mhz
// crystal on a 16F628). The timer increments at 1 us per
// count, so 0xFF = 255 us.
// Actually, to be safer, I'll give it 2 MSB counts, which is
// 511 us. That way, if I lengthen any of the other ISR's,
// we'll still be able to detect the roll-over OK.
// If the timer did roll over after we got a CCP interrupt,
// then we need to increment the timer extension byte, that we
// save. We have to do that because the CCP interrupt has
// priority, and so it executes before the Timer isr can
// execute and increment the extension.
// (Designing the code with the priority switched doesn't help.
// You still have the same type of problem. With CCP first,
// the fix is easier).

// Was CCP captured after Timer1 wrapped ?
// If so, increment the copy of the timer ext.

if(TMR1IF)
{
if(*BytePtr(current_ccp, 1) < 2)
timer_ext_copy++;

// Since we know a timer interrupt is pending, let's just
// handle it here and now. That saves a little load off
// the processor.
gc_timer1_extension++; // Increment the real timer extension
TMR1IF = 0; // Then clear the Timer1 interrupt
}

// Insert the timer extension into the proper place in the
// 32-bit CCP value.
// ie., Insert it into location "EE" as follows: 0x00EEnnnn
// (nnnn = the CCP).
*BytePtr(current_ccp, 2) = timer_ext_copy;

// Because we're using unsigned math, we don't have to worry
// if the current value is less than the old. The result is
// always the absolute value of the difference. The only way
// there could be a problem is if the new CCP value had rolled
// over twice. But with a 24-bit value, and a Timer
// pre-scalar of 1, that's 16.7 seconds. That's way beyond any
// practical value.

// Edited on Jan. 2, 2004: There was a bug in this routine,
// because I was promoting a 24-bit value to a 32-bit data type,
// but the upper byte was always left = 0. This caused a problem
// with the 32-bit subtraction when the 24-bit value rolled over past 0.
// Kenny spotted this error and provided a fix in a PM to me.
// I have commented out the original line, and inserted his fix, below.
//g32_ccp_delta = current_ccp - old_ccp;
g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);

// Save the current ccp value for next time.
old_ccp = current_ccp;
}


void main()
{
int16 frequency;
int32 current_ccp_delta;

   set_timer1(0); // for capture mode CCP1
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
   setup_ccp1(CCP_CAPTURE_RE);

// Clear the CCP1 interrupt flag before we enable
// CCP2 interrupts, so that we don't get an unwanted
// immediate interrupt (which might happen).
 
   clear_interrupt(INT_TIMER1);
   enable_interrupts(INT_TIMER1);
 
   clear_interrupt(INT_CCP1);
   enable_interrupts(INT_CCP1);
   
   enable_interrupts(GLOBAL);

while(1)
 {
    // Now calculate the frequency.

   // Get a local copy of the latest ccp delta from the isr.
   // We have to disable interrupts when we read a global
   // isr variable that is larger than a single byte.
disable_interrupts(GLOBAL);
current_ccp_delta = g32_ccp_delta;
enable_interrupts(GLOBAL);

   // To calculate the frequency of the input signal,
   // we take the number of clocks that occurred
   // between two consecutive edges of the input signal,
   // and divide that value into the number of Timer1
   // clocks per second.   Since we're using a 4 MHz
   // crystal, the Timer1 clock is 1 MHz (Timer1 runs
   // at the instruction cycle rate, which is 1/4 of the
   // crystal frequency).  For example, suppose the
   // the input waveform has a frequency of 244 Hz.
   // 244 Hz has a period of about 4098 usec.
   // Timer1 is clocked at 1 MHz, so between two
   // consecutive rising edges of the input signal,
   // it will count up by 4098 clocks.  To find the
   // frequency, we divide 4098 into the number of
   // clocks that occur in 1 second, which is 1000000.
   // This gives 1000000 / 4098 = 244 Hz.
   
if(gc_capture_flag == TRUE)
  {
   frequency = (int16)((2500000L + (current_ccp_delta >> 1)) / current_ccp_delta);

   printf("%lu Hz\n\r", frequency);

   gc_capture_flag = FALSE;
  }
else
  {
   printf("\n\r");  // instead of displaying "no signal"
  }
delay_ms(500);
 
 }

}

The code seems to be correct, but I'm receiving incorrect frequency...

Is there any explanation ?

Your help will be much appreciated.

Salenko.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jun 11, 2009 11:52 am     Reply with quote

I can see one problem. This is fairly old code. It was written for vs 3
of the compiler. At that time, CCS assumed that all pointer arithmetic
was done as if the pointer was a byte pointer (And I wrote code like that).
But in vs. 4, they changed to use the C standard, which is that pointer
arithmetic will use the declared size of the pointer. In other words, if
you add 1 to an int32 pointer, the pointer will be advanced by 4 bytes,
which is the size of an int32. That's the correct way.

So, to fix this old code, you need to cast the &var address to a char
pointer. Add the (char*) text as shown in bold below:
Quote:

#define BytePtr1(var, offset) (char *)((char*)&var + offset)
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3, 4, 5, 6  Next
Page 3 of 6

 
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