/* DualFrequencyCounter */ | |
// is a bit sketchy, but seems accurate enough. | |
// Relies on | |
// - Adafruit's SPI_VFD library | |
// - one of those fancy Samsung 20x2 VFDs | |
// - and the usual digitalWriteFast lib which I know you've already got. | |
// checked with a DSO Nano oscilloscope, not that they're all that great | |
// audio should probably be buffered, limited to 0-5v | |
// and fed through a comparator before input into pin 2 and 3 | |
#include <SPI_VFD.h> | |
#include <digitalWriteFast.h> | |
#define TIMERLOAD 0 | |
#define AVGLENGTH 21 | |
#define SCREENROW0 0 | |
#define SCREENROW1 1 | |
#define CHANGERISE0 0 | |
#define CHANGERISE1 1 | |
#define CHANGEFALL0 2 | |
#define CHANGEFALL1 3 | |
SPI_VFD vfd(13, 11, 12); // init vfd: data, clock, strobe | |
volatile unsigned long lastTimeRise0, lastTimeFall0, thisTimeRise0, thisTimeFall0; | |
volatile unsigned long lastTimeRise1, lastTimeFall1, thisTimeRise1, thisTimeFall1; | |
volatile unsigned long int timerOverflowCount = 0; | |
byte avgCount0, avgCount1 = 0; | |
unsigned long avgTotal0[AVGLENGTH], avgTotal1[AVGLENGTH]; | |
unsigned long pulseWidthArray0[AVGLENGTH], pulseWidthArray1[AVGLENGTH]; | |
unsigned long pulseWidthHighArray0[AVGLENGTH], pulseWidthHighArray1[AVGLENGTH]; | |
volatile byte change = 0; | |
void setup() { | |
//Serial.begin(115200); // for testing | |
// set up interrupts | |
attachInterrupt(0, changingInt0, CHANGE); | |
attachInterrupt(1, changingInt1, CHANGE); | |
// say helloooooo | |
vfd.begin(20, 2); | |
vfd.print("frequency counter"); | |
delay(1000); | |
vfd.clear(); | |
// initialize timer1 | |
noInterrupts(); // disable all interrupts | |
TCCR1A = 0; | |
TCCR1B = 0; | |
TCNT1 = TIMERLOAD; // preload timer 65536-16MHz/8/32Hz | |
TCCR1B |= (1 << CS10); // 8 prescaler CS11 // 1 prescaler CS10 | |
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt | |
interrupts(); // enable all interrupts | |
} | |
void printRow(unsigned long ticks, const byte screenRow) { | |
float hz = getHertz(ticks); | |
if(hz>0) { | |
String spacer = ""; | |
if(int(hz)==1000) { spacer=" "; } else | |
if(int(hz)<10) { spacer = " "; } else | |
if(int(hz)<100) { spacer = " "; } else | |
if(int(hz)<1000) { spacer = " "; } else | |
if(int(hz)<10000) { spacer = " "; } | |
vfd.setCursor(0, screenRow); | |
vfd.print(spacer); | |
vfd.print(hz, 2); | |
vfd.print("hz "); | |
} | |
} | |
void loop() { | |
unsigned long ticks0 = thisTimeRise0 - lastTimeRise0; | |
unsigned long ticks1 = thisTimeRise1 - lastTimeRise1; | |
unsigned long pulseHigh0 = thisTimeRise0 - thisTimeFall0; | |
unsigned long pulseHigh1 = thisTimeRise1 - thisTimeFall1; | |
unsigned long medianPulseWidthHigh; | |
// chuck out any ridiculously long or short periods | |
if (bitRead(change, CHANGERISE0)==1 && ticks0>400 && ticks0<4000000000) { | |
if(avgCount0 < AVGLENGTH) { | |
avgTotal0[avgCount0] = ticks0; // add current period onto our array for averaging | |
pulseWidthHighArray0[avgCount0] = pulseHigh0; | |
avgCount0++; | |
} else { | |
// when array full up, print median average | |
unsigned long medianTicks = median(avgCount0, avgTotal0); | |
printRow(medianTicks, SCREENROW0); | |
medianPulseWidthHigh = median(avgCount0, pulseWidthHighArray0); | |
printPulseWidth(medianPulseWidthHigh, medianTicks, SCREENROW0); | |
avgCount0 = 0; | |
} | |
change &= ~(1 << CHANGERISE0); | |
} | |
if (bitRead(change, CHANGERISE1)==1 && ticks1>400 && ticks1<4000000000) { | |
if(avgCount1 < AVGLENGTH) { | |
avgTotal1[avgCount1] = ticks1; | |
pulseWidthHighArray1[avgCount1] = pulseHigh1; | |
avgCount1++; | |
} else { | |
unsigned long medianTicks = median(avgCount1, avgTotal1); | |
printRow(medianTicks, SCREENROW1); | |
medianPulseWidthHigh = median(avgCount1, pulseWidthHighArray1); | |
printPulseWidth(medianPulseWidthHigh, medianTicks, 1); | |
avgCount1 = 0; | |
} | |
change &= ~(1 << CHANGERISE1); | |
} | |
} | |
// has to use a floating point thing as one of the operands otherwise it'll end up 1 or 0 | |
float getPulseWidth(unsigned long pulseWidthHigh, unsigned long pulseWidth) { | |
return ((double)pulseWidthHigh / pulseWidth) * 100; | |
} | |
void printPulseWidth(unsigned long pulseWidthHigh, unsigned long pulseWidth, int screenRow) { | |
vfd.setCursor(15, screenRow); | |
float pwPercent = getPulseWidth(pulseWidthHigh, pulseWidth); | |
if(pwPercent<100) { | |
vfd.print(pwPercent, 1); | |
vfd.print("%"); | |
} | |
} | |
float getHertz(unsigned long ticks) { | |
return 1/((0.0625 * ticks) / 1000000); // (x uS in a tick, * number of ticks) / microsec in a second = period | |
} | |
ISR(TIMER1_OVF_vect) { // interrupt service routine that wraps a user defined function supplied by attachInterrupt | |
timerOverflowCount++; | |
} | |
void changingInt0() { | |
if(digitalReadFast(2)) { | |
lastTimeRise0 = thisTimeRise0; | |
thisTimeRise0 = (timerOverflowCount * 65535) + TCNT1; | |
change |= 1 << CHANGERISE0; | |
} else { | |
lastTimeFall0 = thisTimeFall0; | |
thisTimeFall0 = (timerOverflowCount * 65535) + TCNT1; | |
change |= 1 << CHANGEFALL0; | |
} | |
} | |
void changingInt1() { | |
if(digitalReadFast(3)) { | |
lastTimeRise1 = thisTimeRise1; | |
thisTimeRise1 = (timerOverflowCount * 65535) + TCNT1; | |
change |= 1 << CHANGERISE1; | |
} else { | |
lastTimeFall1 = thisTimeFall1; | |
thisTimeFall1 = (timerOverflowCount * 65535) + TCNT1; | |
change |= 1 << CHANGEFALL1; | |
} | |
} | |
unsigned long int median(unsigned long int n, unsigned long int x[]) { | |
unsigned long temp; | |
int i, j; | |
// the following two loops sort the array x in ascending order | |
for(i=0; i<n-1; i++) { | |
for(j=i+1; j<n; j++) { | |
if(x[j] < x[i]) { | |
// swap elements | |
temp = x[i]; | |
x[i] = x[j]; | |
x[j] = temp; | |
} | |
} | |
} | |
if(n%2==0) { | |
// if there is an even number of elements, return mean of the two elements in the middle | |
return((x[n/2] + x[n/2 - 1]) / 2.0); | |
} else { | |
// else return the element in the middle | |
return x[n/2]; | |
} | |
} | |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Show comment Hide comment
funzyv
commented
Oct 2, 2017
hi equalizer, Looking at your code and I like lot's of it. Just few questions:
regards, Vincent |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hi equalizer,
Looking at your code and I like lot's of it. Just few questions:
regards,
Vincent