Grazie agli esempi di Nick Gammon:
// Duty cycle calculation using input capture unit
// Author: Nick Gammon
// Date: 5 November 2013
// Input: Pin D8
#include "LedControl.h"
#define DIN A0
#define CS A1
#define CLK A2
LedControl disp = LedControl(DIN,CLK,CS);
volatile boolean first;
volatile boolean triggered;
volatile unsigned long overflowCount;
volatile unsigned long startTime;
volatile unsigned long finishTime;
uint8_t misura=1; // Positivo.
uint32_t t_positivo;
uint32_t t_negativo;
uint32_t t_periodo;
uint8_t puls_prec=1;
uint8_t stato=1;
uint32_t t_intermittenza=0;
bool acc_sp=true;
// timer overflows (every 65536 counts)
void setup ()
{
// Serial.begin(115200);
pinMode (8, INPUT); // Ingresso
pinMode (9, INPUT_PULLUP); // Pulsante a Gnd
disp.shutdown (0,false); // wakeup MAX7219
disp.setIntensity (0,4); // between 0 and 15
disp.clearDisplay (0);
prepareForInterrupts (); // set up for interrupts
}
void loop ()
{
if(!digitalRead(9))
{
if (puls_prec==1)
{
stato+=1;
puls_prec=0;
}
}
else puls_prec=1;
if(stato>5) stato=1;
if (!triggered) return; // wait till we have a reading
unsigned long elapsedTime = finishTime - startTime; // period is elapsed time
if(misura==1) t_positivo=float(elapsedTime)*62.5e-9*1e6; // convert to microseconds
else t_periodo=float(elapsedTime)*62.5e-9*1e6;
delay(50);
misura=3-misura;
prepareForInterrupts ();
// if (misura==1)
// {
// Serial.print("positivo:"); Serial.print(t_positivo); Serial.print("us ");
// Serial.print("negativo:"); Serial.print(t_periodo-t_positivo); Serial.print("us ");
// Serial.print("periodo:"); Serial.print(t_periodo); Serial.print("us ");
// Serial.print("duty cycle:"); Serial.print((float)t_positivo/t_periodo*100); Serial.println("%");
// }
if(misura==1)
{
t_negativo=t_periodo-t_positivo;
switch (stato)
{
case 1: // Positivo
disp.setRow (0,7,0x62);
scriviValore(t_positivo);
break;
case 2: // Negativo
disp.setRow (0,7,0x1C);
scriviValore(t_negativo);
break;
case 3: // Periodo
disp.setChar (0,7,'p',false);
scriviValore(t_periodo);
break;
case 4: // Frequenza
disp.setChar (0,7,'f',false);
scriviValore((uint32_t)(1000000.0/t_periodo+.5)); // .5: approssimazione.
break;
case 5: // Duty Cycle
disp.setChar (0,7,'d',false);
scriviValore(10000.0*t_positivo/t_periodo);
}
}
}
void scriviValore(uint32_t v)
{
uint32_t v_temp=v;
if(stato==4 && v>10000)
{
if(v<=40000)
{
if(millis()-t_intermittenza>=250) // Intermittenza per f>10kHz.
{
t_intermittenza=millis();
acc_sp=!acc_sp;
}
}
else acc_sp=false; // Per f>40000 spegne i display.
}
else acc_sp=true;
if(stato!=4 || acc_sp)
{
for(uint8_t p=0; p<7; p++)
{
if(v>=pow(10,p))
{
uint8_t x=v_temp%10; v_temp/=10;
if (stato==5) disp.setChar (0,p,x+48,p==2); // Duty Cycle: mette il punto nella posizione 2.
else disp.setChar (0,p,x+48,p==3||p==6); // Nelle posizioni 3 e 6, se c'è un numero accende anche il punto decimale.
}
else disp.setChar (0,p,' ',false);
}
}
else if (stato==4 && v>40000) // Per frequenza maggiori di 40kHz visualizza " OVER ".
{
for(uint8_t p=0; p<7; p++)
{
if(p==4) disp.setRow (0,p,0x7E); // O
else if(p==3) disp.setRow (0,p,0x3E); // V
else if(p==2) disp.setRow (0,p,0x4F); // E
else if(p==1) disp.setRow (0,p,0x77); // R
else disp.setChar (0,p,' ',false);
}
}
else
{
for(uint8_t p=0; p<7; p++) disp.setChar (0,p,' ',false);
}
}
ISR (TIMER1_OVF_vect)
{
overflowCount++;
} // end of TIMER1_OVF_vect
ISR (TIMER1_CAPT_vect)
{
unsigned int timer1CounterValue; // grab counter value before it changes any more
timer1CounterValue = ICR1; // see datasheet, page 117 (accessing 16-bit registers)
unsigned long overflowCopy = overflowCount;
if ((TIFR1&bit(TOV1)) && timer1CounterValue<0x7FFF) overflowCopy++; // if just missed an overflow
if (triggered) return; // wait until we noticed last one
if (first)
{
startTime = (overflowCopy<<16) + timer1CounterValue;
TIFR1 |= bit (ICF1); // clear Timer/Counter1, Input Capture Flag
TCCR1B = bit (CS10); // No prescaling, Input Capture Edge Select (falling on D8)
first = false;
return;
}
finishTime = (overflowCopy << 16) + timer1CounterValue;
triggered = true;
TIMSK1 = 0; // no more interrupts for now
}
void prepareForInterrupts ()
{
noInterrupts (); // protected code
first = true;
triggered = false; // re-arm for next time
// reset Timer 1
TCCR1A = 0;
TCCR1B = 0;
TIFR1 = bit (ICF1) | bit (TOV1); // clear flags so we don't get a bogus interrupt
TCNT1 = 0; // Counter to zero
overflowCount = 0; // Therefore no overflows yet
// Timer 1 - counts clock pulses
TIMSK1 = bit (TOIE1) | bit (ICIE1); // interrupt on Timer 1 overflow and input capture
// start Timer 1, no prescaler
if (misura == 1) TCCR1B = bit (CS10) | bit (ICES1); // plus Input Capture Edge Select (rising on D8) - Impulso positivo.
else TCCR1B = bit (CS10) | !bit (ICES1); // Periodo totale.
interrupts ();
}