Hi
- You are looking for a frequency counter (1Hz-3MHz) that can also display period time?
The code does NOT require a special library. The variable names for the HW setup can be found in the ATmega datasheet.
/* Frequency Counter With LCD Display - by arduinoaleman - May 2015
For analog signals have a look at my preamplifier circuit (arduino forum / look for "frequency counter amplifier"
Pin D5 of Arduino must be used for frequency input. The LCD uses pins 8 thru 13.
Counter1 : 16 bits / used to count the frequency impules
Counter2 : 8 bits / used to genarate a 1000ms or 100ms gate time for measurement
I use "bitClear(TIMSK0,TOIEO)" instead of "TIMSK0 &=~(1<<TOIE0)"
I use "bitSet(TIMSK0,TOIEO)" instead of "TIMSK0 |=~(1<<TOIE0)"
The serial monitor will also show some (unformatted) results.
*/
#include <avr/interrupt.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,10,11,12,13);
volatile unsigned long frequency=0;
volatile boolean measurement_ready;
volatile unsigned char overflow_counter; // number of overflows within gate_time
volatile unsigned int time_so_far; // number of ISR calls
volatile unsigned int gate_time;
void measurement(int ms) {
bitClear(TIMSK0,TOIE0); // disable counter0 in order to disable millis() and delay()
// this will prevent extra interrupts that disturb the measurement
delayMicroseconds(66); // wait for other interrupts to finish
gate_time=ms; // usually 1000 (ms)
// setup of counter 1 which will be used for counting the signal impulses
TCCR1A=0; // reset timer/counter1 control register A
TCCR1B=0; // reset timer/counter1 control register B
TCCR2A=0; // reset timer/counter1 control register A
TCCR2B=0; // reset timer/counter2 control register A
// setup of counter2 which will be used to create an interrupt every millisecond (used for gate time)
TCCR2B |= B00000101; // set prescale factor of counter2 to 128 (16MHz/128 = 125000Hz)
// by setting CS22=1, CS21=0, CS20=1
bitSet(TCCR2A,WGM21) ; // set counter2 to CTC mode
// WGM22=0, WGM21=1, WGM20=0
OCR2A = 124; // CTC divider will divide 125Kz by 125
measurement_ready=0; // reset
time_so_far=0; // reset
bitSet(GTCCR,PSRASY); // reset the prescaler
TCNT1=0; // set frequency counter1 to 0
TCNT2=0; // set gate time counter2 to 0
bitSet(TIMSK2,OCIE2A); // enable counter2 interrupts
TCCR1B |= B00000111; // set CS12, CS11 and CS10 to "1" which starts counting
// on T1 pin (Arduino pin D5)
}
ISR(TIMER2_COMPA_vect) {
if (time_so_far >= gate_time) { // end of gate time, measurement is ready
TCCR1B &= B11111000; // stop counter1 by setting CS12, CS11 and CS10 to "0"
bitClear(TIMSK2,OCIE2A); // disable counter2 interrupts
bitSet(TIMSK0,TOIE0); // enable Timer0 again // millis and delay
measurement_ready=true; // set global flag for end count period
// calculate now frequeny value
frequency=0x10000 * overflow_counter; // mult #overflows by 65636 (0x10000)
frequency += TCNT1; // add counter1 contents for final value
overflow_counter=0; // reset overflow counter
}
else {
time_so_far++; // count number of interrupt events
if bitRead(TIFR1,TOV1) { // if Timer/Counter 1 overflow flag = "1" then ...
overflow_counter++; // increase number of counter1 overflows
bitSet(TIFR1,TOV1); // reset counter1 overflow flag
}
};
}
void setup() {
pinMode(5,INPUT);
lcd.begin(16, 2); // defines a LCD with 16 columns and 2 rows
lcd.clear();
for (int row=0; row<=1; row++) {
for (int column=0; column<=15; column++) { // LDC test
lcd.setCursor(column,row);
lcd.print("*");
delay(70);
};
}
lcd.clear();
Serial.begin(9600);
}
void loop() {
float period;
float floatfrq;
int range;
long frq;
measurement(1000); // 1000ms standard gate time
while (measurement_ready==false);
frq=frequency;
floatfrq=frq; // type conversion (required!!)
period=(1/floatfrq); // period = 1/Frequenz -
if ((frq >= 0)&& (frq < 10)) {range=0;}; // Hertz
if ((frq >= 10)&& (frq < 100)) {range=1;};
if ((frq >= 100)&& (frq < 1000)) {range=2;};
if ((frq >= 1000)&& (frq < 10000)) {range=3; floatfrq=floatfrq/1000;}; // KHz
if ((frq >= 10000)&& (frq < 100000)) {range=4; floatfrq=floatfrq/1000;};
if ((frq >= 100000)&& (frq < 1000000)) {range=5; floatfrq=floatfrq/1000;};
if (frq >= 1000000) {range=6; floatfrq=floatfrq/1000000;}; // MHz
Serial.print("Frequency (Hz): ");
Serial.print(frq);
Serial.print(" Period (sec): ");
Serial.println(period,7);
lcd.setCursor(0, 0);
lcd.print("Freq: ");
lcd.setCursor(0, 1);
lcd.print("Per.: ");
switch(range) {
case 0: // 1Hz thru 10Hz
lcd.setCursor(6, 0); lcd.print(frq);
lcd.setCursor(13,0); lcd.print("Hz ");
lcd.setCursor(6, 1); lcd.print(period,3);
lcd.setCursor(13, 1); lcd.print("s ");
break;
case 1: // 10Hz thru 100Hz
period=period*1000; // convert from seconds to ms
lcd.setCursor(6, 0); lcd.print(frq);
lcd.setCursor(13,0); lcd.print("Hz ");
lcd.setCursor(6, 1); lcd.print(period,2);
lcd.setCursor(13, 1); lcd.print("ms");
break;
case 2: // 100Hz thru 1KHz
period=period*1000;
lcd.setCursor(6, 0); lcd.print(frq);
lcd.setCursor(13,0); lcd.print("Hz ");
lcd.setCursor(6, 1); lcd.print(period,3);
lcd.setCursor(13, 1); lcd.print("ms");
break;
case 3: // 1KHz thru 10KHz
period=period*1000;
lcd.setCursor(6, 0); lcd.print(floatfrq,3);
lcd.setCursor(13,0); lcd.print("KHz");
lcd.setCursor(6, 1); lcd.print(period,3);
lcd.setCursor(13, 1); lcd.print("ms");
break;
case 4: // 10KHz thru 100KHz
period=period*1000*1000;
lcd.setCursor(6, 0); lcd.print(floatfrq,2);
lcd.setCursor(13,0); lcd.print("KHz");
lcd.setCursor(6, 1); lcd.print(period,2);
lcd.setCursor(13, 1); lcd.print("us");
break;
case 5: // 100KHz thru 1MHz
period=period*1000*1000; // convert from s to µ
lcd.setCursor(6, 0); lcd.print(floatfrq,1);
lcd.setCursor(13,0); lcd.print("KHz");
lcd.setCursor(6, 1); lcd.print(period,3);
lcd.setCursor(13, 1); lcd.print("us");
break;
case 6: // above 1MHz
period=period*1000*1000;
lcd.setCursor(6, 0); lcd.print(floatfrq,3);
lcd.setCursor(13,0); lcd.print("MHz");
lcd.setCursor(6, 1); lcd.print(period,3);
lcd.setCursor(13, 1); lcd.print("us");
break;
}
}
Changeing the gate time requires several changes. The accuracy is in the 4 to 5 digit range. For low freqencies it is lower.
If you are looking for a preamplifier search for "frequency amplifier" in the Arduino forum. I posted a circuit diagram for a 2Hz-20MHz(plus) amplifier.
On account of the 9000 character limitation of this forum I had to remove lots of comments in my code.
I am sorry for that. You do not need to understand the code. Just let it run.
Have fun
arduinoaleman - May 2015
ps:
If you have any questions, please use the forum for communication.