Pages: 1 2 [3] 4   Go Down
Author Topic: Measuring Pulse Width  (Read 6373 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12425
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Dubai, UAE
Offline Offline
Edison Member
*
Karma: 21
Posts: 1670
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

Quote
maybe you can post a reusable example how to do use Timer1 as counter?

Thats not out of the question, in the meantime I have been busy with having a look at this -

http://rcarduino.blogspot.com/2012/03/need-more-interrupts-to-read-more.html

Duane B

rcarduino.blogspot.com
Logged


Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12425
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well written DuaneB, bookmarked!
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Jr. Member
**
Karma: 0
Posts: 62
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@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

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12425
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


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

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Jr. Member
**
Karma: 0
Posts: 62
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@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 Offline
God Member
*****
Karma: 3
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 Offline
Jr. Member
**
Karma: 0
Posts: 62
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@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 Offline
God Member
*****
Karma: 3
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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/978230

However, 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 Offline
Jr. Member
**
Karma: 0
Posts: 62
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@ jwatte

Can I use the external counter given by the link below

https://www1.elfa.se/data1/wwwroot/assets/datasheets/ag647877.pdf

Logged

Offline Offline
God Member
*****
Karma: 3
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12425
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@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
Code:
//
//    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:
Code:
//
//    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

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Jr. Member
**
Karma: 0
Posts: 62
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@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

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12425
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


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.
Code:
//
//    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

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Jr. Member
**
Karma: 0
Posts: 62
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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


* out.png (164.63 KB, 1366x768 - viewed 36 times.)
Logged

Pages: 1 2 [3] 4   Go Up
Jump to: