Netherlands
Offline
Tesla Member
Karma: 88
Posts: 9392
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #30 on: March 24, 2012, 03:11:04 am » |
Sorry for the persistence, but why doesn't anyone ever use timer1 input capture for this type of thing ? just to give some reasons: 1) in software you can use (almost) any pin 2) there are far more SW examples how to do the counting (good bad and ugly) 3) not everyone understand in detail how to program the timers as counter ( few examples) 4) not everyone oversees the consequences of using timers - timer0 - 8 bit, used for clock - timer1 - 16 bit, free (servo lib?) - timer2 - 8 bit, free? maybe you can post a reusable example how to do use Timer1 as counter? Best I found sofar is : - http://arduino.cc/playground/Code/ReadReceiver -
|
|
|
|
« Last Edit: March 24, 2012, 03:16:53 am by robtillaart »
|
Logged
|
|
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 88
Posts: 9392
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #32 on: March 24, 2012, 11:34:19 am » |
Well written DuaneB, bookmarked!
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 62
|
 |
« Reply #33 on: March 26, 2012, 10:31:47 am » |
@Robtillaart and others
How can I improve the resolution? as I have to accurately measure the width and the counter should do more fast counting, can I use external clock of more than 16 MHz by doing prescaling? or if you can suggest some other method may be using a fast counter?
Thanks
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 88
Posts: 9392
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #34 on: March 26, 2012, 11:37:55 am » |
switch to a faster processor like the MBED of NCP its around 100Mhz so it shoulc be able to do more counts per microsecond.
Or use Timers as proposed before in this thread, I can't help you on that as I have never really dived into that matter.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 62
|
 |
« Reply #35 on: March 26, 2012, 11:45:28 am » |
@Robtillaart
I have never used MBED of NCP so can it also provide the flexibility of using the serial monitor to see the results and also what about the syntax is it similar to arduino? since arduino is very user friendly
Thanks
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 812
|
 |
« Reply #36 on: March 26, 2012, 12:37:49 pm » |
How can I improve the resolution? as I have to accurately measure the width and the counter should do more fast counting, can I use external clock of more than 16 MHz by doing prescaling? or if you can suggest some other method may be using a fast counter?
The counter1 method can run at 16 MHz. This should give you 0.0625 microsecond resolution (but not accuracy -- that is determined by the interrupt latency.) If you need better accuracy than that, then you will have to use some pretty fancy custom circuitry -- something like a gate for a clock signal that is controlled by the pulse, and an interrupt on the falling pulse edge to read the value and reset the counter. And if you need better resolution, it has to be run with a counter that can run faster than 16 Mhz, which is a pretty specialized part that you would have to hook up externally from the Arduino. I honestly don't think the MBED or LPCExpresso can do any better resolution than the Arduino. Their CPUs are faster, but they also have higher overhead in taking interrupts. At this point, it sounds like what you're asking for is something that you'd pay thousands of dollars for in terms of scientific instrumentation to get a reliable system for doing. Or, alternatively, something that you'd pay several hundreds of dollars for to get a high-bandwidth (100 MHz) digital storage oscilloscope and calculate pulse width from rise/fall edges, if it's only for diagnosis, and not an online system.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 62
|
 |
« Reply #37 on: March 26, 2012, 12:52:51 pm » |
@jwatte
Yes you picked it absolutely right and that's what even I was told earlier that may be I should use a fast external counter which can then work with arduino but unfortunately I am not finding any such fast counter, is there any external fast counter you can suggest me which I can use to get higher resolution?
Thanks again
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 812
|
 |
« Reply #38 on: March 26, 2012, 08:26:58 pm » |
Try a 4040 or similar, perhaps? 12 bits, and some implementations can run at 200 Mhz. You can daisy-chain two to get a 24 bit counter, although interfacing to the Arduino then may need multiplexing. http://search.digikey.com/us/en/products/74VHC4040MTC/74VHC4040MTC-ND/978230However, you'd need to generate that 200 MHz pulse train yourself, probably using a crystal and an amplifier/inverter circuit. Also, you'd need to wire up the right circuit to gate the counter clock while the pulse is on, and then interrupt the Arduino once the pulse completes, so you can read the value and reset the counter. Probably want to use flip/flops to lock out multiple additional triggers until the count has been reset. Finally, at 200 Mhz, the circuit board design starts mattering. You may run into signal quality issues if you're not careful. You probably want to use surface mount manufacture, and you quite likely can't build this very well on breadboard type surfaces at all.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 62
|
 |
« Reply #39 on: March 27, 2012, 03:50:41 am » |
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 812
|
 |
« Reply #40 on: March 27, 2012, 11:23:00 am » |
That's the little brother of the 4040, so the wiring and use would be pretty much the same as what I suggested. If you run it at a lower clock rate (10-20 MHz) then you could probably do it on breadboard, too.
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 88
Posts: 9392
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #41 on: March 28, 2012, 02:02:23 pm » |
@scorp84 I improved on my previous version, I rewrote the counting loop from a while do into a do while. it seems to measure pulsewidths now in 5/16th (< 1/3) of a micro. Please confirm if my math / code is correct. measure the count++ loop sketch // // FILE: PulseWidthMeter.pde // AUTHOR: Rob Tillaart // DATE: 2012-mar-28 // // LINK: http://arduino.cc/forum/index.php?action=post;topic=96971.0 //
unsigned int count = 0; void setup() { Serial.begin(9600); Serial.println("pulse width meter 0.1");
pinMode(3, INPUT); }
void loop() { count = 0; while ((PIND & B00001000) == B00000000); // wait for HIGH unsigned long start = micros(); [color=red] do count++; while (PIND & B00001000); // start counting until LOW[/color] unsigned long stop = micros();
Serial.print("CNT: "); Serial.println(count, DEC); Serial.print(stop-start, DEC); Serial.println(" microseconds "); Serial.print((1.0*count)/(stop-start), 3); Serial.println(" count per microseconds ");
delay(1000); } Output: CNT: 9264 2916 microseconds 3.177 count per microseconds CNT: 27698 8712 microseconds 3.179 count per microseconds CNT: 22776 7164 microseconds 3.179 count per microseconds CNT: 11891 3744 microseconds 3.176 count per microseconds CNT: 9634 3032 microseconds 3.177 count per microseconds
results in ~3.178 counts per usec. => 1/3.178 = 0.3147 uSec/count this implies 0.3147 x 16 = 5.035 => 5 instructions per loop instead of 6 in the previous version. The 0.035 indicates a 0.7% error margin which is not too bad (probable causes the rounding of micros() 0.1-0.2% + crystal inaccuracy?). [please confirm these measurements & math] This results in a new 0.3 version of the pulseWidthMeter sketch: // // FILE: PulseWidthMeter.pde // AUTHOR: Rob Tillaart // DATE: 2012-mar-28 // // LINK: http://arduino.cc/forum/index.php?action=post;topic=96971.0 //
unsigned int count = 0; void setup() { Serial.begin(9600); Serial.println("pulse width meter 0.3");
pinMode(3, INPUT); }
void loop() { count = 0; while ((PIND & B00001000) == B00000000); // wait for HIGH do count++; while (PIND & B00001000); // start counting until LOW
float usec = 1.0 * count * 5/16; Serial.print("CNT: "); Serial.println(count, DEC); Serial.print(" equals "); Serial.print(usec, 2); Serial.println(" microseconds.");
delay(1000); }
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 62
|
 |
« Reply #42 on: March 28, 2012, 02:08:02 pm » |
@Robtillaart
Thanks alot and actually I am back to my room and I would check it now tomorrow and then would confirm you, thanks again
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 88
Posts: 9392
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #43 on: March 30, 2012, 02:52:33 pm » |
This is my new version, now using Timer1 to count 1/16 microseconds. As timer1 is a 16bit timer it counts to 65535 before it overflows so it can do 4096 usec max. That would suit your needs. If it overflows it calls an interrupt and in the IRQ another int is incremented. These two (Timer1 counter + IRQ counter) together make effectively a long, resulting in max time of around 4 minutes. The code is not 100% tested and does sometimes strange - especially first pulse - but the results are promissing. I have to "fiddle" which settings must be between the two while loops, and which can be before the first one. Give it a try. // // FILE: PulseWidthMeter.pde // AUTHOR: Rob Tillaart // DATE: 2012-mar-28 // // LINK: http://arduino.cc/forum/index.php?action=post;topic=96971.0 //
#include <avr/io.h> #include <avr/interrupt.h>
volatile unsigned int cnt = 0;
void setup() { Serial.begin(38400); Serial.println("PulseWidthMeter (timer1) 0.1"); pinMode(3, INPUT); }
void loop() { // initialize Timer1 cli(); // reset counters cnt = 0; TCNT1 = 0; // reset registers TCCR1A = 0; TCCR1B = 0;
// wait for HIGH while ((PIND & B00001000) == B00000000);
// enable Timer1 overflow interrupt: TIMSK1 = (1 << TOIE1); // Set CS10 bit so timer runs at clock speed: 16 MHz TCCR1B |= (1 << CS10); // enable global interrupts: sei();
// keep counting until LOW while ((PIND & B00001000) == B00001000); // stop IRQ's cli();
// Read the counters and convert to long unsigned int x = TCNT1; // work copy unsigned long total = cnt * 65535L + x; float usec = (1.0 * total) / 16;
// Display values Serial.print(total, DEC); Serial.print(" \t "); Serial.println(usec, 1);
// Wait a while delay(1000); }
// count the overflows in IRQ ISR(TIMER1_OVF_vect) { cnt++; }
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 62
|
 |
« Reply #44 on: March 31, 2012, 08:49:11 am » |
Attached is the output of the image for pulses from 1 to 10 microsecond I applied 1 microsecond pulse width and then changed it into steps upto 10 microsecond
|
|
|
|
|
Logged
|
|
|
|
|
|