View previous topic :: View next topic |
Author |
Message |
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
CCP - Problem with capture mode |
Posted: Fri Apr 12, 2013 4:26 am |
|
|
I'm trying to measure and display the frequency value in LCD. I'm using PIC18F2520. Internal oscillator 4Mhz. Frequency from function generator. I have connected output of function generator to pin C2(CCP1) of uC. Using capture mode, I'm trying to capture the signal and displaying. But in the display it shows fixed value and value is not changing in the LCD when i change the frequency in function generator.
Please help.
Code: | #include "18f2520.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);
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;
lcd_init();
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)((1000000) / current_ccp_delta);
lcd_cmd(0x01);
lcd_cmd(0x80);
printf(lcd_data,"%lu Hz", frequency);
delay_ms(500);
}
}
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);
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Apr 12, 2013 12:23 pm |
|
|
Regarding the signal on Pin C2:
Look at the signal with an oscilloscope and post the answers to
these questions:
1. Is the signal a squarewave or a rectangular waveform ?
Or, is it a sinewave or some other shape ?
2. What is the frequency of the input signal ?
3. What are the low and high level voltages of the input signal ?
For example, does the signal go from 0v to 3.3v, or 0 to 5v ?
Quote: | the display it shows fixed value and value is not changing in the LCD |
Post what you see displayed on the LCD. |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Sat Apr 13, 2013 1:48 am |
|
|
Sorry. I noticed now only, that output level from function generator was about 1V. I increased to +4.5V. Now the code works good. Thanks for the valuable information. But now I faced another problem, when i give input frequency from function generator say about 5Khz. LCD display value keeps changing. So i thought to use PLL.
I declared in the fuses line as H4 and used external crystal 4Mhz.
Now the LCD fluctuates from 5Khz to 5.025Khz.
Can i control with any methods?
code changes
Code: | #include "18f2520.h"
#fuses H4
#use delay(clock=16000000) // crystal used 4Mhz . So 4*4 = 16Mhz is this right?
|
Code: | frequency = (int16)((4000000) / current_ccp_delta); |
If the error is 1Hz, that doesn't matter. But error increases as frequency increases. Please help me how to control it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sat Apr 13, 2013 3:41 am |
|
|
You need to start by looking at your input signal.
Now, unless this is a TTL source, you have a waveform (possibly programmable in shape), which will almost certainly be going +ve and -ve of it's ground. You are then feeding this into a logic input, with clamp diodes, which stop the -ve excursions going more than about 0.6v below ground, and the remainder of the waveform then goes +ve of ground. The logic input detects 'high' at a particular voltage about ground. So unless everything is very stable indeed, there will be variation with this point, and the signal coming in.
To feed an AC signal like this into the processor, you really need to probably clamp the incoming to half the supply rail, and process it with something like a zero crossing detector and comparator to give a a nice logic square wave to feed the PIC.
You need to get this done first.
Then look at smoothing the count result.
Best Wishes |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat Apr 13, 2013 4:41 am |
|
|
OK.
Have a play at being computer.
When your input frequency is 5kHz, the period is 200us.
With your original 4MHz clock that's 200 counts.
Suppose the real period was 199.5us:-
1) Your count would be 200 one time. Displays 1e6/200 -> 5.000kHz
2) Your count would be 199 next time. Displays 1e6/199 -> 5.025kHz
Your display is doing exactly as what you're telling it.
Your method for calculating frequency is great for low frequencies, & falls over for higher ones.
So, you need to either:-
a) Modify your present method to deal with higher frequencies
OR
b) Use a different approach for higher frequencies.
BUT first, do as Ttelmah suggests and clean up your input signal.
Mike |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Sat Apr 13, 2013 5:39 am |
|
|
Thanks Ttelmah for the information. Now i'm giving input to PIN C2 from Pulse generating circuit which will be clean 5V and 0V. There will no negative pulse. I did everything whatever you said.
But still the problem remains the same. Do i have to change anything in the program?
I have one doubt. Please clarify me. If i use PLL, my program instructions will be executing fast right?
say #fuses H4 . and crystal 4Mhz. So the frequency could be 16Mhz? is it right?
Also i have did in my program
Code: | frequency = (int16)((4000000) / current_ccp_delta); |
like that, instead of
Code: | frequency = (int16)((1000000) / current_ccp_delta); |
Thanks in advance. Please help. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat Apr 13, 2013 6:12 am |
|
|
Quote: | But still the problem remains the same. do i have to change anything in the program?
|
Please clarify, what reading(s) do you get for:-
1) 4MHz crystal, #fuses HS, formula used for frequency, 5kHz applied to pin C2.
2) 4MHz crystal, #fuses H4, formula used for frequency, 5kHz applied to pin C2.
Have you had a play at being computer?
When you do, you may then understand what the fundamental problem is.
Mike |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Tue Apr 16, 2013 2:44 am |
|
|
Sorry for the late reply.
I have measured the frequency.
With crystal 4Mhz and for #fuses XT and 5Khz from function generator.
LCD display 5000 Hz and sometimes 5025 Hz. When i increase the frequency little higher, say about 5002 Hz, LCD still displays 5000 Hz and 5025 Hz. It seems that LCD counts every 25 Hz as stated in below post
Quote: |
1) Your count would be 200 one time. Displays 1e6/200 -> 5.000kHz
2) Your count would be 199 next time. Displays 1e6/199 -> 5.025kHz |
Please help me how can i display with fine resolution? I want to display every 1 hz. If i keep the frequency 5001 Hz, LCD should display 5001 Hz. Is it possible to achieve? What changes i have to do? Please help.
Thanks in advance |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Apr 16, 2013 3:33 am |
|
|
I thought I'd explained in my previous post.
You're trying to measure ~5000Hz frequency to one part in 5000.
That's 0.02%.
You're doing it by measuring period to 1 part in 200.
That's 0.5%.
The LCD is displaying what you're telling it to do!
So like I said before either:-
a) Modify your present method to deal with higher frequencies
OR
b) Use a different approach for higher frequencies.
You can do (a) by measuring several periods, then take average.
You do (b) by measuring frequency (i.e. No of cycles in 1s) directly.
It's been done loads of times here on the forum.
Do a search.
I know I've covered it myself at least once.
Mike |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Tue Apr 16, 2013 3:53 am |
|
|
How can i modify or to use different approach?
I'm totally clueless. Can you please change my above code to error of 1HZ? So that i ll learn from it.
Do i have to change the crystal frequency to minimize the error?
Can you please direct me to those links?
Thank you . |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Apr 16, 2013 4:38 am |
|
|
hemnath wrote: | I'm totally clueless...
| Yes . I have to agree.
No, seriously here are two links
http://www.ccsinfo.com/forum/viewtopic.php?t=47653&start=0
http://www.ccsinfo.com/forum/viewtopic.php?t=47375&start=15
To get good resolution @ ~5kHz with 1s update you can modify.
In other words measure the average period of ~5000 cycles.
With your 1MHz instruction rate, you'll then be measuring ~1s worth of complete cycles to within 1us.
That's 0.0001%.
Should be more than good enough.
Another way of thinking of it, is to measure the number of cycles in ~1s, taking care to start and stop on one edge of your input signal.
Mike
EDIT
Going to a higher frequency crystal will improve resolution in direct proportion to frequency |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Tue Apr 16, 2013 4:58 am |
|
|
Thank you. I ll look into those links.
Quote: | Going to a higher frequency crystal will improve resolution in direct proportion to frequency |
I prefer to increase my crystal frequency to increase more resolution. But what frequency formula should i use?
Please help me how to calculate with 20Mhz crystal?
This is the code im using right now,
Code: | #include "18f2520.h"
#fuses XT
#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);
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;
lcd_init();
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)((1000000) / current_ccp_delta);
lcd_cmd(0x01);
lcd_cmd(0x80);
printf(lcd_data,"%lu Hz", frequency);
delay_ms(500);
}
}
void lcd_init()
{
lcd_cmd(0x30); // Configure the LCD in 8-bit mode, 1 line and 5x7 font
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);
} |
What changes i have to do in the program? |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Apr 16, 2013 5:29 am |
|
|
To calculate for 20MHz crystal you simply change these lines in your code
Code: | #use delay(clock=4000000) | And Code: | frequency = (int16)((1000000) / current_ccp_delta); |
BUT. Doesn't achieve what you want!
It's simple maths. Assuming your input signal is 5kHz:-
20MHz crystal -> 5MHz instuction cycles. Thats 200ns per instruction.
You're measuring 200us period as 1000 off 200ns intervals. That's 0.1%
You claim to want 5000Hz +/-1Hz. That's 0.02%
You're still out by a factor of 5. At this rate you need 100MHz crystal!
I've already outlined how to get 0.0001% with your existing 4MHz crystal.
What more do you want?
Mike |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Wed Apr 17, 2013 6:03 am |
|
|
Thank you very much.
It took some time for me to understand why you have mentioned 100Mhz crystal.
If possible, Can you please explain with small example program with 0.0001% with my existing 4Mhz external crystal?
Everything is good when i work out in theoritical. But practically, it's not attaining for me.
Please bear with my ignorance. Sorry . |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Apr 17, 2013 7:16 am |
|
|
Before we go any further please tell us:-
1) Total range over which you are trying to measure frequency.
2) Required accuracy over each range.
3) Purpose of the exercise.
What I'm trying to avoid is, showing you how to do one thing, then you coming back and saying "Oh! But I want to do this elsewhere".
i.e. moving the goal posts.
Mike |
|
|
|