View previous topic :: View next topic |
Author |
Message |
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Reality check. |
Posted: Sun Feb 12, 2012 7:44 am |
|
|
You appear to have lifted your code straight from the CCS example set up to work with a 16F877 @ 20MHz.
I tried this simple test.
Connect T1 clock input directly to the MCU clock.
You SHOULD get EXACTLY the correct reading with no deviation.
With a 16F877 I got 20,000,002Hz.
With a 18F458 I got 20,002,246Hz.
(I don't have 18F25K22 to try.)
Food for thought.
Mike |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Sun Feb 12, 2012 7:59 am |
|
|
Non-Working ( external crystal ) code:
Code: |
#include <18f25k22.h>
#device adc=16
#FUSES HSH,NOFCMEN
#use delay(clock=64000000)
#use rs232(baud=9600, UART1)
//#define LED PIN_C3
//#define DELAY 9000
unsigned int32 frequency=0;
void main()
{
setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_128); //2.1 s overflow
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_timer_4(T4_DISABLED,0,1);
//setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
//setup_oscillator(OSC_16MHZ|OSC_NORMAL|OSC_31250|OSC_PLL_OFF);
while(1) { //*****************************************Endless Loop
delay_ms(1000);
frequency=get_timer0();
set_TIMER0(0);
printf("frequency: %Ld Hz", frequency); // Show frequency
}
}
|
Working internal 16 MHz OSC:
Code: |
#include <18f25k22.h>
#device adc=16
//#FUSES HSH,NOFCMEN
#use delay(clock=16000000)
#use rs232(baud=9600, UART1)
//#define LED PIN_C3
//#define DELAY 9000
unsigned int32 frequency=0;
void main()
{
setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_128); //2.1 s overflow
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_timer_4(T4_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
setup_oscillator(OSC_16MHZ|OSC_NORMAL|OSC_31250|OSC_PLL_OFF);
while(1) { //*****************************************Endless Loop
delay_ms(1000);
frequency=get_timer0();
set_TIMER0(0);
printf("frequency: %Ld Hz", frequency); // Show frequency
}
}
|
I have done the led test with the external 64 MHz one...is not working properly...i get like 7 seconds of light instead of 9s..
I do not have on hand a oscilloscope on hand right now but i changed about 3 different crystals..( all new ones)...no one is working...
The crystal is on pin 9 , 10 on SPDIP 28 PACKAGE. The data appear to just come at a different baud rate(Garbage).
Regarding the code with the internal clock ( 16 MHZ) is working....but have a kind of bad precision
The gate time is 1000 ms ..just like in the frequency formula..
As for the freq-meter code..I am using only TMR0 in 16 bit mode and 128 prescaler...it will overflow in 2.1 seconds..but i will never let him overflow...i read him at 1 second and then clear it...and after that i multiply the result with 128..it works kind of ok...but instead of 4.155.000 HZ known frequency im getting like 4.190.0000 ...maybe from the drift of the internal OSC...I know for sure that the timer wont overflow because my frequency that I`m measuring never step any more than 6 MHZ
Last edited by maria100 on Sun Feb 12, 2012 8:15 am; edited 3 times in total |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Sun Feb 12, 2012 8:02 am |
|
|
I'll try the new test, thanks for help Mike but I don't know it will work...if even the led is not blinking properly. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Testing, testing, testing |
Posted: Sun Feb 12, 2012 11:23 am |
|
|
I can't check your code because I don't have 18F25k22's
When you use the internal clock, the data sheet tells you to expect errors of around 1%, plus loads of drift with temperature and time. 1% error equates to 40kHz, i.e. more than the difference between your reference frequency and the measured value. Asmboy told you about prescalers. With a 128 prescaler, you can't hope to get 100Hz resolution.
The system based on the CCS sample is your best offering so far. As it stands the code is good up to Giga Hz (maybe Tera Hz) without overflow problems.
This is basically how it operates:-
(1) The input frequency source is connected to T1 external clock input.
(2) T1 clock and the freqc_high are set to zero.
(3) T1 is enabled to count for one second, (the gating period).
(4) The gating period is determined by counting machine clock cycles very carefully.
(5) Every time the T1 overflows the overflow flag is reset and freqc_high is incremented.
(6) The machine clock count is adjusted to take care of the difference in execution times. (Like I said before I'm not a software expert, I have to admit I originally overlooked this bit.)
(7) At the end of the one second period the T1 contents are then merged with freqc_high (and a possible extra overflow) to give your frequency.
When I did my tests on REAL PIC's I:-
(1) Used the CCS code for a 16F877 exactly as is.
(2) Connected T1 clock input to the external clock.
(3) Got a readout of 2,000,002 Hz.
What that's telling you is that the during 5 million machine cycles T1 clocked 20,000,002 times. An error of half a machine cycle!
I then recompiled the '877 code as is for an 18F458 and got a measured frequency of 20,002,246 Hz. In other words the code is not totally portable across PICs. There's an error creeping in of around one part in 8900. Converting to a different PIC means taking the sample code apart, working out (in detail) how it functions, then modifying to suit. You may have to play at being a computer pushing numbers around to get there.
Have you actually got a crystal (or preferably a module) which works correctly as an external clock? If you have, you can use the reality check test. It doesn't matter what your real clock frequency is, you will always get the same apparent measured frequency of close to 20MHz when the system measures itself. You MUST start from KNOWN GOOD hardware, else you're wasting your time.
Mike
Last edited by Mike Walne on Sun Feb 12, 2012 11:23 am; edited 1 time in total |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Sun Feb 12, 2012 11:23 am |
|
|
Ok, I noticed something. Ttell me if I'm right. I compile the software and when I import it in the PICKIT2 software...on the OSCCAL LINE..it does not say anything. Is possible that CCS do not export the fuses too? |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
PICKIT2 |
Posted: Sun Feb 12, 2012 11:26 am |
|
|
Sorry, can't help you. I don't have any version of PICKIT. I use MPLAB ICD2.
Mike |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Sun Feb 12, 2012 11:34 am |
|
|
The main problem with the source code offered by CCS is that the controller can't do anything beside measure a frequency because it will "waste" a second. I need a way that I will read the timer and go along with my code (receiving serial data). Is that possible? |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Other methods |
Posted: Sun Feb 12, 2012 12:27 pm |
|
|
Yes, of course you can.
I did not get that impression from your latest codings.
You see code of the delay_ms(xx) variety also ties up the PIC completely.
Some methods spring to mind.
(1) Polling.
(2) Interrupts.
(3) Hybrid of (1) & (2)
Polling.
In polling you perform ALL of your tasks in turn. Each task is designed to take a specific number of machine cycles. Each task must take the same number of cycles which ever code path it follows. For example the UART takes the same time whether there is anything to transmit/receive or not. The different tasks can have different allocated times.
Interrupts.
Make your tasks interrupt flag driven. Eases your timing problems, but they don't totally go away.
Hybrid.
Use a hardware clock to drive the polling timing, i.e. make each task give up after a fixed time. (Sort of multi-tasking approach.)
Which ever route you choose you will need to become familiar with watching your timings to the nearest cycle or so.
Good luck.
Mike |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
One solution |
Posted: Sun Feb 12, 2012 3:59 pm |
|
|
OK. I've had time to think about it.
I'd use interrupts.
Assuming the PIC processor has priority interrupts.
For the frequency measurment gate timing I'd use high priority, everything else low.
Even if say a UART or ADC are being serviced, the high priority request will be dealt with promptly.
Then there are two major tasks to consider amongst others:-
(1) Creating the timing gate.
(2) Handling primary pulse counter overflow.
I'd use timer2 to create gate period. I find it's easiest for timer2 to generate non-power of 2 clock periods (makes the maths simpler).
Let the primary pulse counter overflow generate an interrupt.
At the end of the gate period, the issues to decide include:-
(1) Has the gate period been extended (or curtailed) for some reason? Is the gating period being affected by other activity?
(2) Is there a genuine primary pulse counter overflow to be handled? If you're clumsy you could miss a complete 65,536 count!
(3) Do you need to allow for the time taken to get into and out of interrrupt routines? Interrupt overhead can be greater than allowed error margins.
Deal with the above and correct.
Then TEST, TEST, TEST. Envisage ALL the possible situations which can arise under ALL possible conditions. Devise tests to provoke worst case scenarios.
If you don't, Sod's law will catch you out.
Mike |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Sun Feb 12, 2012 4:37 pm |
|
|
haha..you are kind of funny..regarding the project i will do as you told, and after that i promise to post my results..thank you:) |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Interrupt driven timing gate |
Posted: Mon Feb 13, 2012 7:55 am |
|
|
The code below generates an interrupt driven 100ms gate period.
What happens is the start and stop both occur following a delay after a T2 overflow.
We don't need to know what that delay is, it does not matter as long as both are equal, hence the padding.
Code: |
/////////////////////////////////////////////////////////////////////////
//// 100ms Gate ////
/////////////////////////////////////////////////////////////////////////
// External source connected to T1 clock input
// T2 used as gate timer
// T2 timer set for /16 /250 /4 -> overflows every 4ms
// 25 overflows -> 100ms gate time
// T1 enabled when gating_count is 10 and disabled on 35 (25 later)
// Takes 3 extra cycles to reach turn off, so padded at turn on
// 16MHz clock -> 250ns instruction time
#define START 10
#define STOP 35
#include <18F458.h>
#fuses HS,NOWDT,NOLVP
#use delay(clock=16000000) //16 MHz clock, one instruction=0.25us
int gating_count; // counts T2 interrupts
void main()
{
setup_timer_2(T2_DIV_BY_16,249,4);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
gating_count = 0;
while (TRUE)
{
output_high(PIN_B1); //Twiddle thumbs here
output_low(PIN_B1); // toggle LEDs for something to do
}
}
#INT_TIMER2
void gating_isr()
{
gating_count++;
if (gating_count == START)
{
delay_cycles(3); // pads out timing difference
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
output_high(PIN_B0); // something to see on a 'scope
}
if (gating_count == STOP)
{
setup_timer_1(T1_DISABLED); //turn off counter
output_low(PIN_B0); // can see on scope
gating_count = 0; // get ready to start again
}
}
|
I checked it on my 'scope. It looks OK.
If you only have the one interrupt you don't have to worry about contention issues.
What you now have to do is get everything else into main() loop as a polling system.
The only timing constraint for the frequency measurement is that the loop goes round fast enough not to miss a T1 overflow.
Should be doable as you've got >16,000 machine cycles to play with. RS232 at 9,600 gives you ~4,000 cycles between characters.
I think I've done enough for you.
Good luck with the rest.
Mike |
|
|
Jhonny
Joined: 30 Jan 2011 Posts: 16
|
|
Posted: Sun May 26, 2013 3:19 am |
|
|
I would like to ask for help:
I use the word "EX_FREQ.C" code, but the sampling period of 1 second too long. What do you have to change to 1ms, 10ms and 100ms time be?
Possibly can be selection use the a constant to be switched to sampling time?
Thank you very much if someone would write a piece of code! (I use PIC16F886 @ 20MHz crystal) |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sun May 26, 2013 5:26 am |
|
|
Before jumping in here and asking for someone to write your code for you
how about READING the post just before yours. Mike has done most
of the work for you.
Take the time to READ and UNDERSTAND the code he has written, which is
well commented, and the answer should be fairly clear.
Changing Mike's code to any sample time is pretty straightforward if you
understand what he provided. _________________ Google and Forum Search are some of your best tools!!!! |
|
|
Jhonny
Joined: 30 Jan 2011 Posts: 16
|
|
Posted: Sun May 26, 2013 6:13 am |
|
|
Dear dyeatman!
Thanx comment, but:
1., Mike uses 16MHz, but I use 20MHz
2., As I write now, I'm just a "EX_FREQ.C" code and I want to modify. I do not want another (new) code.
The rest is all true what you wrote. (The code is hard even for me to understand because I am an absolute beginner) |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sun May 26, 2013 6:55 am |
|
|
Are you here to learn or just finish a school project assignment?
If you are here to learn you need to understand the basics about how
frequency counting works.
The code basically does two things:
1. creates a measurement period
2. counts the number of cycles that occur within the measurement period.
The number of cycles counted during the selected measurement period
and a little math gives the frequency.
Examples: multiply cycles in 100ms by 10 to get number in a second (Hz)
multiply cycles in 500ms by 2 to get number in a second (Hz)
Shorter measurement periods typically give less accuracy.
The CCS version is much harder to understand because it uses delays rather than
a defined period like Mikes does. Mikes version is much cleaner and
easier to implement. _________________ Google and Forum Search are some of your best tools!!!! |
|
|
|