Sto completando lo stroboscopio. Mi capita saltuariamente che la scritta "OVR" sul display, che indica il superamento del 10% di duty cycle con un trigger esterno, non venga cancellata o che addirittura funzioni al contrario. L'unica spiegazione è che, poiché il trigger esterno attiva un interrupt, questo vada a cambiare le carte in tavola durante l'esecuzione della funzione OVR_display(), che controlla sia la scritta "OVR" che lo stato del LED rosso, spento o intermittente.
Come posso risolvere il problema? Ho provato con ATOMIC_BLOCK (#include <util/atomic.h>), ma non funziona più lcd.print!
Grazie
Gianluca
volatile uint32_t cont_match=0; // Conta i compare Match di 20us ciascuno.
volatile bool over=false; // Per evitare il superamento del 10% di duty cycle con il trigger esterno (Ext).
setup()
{
//...
attachInterrupt(0, EXT_TRIGGER, FALLING); // Ext.
}
void EXT_TRIGGER() // Chiamata dal trigger esterno.
{
if(!ind_freq) // Se è 0, cioè Ext:
{
if(shutter>=485000L/cont_match) // f OK. Metto 485000 anziché 500000 per lasciare un po' di tolleranza.
{
cont_match=0;
PORTD|=0b10000000; // Lampo ON.
PORTB|=(0b00000010 | Ticon); // LED verde (PB1) e Tic (PB0) se è attivato.
over=false;
}
else // f OVER.
{
cont_match=0;
over=true;
}
}
}
void OVR_display() // Chiamata periodicamente nel loop().
{
if(!over) // Non over.
{
PORTC &= (byte)~0b00000100; // Spegne il LED rosso se è acceso. Senza il casting, esce a 16 bit!
}
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
if(!ind_freq && over)
{
if(millis()-t_interm_rosso>249) // Fa lampeggiare il LED rosso.
{
t_interm_rosso+=250;
PINC |= 0b00000100;
}
if(over != over_prec)
{
lcd.setCursor(12,0);
if(over) lcd.print("OVR");
else lcd.print(" ");
}
over_prec=over;
}
} // END ATOMIC
}
Comunque l'ATOMIC andava a interferire con la temporizzazione principale!
Ho abolito il nucleare e ho fatto semplicemente un aggiornamento periodico dello stato della scritta "OVR":
void OVR_display()
{
if(!over) // Non over.
{
PORTC &= (byte)~0b00000100; // Spegne il LED rosso se è acceso. Senza il casting, esce a 16 bit!
}
if(!ind_freq)
{
if(millis()-t_aggiorn_OVR>500)
{
t_aggiorn_OVR+=500;
lcd.setCursor(12,0);
if(over) lcd.print("OVR");
else lcd.print(" ");
}
if(over)
{
if(millis()-t_interm_rosso>249) // Fa lampeggiare il LED rosso.
{
t_interm_rosso+=250;
PINC |= 0b00000100;
}
}
}
}
void EXT_TRIGGER()
{
if(!ind_freq) // Se è 0, cioè Ext:
{
if(shutter>=485000L/cont_match) // f OK. Metto 485000 anziché 500000 per lasciare un po' di tolleranza.
{
if(millis()-t_over>500)
{
over=false;
cont_match=0;
PORTD|=0b10000000; // Lampo ON.
PORTB|=(0b00000010 | Ticon); // LED verde (PB1) e Tic (PB0) se è attivato.
}
}
else // f OVER.
{
cont_match=0;
over=true; t_over=millis();
}
}
}
void OVR_display()
{
if(!over) // Non over.
{
PORTC &= (byte)~0b00000100; // Spegne il LED rosso se è acceso. Senza il casting, esce a 16 bit!
}
if(!ind_freq)
{
if(over!=over_prec)
{
over_prec=over;
lcd.setCursor(12,0);
if(over) lcd.print("OVR");
else lcd.print(" ");
}
if(over)
{
if(millis()-t_interm_rosso>249) // Fa lampeggiare il LED rosso.
{
t_interm_rosso+=250;
PINC |= 0b00000100;
}
}
}
}
Cioè quando si dice; chi fa da se fa per tre (te).
Tanto per argomentare circa ATOMIC così sai cosa fa di preciso.
Salva il registro SREG di cui un bit indica se gli interrupt globali sono o meno abilitati.
Disabilita gli interrupt globali
Esegue il codice all'interno delle graffe e per finire rimette SREG come lo aveva trovato prima.
Quindi ad esempio se gli interrupt sono disabilitati restano disabilitati sia durante {} che dopo.
Impedendo il ritorno di over a false prima di 500ms con if(millis()-t_over>500) il difetto non si è mai manifestato.
Forse ho finito il programma dello strobocopio. Certo, però, che nonostante tutto quello che ci ho messo (con 3 interrupt "sotto") ho ancora il 64% +80% di spazio libero...
ah ovviamente il tipo di dato usato per le costanti manifeste è sempre int, sia che esprimi in decimale, binario, ottale ed esadecimale. Per cui il cast esplicito è necessario.
Si risparmi flash non usando digitalWrite/Read ecc.
Sì, hai ragione. Infatti già l'ho fatto per leggere lo stato del pulsante, senza dover pensare che il pulsante premuto è a livello basso: #define puls_prem !(PIND&0b01000000)