timer interrupt - variabili globali che non si aggiorano - noInterrupt che va.

Ho risolto ma avrei bisogno di un chiarimento perchè non ho capito.
Allora: codice abbastanza semplice: Timer1 chiama una routine di interrupt ogni (penso) mezzo millisec. All’interno del interrupt viene confrontato un contatore (clkPin1) e se supera il valore di un intero globale (SetPin1) scambia lo stato di un Pin generando essenzialmente un’onda quadra.
Il problema sorge nel momento in cui nel ciclo principale del loop setto la variabile SetPin1: sembra non prenda le modifiche e lasci sempre il valore 3 nonostante in teoria dovrei ogni tot secondi aggiornarlo…in pratica l’interrupt continua ma la frequenza non varia… quasi che la variabile rimanesse “locale”.

Se però (come ho scoperto dopo un mal di testa) prima di settare la variabile stacco gli interrupt con la funzione noInterrupts tutto magicamente funziona.

Perchè? Perchè non prende la modifica della variabile globale se prima non blocco gli interrupt? è normale?

codice che va:

int led = 13;
int timer1_counter;

int clkPin1 = 0;
int SetPin1=9;

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;

  // Set timer1_counter to the correct value for our interrupt interval
 //timer1_counter = 64911;   // preload timer 65536-16MHz/256/100Hz
  //timer1_counter = 64286;   // preload timer 65536-16MHz/256/50Hz
 // timer1_counter = 34286;   // preload timer 65536-16MHz/256/2Hz

  timer1_counter = 65536-16;   //2k herz freq.
  
  TCNT1 = timer1_counter;   // preload timer
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts

  
}


ISR(TIMER1_OVF_vect)        // interrupt service routine 
{
  TCNT1 = timer1_counter;   // preload timer
  scambia();
}

void scambia(){
  static byte Pin1 = LOW;
  if (clkPin1 >= SetPin1) {
    digitalWrite(led, Pin1);
    Pin1 = not Pin1;  
    clkPin1 = 0;
  } else {
    clkPin1++;
    
  }
}

// the loop routine runs over and over again forever:
void loop() {
  //scambia();
  
  noInterrupts();
  SetPin1 = 20;
  interrupts(); 
  delay(500);               // wait for a second
  noInterrupts();
  SetPin1 = 3;
  interrupts(); 
  delay(500);               // wait for a second
  
}

loop che non va

void loop() {
  // NON VA... SEMBRA RIMANGA FISSO SETPIN = 3
  
  //   noInterrupts();
  SetPin1 = 20;
 //    interrupts(); 
  delay(500);               // wait for a second
 //    noInterrupts();
  SetPin1 = 3;
 //    interrupts(); 
  delay(500);               // wait for a second

Grazie mille in anticipo.

Devi dichiarare SetPin volatile. Ti lascio al K&R per la spiegazione ;).

Comunque visto che è una variabile che occupa più di un byte, disabilitare gli Interrupt mentre ne cambi il valore è una buona idea per garantire l'atomicità della cosa.

Grande Sukko! Grazie 1000. Adesso finalmente ho capito cosa cacchio voleva dire quel "volatile" che tutti scrivevano nelle librerie. Pensavo non servisse ad un tubo :grin:

Per velocizzare l'ISR sarebbe meglio evitare il salto alla funzione e usare PORT anziché digitalWrite:

ISR(TIMER1_OVF_vect) // interrupt service routine 
{
  TCNT1 = timer1_counter;    // preload timer
  static byte Pin1 = LOW;
  if (clkPin1 >= SetPin1)
    {
    if(Pin1) PORTB|=B00100000;
    else     PORTB&=B11011111;
    Pin1=!Pin1;  
    clkPin1 = 0;
    }
  else clkPin1++;
}