interrupt sul timer

Ciao
ho un'applicazione che sfrutta dei sensori (nunchuk) che però alle volte si impallano( okok, è che salta qualche cavetto ogni tanto :-), devo decidermi a imparare kikad e farmi sto benedetto PBC ), bloccando tutto lo scetch.
Dato che il mezzo gestito è un coso volante la cosa è problematica, volevo mettere un interrupt sul timer che venisse lanciato almeno una volta al secondo, che se rileva che il loop non gira spegne i motori.
Non voglio però andare a modificare prescaler o roba del genere, in modo da non incasinare il resto del codice (uso varie librerie e vorrei evitare di stare a spulciare i casini che possono nascere)

il codice di test (che non va) che ho scritto finora:
credo non funzioni perchè aspetto l'evento overflow del timer2 che avviene chissà ogni quanto... o no?

void setup(){
  Serial.begin(19200);
  TIMSK2 |= B00000100;
}
unsigned long time = micros();
void loop(){
}

ISR(TIMER2_OVF_vect) {
  Serial.println(micros()-time);
  time=micros();
};

Ciao lesto credo che per abilitare l'interrupt devi usare il registro TCCR2B, guarda il datasheet perchè ricordo che i timer sono un pò diversi.

Questo codice è preso da il pid atmel:

 // Set up timer, enable timer/counte 0 overflow interrupt
  TCCR0A = (1<<CS00);
  TIMSK0 = (1<<TOIE0);
  TCNT0 = 0;

e questa e la routine di interrupt:

/* Specify the desired PID sample time interval
 * With a 8-bit counter (255 cylces to overflow), the time interval value is calculated as follows:
 * TIME_INTERVAL = ( desired interval [sec] ) * ( frequency [Hz] ) / 255 */
#pragma vector = TIMER0_OVF_vect
__interrupt void TIMER0_OVF_ISR( void )
{
  static uint16_t i = 0;
  if(i < TIME_INTERVAL)
    i++;
  else{
    gFlags.pidTimer = TRUE;
    i = 0;
  }
}

Il watchdog dovrebbe servire proprio a questo, è un contatore che devi azzerare durante il programma prima che vada in overflow se ci và resetta e riparte da capo il programma, però credo che questo venga usato nel bootloader, purtroppo questa parte non l'ho ancora studiata.

Ciao.

giusto quello che mi serviva! +1 :smiley:

per il watchdog ho dato un'occhiata ma pare non essere supportato dal bootloader, ma è supportato da quello adafruit

Ciao lesto, anche se credo che tu non ne abbia bisogno, ti dò un piccolo consiglio...
togli la sctittura sulla seriale dalla routine di interrupt e sostituiscila con una variabile che viene controllata appena il loop riprende :wink: così avrai una risposta più rapida del sw nell'eventualità di trigger ripetuti.

giusto quello che mi serviva! +1 smiley-grin

Ok grazie.

per il watchdog ho dato un'occhiata ma pare non essere supportato dal bootloader, ma è supportato da quello adafruit

Qua bisogna vedere nel sorgente del bootloader perchè in quello dell'UNO c'è.
Eccolo:

void watchdogConfig(uint8_t x) {
  WDTCSR = _BV(WDCE) | _BV(WDE);
  WDTCSR = x;
}

Ora non so come funziona la cosa, forse puoi avviare il watchdog anche nello sketch c'è da vedere se non va in contrasto con il bootloader.

Ciao lesto, anche se credo che tu non ne abbia bisogno, ti dò un piccolo consiglio...
togli la sctittura sulla seriale dalla routine di interrupt e sostituiscila con una variabile che viene controllata appena il loop riprende smiley-wink così avrai una risposta più rapida del sw nell'eventualità di trigger ripetuti.

In effetti all'interno delle routine ISR, il global interrupt è disabilitato, quindi un'interrupt che si verifica quando si è all'interno di una ISR non ha esito, anche chimare una funzione che fà affidamento sugli interrupt non funziona e il motivo è ovvio.
C'è un metodo per modificare il comportamento degli interrupt e la trovi nella doc delle libc, ora non ricordo mi pare siano due macro o tre.
Alternativa è quella di usare asm volatile {your code....}, ad esempio li dentro puoi scivere in seriale direttamente nel registro della seriale, dovrebbe funzionare.

Il codice all'interno delle ISR dovrebbe essere il più a basso livello possibile o comunque deve entra ed uscire molto velocemente.

Ciao.

so che la serial funziona sicuramente negli interrupt esterni, comunque si tratta solo di debug.
un'altra cosa che non ho capito bene è cosa può fare il watchdog. Mi pare che lui resetti l'arduino.
Io ho semplicemente bisogni di mettere a 0 con la libreria Servo 4 uscite (quelle dei motori)..

ah nel forum inglese mi han detto di usare variabili volatili se sono "in comune" tra ISR e normale codice

link: Arduino Forum

p.s. non prendetemi in giro per il mio pessimo inglese

p.s. non prendetemi in giro per il mio pessimo inglese

hahaha io sto messo peggio.

Mi pare che lui resetti l'arduino.
Io ho semplicemente bisogni di mettere a 0 con la libreria Servo 4 uscite (quelle dei motori)..

Si si, serve nel caso il programma dovesse andare in loop escludendo delle parti di codice vitale, se accade che entra in loop non previsto e li azzeri il watchdog non hai fatto niente. Nel tuo caso non ti serve allora perchè a quello che ho capito se un cavetto si scollega non gira più nel loop, io ho capito così, potrebbe essere più semplice.
PseudoCode
in runner = 0
int count = 0
ISR_OVF()
{
if (count == 0) save_runner = runner
if (count => 1)
{
if (save_runner == runner) spegni i motori
}
count++
}

void loop()
{
runner++
}

Non c'è bisogno di volatile se fuori da ISR non modifichi la variabile così mi è stato detto però è meglio usare volatile in fase di sviluppo.

Se hai lo schema elettrico decente e non è molto complesso (tipo 200 componenti) posso farlo io il disegno con kicad.

Ciao.

emh.. cos'è ISR_OVF()? un'iterrupt di overflow ma su che timer?

[offtopic]
grazie per il kicad, ma voglio imparare ad usarlo... il bromografo fai da te è già pronto e testato :slight_smile:
però non trovo i componenti passivi nella libreria(resistenze, condensatori.. dove siete??).. ho trovato l'atmega ecc...

se non ho capito male, finito lo schema elettrico poi da solo ti tira fuori il pbc (mi serve a faccia singola)
[/offtopic]

emh.. cos'è ISR_OVF()? un'iterrupt di overflow ma su che timer?

Si è la routine di interrupt, su quale timer lo hai già scritto ISR(TIMER2_OVF_vect).
Il timer2 su arduino non viene usato.

[OT]
Per kicad c'è il porting delle librerie di eagle ma non ricordo dove fai prima a cercare su google, se non trovi fa sapere che tra i tremilatriliardi di file su 8 partizioni farò il possibile di trovarlo.

se non ho capito male, finito lo schema elettrico poi da solo ti tira fuori il pbc (mi serve a faccia singola)

Bello sarebbe, a me come vengono in automatico non mi piace, al limite si procede così, i connettori si posizionano nella posizione finale e li blocchi, così per il resto che sai dove lo vuoi mettere di preciso, il resto C?, R?, L?, Q?, U? li lasci liberi e fai fare l'autoposizionamento.
Poi chiedi di fare l'auto tracciamento o sbroglio automatico.
Non pensare di ottenere il miglior posizionamento alla prima volta, riprova più volte i passi precedenti, quando ti sembra ok, puoi passare a definire alcune piste manualmente o ad ingrandire qualche pad a sistemare le scritte.

Cosa che mi ha fatto impazzire all'inizio e che devi disegnare il contorno del pcb "pcb edge" altrimenti non funge nulla.

Ciao.

ciao belli, ho risolto: in pratica ho sbagliato ad attivare il bit di interrupt!
TIMSK2|=B00000001;
è l'attivazione giusta!
e anzichè scrivere B00000001 si usa fare (è più leggibile e forse pure "portabile") 1<<TOIE2

quindi:

void setup(){
  Serial.begin(19200);
  TIMSK2 |= (1<<TOIE2);
}
volatile unsigned long time = micros();
volatile int loopOk=0;
void loop(){
  loopOk++;
  //Serial.println("a");
}

ISR(TIMER2_OVF_vect) {
  if (micros()-time >= 1000000){//every second
    time=micros();
    if (loopOk!=0){
      Serial.println("loop ok");
      loopOk=0;
    }else{
      Serial.println("loop bloccato");
    }
  }
};