Original: https://www.electronicsblog.net/arduino-frequency-counterduty-cycle-meter/
Added feature: analog input, able to preset threshold level.
(and we fixed a bug at the auto range feature.)
Sketch:
//Arduino frequency counter/duty cycle meter (analog input)
//www.electronicsblog.net/
#include <LiquidCrystal.h>
#include <TimerThree.h>
#include <TimerFour.h>
//LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int rs = 8, en = 9, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// cycle meter input is pin 21
#define Button A1 // 52
#define ClkOut A7 // clock generator output
#define ClkLed 16 // to check generated clock
#define CmpSig A2 // analog comparator input
#define CmpOut 21 // analog comparator output
#define CmpLed 17 // to check signal detected
int divider[6] ={
0,1,8,64,256,1024};
volatile int prescaler=5;
int b=0;
int screen =0;
volatile double count =0;
volatile double middle =0;
double usage =0;
bool x = false;
ISR(TIMER1_OVF_vect) {
if (prescaler<4) {
prescaler++;
}
}
void interrupt()
{
if (!x) {
count=TCNT1;
TCNT1=0x000;
TCCR1B=prescaler;
attachInterrupt(2, interrupt, FALLING);
}
else {
middle=TCNT1;
attachInterrupt(2, interrupt, RISING);
}
x=!x;
}
void timerClock() {
// clock generator interrupt handler
static int tcnt = 0;
bool out = (tcnt % 4 == 0);
++tcnt;
digitalWrite(ClkOut, out);
digitalWrite(ClkLed, out); // high = led lit
}
void setup_clock_gen() {
pinMode(ClkOut, OUTPUT);
pinMode(ClkLed, OUTPUT);
Timer3.initialize(120000); // in micro second
Timer3.attachInterrupt(timerClock);
}
volatile int volt = 0;
void timerAnalog() {
// analog read interrupt handler
const int vth1 = 400;
const int vth0 = 320;
static int out = 0;
int val = analogRead(CmpSig);
if (val > vth1) {
out = 1;
}
if (val < vth0) {
out = 0;
}
volt = val;
digitalWrite(CmpOut, out);
digitalWrite(CmpLed, out); // high = led lit
}
void setup() {
lcd.begin(16, 2);
pinMode(Button, INPUT);
digitalWrite(Button, HIGH); //pull up resistor
pinMode(CmpSig, INPUT);
pinMode(CmpOut, OUTPUT);
pinMode(CmpLed, OUTPUT);
TIMSK1=0x01; // enabled global and timer overflow interrupt;
TCCR1A = 0x00; // normal operation page 148 (mode0);
attachInterrupt(2, interrupt, RISING);
//setup_clock_gen();
analogReference(DEFAULT);
ADCSRA = ADCSRA & 0xf8; // 分周比を決めるビット(ADPS2:0)を000へ
ADCSRA = ADCSRA | 0x04; // 分周比を決めるビットに分周比16(100)をセット
Timer4.initialize(100); // in micro second
Timer4.attachInterrupt(timerAnalog);
}
void loop()
{
usage=count/65536*100;
/// screen modes
switch (screen) {
case 0:
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print("Freq ");
lcd.print(16000000.0/divider[prescaler]/count);
lcd.print(" Hz");
lcd.setCursor(0, 1);
lcd.print("Duty ");
lcd.print(middle/count*100);
lcd.print(" % ");
lcd.print(" ");
break;
case 1:
lcd.setCursor(0, 0);
lcd.print("Period: ");
lcd.print(volt);
lcd.setCursor(0, 1);
lcd.print(0.0000625*divider[prescaler]*count);
lcd.print(" ms ");
break;
case 2:
lcd.setCursor(0, 0);
lcd.print("H ");
lcd.print(0.0000625*divider[prescaler]*middle);
lcd.print(" ms ");
lcd.setCursor(0, 1);
lcd.print("L ");
lcd.print(0.0000625*divider[prescaler]*(count-middle));
lcd.print(" ms ");
break;
case 3:
lcd.setCursor(0, 0);
lcd.print("Prescaler /");
lcd.print(divider[prescaler]);
lcd.setCursor(0, 1);
lcd.print("Count.use ");
//usage=count/65536*100;
lcd.print(usage);
lcd.print("% ");
break;
}
delay(250);
if (prescaler>1) {
if (usage<0.15) {
prescaler--;
delay(200);
}
}
///button /////////
if (!digitalRead(Button)&&!b) {
screen++;
if (screen==4) {
screen=0 ;
}
lcd.clear();
b=3;
}
if (!b==0) b--;
}