Je m’initie à l’Arduino et fais des petits montages simples qui fonctionnent assez bien et cela encourage.
Mais, mes montages n’ont qu’une fonction de simple tâche.
A savoir par exemple ; une led s’allume quand il pleut puis s’éteint quand il ne pleut plus.
J’aimerai réaliser pour mes petits neveux un jeu de lumière à mettre dans leurs chambres.
Ce jeu de lumière et une sorte de vu-mètre géant réalisé par des bandes de ruban led de 20 cm de long sur 27 ‘’étages’’ piloté par une Arduino Méga. Il fonctionnera comme un chenillard. Pour l’instant pas de souci pour la partie électronique et programmation.
Le souci est, pour améliorer l’effet, je vais placer un deuxième vu-mètre identique, tout contre celui-ci avec des programmes identiques et d’autres différents ou en oppositions.
C'est-à-dire, par exemple quand un vu-mètre descend sur toute sa hauteur, l’autre va monter.
Deux vu-mètre, deux programmes en un seul. Mon Arduino devient multitâche et cela je ne sais pas faire.
Faire monter un vu-mètre par une boucle for pas de problème mais faire descendre l’autre en même temps………. Je sèche.
Si vous pouviez me guider, je vous en serais reconnaissant.
Rien de bien dur dans ton idée, mais il va falloir oublier la fonction "delay()" au profit des timers.
delay() impose un temps d'inactivité de x secondes (entre deux actions, on ne peut rien faire d'autre qu'attendre)...
les timers déclenchent une action toutes les x secondes (entre deux actions, on fait tourner loop() ou on ne fait rien)...
le premier multitâche sous windows 3.x était simple : toutes les 20ms, on passe la main au programme suivant (soit 50 fois par seconde, l'oeil humain n'y voit rien).
Voilà des premières pistes de réflexion, mais je sais que ce sont des notions qui font peur. Le temps passé à les découvrir sera largement récompensé! J'ai développé des systèmes entièrement gérés par les timers et interruptions. La boucle loop() est vide, et pourtant, mon arduino ne chôme pas!
Le gros avantage, c'est qu'une fois maîtrisé, on peut définir des priorités de traitement, s'offrir le luxe du "réentrant"... l'exécution de chaque tâche dépend d'un évènement externe au CPU (interruption via un capteur ou un bouton, timer, compteur d'évènements, comparateur analogique...) et cela se fait tout seul. Il faut juste savoir exactement ce qu'on veut.
Le passage au traitement par interruptions modifie un peu la programmation. Là où on avait une boucle while ou for (boucle récursive) avec des variables locales, il faut utiliser un if (ponctuel) avec des variables globales. Mais au final, ça marche tout pareil...
donc la solution : les timers (il y en a 7 dans un mega, ce qui peut permettre de gérer jusqu'à 17 tâches "timées", mais une "infinité" (plus de 10 000 à la louche) si on crée des "couches"...) Mais là comme ça, pas facile d'expliquer, mieux vaut partir de ce que tu cherches exactement à faire et en profiter pour faire un exemple... la datasheet prend une centaine de pages sur les timers, donc j'aurai du mal à les recopier ici...
ouais, t'y vas peut-être un peu fort pour un débutant même si ce que tu dis est bien ce qu'il faudrait faire pour "bien le faire".
Il y a tout de même des techniques "intermédiaires" plus simples à comprendre pour commencer à appréhender les joies du "réentrant"...
A mon humble avis, commencer par utiliser millis() au lieu de delay() serait déjà un bon début...
Charge ensuite d'écrire le contenu des fonctions setupA(), loopA(), etc. sans jamais utiliser la fonction delay(), ce qui permet d'enchaîner rapidement le différentes fonctions loop.
Et tu peux utiliser des variables globales pour qu'une donnée mise à jour par le processus A (exemple : valeur d'un capteur) soit utilisée dans un autre processus.
Ce type d'approche permet de répondre à plein de besoins simples sur arduino.
Il présente aussi l'avantage de structurer le code et de faciliter sa mise au point : on peut ajouter progressivement les processus, les valider et passer au suivant.
Et pour aller un peu plus loin, sans aller jusqu'aux problèmes inhérents aux interruptions et à la réentrance, un ordonnanceur peut être bien pratique.
Personnellement j'utilise cette bibliothèque pour tous mes développements.
Merci à vous pour votre aide. C'est super sympa.
Super_Cinci, ta méthode est faite pour des pros, je n'ai hélas pas le niveau pour cela.
Je vais utiliser les millis () que Zorro_X me conseille gentiment.
bricoleau, je pense que la solution que tu me propose est la bonne.
Mais j'ai du mal a en appréhender la syntaxe.
Pour faire simple et pour bien comprendre, si par exemple sur la pin 10 de mon arduino, je veux faire clignoter une led deux fois par seconde et que sur la pin 11 je veux faire clignoter une led toute les secondes le tout bien entendu en même temps pourrais-tu m'aiguiller sur la syntaxe.
On ne ressort jamais de l'appel ordonnanceur.lancer(), donc on peut le placer où on veut.
C'est même mieux de le mettre dans setup() car là au moins il n'y a plus d'ambiguïté sur son fonctionnement.
Certains ordonnanceurs se bornent en effet à exécuter la prochaine tâche et rendent la main, ce qui oblige à les appeler en boucle depuis le loop.
Mais ce n'est pas le cas de celui-ci.
Nb : il existe toutefois une méthode ordonnanceur.stopper() appelable depuis n'importe quelle tâche, pour arrêter l'ordonnanceur et sortir de la méthode lancer(). Ainsi qu'une méthode estActif() pour savoir si l'ordonnanceur est en cours d'exécution ou non.
Je les ai prévues pour être propre, mais avoue n'en n'avoir pas eu l'usage jusqu'à présent.
balisto56:
C'est-à-dire, par exemple quand un vu-mètre descend sur toute sa hauteur, l’autre va monter.
Deux vu-mètre, deux programmes en un seul. Mon Arduino devient multitâche et cela je ne sais pas faire.
Faire monter un vu-mètre par une boucle for pas de problème mais faire descendre l’autre en même temps………. Je sèche.
Le plus simple est de gérer les 2 vu-mètres dans la même boucle.
Il ne s'agit pas de multi-tâche mais de 2 actions décalées du temps (imperceptible) d'exécuter une instruction.
balisto56:
Pour faire simple et pour bien comprendre, si par exemple sur la pin 10 de mon arduino, je veux faire clignoter une led deux fois par seconde et que sur la pin 11 je veux faire clignoter une led toute les secondes le tout bien entendu en même temps pourrais-tu m'aiguiller sur la syntaxe.
Voici un code illlustrant ce que tu suggères avec les sorties 10 et 11 :
// date pour la gestion du temps de la LED1
int dateLed1;
// etat de la LED 1
bool led1Allumee = false;
void led1_setup()
{
pinMode(10, OUTPUT);
// initialisation de la date de la led 1
dateLed1 = millis();
}
// date pour la gestion du temps de la LED2
int dateLed2;
// etat de la LED 2
bool led2Allumee = false;
void led2_setup()
{
pinMode(11, OUTPUT);
// initialisation de la date de la led 2
dateLed2 = millis();
}
void led1_loop()
{
// date de maintenant
int date = millis();
// si 250ms se sont écoulées
// Le clignottement 2 fois par seconde, ca fait 2 x 250ms / seconde :
// 250ms éteint -> 250ms allumé -> 250ms étient -> 250ms allumé => 1 seconde
if ( (date - dateLed1) >= 250 )
{
// changer l'état de la led
led1Allumee = !led1Allumee; // inversion de l'état
// changer l'état de la sortie
digitalWrite(10, (led1Allumee ? HIGH : LOW));
// mettre à jour la date de la LED
dateLed1 = date;
}
}
void led2_loop()
{
// date de maintenant
int date = millis();
// si 1000ms se sont écoulées
// Le clignottement toutes les secondes, ca fait :
// 1s éteint -> 1s allumé
if ( (date - dateLed2) >= 1000 )
{
// changer l'état de la led
led2Allumee = !led2Allumee; // inversion de l'état
// changer l'état de la sortie
digitalWrite(11, (led2Allumee ? HIGH : LOW));
// mettre à jour la date de la LED
dateLed2 = date;
}
}
void setup()
{
led1_setup();
led2_setup();
}
void loop()
{
led1_loop();
led2_loop();
}
Dans ce paragraphe tu trouveras un résumé de ce qui se fait avec millis(). Sinon, le tuto d'eskimon cité plus haut le détaille vraiment très bien.
En pratique tu peux utiliser autant de variables "dateQuelquechose" que t'as besoin de compter le temps.
Je n'avais pas eu le temps de répondre avant, désolé. Les autres réponses, notamment l'ordonnanceur de bricoleau ont l'avantage de "masquer" ce genre de choses et souvent de "bien le faire" (je ne sais pas comment c'est codé dans la librairie de bricoleau) en utilisant les timers du processeur comme le suggérait Super_Cinci.
Ce qu'il faut retenir aussi, c'est le coté "réentrant" auquel faisait référence Super_Cinci : la mécanique et la logique changent un peu maintenant. Il faut garder l'état de ta LED quelque part pour pouvoir l'utiliser lorsque "t'y reviens", c'est ce que je fais avec les variables "ledXAllumee". Mais ca peut être toute autre chose comme un tableau, pour gérer un chenillard par exemple...
En espérant que c'est au moins plus clair maintenant !