|
|
View previous topic :: View next topic |
Author |
Message |
zero1581`
Joined: 11 Nov 2012 Posts: 1
|
Frequency measurement with PIC18F45k22 |
Posted: Sun Nov 11, 2012 1:09 am |
|
|
Good afternoon.
I'm new programming PIC's and I have issues measuring frequencies with my PIC.
Looking for many posts I have seen codes but no one has worked for me. I'm looking to get frequencies 0-100 Hz and if the frequency is higher it supposed to show in a lcd that the frequency is unvalid.
I'm able to show a message for the LCD but it seems that I can't get the capture mode work.
First at all, I tried to measure any frequency but I haven't been successful.
Here is a code that is around:
#include"18F45K22.h"
#include"P18F45K22.h"
#use delay(clock=4000000)
#fuses INTRC_IO, NOWDT, NOPLLEN, NOBROWNOUT
#fuses NOMCLR,NOPROTECT
// This global variable holds the time interval
// between two consecutive rising edges of the
// input signal.
int16 isr_ccp_delta;
// When a rising edge occurs on the input signal,
// the CCP1 will 'capture' the value of Timer1
// at that moment. Shortly after that, a CCP1
// interrupt is generated and the following isr
// is called. In the isr, we read the 'captured'
// value of Timer1. We then subtract from it the
// Timer1 value that we 'captured' in the previous
// interrupt. The result is the time interval
// between two rising edges of the input signal.
// This time interval is then converted to a frequency
// value by code in main().
#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
//static int16 old_ccp = 0;
// Read the 16-bit hardware CCP1 register
current_ccp = CCP_1; // From 16F877.H file
// Calculate the time interval between the
// previous rising edge of the input waveform
// and the current rising edge. Put the result
// in a global variable, which can be read by
// code in main().
isr_ccp_delta = current_ccp - old_ccp;
// Save the current ccp value for the next pass.
old_ccp = current_ccp;
}
//=======================
#define LCD_DB4 PIN_D4
#define LCD_DB5 PIN_D5
#define LCD_DB6 PIN_D6
#define LCD_DB7 PIN_D7
#define LCD_RS PIN_D2
//#define LCD_RW PIN_B2
#DEFINE LCD_E PIN_D3
#include <flex_lcd_c.h>
void main()
{
int16 current_ccp_delta;
int16 frequency;
// Setup Timer1 and CCP1 for Capture mode so that
// we can measure the input signal's frequency.
// The input signal comes from the CCP2 pin, which
// is connected to the CCP1 pin with a wire.
set_timer1(0);
//setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
//setup_timer_1(T1_INTERNAL);
setup_ccp1(CCP_CAPTURE_RE);
// Clear the CCP1 interrupt flag before we enable
// CCP1 interrupts, so that we don't get an unwanted
// immediate interrupt (which might happen).
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 = isr_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.
//frequency = (int16)(1000000L / current_ccp_delta); ( I don't know what why of this part, if they calculate the time what is equal to "current_ccp_delta")
frequency = 1 / current_ccp_delta);
printf(lcd_putc,"\f");
printf(lcd_putc, "%Lu\n\r", frequency);
delay_ms(1000);
}
}
Compiler version: 4.134
If there is a way I can get some info about the CCP module, why it is not working for me or another way to measure the frequency would be pretty nice.
Thanks in advance. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19480
|
|
Posted: Sun Nov 11, 2012 3:44 am |
|
|
Learn to use the code buttons.....
Now, everything here is potentially fine, for higher frequencies. (Except you have removed the setup_timer1 line - this is essential or nothing is going to work....). Problem is your low frequency. Think about it, the CCP, can count just 65535 transitions. It counts master clock/4, so the _lowest_ frequency that can be handled by the code as posted, is just over 15Hz (1000000/65535).
Now, on the CCP, look at the Microchip application notes. They have a superb description of the CCP and it's abilities.
So, to go down (say) to 2Hz, you could work by using a prescaler on the timer of /8.
The timer then counts 125000 cycles/second, instead of 1000000, so the calculations would need to change to suit this.
Now you ask about the division "I don't know what why of this part, if they calculate the time what is equal to "current_ccp_delta"".
The CCP, is measuring 'counts'. With the default code, assuming the timer1 setup was put back, it counts in 'millionths of a second'. Now frequency is 1/time interval. So if we had a 'time interval' of 1mSec, frequency would be 1000Hz (1/0.001). The timer is measuring in uSec (millionths of a second), so the same calculation becomes:
freq=1/(count * 0.000001)
If we multiply both sides of this equation by 'one million', we get:
freq=1000000/count
Using timer/8 (T1_DIV_BY_8), the timer then counts in 1/125000th second lumps, so the formula becomes:
frequency=125000/count
Now to go to lower frequencies, you'd have top extend the size of the timer1 counter. This can be done by using 32bit values, and INT_TIMER1 to handle the timer overflow. Do a search here in the forum. Code has been posted many times in the past.
The CCP is _designed_ to measure time intervals (and therefore by implication frequencies, since these are the reciprocals of one another), and there is no 'better way' of doing this. However at your very low frequencies, depending on the resolutions you want, you could even just sit counting loops watching for the edges. The maths and basic operation would be exactly the same.
On the 'overflow', if current_ccp_delta is less than the value needed for 100Hz, then display this.
However _beware_ your problem is at the other end. You need to consider adding code, so if the wrapped value in the 32bit timer exceeds the count in one second, an underflow is displayed. Otherwise there will be problems when the timer reaches it's 32bit overflow.
Best Wishes |
|
|
|
|
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
|