Avis au spécialistes des registres.

Bonjour à toutes et à tous,

J'ai réalisé un petit programme, non bloquant, qui génère une impulsion :
Une fonction "pulse" met au niveau haut une sortie et configure les paramètres adéquats du Timer2,
Quand le timer2 arrive au débordement, il génère une ISR qui remet au niveau bas la sortie.

Ça fonctionne très bien, mais j'y trouve un petit inconvénient. Tant que l'impulsion "pulse" n'est pas relancée, le timer2 continu à tourner et à chaque débordement génère une ISR. Celle-ci remet au niveau bas la sortie qui l'était déjà suite à la première ISR, donc, vu de l'extérieur, ça ne se voit pas. Par contre, chaque ISR me mange quelques micro-secondes de temps de calcul. C'est négligeable, mais pour le principe, ça me gêne.

Pour supprimer ces ISR consécutives, il m'est venu l'idée de remettre à zéro le bit TOIE2 de masquage des interruptions du registre TIMSK2 à la fin de l'ISR et de la remettre à un dans la fonction "pulse" afin de les démasquer à nouveau.

Voir lignes commentées dans le programme ci-joint.

Mais cela ne fonctionne pas et selon l'endroit où je place ces instructions dans la fonction "pulse" et dans l'ISR, soit la sortie reste constamment au niveau haut soit j'ai une impulsion de quelques micro-secondes ; ce temps étant totalement indépendant du temps que je programme.

Voilà. Si vous avez une idée de ce qui pourrait solutionner (pas saucissonner :wink: ) cela

Cordialement.

Pierre

PulseOut.ino (1.97 KB)

Bon, il suffit que je pose un problème pour qu'en général, j'en trouve la solution :

J'avais oublié de réinitialiser le bit d'overFlow (TOV2 dans le registre TIFR2) dans ma fonction "pulse". Ça donne ca maintenant :

   void pulse() { // Met la sortie à l'état haut
      TIFR2 = 0b00000001; // TOV2 -> RaZ du bit d'overFlow
      switch (port) {
        case 2:
          PORTB |= bit;
          break;
        case 4:
          PORTD |= bit;
          break;
      }
      TCNT2 = n; // Rechargement du timer à n
      TIMSK2 = 0b00000001; // TOIE2 : masque ré-autorisant les interruptions du Timer 2
    };

Cordialement.

Pierre

Merci pepe pour cette solution alternative. Pour autant, je n'ai rien compris.

Est-ce que ce que cette proposition :

  • permet de générer une impulsion unique ou est-elle récurrente ?
  • démarre l'impulsion dès la fin de la commande ou y a-t-il un délai lié au différents seuils ?

Cordialement.

Pierre

Bonsoir,

Quand on en a plus besoin, il suffit d'arrêter le timer dans l'ISR en faisant CS2 = 0 dans TCCR2B.
Concrètement, ajouter dans l'ISR :
TCCR2B = 0;

Pour lancer l'impulsion, il faut redémarrer le timer.
Avec les réglages utilisés prédiviseur de 8, il suffit d'ajouter, dans pulse(), après le chargement du compteur :
TCCR2B = 0b00000010; /* Démarre le timer avec un prescaler de 8 */

Avec cela, les réglages de TCCR2B dans l'init ne servent plus à rien.

Bonne bidouille,

MicroQuettas

Je n'ai peut-être pas compris la question :

S'il s'agit de faire du one-shoot, en gros, un monostable, il suffit, une fois dans l'ISR de désactiver l'int TOVF2 via le registre TIMSK2 (TIMSK2 &= 0xFE; ). Le timer continuera à tourner, mais l'int ne sera plus déclenchée. Pour relancer le monostable, il suffit de faire TCNT2=0; TIMSK2 |= 1;

J'utilise ça très souvent, car ça permet de gérer trois ISR de tempo sur le même timer, donc optimisation des ressources...

@ MicroQuettas : Cette solution a l'air simple, je l'essaierai.

@Super_Cinci : Ce que vous me proposez est ce que j'avais essayé de faire et qui ne fonctionnait pas ... mai qui fonctionne si je rajoute l'instruction "TIFR2 = 0b00000001; // TOV2 -> RaZ du bit d'overFlow" dans ma fonction "pulse()"
@ pepe : pour l'instant, je ne maitrise pas bien, voire pas du tout les modes PWM. Il faut que je les regarde de plus près avant que de pouvoir comprendre votre solution.

En tous cas, merci à chacun pour les idées que vous m'avez apportées.

Cordialement.

Pierre

@ pepe : J'ai essayé ce que vous me proposez à la réponse #2 (que j'ai cru comprendre après lecture des spécificités du Timer1), mais j'obtiens un calme plat aux sorties 9 ou 10 de mon Pro- Mini.

J'ai sûrement raté quelque chose : Voici mon code :

NOTA : j'ai essayé les deux formes d'écriture des registres 16 bits : par octet ou d'un coup : même résultat.

void setup() {
  // put your setup code here, to run once:
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  TCCR1A = 0b01010010; // Mode 14 et CTC
  TCCR1B = 0b00011010; // Mode 14 et clock/8
  /*  ICR1L = 0x10; // faible valeur sur ICR
    ICR1H = 0x00;
    OCR1AL = 0x00;
    OCR1BL = 0x00;
    OCR1AH = 0x10; // durée d'environ 2 mS
    OCR1BH = 0x10; // durée d'environ 2 mS*/
  ICR1 = 0x0010;
  OCR1A = 0x1000; // durée d'environ 2 mS
  OCR1B = 0x1000; // durée d'environ 2 mS

}

uint32_t t0;
void loop() {
  // put your main code here, to run repeatedly:
  if (millis() - t0 > 10) {
    t0 = millis();
    /*    TCNT1L = 0x01;
        TCNT1H = 0x00;*/
    TCNT1 = 0x0100; // Valeur de départ > ICR1
  }
}

Cordialement.

Pierer

Merci pepe. Le fait que ma solution ne marchait pas était que je n'avais pas choisi le bon Mode "Compare Out Mode". J'avais pris le mode "toogle" (0:1) au lieu du mode "set/clear" (1:1).

Un petit inconvénient, s'il en est, est que ce mode impose d'utiliser la pin 9.

Cordialement.

Pierre

pepe:
Cela a plus de chance de le devenir dans le monde Arduino, notamment quand on utilise des shields, car la démarche de conception y est menée à l'envers : au lieu de réaliser un circuit et un logiciel en fonction des capacités et des limitations du micro-contrôleur, on impose a priori une configuration, quitte à ne plus pouvoir tirer partie des possibilités initialement offertes et à devoir éventuellement acheter le modèle au-dessus pour réaliser ce qui était prévu.

Entièrement d'accord.
D'un autre coté la vente de shields et de cartes plus performantes c'est alimentaire.
Le projet Arduino n'est pas un projet bizounours.