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

Frequency meter with Pic 16F877
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
theasus



Joined: 31 May 2009
Posts: 79

View user's profile Send private message

Frequency meter with Pic 16F877
PostPosted: Tue Jan 05, 2010 11:00 am     Reply with quote

I want to design a frequency meter. Actually I will count pulses for one minute? Could you propose any method for this operation please? I think RB0 can be usefull but I couldn't determine yet.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jan 05, 2010 2:08 pm     Reply with quote

Use the PIC's CCP module in Capture mode to measure frequency.
There are several multi-page threads on this topic in the archives.
Please read all of them before asking any questions. Most of the
mistakes that you might make in your project have been discussed
and resolved in these threads:
http://www.ccsinfo.com/forum/viewtopic.php?t=33153
http://www.ccsinfo.com/forum/viewtopic.php?t=29963
http://www.ccsinfo.com/forum/viewtopic.php?t=36852
http://www.ccsinfo.com/forum/viewtopic.php?t=38013
theasus



Joined: 31 May 2009
Posts: 79

View user's profile Send private message

PostPosted: Sun Jan 10, 2010 3:56 am     Reply with quote

Ok I found a code for this operation but I couldn't understand some codes as shown below;

Code:

1-#define BytePtr(var, offset) (char *)((char*)&var + offset)
------------------------------------------------------------------
2-*BytePtr(current_ccp, 2) = timer_ext_copy;
----------------------------------------------------------------------
3-g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);

---------------------------------------------------------------------------
-----------------------------------------------------------------------------
Here is my program;
Code:

#include <16F877.H>
#fuses HS,NOWDT, PUT, BROWNOUT, NOLVP // 20 MHz xtal
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#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;   
timer_ext_copy = gc_timer1_extension;
if(TMR1IF)
  {
   if(*BytePtr(current_ccp, 1) < 2) 
      timer_ext_copy++;     
      gc_timer1_extension++;
      TMR1IF = 0;   
  }

*BytePtr(current_ccp, 2) = timer_ext_copy;
g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);
old_ccp = current_ccp;
}
//=======================
void main()
{
float frequency;
int32 current_ccp_delta;

set_timer1(0);           
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);   
setup_ccp1(CCP_CAPTURE_RE);   
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);

while(1)
  {
   if(gc_capture_flag == TRUE)
     {
      disable_interrupts(GLOBAL);
      current_ccp_delta = g32_ccp_delta;;
      enable_interrupts(GLOBAL);
      frequency =  (5000000L / (float)current_ccp_delta);
      printf("%4.2f\n\r", frequency);
      gc_capture_flag = FALSE;
     }
  }
}

Thanks for considering...
lopb



Joined: 09 Dec 2010
Posts: 6

View user's profile Send private message

PostPosted: Thu Dec 09, 2010 9:26 am     Reply with quote

Hi, I'm using this code in a 18f452 and measures 30hz instead the real which is 50hz, can you help me?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Dec 09, 2010 2:09 pm     Reply with quote

The code by Theasus is weird, because he's using a 16F877 but the
register address of PIR1 is for an 18F PIC. That won't work.

Then in your code, you claim to be using an 18F452, but you still quote
code with a 16F877 in the #include line.

Post the true, actual code that you are testing. Also post your compiler
version. Post the high and low voltage levels of your input signal.
Look at the signal with an oscilloscope to see this.
lopb



Joined: 09 Dec 2010
Posts: 6

View user's profile Send private message

PostPosted: Mon Dec 13, 2010 9:33 am     Reply with quote

PCM programmer wrote:
The code by Theasus is weird, because he's using a 16F877 but the
register address of PIR1 is for an 18F PIC. That won't work.

Then in your code, you claim to be using an 18F452, but you still quote
code with a 16F877 in the #include line.

Post the true, actual code that you are testing. Also post your compiler
version. Post the high and low voltage levels of your input signal.
Look at the signal with an oscilloscope to see this.

Sorry, there is my code:
Code:
#if defined(__PCH__)
#include <18F452.h>
//////// Fuses: LP,XT,HS,RC,EC,EC_IO,H4,RC_IO,PROTECT,NOPROTECT,OSCSEN
//////// Fuses: NOOSCSEN,NOBROWNOUT,BROWNOUT,WDT1,WDT2,WDT4,WDT8,WDT16,WDT32
//////// Fuses: WDT64,WDT128,WDT,NOWDT,BORV20,BORV27,BORV42,BORV45,PUT,NOPUT
//////// Fuses: CCP2C1,CCP2B3,NOSTVREN,STVREN,NODEBUG,DEBUG,NOLVP,LVP,WRT
//////// Fuses: NOWRT,NOWRTD,WRTD,NOWRTB,WRTB,WRTC,NOWRTC,CPD,NOCPD,CPB
//////// Fuses: NOCPB,EBTR,NOEBTR,EBTRB,NOEBTRB
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOOSCSEN
#FUSES NOPUT
#FUSES CCP2C1
#FUSES NOSTVREN
#FUSES NODEBUG
#FUSES NOWRTD
#FUSES NOWRTB
#FUSES NOWRTC
#FUSES NOCPB
#FUSES NOEBTR
#FUSES NOEBTRB

#use delay(clock = 20000000)
#use rs232 (baud=9600,parity=N,xmit=PIN_B2,rcv=PIN_B1,bits=8)

#priority CCP1, TIMER1

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

#byte PIR1 = 0x0C
#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()
{
float 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)
 {
  if(gc_capture_flag == TRUE)
     {
      disable_interrupts(GLOBAL);
      current_ccp_delta = g32_ccp_delta;;
      enable_interrupts(GLOBAL);

      frequency =  (5000000L / (float)current_ccp_delta);
      printf("%4.2f\n\r", frequency);

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

  delay_ms(500);
 }

}

I'm relatively new on this, can you tell me what should I change in this code written for 16f877 on 18f452?
Right now only says no frequency, and the loop is not working, it says none signal only once.

Thanks
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Dec 13, 2010 2:15 pm     Reply with quote

Right, but I also asked for your compiler version. If you want me to test
it, I need to install your exact version.
lopb



Joined: 09 Dec 2010
Posts: 6

View user's profile Send private message

PostPosted: Tue Dec 14, 2010 2:55 pm     Reply with quote

PCM programmer wrote:
Right, but I also asked for your compiler version. If you want me to test
it, I need to install your exact version.

OK, thank you.
My compiler version is 4.104
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Dec 14, 2010 3:25 pm     Reply with quote

That code seems to have problems. I don't want to trouble-shoot it.
Use the following code instead. I ran it just now on a 18F452 on a
PicDem2-Plus board, with a B&K Function Generator putting out a 239 Hz
0v to 5v square wave (50% duty cycle), and I got this output in a
TeraTerm window:
Quote:

239 Hz
239 Hz
239 Hz
239 Hz
239 Hz
239 Hz
239 Hz
239 Hz
239 Hz
239 Hz

I tested it with CCS versions 4.104 and 4.114 and it works with both.
Code:

#include <18F452.h>
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock = 20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

int16 isr_ccp_delta;

#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

current_ccp = CCP_1;   

isr_ccp_delta = current_ccp - old_ccp;

old_ccp = current_ccp;
}


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

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

clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);

while(1)
  {
   disable_interrupts(GLOBAL);
   current_ccp_delta = isr_ccp_delta;
   enable_interrupts(GLOBAL);
   
   frequency = (int16)(5000000L / current_ccp_delta);

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

   delay_ms(500);
  }

}
lopb



Joined: 09 Dec 2010
Posts: 6

View user's profile Send private message

PostPosted: Wed Dec 15, 2010 7:22 am     Reply with quote

Is not working PCM
Your code is more clean than the other.

i have a rectified signal from the 50hz of my line (just the positive cycle) with a diode and a zener, this singal is very clear i believe.

The signal must be right, because it was showing 50hz in the 16f877.

i'm getting a constant of 3528hz
Any idea?

thanks again
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Dec 15, 2010 1:03 pm     Reply with quote

To reduce the lower limit on the frequency range, for the tachometer
program, you can increase the pre-scaler on Timer1. Edit the line in
bold below, and change it to a divisor of 8:
Quote:

void main()
{
int16 current_ccp_delta;
int16 frequency;

set_timer1(0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
setup_ccp1(CCP_CAPTURE_RE);


Then adjust the frequency equation. Also divide it by 8, as shown in
bold below:
Quote:
while(1)
{
disable_interrupts(GLOBAL);
current_ccp_delta = isr_ccp_delta;
enable_interrupts(GLOBAL);

frequency = (int16)((5000000L/8) / current_ccp_delta);

Then the program should work down to approximately 9 Hz.
lopb



Joined: 09 Dec 2010
Posts: 6

View user's profile Send private message

PostPosted: Thu Dec 16, 2010 8:43 am     Reply with quote

Thank you PCM, it is working now.
lopb



Joined: 09 Dec 2010
Posts: 6

View user's profile Send private message

PCM i was wondering if u have time to check this.
PostPosted: Thu Dec 16, 2010 3:16 pm     Reply with quote

PCM, I should solve this problem. But, I think you are faster than me. If you can, take a look to this: http://dpaste.org/LHoZ/ I am using your code inside a more large program. The problem is that I'm not getting the frequency.
Anyway, if you can, otherwise I will keep working on it.
Thanks again man.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Dec 16, 2010 3:34 pm     Reply with quote

You have too much code. I don't really want to look at a lot of code.

However, here is a suggestion. Give the INT_CCP1 interrupt the highest
priority. It may help. Add the statement shown in bold below:
Quote:
#include <18F452.h>
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=20000000)

#priority CCP1, TIMER2, RB // Set interrupt priority
MAKInnovation



Joined: 16 Nov 2010
Posts: 61

View user's profile Send private message

PostPosted: Thu Dec 30, 2010 1:12 am     Reply with quote

how can we print int32 with printf command
& can we get frequency upto 1MHz with this code
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 1, 2  Next
Page 1 of 2

 
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