[RESOLU] Curiositée - Delay();

Salut!

je suis à mes balbutiements de programmation en C, et je suis face à une énigme!

Mon code est le suivant:

int sCount=2;                                       //pin Compteur d'impulsion cadran
int sRead=3;                                        //pin d'interruption front descendant, "readWriteInterrupt"
int lcdLed=9;
int ywLed=12;
int rdLed=13;
int volatile nCount=0;
int volatile nEssai=0;
int volatile dialArray[10]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

void setup() {
  Serial.begin(9600);
  pinMode(sCount, INPUT_PULLUP);
  pinMode(sRead, INPUT_PULLUP);
  pinMode(lcdLed, OUTPUT);
  pinMode(ywLed, OUTPUT);
  pinMode(rdLed, OUTPUT);
  attachInterrupt(1, readWriteInterrupt, RISING);
}

void loop() {
  interrupts();
  while(digitalRead(sRead)==LOW){
  if(digitalRead(sCount)==0){
    digitalWrite(ywLed, HIGH);
    nCount++;
    delay(50);
  }
  digitalWrite(ywLed, LOW);
  }
  if(nEssai==10){
  noInterrupts();
  Serial.println("Hello World");
  nEssai=0;
  digitalWrite(rdLed, HIGH);
  delay(300000);
  digitalWrite(rdLed, LOW);
  }
  interrupts();
}

void readWriteInterrupt(){
  if(nCount==10){
  nCount=0;
  }
  dialArray[nEssai]=nCount;
  Serial.print(dialArray[nEssai]);
  nEssai++;
  nCount=0;
}

Vous remarquerez qu'à la ligne 35 un delay de 300000, milliseconde selon https://www.arduino.cc/en/Reference/Delay donc, la "rdLed" devrait être "HIGH" 300s non?

Seulement la led s'allume 5 secondes. chronomètre à la main!

Je comprends pas...

Merci pour vos lumières!

Bonjour,

Ta constante est un long. Essaie de mettre delay(300000L);

Je précise encore que le but est d'avoir une tempo de 3s et non pas 300 (:

Le fait de mettre (300000L) ne change rien au problème, la fonction fait automatiquement appel à une constante de type long non?

Je remarque une chose bizarre à propos du message "Hello World":

Au 10ème essai un H s'affiche, et c'est seulement à la fin de ces 5 secondes que le reste du message apparait.

Pour ce qui est de l'utilisation de l'interruption je me suis fait la même reflexion.

J'ai fais ce choix pour des raisons d'apprentissage. Si je raccourci au maximum l'interruption le problème est le même.

Ma carte est une ArduinoUNO.

Ganjouille:
Au 10ème essai un H s'affiche, et c'est seulement à la fin de ces 5 secondes que le reste du message apparait.

C'est parce que tu as dévalidé les interruptions.

Sa marche!

Maintenant c'est clair! Toutes les fonctions fesant appels au timer ont besoin des interruptions! Merci!
J'arrive pas vraiment à saisir le fond, et je ne comprends pas exactement ton code pepe. Très intéressant cependant!

Ce que j'ai compris c'est que le flag OverFlow est mis a jour dans le uC grâce à une interruptions, ce qui est logique. Si ce n'est pas le cas, le compteur "Déborde".

Le poids fort et faible dont tu parle correspond au MSB et LSB?

CE site est-il pertinant dans mon cas?

Merci pour vos réponses, je vais essayer de mettre le sujet en résolu!

Si overflow est codé sur 22bits, il peut prendre 484 états différents. 8 bits donnent 255, le total de combinaison donnent 255x484=123420ms puisque overlow correspond à des pas de 1ms, ce qui donne à peu près 123s. Est-ce que la raison du nom "poid fort" vient du fait que c'est lui qui défini la valeur "maximum"? Ou je me plante totalement? (:

f = pulse en 1s = 250000 impulsions sur le compteur matériel codé sur 8 bits. Ce qui donne une résolution de 1/250000=4us! Facile...

Le poids faible contient 255 valeurs correspondant à des pas de 4us donnent une plage de 255x4 = 1020valeurs retournées avant que le compteur "déborde" et qui est le contenu des bits 2-9 dans le (uint_16_t)micros(). Mais enfaite le compteur déborde. Mais puisque la valeur 1020 dépasse les 255 possible sur 8bits cette valeur eststockée ailleur dans la fonction millis().

1020 valeurs correspondant à des pas de 4us donnent 4080us. (mais...on s'en fout!)

Dans ce bout de programme on voit la variable de type unsigned long "ms",

void delay(unsigned long ms)
{
	uint16_t start = (uint16_t)micros();

	while (ms > 0) {

Je la comprend comme étant la variable utilisée par delay mais je comprend pas comment elle peux rentrer dans la boucle while si ms est à 0 par hasard...
Je sens que je me perds un peu quand je lis le code, je n'arrive pas à faire les liens. Je ne trouve également pas la function de yield() mais je vais aller voir la fonction micros() et essayer d'en apprendre plus sur le language C...

Mais dans le fond delay() dépend de micros() qui dépend des interruptions... La mémoire finale du compteur logiciel peut être bien supérieur à 1020 seul la différence compte, donc si à un moment t1 count=20000 l'interruption se declenchera à t2 count=2000-21000=1000 et overflow remettra count=20000. Si les interruptions sont désactivées alors tout d'un coup à t3 count=1000 devient possible. et comme 1000-20000=-19'000. Ceci associé à un type unsigned donne un chiffre hasardeux j'imagine.

Merci Pour les explications et pour les quelques pistes! J'espère que je me plante pas totalement haha :smiley:

Si je peux encore ajouter à la confusion, sur DUE c'est encore différent.

L'AT91SAM dispose d'un décompteur 24 bits (systick timer). Au passage à zéro, par interruption, il incrémente une variable système déclarée dans 'timetick.c': static volatile uint32_t _dwTickCount;, c'est celle retournée par GetTickCount(),ou par millis().
Le décompteur est programmer pour générer une IT toutes les 1mS pour l'utilisation de delay().

Je pense que cela entraine un fonctionnement légèrement different de celui des AVR.

Merci pour les précisions... :slight_smile:

Enfaite les bits [0-1] restent à zéro car:

T1[31:0...0:10][9:00 0000 0000:0]micros=0  start=micros=0
T2[31:0...0:10][9:00 0000 0100:0]=4!
T2[31:0...0:10][9:00 0000 1000:0]=8!
T3[31:0...0:10][9:00 0000 1100:0]=12!
...
T4[31:0...0:10][9:11 1111 1100:0]=1000   start+=1000=1000
...
T5[31:0...0:10][9:11 1111 1100:0]=1020
T6[31:0...1:10][9:00 0000 0000:0]=1024
T7                    interruptions désactivées
T8[31:0...1:10][9:11 1101 0000:0]=2000   start +=1000=2000
T9[31:0...1:10][9:00 0000 0000:0]=1024

A T9 le calcul micros-start = 1024-2000 = -976 donne 64560 en unsigned long ->start=+1000 et ms-- alors que le temps réel écoulé entre les 2 est de 48us. Passionnant!

CQFD!

Merci beaucoup pour l'aide!

bilbo83:
Si je peux encore ajouter à la confusion, sur DUE c'est encore différent.

Pour le moment, je fais avec ce que j'ai... Mais ce que tu dis est toujours bon à savoir (: A bientôt!

Une réponse qui ne résout pas la difficulté, en fait naître mille autres.

proverbe chinois :slight_smile:

La raison pour laquelle les deux bits de poids faible restent inchangés est que la valeur représente des microsecondes, et que le prédiviseur du timer 0 a été programmé pour le faire avancer d'un pas toutes les 4 µs (= 64/16 MHz).

Déjà la pour moi sa coinçait. J'ai lu sa dans le fichier wiring.c à la ligne 42:

// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
// the overflow handler is called every 256 ticks
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))

Ce qui me chagrine vraiment dans cette instruction, c'est que je la comprend de cette façon: (clockCyclesToMicrosecondes=64*256=16384... et alors?
Et la j'me suis dit qu'il doit y avoir un lien avec d'autres codes et que:

#include "wiring_private.h"

N'était pas la pour rien...

Maintenant je comprend que le "prescaler" est un diviseur matériel et c'est une mise à l'échelle. Dans ce cas 250kHz(16*10^6Hz/64Hz=250000Hz)
J'ai fait le lien de 8 ou 16Mhz d'après:

// the fractional number of milliseconds per timer0 overflow. we shift right
// by three to fit these numbers into a byte. (for the clock speeds we care
// about - 8 and 16 MHz - this doesn't lose precision.)
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)

Je suis tout de suite tombé sur 250kHz avec les 16MHz/64Hz, et le lien avec 256 et les 8 bits du timer m'est évident aussi, mais sa m'a pas aidé plus. :confused: J'ai laissé de coté et passé à la couche supérieure (:

Et:

#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)

M'a mis la puce à l'oreille avec le shiftBit à droite de 3(=0, 1, 2, 3, 4=4! Farfelu?) mais je comprends pas le modulo car je ne saisis pas les valeurs impliquées... Bref, la j'me perds...

Il faut que je regarde presque ce que chaque mot veux dire hehe...
et la je tombe sur du uint8_t (fixedWidth integrer de 8bit!) fixed->tourne en boucle?! J'ai trouvé une référence intéressante? Esc-ce que sa s'applique à l'IDE d'arduino?

Je vais encore bien prendre le temps de comprendre ce que tu m'a écrit, lire ces codes, faire quelques tables de vérités et continuer de creuser dans ce gouffre... Je suis attiré par le coté obscure de l'éléctronique! Le numérique!

Peux-être un peu de multiplexage avec un petit écran OLED qui va arriver, et programmer mon module GSM pour faire de mon vieux téléphone à cadran un super portable NewAge! :o "il est fou" :o

Tu me file de super pistes, C'est sympa de prendre le temps de m'expliquer :slight_smile: Mais je comprendrai si t'en as marre :smiley:

p.s: je n'arrive pas à faire les cadres du code plus petit...