Tempo tra impulsi

Ciao a tutti... vorrei contare il tempo che intercorre tra un impulso ed un altro. Piu nello specifico sto usando un tone decoder (un lm567) che mi decifra una certa frequenza. Funziona con un PLL che quando l'anello aggancia un segnale d'ingresso uguale alla frequenza propria del VCO interno fissata con resistenze e condesatori manda su di un pin un uscita a livello alto. Vorrei contare quanto tempo sta a livello alto ma ho dei dubbi sulla precisione oltre su come procedere. Posso contare intervalli sui microsecondi 600/700??? che strada mi consigliate per procedere???

Ciao,
allora, un modo semplice sarebbe impostare una variabile long per immagazzinare questo intervallo in modo tale che, quanto il pin da analizzare passa a livello alto, questa sia uguale a millis(), mentre quando diventa basso questa ti restituisca il valore con la semplice sottrazione (millis() - intervallo). Ti faccio un esempio banale, poi tu lo modificherai se sceglierai questo:

long intervallo = 0;
bool pinState = false;

void setup() {
  Serial.begin(9600);
  pinMode(7,INPUT_PULLUP);
}
void loop() {
  if(digitalRead(7) && pinState == false){
    intervallo = millis();
    pinState = true;
  }

  if(digitalRead(7) == LOW && pinState == true){
    Serial.println(millis() - intervallo);
    pinState = false;
  }
  
}

spero di esserti stato di aiuto.

Ciao, Giovicavalla

@Giovicavalla: quando si lavora con i millis() le variabili DEVONO essere "unsigned long" ... o, superato un determinato tempo (circa 24 gg) hai problemi.

Guglielmo

Ciao, grazie mille Guglielmo, è che a una certa ora anche io sfaso, ci sarà qualche "unsigned" mancante anche nella mia testa? :grinning:

gpb01: @Giovicavalla: quando si lavora con i millis() le variabili DEVONO essere "unsigned long" ... o, superato un determinato tempo (circa 24 gg) hai problemi.

Oltre a questo il fatto che con la millis() al massimo si misurano i millisecondi, non i microsecondi come richiesto, in questo caso tocca usare la micros(), meglio ancora usare un timer e un interrupt.

Se cuoi una misura più precisa in microsecondi, puoi usare la funzione pulseIn:

https://www.arduino.cc/en/Reference/PulseIn

Ciao, scusate, mi era sfuggito il microsecondi..perdono!

Giovicavalla

Non vorrei sbagliare, ma credo sia proprio quello che fa la funzione pulseIn.

Un compagno mi ha fornito questa soluzione non ho capito molto perché non parla italiano ma sembrerebbe funzionare. Chiedo consiglio anche a voi…
Da quel poco che ho capito lui chiama “Input Capture” questo metodo per trattare i segnali in ingresso e questo metodo è implementato interamente nell’hardware chip di controllo e mi permetterebbe di non perdere tempo nella gestione interrupt, permettendomi di trattare impulsi molto brevi accuratamente

*/ uses timer hardware to measure pulses on pin 8 

const int inputCapturePin = 8; // input pin fixed to internal Timer
const int ledPin = 13;
const int prescale = 8; // prescale factor (each tick 0.5 us @16MHz)
const byte prescaleBits = B010; // see Table 18-1 or data sheet
// calculate time per counter tick in ns
const long precision = (1000000/(F_CPU/1000)) * prescale ;
const int numberOfEntries = 64; // the max number of pulses to measure
const int gateSamplePeriod = 1000; // the sample period in milliseconds
volatile byte index = 0; // index to the stored readings
volatile byte gate = 0; // 0 disables capture, 1 enables
volatile unsigned int results[numberOfEntries]; // note this is 16 bit value
/* ICR interrupt vector */
ISR(TIMER1_CAPT_vect)
{
TCNT1 = 0; // reset the counter
if(gate)
{
if( index != 0 || bitRead(TCCR1B ,ICES1) == true) // wait for rising edge
{ // falling edge was detected
if(index < numberOfEntries)
{
results[index] = ICR1; // save the input capture value
index++;
}
}
}
TCCR1B ^= _BV(ICES1); // toggle bit to trigger on the other edge
}
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(inputCapturePin, INPUT); // ICP pin (digital pin 8 on Arduino) as input
TCCR1A = 0 ; // Normal counting mode
TCCR1B = prescaleBits ; // set prescale bits
TCCR1B |= _BV(ICES1); // enable input capture
bitSet(TIMSK1,ICIE1); // enable input capture interrupt for timer 1
Serial.println("pulses are sampled while LED is lit");
Serial.print( precision); // report duration of each tick in microseconds
Serial.println(" microseconds per tick");
}
// this loop prints the number of pulses in the last second, showing min
// and max pulse widths
void loop()
{
digitalWrite(ledPin, LOW);
delay(gateSamplePeriod);
digitalWrite(ledPin, HIGH);
gate = 1; // enable sampling
delay(gateSamplePeriod);
gate = 0; // disable sampling
if(index > 0)
{
Serial.println("Durations in Microseconds are:") ;
for( byte i=0; i < numberOfEntries; i++)
{
long duration;
duration = results[i] * precision; // pulse duration in nanoseconds
if(duration >0)
Serial.println(duration / 1000); // duration in microseconds
}
index = 0;
}
}

Jason_Nathan: Da quel poco che ho capito lui chiama "Input Capture" questo metodo per trattare i segnali in ingresso e questo metodo è implementato interamente nell'hardware chip di controllo e mi permetterebbe di non perdere tempo nella gestione interrupt,

Ed è esattamente quello che ti ho consigliato, usare un timer e il relativo interrupt.