impossible d'activer l'interruption timer 1 compare

Bonsoir, j'ai une carte banale sur laquelle mon arduino Nano active des relais et quand je veux mettre une tempo en interruption avec timer 1, ça bug: ma led ne test ne s'éteint pas !

void setup() {
  /*
   * Port registers allow for lower-level and faster manipulation of the i/o pins of the microcontroller on an Arduino board. 
   * The chips used on the Arduino board (the ATmega8 and ATmega168) have three ports:
     -B (digital pin 8 to 13)
     -C (analog input pins)
     -D (digital pins 0 to 7)   
  //All Arduino (Atmega) digital pins are inputs when you begin...
  */  
   
  PCICR |= (1 << PCIE0);    //enable PCMSK0 scan                                                 
  PCMSK0 |= (1 << PCINT0);  //Set pin D8 trigger an interrupt on state change. Input from optocoupler
  pinMode(3,OUTPUT);        //Define D3 as output for the DIAC pulse
  
  pinMode(test, OUTPUT);
  pinMode(power1, OUTPUT);
  pinMode(direction1, OUTPUT);
  
  /// pour les tests de fonctionnement
  digitalWrite (test,HIGH);
  digitalWrite (power1,HIGH);
  delay(1000);              // wait for a second
  digitalWrite (direction1,HIGH);
  delay(1000);              // wait for a second
  digitalWrite (power1,LOW);
  delay(1000);              // wait for a second
  digitalWrite (direction1,LOW);
  delay(1000);              // wait for a second
  digitalWrite (test,LOW);
  
  //  alimentation moteur1
  digitalWrite (power1,HIGH);
  //  activation moteur1 sens 1
  digitalWrite (direction1,LOW);

  cli();//stop interrupts
  
    //////////////////////////////////////////////////////////////
    //set timer1 interrupt at 0.28Hz
    TCCR1A = 0;// set entire TCCR1A register to 0
    TCCR1B = 0;// same for TCCR1B
    TCNT1  = 0;//initialize counter value to 0
    // set compare match register for 1hz increments
    //OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536) 
    // maximum de registre compare, soit 0.28 Hz soit 4.19 secondes
    OCR1A = 65535;// = (16*10^6) / (1*1024) - 1 (must be <65536)
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS12 and CS10 bits for 1024 prescaler
    TCCR1B |= (1 << CS12) | (1 << CS10);
    TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
    /////////////////////////////////////////////////////////////
    
    sei(); // Active l'interruption globale
    valor = 10;  

}

void loop() {
  
  
  delayMicroseconds(valor); //This delay controls the power
  digitalWrite(3,HIGH);
  delayMicroseconds(100);
  digitalWrite(3,LOW);
  }


//timer1 interrupt en comparateur, voir réglages dans le setup
ISR(TIMER_COMPA_vect){
  if (toggle1 == 1)  {
    digitalWrite (test,HIGH);
    valor = 10;
    toggle1 = 0;
  }  else  {
    digitalWrite (test,LOW);
    valor = 150;
    toggle1 = 1;
  }
}

J'ai eu du mal à trouver l'erreur mais c'est seulement à l'activation de timer1 compare interrupt que ça plante; TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt

Que se passe t-il ?

Je ne comprends pas en quoi l'activation de l'interruption timer 1 fait bugger le programme, la ligne:

digitalWrite (test,LOW);

qui est avant:

TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt

ne s'exécute pas et le programme qui suit non plus, qu'est-ce qu'il se passe ?

Par contre tout rentre dans l'ordre si j'enlève TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt

Bonjour,

Tout d'abord, je suppose que les variables que vous utilisez dans l'ISR sont bien globales et déclarées en "volatile"...
Postez tout votre code, cela évitera de se poser des questions sur la déclaration des variables globales.

Concernant le timer 1, avant le set-up, un Arduino déroule du code (le boot-loader) et il ne laisse pas les registres du timer 1 dans l'état de propreté où vous auriez souhaité les trouver...
En particulier, vous n'effacez pas le bit OCF1A dans le TIFR1. Si le bit est à 1, l'interruption va partir de suite...

Essayez l'initialisation suivante, plus conservatrice, pour une IT environ toutes les 4,19s :

TCCR1A= 0x00;
TCCR1B= (1<<WGM12) | (1<<CS10) | (1<<CS12);
TCCR1C=0x00;
OCR1A=65535;
TIFR1= 1<<OCF1A;
TIMSK1= 1<<OCIE1A;

Bonne bidouille

MicroQuettas

Ah effectivement, ça fonctionne un peu mieux ; le programme ne bug pas au début mais après la première interruption timer 1.

C'est autour du flag TIFR1 qu'il faut regarder, je doit effacer OCF1A à chaque passage dans l'interruption ?

/*TRIAC control with potentiometer; author: ELECTRONOOBS 
 * Subscribe: http://www.youtube.com/c/ELECTRONOOBS
 * Tutorial: http://www.ELECTRONOOBS.com/eng_circuitos_tut20.php
 * Thank you
*/

//  bibliothèque personnelle
#include "configuration.h"


volatile int detectado = 0;
int valor=0;
int last_CH1_state = 0;

volatile boolean toggle1 = 0;  //  toggle de timer1

void setup() {
  /*
   * Port registers allow for lower-level and faster manipulation of the i/o pins of the microcontroller on an Arduino board. 
   * The chips used on the Arduino board (the ATmega8 and ATmega168) have three ports:
     -B (digital pin 8 to 13)
     -C (analog input pins)
     -D (digital pins 0 to 7)   
  //All Arduino (Atmega) digital pins are inputs when you begin...
  */  
   
  PCICR |= (1 << PCIE0);    //enable PCMSK0 scan                                                 
  PCMSK0 |= (1 << PCINT0);  //Set pin D8 trigger an interrupt on state change. Input from optocoupler
  
  PCMSK0 |= (1 << PCINT4);  //  OPEN A sur D12 (PCINT4)
  
  pinMode(3,OUTPUT);        //Define D3 as output for the DIAC pulse
  
  pinMode(test, OUTPUT);
  pinMode(power1, OUTPUT);
  pinMode(direction1, OUTPUT);
  pinMode(opena, INPUT);
  
  /// pour les tests de fonctionnement
  digitalWrite (test,HIGH);
  digitalWrite (power1,HIGH);
  delay(1000);              // wait for a second
  digitalWrite (direction1,HIGH);
  delay(1000);              // wait for a second
  digitalWrite (power1,LOW);
  delay(1000);              // wait for a second
  digitalWrite (direction1,LOW);
  delay(1000);              // wait for a second
  digitalWrite (test,LOW);
  
  //  alimentation moteur1
  digitalWrite (power1,HIGH);
  //  activation moteur1 sens 1
  digitalWrite (direction1,LOW);

  cli();//stop interrupts
  /*
    //////////////////////////////////////////////////////////////
    //set timer1 interrupt at 0.28Hz
    TCCR1A = 0;// set entire TCCR1A register to 0
    TCCR1B = 0;// same for TCCR1B
    TCNT1  = 0;//initialize counter value to 0
    // set compare match register for 1hz increments
    //OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536) 
    // maximum de registre compare, soit 0.28 Hz soit 4.19 secondes
    OCR1A = 65535;// = (16*10^6) / (1*1024) - 1 (must be <65536)
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS12 and CS10 bits for 1024 prescaler
    TCCR1B |= (1 << CS12) | (1 << CS10);
    //TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
    /////////////////////////////////////////////////////////////
   */

    // set entire TCCR1A register to 0
    TCCR1A= 0x00;
    // Set CS12 and CS10 bits for 1024 prescaler
    // turn on CTC mode
    TCCR1B= (1<<WGM12) | (1<<CS10)  | (1<<CS12);
    // set entire TCCR1C register to 0
    TCCR1C=0x00;
    // maximum de registre compare, soit 0.28 Hz soit 4.19 secondes
    OCR1A = 65535;// = (16*10^6) / (1*1024) - 1 (must be <65536)
    TIFR1= 1<<OCF1A;
    // enable timer compare interrupt
    TIMSK1= 1<<OCIE1A;






    
    sei(); // Active l'interruption globale
    valor = 10000;  

}

void loop() {
  
  if (digitalRead(opena) == LOW) {
    valor = 10;
  }
  delayMicroseconds(valor); //This delay controls the power
  digitalWrite(3,HIGH);
  delayMicroseconds(100);
  digitalWrite(3,LOW);
  
   //Read the value of the pot and map it from 10 to 10.000 us. AC frequency is 50Hz, so period is 20ms. We want to control the power
   //of each half period, so the maximum is 10ms or 10.000us. In my case I've maped it up to 7.200us since 10.000 was too much
   
   //valor = map(analogRead(A0),0,1024,10000,10);
   //valor = map(analogRead(A0),0,1024,15000,100);
   //valor = map(analogRead(A0),0,1024,5000,10);
   
  /* 
   //In my case I've used valor = map(analogRead(A0),0,1024,7200,10); for better results
    if (detectado)
    {
      delayMicroseconds(valor); //This delay controls the power
      digitalWrite(3,HIGH);
      //delayMicroseconds(100);
      delayMicroseconds(300);
      digitalWrite(3,LOW);
      detectado=0;
    } 
    */
    
}




//This is the interruption routine
//----------------------------------------------

ISR(PCINT0_vect){
  /////////////////////////////////////               //Input from optocoupler
  if(PINB & B00000001){                               //We make an AND with the pin state register, We verify if pin 8 is HIGH???
    if(last_CH1_state == 0){                          //If the last state was 0, then we have a state change...
      detectado=1;                                    //We haev detected a state change!
    }
  }
  else if(last_CH1_state == 1){                       //If pin 8 is LOW and the last state was HIGH then we have a state change      
    detectado=1;                                      //We haev detected a state change!
    last_CH1_state = 0;                               //Store the current state into the last state for the next loop
    }
}

/////  ==> routine avec vecteur d'interruption
//timer1 interrupt en comparateur, voir réglages dans le setup
ISR(TIMER_COMPA_vect){
  if (toggle1 == 1)  {
    digitalWrite (test,HIGH);
    valor = 10;
    toggle1 = 0;
  }  else  {
    digitalWrite (test,LOW);
    valor = 150;
    toggle1 = 1;
  }
}

ISR(PCINT4_vect){
  /////////////////////////////////////    
  if(PINB & B00010000){                               //We make an AND with the pin state register, We verify if pin 8 is HIGH???
    return;
  } else if (PINB & B00010000 == 0) {   //  OPENA activé      
    valor = 10;
    }
}

Bonjour,

Heureux de voir que l'interruption s'active au moins une fois...

C'est autour du flag TIFR1 qu'il faut regarder, je doit effacer OCF1A à chaque passage dans l'interruption

Le flag c'est OCF1A. Il est contenu dans le registre TIFR. Il n'y a rien à faire car le flag est effacé quand le processeur entre dans l'ISR correspondante.

Ce qui me chagrine dans votre programme, c'est que n'arrive pas à voir ce qu'il fait. Je ne comprends pas non plus son architecture.

Pourquoi utilisez vous une interruption pour faire des délais relativement longs (4s au maximum) et des attentes delayMicroseconds() pour faire des délais courts ?
En plus, l'interruption peut tomber pendant la boucle d'attente du delayMicroseconds(), ce qui va allonger la durée...

D'une manière générale, sauf cas particulier, si vous faites du temps réel, oubliez les attentes (delay() ou delayMicroSeconds()). Ces routines "bloquent" pendant les attentes et, sauf interruption qui va perturber la boucle d'attente, le processeur ne peut rien faire d'autre pendant ce temps là !

Les délais courts (< qq ms) se font avec les ITs et les délais longs (> 10ms avec millis()). Avec millis() on peut aller jusqu'à qq dizaines de jours, le tout sans rien bloquer !

Si vous voulez piloter un triac, il faut un délai bien précis après la synchro du passage à zéro. A faire avec des ITs, mais pas complètement simple.

Bonne bidouille,

MicroQuettas

:sweat_smile: j'avais oublié le 1 dans ISR(TIMER_COMPA_vect){... d'où le bug

Sinon vous avez raison au sujet de l'utilisation des interruptions au lieu des delay mais c'est l'exemple le plus rapide que j'ai trouvé pour tester ma carte, il faut que je peaufine la partie soft maintenant.

D'ailleurs je n'arrive pas très bien à commander mon triac, pourtant, j'ai bien le bon signal Vsync1 (en bas à droite du schéma) qui attaque D8; du 0-5 V synchronisé sur le 50 Hz.

A l'oscilloscope, je vois de temps en temps que la période positive est manquante, c'est sûr ça va moins bien marcher !

j'avais oublié le 1 dans ISR(TIMER_COMPA_vect){... d'où le bug

et moi non-plus... :wink:

La demi alternance positive disparaît du signal de synchro ou n'est pas traitée par l'Arduino ?

Bonne bidouille

MicroQuettas

Merci de m'aiguiller dans la recherche d'erreurs.

L'arduino envoi bien une belle pulse selon l'état du potentiomètre mais l'erreur est dans le schéma en fait; je n'ai pas pris le même optocoupleur que sur le schéma.

J'ai un MOC3061 qui a le zero-cross; il faut que je refasse des essais sur une breadboard (en 230 V c'est pas facile) pour souder mon MOC comme il faut

To be continued...