You are on page 1of 4

/*

Arduino Frequency Counter


Dr Paul Connor
Wharfe Education
August 2012
Addapted from "Timer and Counter example" authored by Nick Gammon
Date: 17th January 2010
Uses Timer 1 as a pulse counter to count input pulses.
Uses Timer 2 as a 1 ms timebase to construct a gate (counting period).
Digital pin 5 is the frequency input. Frequency measurements are
sent to the serial port.
A BelleVue display module can be connected to the serial TX (Digital pin 1).
Digital Pins 11 & 12 should be pulled up to 3V3 with 10k resistors.
Connect pin 12 to Gnd for MHz scaling.
Connect pin 11 to Gnd for Hz scaling.
Both pulled up give kHz scaling.
*/
#define GATE_PERIOD 1000
#define MAX_MHZ 5000000
#define MAX_KHZ 999999

// Gate period in ms
// Maximum count in MHz mode
// Maximum in KHz Mode

volatile boolean measurement_ready = false;


volatile unsigned int overflows = 0;
volatile unsigned long freq_measurement = 0;
void setup() {
// initialize the digital pin as an output.
// Pin 13 has an LED connected on most Arduino boards:
pinMode(13, OUTPUT);
// Initialise the input pins
pinMode(12, INPUT);
pinMode(11, INPUT);
// Initialise serial port
Serial.begin(9600);
// Zero counters
TCNT1 = TCNT2 = 0;
// Set timer 1 to count pulses on D5 pin
TCCR1A = 0;
TCCR1B = _BV(CS11) | _BV(CS12);
// Enable Timer 1 O/F interrupt
TIMSK1 = _BV(TOIE1);
// Set timer 2 to count 125 ticks from the 16 MHz clock
// with a prescaler of 128. This give a tick every 8 us
// and thus an overflow every ms.
TCCR2A = _BV(WGM21);
TCCR2B = 0;
OCR2A = 124;
// Enable Timer 2 Match Interrupt
TIMSK2 = _BV(OCIE2A);

// Reset prescaler
GTCCR = _BV (PSRASY);
// start Timer 2 with a prescaler of 128
TCCR2B = _BV (CS20) | _BV (CS22) ;
}
// Timer 1 interrupt.
// This counts the number of times the counter has overflowed.
ISR (TIMER1_OVF_vect)
{
overflows++;
}
// Timer 2 Interrupt
ISR (TIMER2_COMPA_vect)
{
static unsigned int ticks = 0; // Tick counter (counts milliseconds)
static unsigned char led_state = 0;
unsigned char OF_flag; // Holds the state of timer 1 overflow flag.
unsigned int timer_value; // The sampled value of timer 1
unsigned long new_pulse_count; // The total number of pulses so far.
static unsigned long old_pulse_count = 0; // The number of pulses last time.
if( ++ticks > GATE_PERIOD )
{
// Reset ticks counter. This if-statement is true once every gate period.
ticks = 0;
//
//
//
//
do

Read Timer 1
Need to check to see if the counter overflows
while we're in the act of reading it. If it does
we just read all over again.
{
OF_flag = (TIFR1 & TOV1);
timer_value = TCNT1;
} while( OF_flag != (TIFR1 & TOV1) );
// If there was an overflow deal with it here
// NB This ISR has a higher priority than Timer 1 overflow.
//
This means that the Timer 1 interrupt can't run while this
//
interrupt is executing.
if( OF_flag )
{
overflows++; // Count the overflow
TIFR1 |= _BV(TOV1); // Clear the interrupt
}
new_pulse_count = ( (unsigned long)overflows << 16 ) + timer_value;
// Set measurement ready flag
if( !measurement_ready )
{
freq_measurement = new_pulse_count - old_pulse_count;
measurement_ready = true;
}
// The new pulse count this time becomes the old pulse count last time.
old_pulse_count = new_pulse_count;
// Toggle LED - just to show code is running
if( led_state == 0 )
{
digitalWrite(13, HIGH); // set the LED on

led_state = 1;
}
else
{
digitalWrite(13, LOW);
led_state = 0;
}

// set the LED off

}
}
String Format_MHz( unsigned long n )
{
// Return an error message if over range
if( n > MAX_MHZ ) return String(" OVER ");
// Pack some leading zeros
String Formatted = "000000" + String(n);
// Get the 6 digits from 1 MHz to 10 Hz
Formatted = Formatted.substring( Formatted.length() - 7, Formatted.length() 1 );
// split the string and put the decimal point in.
Formatted = Formatted.charAt(0) + String(".") + Formatted.substring(1);
// Return the result
return Formatted;
}
String Format_kHz( unsigned long n)
{
// Retunr an error if over range
if( n > MAX_KHZ ) return String(" OVER ");
// Pack some leading zeros
String Formatted = "00000" + String(n);
// Get the last 6 digits 100 kHz to 1 Hz
Formatted = Formatted.substring( Formatted.length() - 6 );
// split the string and put the decimal point in.
Formatted = Formatted.substring(0,3) + String(".") + Formatted.substring(3,6);
// Return the result
return Formatted;
}
String Format_Hz( unsigned long n)
{
// Retunr an error if over range
if( n > MAX_KHZ ) return String(" OVER ");
// Pack some leading zeros
String Formatted = "00000" + String(n);
// Get the last 6 digits 100 kHz to 1 Hz
Formatted = Formatted.substring( Formatted.length() - 6 );
// Add the decimal point.
Formatted = Formatted + String(".");
// Return the result
return Formatted;

}
void loop() {
String freq_format;
// Wait for measurement ready
while( !measurement_ready )
{;}
// Send format string
if( digitalRead(12) == LOW )
{
Serial.println( Format_MHz(freq_measurement) );
}
else
{
if( digitalRead(11) == HIGH )
Serial.println( Format_kHz(freq_measurement) );
else
Serial.println( Format_Hz(freq_measurement) );
}
measurement_ready = false;
}

You might also like