/* Frequency Counter With LCD Display - by arduinoaleman - May 2015 updated by alexP December 2018 Pin D5 of Arduino must be used for frequency input. Counter1 : 16 bits / used to count the frequency impules Counter2 : 8 bits / used to generate a 1000ms or 100ms gate time for measurement I use "bitClear(TIMSK0,TOIEO)" instead of "TIMSK0 &=~(1< #include LiquidCrystal lcd(13,11,6,4,3,2); 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(A4, INPUT_PULLUP); 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<=16; column++) { // LDC test lcd.setCursor(column,row); lcd.print("*"); delay(20); }; } lcd.clear(); } void loop() { float floatfrq; int range; long frq; if(digitalRead(A4)== LOW) {softReset();} measurement(1000); // 1000ms standard gate time while (measurement_ready==false); frq=frequency; floatfrq=frq; // type conversion (required!!) 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 lcd.setCursor(0, 0); lcd.print("Freq: "); switch(range) { case 0: if (frq!=0) {lcd.setCursor(6, 0);lcd.print(frq); lcd.setCursor(13,0);lcd.print("Hz ");} else {lcd.clear();lcd.setCursor(0, 0); lcd.print("No signal... ");} break; case 1: // 10Hz thru 100Hz lcd.setCursor(6, 0); lcd.print(frq); lcd.setCursor(13,0); lcd.print("Hz "); break; case 2: // 100Hz thru 1KHz lcd.setCursor(6, 0); lcd.print(frq); lcd.setCursor(13,0); lcd.print("Hz "); break; case 3: // 1KHz thru 10KHz lcd.setCursor(6, 0); lcd.print(floatfrq,3); lcd.setCursor(13,0); lcd.print("kHz"); break; case 4: // 10KHz thru 100KHz lcd.setCursor(6, 0); lcd.print(floatfrq,2); lcd.setCursor(13,0); lcd.print("kHz"); break; case 5: // 100KHz thru 1MHz lcd.setCursor(6, 0); lcd.print(floatfrq,1); lcd.setCursor(13,0); lcd.print("kHz"); break; case 6: // above 1MHz lcd.setCursor(6, 0); lcd.print(floatfrq,3); lcd.setCursor(13,0); lcd.print("MHz"); break; } } void softReset(){ lcd.clear(); lcd.setCursor(0,0); lcd.print("reset..."); delay(3500); asm volatile (" jmp 0"); }