Frequency measurement using pic

Status
Not open for further replies.

hemnath

Advanced Member level 3
Joined
Jun 24, 2012
Messages
702
Helped
61
Reputation
120
Reaction score
57
Trophy points
1,308
Location
Chennai
Activity points
6,589
I'm trying to measure the frequency and display the value in the LCD using Capture mode. How to do that? Please explain in steps.

Thanks in advance
 


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
CCP1CON = 0X05;
T3CON = 0X00;
T1CON = 0X00;
TRISB = 0X00;
TRISD = 0X00;
TRISCbits.TRISD = 0X01;
CCPR1L = 0;
CCP1RH = 0;
 
unsigned int hbyte, lbyte;
 
void main(){
 
    while(1){
 
            TMR1H = 0;
        TMR1L = 0;
        PIR1bits.CCP1IF = 0;
        while(pir1BITS.CCP1IF == 0);
        T1CONbits.TMR1ON = 1;
        PIR1bits.CCP1IF = 0;
        while(PIR1bits.CCP1IF == 0);
        T1CONbits.TMR1ON = 0;
        lbyte = CCPR1H;
        hbyte = CCPR1H;
        //lbyte and hbyte gives the value of freq count.
    
    }
}



Convert the result to character and display on LCD.
 

I'm giving a pulse of about 12Khz square wave from function generator directly to PIN C2. But in the LCD, it displays 4920 hz.
Please check whats wrong with the program?
HTML:
#include "18f2520.h"
#include "f2420_regs.h"
#fuses INTRC
#use delay(clock=4000000)

#define RS PIN_A2
#define EN PIN_A1

void lcd_init();
void lcd_cmd(unsigned char);
void lcd_data(unsigned char);

unsigned int16 value;
unsigned int8 high_byte, low_byte;

void main()
{
lcd_init();
TRIS_C2	=	1;				//	PIN C2 configured as input for capture mode
TRISB	=	0;

CCP1CON	=	0b00000101;		//	Capture mode, every rising edge
CCPR1H	=	0;
CCPR1L	=	0;

T1CON	=	0b11001000;		//	16-Bit, 1:1 Prescale value

while(1)
{
TMR1H	=	0;
TMR1L	=	0;
CCP1IF	=	0;				//	Interrupt flag is cleared
while(CCP1IF == 0); 		//	waits till Interrupt flag gets cleared

TMR1ON	=	1;				//	Timer1 ON

CCP1IF	=	0;				//	Interrupt flag is cleared
while(CCP1IF == 0); 		//	waits till Interrupt flag gets cleared

TMR1ON	=	0;				//	Timer1 OFF

low_byte = CCPR1L;
high_byte = CCPR1H;

value   =   ((high_byte * 256) + low_byte)*60;

CCP1IE	=	0;
CCP1IF	=	0;
lcd_cmd(0x01);
lcd_cmd(0x80);
printf(lcd_data,"%lu HZ",value);
delay_ms(1000);
}
}

void lcd_init()
{
lcd_cmd(0x30);      // Configure the LCD in 8-bit mode, 1 line and 5x7 font
//lcd_cmd(0x28);
lcd_cmd(0x0c);      // display on and cursor off
lcd_cmd(0x01);      // clear display screen
lcd_cmd(0x06);      // increment cursor
lcd_cmd(0x80);      // set cursor to 1st line
}

void lcd_cmd(unsigned char c)
{
output_b(c);
output_low(RS);
output_high(EN);
delay_ms(15);
output_low(EN);
}

void lcd_data(unsigned char z)
{
output_b(z);
output_high(RS);
output_high(EN);
delay_ms(15);
output_low(EN);
}
*/
 

Use this code.

Code C - [expand]
1
2
3
value = high_byte;
value = value << 8;
value = value | low_byte;


low_byte and high_byte are 8 bit variables and value is 16 bit variable.
 
Reactions: PA3040

    PA3040

    Points: 2
    Helpful Answer Positive Rating
still the problem remains the same. I'm not simulating in proteus. Working in real hardware only.
 

Hi,
Here Attached is the code and Proteus simulation for frequency capture. Enjoy
 

Attachments

  • CCP-Capture 18.rar
    221.9 KB · Views: 131

Could you please explain what I'm doing wrong in my program. So that i can rectify the problem.
 

I want to measure 100 Hz to 6Khz frequency and display the value in LCD. I have completed the coding by using CCP - capture mode in PIC and the program executes well but the problem is, there is an error of about +/- 10Hz difference with my actual frequency. I want to reduce the error of about +/-2Hz. Im using 4Mhz external crystal. Is it possible to achieve? or do i have to increase my crystal?
 

check weather your device is dividing clock freq by 4 (fcy/4) or not.

- - - Updated - - -

check weather your device is dividing clock freq by 4 (fcy/4) or not.
 

I'm using PIC18F2520. External crystal 4Mhz.
Formula to find frequency:

frequency = (int32)((1000000) / (current_ccp_value)); // current_ccp_value holds the timer values.
 
Reactions: PA3040

    PA3040

    Points: 2
    Helpful Answer Positive Rating
in T1CON reg.

Code:
bit 1 TMR1CS: Timer1 Clock Source Select bit
1 = External clock from pin RC0/T1OSO/T13CKI (on the rising edge)
0 = Internal clock (FOSC/4)

you have set it to 0 so it will drive by fosc/4

may be you have to multiply your answer by 4.
or have you already done this?
 

I'm using CCS c compiler.
I have declared as
HTML:
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); 		//	Timer1 internal & 1:1 Prescaler
So the compiler will takes care of those registers. Also i have written the program using registers. I have configured those registers correctly. For both the case, I got the error of about 10Hz difference with my actual frequency.
 

Hi,

It had happened with me before. Try to do it with capture Interrupt. Reading a high to next high or low to next low of the pulse. Also take care about the interrupt latency time?

Enjoy!
 
Last edited:

Hi,

It had happened with me before. Try to do it with capture Interrupt. Reading a high to next high or low to next low of the pulse. Also take care about the interrupt latency time?

Enjoy!

yes laency time,,, i completely forgot about that thing... as you are using only 4MHz so, latency may be high enough to make your calculations some what false..
 

Dear All.

What is the most suitable peripheral for frequency counter
I mean CCP or Timers ( Timer0 / Timer1 )

Sorry for comes to the middle

Thanks in advance
 

What do u mean by interrupt latency time? how to configure?
Below program works but shows error of about +/- 10Hz at 5000Hz. For lower frequency, error is about 1Hz.
Program in CCS c compiler
HTML:
#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

current_ccp = CCP_1;    // ccp_1 holds the timer values

isr_ccp_delta = current_ccp - old_ccp; // difference between 2 rising edges

old_ccp = current_ccp;
}


//=======================
void main()
{

int16 current_ccp_delta;
int16 frequency;

lcd_init();

set_timer1(0);           
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); // timer 1; prescaler 1:1
setup_ccp1(CCP_CAPTURE_RE);   // rising edge

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)((1000000) / current_ccp_delta);
   lcd_cmd(0x01);
   lcd_cmd(0x80);
   printf(lcd_data,"%lu Hz", frequency);

   delay_ms(500);
  }
}
 

Hi,
What do u mean by interrupt latency time?[/HTML]
Before Asking this question have you tried to read about Interrupt latency. In one minute i have got several links that talk about it. Have a look at the following links.
HTML:
http://www.ccsinfo.com/faq.php?page=functions_in_interrupts
HTML:
http://en.wikipedia.org/wiki/Interrupt_latency
HTML:
http://whatis.techtarget.com/definition/interrupt-latency
how to configure?[/HTML]
Have you tried to read about the CCS compiler manual? If no read this before you start working on any device. The experience guys say "Understand your compiler 1st".
 

interrupt latency time is the time, which your isr consumes, in that time, your main program stops to being executed, this is called interrupt latency, you can minimise your latency by using higher clock rate and by optimising your isr code,

try to minimize your interrupt routine,
 



Interrupt latency is defined as the time from the interrupt event (the interrupt flag bit gets set) to
the time that the instruction at address 0004h starts execution (when that interrupt is enabled).
For synchronous interrupts (typically internal), the latency is 3TCY. ( PIC 16F )
For asynchronous interrupts (typically external), such as the INT or Port RB Change Interrupt,
the interrupt latency will be 3 - 3.75TCY (instruction cycles). The exact latency depends upon
when the interrupt event occurs in relation to the instruction cycle.

Time consume by ISR is not calculated
 


ok i agree with that..
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…