Go Down

### Topic: Measuring the Frequency of a TTL circuit (Read 9548 times)previous topic - next topic

#15
##### Feb 06, 2011, 03:35 amLast Edit: Feb 07, 2011, 11:15 pm by tchadwick Reason: 1
I have re-written the code and so let me know what you think-
Code: [Select]
`#include <MsTimer2.h>// Switch on LED on pin 13 each secondint signalstate = 0;int laststate = 0;long int counter = 0;void flash() {  Serial.println(counter, DEC);  counter = 0;}void setup() {  pinMode(9, INPUT);  MsTimer2::start();}//each time through the loop it does a read on the digital port,//nothing happens till the pin goes "LOW" then each time through// it checks to see if the state has changed, if so, then and//only then does it increment the counter.void loop() {  signalstate = digitalRead(9);  if(signalstate == LOW)  {    laststate = 1;  }  if(laststate == 1 && signalstate == HIGH)  {    counter++;    laststate = 0;  }  }`

#16
##### Feb 08, 2011, 06:17 am
So I re-wrote the program again due to my class using the Arduino Mega and the Mstimer2 not working with it.  So here is the new revision, which when outputting to the screen at 1/10th of a second, is fairly accurate, but when going above that, it quickly loses accuracy, any ideas why?
Code: [Select]
`#include <SimpleTimer.h>SimpleTimer timer;int signalstate = 0;int laststate = 0;long int counter = 0;long int screen = 0;void repeatMe() {  long int tempequ = ((counter / 5) * 6);  screen = tempequ;  Serial.println(screen, DEC);  counter = 0;} void setup() {  pinMode(9, INPUT);  Serial.begin(9600);  timer.setInterval(100, repeatMe);}//each time through the loop it does a read on the digital port,//nothing happens till the pin goes "LOW" then each time through// it checks to see if the state has changed, if so, then and//only then does it increment the counter.void loop() {  timer.run();  signalstate = digitalRead(9);  if(signalstate == LOW)  {    laststate = 1;  }  if(laststate == 1 && signalstate == HIGH)  {    counter++;    laststate = 0;  }  }`

#17
##### Feb 08, 2011, 07:11 am
Quote
1/10th of a second, is fairly accurate, but when going above that, it quickly loses accuracy, any ideas why?

By that do you mean of the timer has a lower value and is therefore triggered at a faster rate?

If so it's possible that all the overhead in the code and the Serial.print becomes more significant at shorter periods. Try upping the bit rate to 115200 and see if that makes a difference.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

#### AltairLabs

#18
##### Feb 08, 2011, 08:14 am
Here is freq counter we use for DCDW, its speed is determined by the incoming freq and the number of digits of precision you specify.  It also has code to reject noisy signals.  Probably slower than you want and too many features, but you might find the autoscaling approach useful.  There is a fundamental limit on precision vs measurement rate and this is one way to approach it.

Code: [Select]
`long countFrequency (int pin, int precision)  {// counts frequency of an incoming pulse train// this code is licensed under Creative Commons Attribution-ShareAlike//// pin              any digital input pin (int)// precision        number of significant digits, 2, 3 or 4 (int)// returns:         frequency in Hz (long)//// written for Dirt Cheep Dumb Wireless sensor telemetry boards// using OOK radio links (SparkFun etc) which output noise on no RF in// so this looks for consistent pulse width as criterion against noise// returns negative numbers for all errors such as noise//  int pulses;                   // total number of pulses to time   int pulse;                    // pulse count  unsigned long timeout= 10000; // microsecs for pulseIn() to wait before giving up  unsigned long t0;             // start time hack  unsigned long time;           // delay in millisec  unsigned long needTime = 1;   // delay needed for precision in millisec  unsigned long duration;       // length of one pulse   unsigned long totDuration;    // total duration of first ten pulses   unsigned long minDuration;    // minimum length of a valid pulse   unsigned long maxDuration;    // maximum length of a valid pulse   constrain (precision, 1, 5);                 // keepin it sane  for (int i = 1; i < precision; i++) {    needTime = needTime * 10;  }  // millisecs of tone count needed to get desired precision  long DCDWfrequency = 0;                      // nothin' yet  totDuration = 0;                             // clear this to start  for(pulse = 0; pulse < 10; pulse += 1)       // count 10 incoming pulses   {                                       duration = pulseIn(pin, LOW, timeout);     // wait for one complete pulse cycle    if (duration == 0) {      return -(long)pulse;    }  // if pulse timout then abort, return neg of bad pulse    totDuration += duration;  }   maxDuration = totDuration / 7;  minDuration = totDuration / 14;  // now we have a range of average pulse durations  // so start counting 'pulses' pulses, increasing 'pulses' by 10x each time  // until a string of pulses meets the minimum total time for accuracy  for (pulses = 10; pulses < 100000; pulses = pulses * 10)  {    DCDWfrequency = 0;                           // nothin' yet    t0 = millis();                               // start time    for(pulse = 0; pulse < pulses; pulse += 1)   // count incoming pulses     {                                         duration = pulseIn(pin, LOW, timeout);     // wait for one complete pulse cycle      if (duration == 0) {        return -(long)pulse;      }    // pulse timout: abort, return neg of bad pulse      if (duration > maxDuration)                  // pulse too long: abort, return error code      {        return -(long)duration;      }      if (duration < minDuration)       {        return -(long)duration;      }    }     time = millis()-t0;                          // got all pulses, so time = now - start    if (time > needTime)                              // if time is enough for precision we are done    {      if (debug)      {        Serial.print(precision);          Serial.print(" digits ");          Serial.print(needTime);          Serial.println(" ms need:   ");          Serial.print(pulses);          Serial.print(" pulses = ");          Serial.print(time);          Serial.println(" millisecs ");        }      DCDWfrequency = 1000 * (unsigned long)pulses / time;  // frequency in Hz      return (long)DCDWfrequency;     }  }  return -9999;}  `

#19
##### Feb 25, 2011, 12:29 amLast Edit: Feb 25, 2011, 04:14 am by tchadwick Reason: 1
Thank you for your post, and we will probably give it a try if we can't get the freqcounter.h library to work, which is currently having problems, because it won't work with the arduino mega 2560.  (Keeps saying sbi and cbi are not defined, which I don't understand)   I'm pulling most of what I'm doing from this forum: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231326297/15
Anyone with ideas on how to fix the freqcounter.h for the mega 2560, that would be amazing!  I've tried entering the 2560 to the #define section, but no luck.  Please help!  Thanks ahead of time!

#### retrolefty

#20
##### Feb 25, 2011, 12:46 am

Here is freq counter we use for DCDW, its speed is determined by the incoming freq and the number of digits of precision you specify.  It also has code to reject noisy signals.  Probably slower than you want and too many features, but you might find the autoscaling approach useful.  There is a fundamental limit on precision vs measurement rate and this is one way to approach it.

That code looks interesting but it's not Arduino ready is it, no setup, loop, Serial.begin(), etc.

I tried adding stuff to try and run it, but gave up after two or three fixes. Compilers are so finicky.

Lefty

#21
##### Feb 25, 2011, 04:17 am
Also, does anyone know off the top of their head, what the precision and maximum measurable frequency is for the Arduino? (using freqCounter.h)
Thanks again for all the great posts, keep them coming!  (Oh after we finish this project, I plan on posting everything learned for others so they don't have to struggle like we are!  )

#22
##### Feb 25, 2011, 04:55 amLast Edit: Feb 25, 2011, 05:02 am by Graynomad Reason: 1
Quote
(Keeps saying sbi and cbi are not defined, which I don't understand)

That can be fixed with a define or or some inline assembler. SBI/CBI are single assembler instructions, I didn't look at the code but you can replace all occurances that are giving you trouble with

asm ("sbi");

and

asm ("cbi");

EDIT: Are we talking about the code a couple of posts up? There is no tCBI/SBI in that.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

#23
##### Mar 01, 2011, 06:19 am
No the code above was a sample attempt at programming, however, we have finally achieved success! (With getting RPM)  Using the extra Interrupt on the Arduino Mega, it was much easier.
So the way it works is by attaching the encoder's output (either A or B or the Index) to pin 18, then attaching the interrupt to interrupt 5
which is only triggered when pin 18 goes from low to high.
It then calls the incrementit function that does just that, increments the counter.
Then after 10, or 100 ms the count is tallied.
(Thus far tested to 17Khz or 1900+ RPM)
Code: [Select]
`#include <MsTimer2.h>#include <LiquidCrystal.h>LiquidCrystal lcd(52, 50, 48, 46, 44, 42);volatile int count = 0;double out = 0.0;double motorout = 0.0;double kp = 3.0;double setpoint = 1450.0;void setup(){  lcd.begin(16, 2);  pinMode(12, OUTPUT);  Serial.begin(115200);   // start serial communication  attachInterrupt(5, incrementit, RISING);  //attaches interrupt to the mega's pin 18 (interrupt 5)  MsTimer2::set(100, flash); // 100ms period  MsTimer2::start();}void loop(){ //  out = (1450 - out);//  lcd.print(out);//  delay(500);//  lcd.clear();}void incrementit(){  count++;}void flash() {  lcd.clear();  out = count;  out = (setpoint - out);  lcd.print(out);    motorout = (setpoint+kp*out)*(5735.0/10000.0) - 661;  motorout = constrain(motorout, 0, 255);  Serial.println(motorout,DEC);  analogWrite(12, motorout);  //Serial.println(count,DEC);  count = 0;}`

Go Up

Please enter a valid email to subscribe