Possible improvements? arduino frequency counter - Page 1
Forum section: electronics / general

author: Rerouter
author_rank: Super Contributor
timestamp: April 27, 2013, 01:13:47 pm
content: over the past few weeks while my Internets been flaky I've been working on a multipurpose little tool, though i have come across something i cant quite pin down,while feeding in an external input driver directly off a buffer (though not quite de-bounced) I'm seeing i need to add some 14.6 milliseconds to the lcd loop time for above 2Khz signals to get the correct reading, the required delay appears to be correct all the way up to 70Khz, and i cannot quite explain it. now i have removed all the code but this one function for simplicities sake and the problem remains?I am hoping its something glaring in my face that i am missing, and at the same time possible insight into ways to improve this little snippet, (possible directly writing to the LCD as opposed to the library?)As for why i am using an interrupt, its as another function measures pulse time, and hope to reuse the same pin.Code:#include <LiquidCrystal.h>// Working Valuesunsigned long duration = 0; // Time of last valid action for frequency patternsunsigned long temp = 0; // Temporariy variable for holding count for frequency measurement,unsigned long last = 0; // Used variable for holding count for frequency measurement,// Interrupt Valuesvolatile unsigned long count = 0; // Volitile variable for counting pulses for frequency measurement,// Pin Definitions#define COUNT 2 // Pin 2 - Pulse counting input// Task DefinitionsLiquidCrystal lcd(A5, A4, A3, A2, A1, A0); // defines LCD pin locations/* Setup *//*IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII*/void setup() {// Set Device I/O PinmodespinMode(COUNT, INPUT);// Initialises LCDlcd.begin(16, 2); // LCD Setuplcd.noCursor();}/*-------------------------------------------------------------------------------------------------------*/void loop() {hz();}// interupt routine for pulse countingvoid pulse() {count++; // increment count for every pulse}// for counting frequencyvoid hz() {count = 0; // Reset count for current loopduration = micros();attachInterrupt(0, pulse, RISING); // Set up interrupt for counting on input 2lcd.clear();lcd.setCursor(4,0); // set cursor to beginwhile(1) {if (micros() - duration >=1000000 ) { // 1 second gate time increased to correct for lcd loopduration = micros(); // sets duration to current time, resetting the if statementtemp = count; // sets temp to current count to avoid lcd delay variationlcd.setCursor(4,0); // sets cursor back to start positionlcd.print((count - last)); // prints frequency, (yet to work out why its doubled)lcd.print(" Hz "); // prints Hz after variable and blanking spaces to avoid a full clearlast = temp; // updates last to current count}}detachInterrupt(0); // removes the interrupt as its no longer needed}thanks for any help in advance,Ryan,

author: amspire
author_rank: Super Contributor
timestamp: April 28, 2013, 12:32:27 am
content: I haven't worked through your code, but I see you are using the LiquidCrystal routine and it is bad news when you are using interrupts. Talking to a generic LCD involves a lot of rediculously long delays well into the mS region, and the Arduino code has terrible delay routines that mess up other interrupts.I have attached a bodged version of the LiquidCrystal code that I used to solve the problem.By the way, if you want to get the best possible accuracy for frequency measurements, the method is to measure the period of a a seconds worth of input frequency cycles.So if in in 1.0000126 seconds, you measure 15,678 cycles, you calculate the frequency to be 15,678/1.0000126 = 15,678.197 Hz. If you are using a 16MHz clock, then you will always get the over 7 digits resolution regardless of frequency. With the counting cycles per second, then if you measure 50Hz, you only get resolution to 1Hz which is only +/-2% resolution which is pretty lousy.If you do not use any LCD functions at all during a measurement, you can probably use the original Arduino LCD routine and you can probably get the interrupt latency variation down to a few cycles that means you can get a 6 digit accuracy which is much more then the accuracy of the Arduino crystal oscillator.In my case, I had real time interrupts that had to be function 100% of the time, so I had to change the LCD routine.Richard

author: Rerouter
author_rank: Super Contributor
timestamp: April 28, 2013, 12:56:15 am
content: thank you very much amspirei'll give that a shot,EDIT: works beautifully, and thank you for the odd division ration for decimal points, helps out on another part of it that i hadn't even gotten around to implementing (was only ever after 1 decimal place)

author: bingo600
author_rank: Super Contributor
timestamp: April 28, 2013, 10:44:44 am
content: Have a look herehttp://www.mshopf.de/proj/avr/freq_meter.html64bit atithmetichttp://www.mshopf.de/proj/avr/uint64_ops.htmlDiscussionhttp://translate.google.com/translate?sl=de&tl=en&js=n&prev=_t&hl=en&ie=UTF-8&eotf=1&u=http%3A%2F%2Fwww.mikrocontroller.net%2Ftopic%2F186801Another 64bit implementation (can be tricky if you want the linker to overlay the routines)I just defined the assembler routines with my own name , and called those from within C , as theoverlaying was a bit messy , and drew in some other stuff. But i got it to fit in a Tiny13http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=113673/Bingo

author: Rerouter
author_rank: Super Contributor
timestamp: April 28, 2013, 11:50:04 am
content: i was only ever after 25Khz max (automotive), and i have to say while i've been starting to peer my head into the registers, i'm not that keen a programmer just yet...for now I've got that part working and successfully tested my code to 150Khz without any issues, also added a reciprocal mode based on the microseconds interrupt for sub 100Hz measurement, and moved onto some of the more boring parts of it, that becomes very task specific, (25Khz at 1Hz steps and 0-100Hz at 0.1Hz where pretty much my design requirements) but if i ever need to revamp it to do more I'll chase it up,also to any future lurkers, using micros rather than millis removed fluctuations in my measurements, and that is why i used it in my code,