Problème arrêt, fonction millis()

Salut à tous,

Je suis nouveau sur arduino et dans la programmation.
J'essaye de faire une machine de curing pour mes pièces en SLA, sortie de FAB-ADD.
J'ai toute ma structure, mon environnement, etc... Il me reste plus qu'à coder le côté elec.

J'ai fais un premier programme :

Celui-ci me permet lors de l'appui sur un bouton poussoir d'allumer des LED's pendant 5s et de faire fonctionner un servo à 12rpm. Et ainsi de suite à chaque appui sur le bouton poussoir.

Le but recherché est maintenant de mettre un temps d'opération plus long (1heure) ainsi que de rajouter une option qui me permettrait d'arrêter ma boucle et d'éteindre led et moteur si j'appuie sur le bouton poussoir lors du cycle.

Ce qui revient pour moi, à changer mon delay de 5000ms à 360000ms.

Première question, est-ce qu'il est pertinent de mettre 360000ms dans un delay ?

Et concernant la partie "sortir de la boucle" grâce au bouton poussoir je vous avoue que je suis un peu perdu, enfaite l'objectif de la manoeuvre serait de créer un bouton type Pause, sur le même boutton qui me permet d'allumer mon système.

Je vous joins le code et la photo de mon montage que j'ai réalisé pour le moment, si j'ai omis de vous fournir des élèments je suis bien entendu à votre disposition pour essayer de vous les fournir.

#include <Servo.h>// on importe la bibliothèque
Servo servo; // on crée l'objet Servo
int pinBouton, pinLed,pinLed1,pinLed2,pinLed3,pinLed4,pinLed5,pinLed6,pinLed7,pinLed8,pinLed9, i;
boolean etatAllumage;
unsigned long previousMillis=0;
void setup()
{
  ;
  //initialisation des variables
  
  i=1;
  pinBouton = 2;
  pinLed = 3;
  pinLed1 = 4;
  pinLed2 = 5;
  pinLed3 = 6;
  pinLed4 = 7;
  pinLed5 = 8;
  pinLed6 = 9;
  pinLed7 = 10;
  pinLed8 = 11;
  pinLed9 = 12;
  etatAllumage=0;
  //définition des modes
  servo.attach(13);
  pinMode(pinBouton, INPUT_PULLUP);
  pinMode(pinLed, OUTPUT);
  pinMode(pinLed1, OUTPUT);
  pinMode(pinLed2, OUTPUT);
  pinMode(pinLed3, OUTPUT);
  pinMode(pinLed4, OUTPUT);
  pinMode(pinLed5, OUTPUT);
  pinMode(pinLed6, OUTPUT);
  pinMode(pinLed7, OUTPUT);
  pinMode(pinLed8, OUTPUT);
  pinMode(pinLed9, OUTPUT);
  Serial.begin(9600);
}
void loop()
{

  {
    while (etatAllumage) {
      digitalWrite(pinLed, HIGH);//on allume la LED
      digitalWrite(pinLed1, HIGH);//on allume la LED
      digitalWrite(pinLed2, HIGH);//on allume la LED
      digitalWrite(pinLed3, HIGH);//on allume la LED
      digitalWrite(pinLed4, HIGH);//on allume la LED
      digitalWrite(pinLed5, HIGH);//on allume la LED
      digitalWrite(pinLed6, HIGH);//on allume la LED
      digitalWrite(pinLed7, HIGH);//on allume la LED
      digitalWrite(pinLed8, HIGH);//on allume la LED
      digitalWrite(pinLed9, HIGH);//on allume la LED
      servo.write(100);
      delay(5000);
       digitalWrite(pinLed, LOW);//on allume la LED
      digitalWrite(pinLed1, LOW);//on allume la LED
      digitalWrite(pinLed2, LOW);//on allume la LED
      digitalWrite(pinLed3, LOW);//on allume la LED
      digitalWrite(pinLed4, LOW);//on allume la LED
      digitalWrite(pinLed5, LOW);//on allume la LED
      digitalWrite(pinLed6, LOW);//on allume la LED
      digitalWrite(pinLed7, LOW);//on allume la LED
      digitalWrite(pinLed8, LOW);//on allume la LED
      digitalWrite(pinLed9, LOW);//on allume la LED
      servo.write(90);
      etatAllumage=0;
      delay(100);
      break;
      
    }
   

  }

  boolean etatPinBouton = digitalRead(pinBouton);
  Serial.println(etatPinBouton);
  //test des conditions
  if (!etatPinBouton)
  {
    if (etatAllumage) 
    {
      etatAllumage=0; 
    }
    else //sinon
    {
      etatAllumage=1; 
    }
  }
  
}

Je pense qu'il faut utiliser la fonction millis(), mais j'ai du mal à comprendre son fonctionnement !

En vous remerciant par avance,
Aymeric

arduino.JPG

Une explication claire de millis() a été fournie par Zlika en Exiger une action sur la durée - Français - Arduino Forum

J'ai vu quelques lourdeurs dans votre code -sans me prononcer sur sa validité- :
a) vous avez tout plein de sorties; le code serait plus facile à écrire -et prendrait moins de place dans votre arduino- si vous les initialisiez en sortie et les allumiez avec des boucles . Ce qui implique de mettre pinLed....pinLed7 dans un tableau.
b) il y a une inconsequence entre les commentaires et l'extinction des LEDs -le copier coller est abominable-
c)

 boolean etatPinBouton = digitalRead(pinBouton);
  Serial.println(etatPinBouton);
  //test des conditions
  if (!etatPinBouton)
  {
    if (etatAllumage)
    {
      etatAllumage=0;
    }
    else //sinon
    {
      etatAllumage=1;
    }
  }
}

pourrait se réecrire (plus facile à saisir d'un coup d'oeil

boolean etatPinBouton = digitalRead(pinBouton);
 Serial.println(etatPinBouton);
 /test de/s conditions
 if (!etatPinBouton)  {

  etatAllumage= 1 - etatAllumage;
// je suppose que True et 1 sont pareils, et on voit plus facilement
// que pinBouton fait basculer  etatAllumage; si ma correspondance int bool est folklo, nier etatAllumage
//  etatAllumage= !etatAllumage; //  
   

 }
}

Bonjour amrKRDM

Cordialement,
bidouilleelec

Première question, est-ce qu'il est pertinent de mettre 360000ms dans un delay ?

Usage du delay() :
Si ton programme ne fait qu'une seul chose tu peux mettre un delay(x) dans cette chose.
Exemple le programme Blink qui ne fait pas autre chose que de faire clignoter une diode.

Si ton programme fait plusieurs choses il ne faut pas utiliser delay(x) car cet ordre bloque le microcontrôleur et l'empêche de traiter le reste du programme.

Le seul cas où l'usage de delay(x) est incontournable c'est quand tu interroge un composant par I2C ou SPI (liste non limitative) et que le composant a matériellement besoin d'un temps de pause pour préparer sa réponse.
Cet usage est vraiment rare et exceptionnel.

Valeur max de delay() :
Tu as toutes les possibilités pour trouver l'information par toi même.
Il y a sur ce site une source de documentation essentielle : onglet Ressources-> Reference. Tu y trouvera la définition de toutes les fonctions wiring/arduino.

Dans les définitions de delay(x) il y a le type de variable que delay() attend.
La valeur max dépendra du type que tu lira dans la doc : entier court ou byte (8bits), entier "normal" ou int (16 bits) ou long integer (32 bits).
Je te laisse regarder.

Première question, est-ce qu'il est pertinent de mettre 360000ms dans un delay ?

Non:
a) Si vous voulez temporiser une heure, il faut mettre 3600000ms (un tout petit zero de plus)
b) Quand avr-g++ voit une constante, il est bien capable de la convertir en entier (borné à 65536 sur arduino). Pour forcer le delay -en faire un uint32_t ou unsigned long, il faut écrire 3600000UL pour être sur qu'il ne tronquera pas.... et ne vous fera pas tourner en bourrique, avec des heures de quelques minutes (une faille temporelle) .

Stackoverflow me confirme ma pire crainte c - what is the reason for explicitly declaring L or UL for long values - Stack Overflow embedded - Making large constants in C source more readable? - Stack Overflow
Il faut (au pire, ça ne fera pas de mal) déclarer l'heure en unsigned long -long pour les petits arduini- (et le terminer par UL)
Ma remarque est valable aussi quand vous passerez sagement à millis()

Passage à millis() effectué j'ai super bien compris avec le post de Zlika.

Je suis arrivé à résoudre mon problème et j'ai bien compris la différence entre millis() et delay().

C'est cool je vais pouvoir aller un peu plus loin maintenant, prochaines étapes, croiser les millis() pour un allumage de LED's en progressif !

En vous remerciant encore !
Aymeric

dbrion06:
b) Quand avr-g++ voit une constante, il est bien capable de la convertir en entier (borné à 65536 sur arduino). Pour forcer le delay -en faire un uint32_t ou unsigned long, il faut écrire 3600000UL pour être sur qu'il ne tronquera pas.... et ne vous fera pas tourner en bourrique, avec des heures de quelques minutes (une faille temporelle) .

c'est un peu plus subtil que cela, mais la recommandation est bonne :slight_smile:

en pratique ce n'est pas just avr-g++ mais la spécification du langage C ou C++ qui dit que en l'absence de suffixe, le compilateur allouera la constante dans le type signé le moins gourmand en mémoire pour représenter cette constante dans l'ordre suivant: int, long int, long long int.

Donc si vous faites unsigned long t0 = 60000; // 1 minute le compilateur voir la constante 60000, elle ne tient pas sur int (max sur 2 octets est 32767) et donc allouera un long int. Ensuite comme la valeur n'est pas négative, il n'y aura pas de soucis à la convertir en unsigned long et tout fonctionne.

Là où le bât blesse c'est quand vous faites des calculs. si vous écrivezunsigned long t1 = 60 * 1000; // 60 secondes = 1 minutelà le compilateur voit 60 donc il le met dans un int puisque ça rentre, il voit 1000 qu'il met aussi dans un int puisque ça rentre et comme les types sont compatibles, il n'y a pas promotion, le pré-processeur effectue le calcul donc en int. 60000 bien sûr ne tient pas sur un int
donc l'opération déborde et vous obtenez -5536 qui sera ensuite convertit en unsigned long ce qui vous donnera 4294961760... Oops...

Notez que le compilateur est sympa et vous donnera un warning

** **warning: integer overflow in expression [-Woverflow] unsigned long t1 = 60 * 1000;                       ^** **

Donc si vous ne voulez pas de soucis il faut forcer le calcul en formal long ou long non signé en utilisant pour au moins une des deux constante le suffixe L ou UL

unsigned long t2 = 60 * 1000L;
unsigned long t3 = 60L * 1000;

Quand le compilateur voit cela, une des deux valeurs va dans un int, l'autre dans un long et donc au moment de faire le calcul, le pré-processeur fait la promotion du plus petit type vers le plus grand et tout est fait en long et le résultat est correct.

Voici un bout de code d'exemple

unsigned long t0 = 60000;
unsigned long t1 = 60 * 1000;
unsigned long t2 = 60 * 1000L;
unsigned long t3 = 60L * 1000;

void setup() {
  Serial.begin(115200);
  Serial.print(F("t0 = ")); Serial.println(t0);
  Serial.print(F("60 * 1000 = ")); Serial.println(60 * 1000);
  Serial.print(F("t1 = ")); Serial.println(t1);
  Serial.print(F("t2 = ")); Serial.println(t2);
  Serial.print(F("t3 = ")); Serial.println(t3);
}

void loop() {}

qui vous affichera dans la console série

[color=purple]t0 = 60000
60 * 1000 = -5536
t1 = 4294961760
t2 = 60000
t3 = 60000
[/color]

Il serait donc interessant une constante msHeure de la forme
const uint32_t msHeure = 3600UL * 1000UL ; // je sais, mais 2 précautions valent mieux qu'une

dbrion06:
Il serait donc interessant une constante msHeure de la forme
const uint32_t msHeure = 3600UL * 1000UL ; // je sais, mais 2 précautions valent mieux qu'une

ou

const uint32_t uneSeconde = 1000UL;
const uint32_t uneMinute = 60 * uneSeconde;
const uint32_t uneHeure = 60 * uneMinute;
const uint32_t unJour = 24 * uneHeure;

et éviter de faire cela avec des #define qui n'embarquent pas de typage fort

Je me suis efforce d'éviter les #define (quoiqu'ils soient agnostiques en ce qui concerne le langage: le preprocesseur "C" est bien commode en Fortran -j'en suis sûr- et, m'a-t-on dit, en assembleur...) et je ne me sers plus de #define pour des constantes ou des fonctions (ça me sert encore à mettre des bouts de code en "commentaire", par compilation conditionnelle: cppcheck explore toutes les possibilités)

pour la compilation conditionnelle c'est bien, pas de soucis