A défaut de pouvoir l'éteindre, je souhaite pouvoir mettre en veille profonde mon Arduino Mini en pressant un bouton pendant 2 secondes. Mais aussi pouvoir le réveiller en pressant sur ce même bouton toujours 2 secondes.
Pour vérifier si le bouton est bien pressé durant 2 secondes, j'utilise une boucle for qui vérifie toutes les 100ms si l'état de la pin est toujours HIGH durant 20 cycles (soit 2 secondes).
Si les conditions sont réunies, alors j'éteint tout (juste une led pour ce test), et je met l'Arduino en veille grâce à la bibliothèque LowPower.h
J'utilise simplement la ligne de code LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF)
J'utilise une variable x qui s'incrémente à chaque fin de loop et je l'affiche simplement pour vérifier que mon Arduino s'est bien mis en veille. Ca a l'air de fonctionner.
Seulement voilà... une fois qu'il est en veille, comment je fais pour le réveiller avec ce même bouton ?
Voici mon code :
#include "LowPower.h"
const int bouton = 2 , led = 3 ;
int sleep_time = 20 ; // Le temps qu'il faut au bouton pour mettre en veille (en dicimes de secondes)
int x = 0 ;
void setup() {
Serial.begin(9600);
pinMode(bouton, INPUT);
pinMode(led, OUTPUT);
}
void loop () {
if (digitalRead(bouton) == HIGH)
{
for (int i = 0 ; i <= sleep_time ; i++)
{
if (digitalRead(bouton) == LOW)
{
// Il y a interruption dans le pressage du bouton, on quitte la boucle
break;
}
else if (digitalRead(bouton) == HIGH && i == sleep_time)
{
// On a bien maintenu le bouton appuye
// On eteint tout et on met en veille profonde
digitalWrite(led, LOW);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
}
delay(100);
}
}
// La led temoin est toujours allumee
digitalWrite(led, HIGH);
// On incremente une valeur et on l'affiche, simplement pour savoir si on est en veille ou pas
x++;
Serial.println(x);
delay(100);
}
Après quelques test, je tente un début d'auto réponse.
Et si j'utilisait un attachInterrupt sur l'entrée du bouton ?
Je renvoie alors vers une autre fonction qui ne fait rien en boucle tant que le bouton est en etat LOW.
Ca a l'air de fonctionner. Sauf que je ne sais pas si c'est une bonne idée de mettre un while vide qui tourne en boucle quand je suis en "veille". Est-ce que ça fait pas justement trop travailler l'Arduino, ce qui serait contre-productif en consomation...
Voici un deuxième code donc :
#include "LowPower.h"
const int bouton = 2 , led = 3 ;
int sleep_time = 20 ; // Le temps qu'il faut au bouton pour mettre en veille (en dicimes de secondes)
int x = 0 ;
void setup() {
Serial.begin(9600);
pinMode(bouton, INPUT);
pinMode(led, OUTPUT);
}
void wakeUp()
{
while ( digitalRead(bouton) == LOW )
{
}
}
void loop () {
if (digitalRead(bouton) == HIGH)
{
for (int i = 0 ; i <= sleep_time ; i++)
{
if (digitalRead(bouton) == LOW)
{
// Il y a interruption dans le pressage du bouton, on quitte la boucle
break;
}
else if (digitalRead(bouton) == HIGH && i == sleep_time)
{
// On a bien maintenu le bouton appuye
// On eteint tout
digitalWrite(led, LOW);
//Et on se met en veille profonde
attachInterrupt(0, wakeUp, RISING);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
detachInterrupt(0);
}
delay(100);
}
}
// La led temoin est toujours allumee
digitalWrite(led, HIGH);
// On incremente une valeur et on l'affiche, simplement pour savoir si on est en veille ou pas
x++;
if (x == 10)
{
x = 1;
}
Serial.println(x);
delay(100);
}
La bibliothèque "Button" a l'air pas mal du tout,effectivement ça peut simplifier mon code.
Tant pis s'il est impossible de réveiller l'Arduino en appuyant plusieurs secondes... Je me contenterai pour l'instant de le mettre en veille en appuyant plusieurs secondes, et de le réveiller avec un simple appui.
En ce qui concerne le while dans l'interruption, j'aimerais comprendre : Pourquoi c'est "mal" ?
Quel est le risque ?
Et si ce n'est pas une bonne solution, alors comment faire ? Je suis un peu à court d'idées...
L'exemple Blink Without Delay fonctionne parce que il y a boucle infinie via le void loop().
Or justement ma fonction wakeUp() n'est pas une boucle. A moins que je lui même un while. Ce qui apparemment est "interdit".
Je pense que ça doit être possible en procédant comme ceci :
Bonjour,
moi aussi !
Appui long sur le bouton met l'Arduino en veille
ici tu peux incrémenter une variable si le bouton est appuyé, si non la décrémenter sans descendre sous zéro
quand la variable atteint la valeur cible, elle est raz et on passe en mode veille
la valeur de la variable dépend du temps d'exécution de le boucle principale
Appui simple sur le bouton réveille l'Arduino, mais le code principal ne se lance pas tout de suite
Tout juste réveillé, il vérifie que le bouton soit maintenue durant 2 secondes
Si le bouton est maintenu durant 2 secondes, la suite du code se lance normalement
Si le bouton a été laché avant les 2 secondes, l'Arduino replonge une nouvelle fois en veille jusqu'au prochain appui sur le bouton
pareil, sauf que la boucle principale sera vide, donc tournera plus vite : en tenir compte pour déterminer la valeur cible, et la taille de la variable par conséquent
J'ai opté pour une fonction AppuiLong() qui, avec une boucle for, vérifie 4 fois par intervalles de 500ms si le bouton est toujours en état HIGH.
Si au bout des 4 vérifications le bouton est toujours en HIGH, il renvoie true
A la première vérification où le bouton est en état LOW on quitte la boucle et il renvoie false.
Ca a l'air de fonctionner.
Mais toujours cette question restante... est-ce que c'est "bien" d'utiliser cette boucle while vide dans l'interruption pour réveiller l'Arduino ?
Oui c'est bien d'utiliser while dans l'interruption pour réveiller l'arduino
Quand on dit qu'il ne faut pas utiliser while dans une interruption, c'est que ça empêche de faire autre chose, mais si tu n'as rien d'autre à faire tu peux l'utiliser.
Et d'ailleurs, je ne sais plus pourquoi j'ai eu besoin de mettre quelque chose dans cette fonction wakeUp, mais dans l'état actuel du code je n'en ai plus besoin. Donc la question ne se pose plus...
Voici le code actuel, ça a l'air de marcher :
#include "LowPower.h"
const int bouton = 2 , led = 3 ;
void setup() {
pinMode(bouton, INPUT);
pinMode(led, OUTPUT);
}
void wakeUp()
{
// Fonction vide pour l'interruption qui reveille l'Arduino
}
boolean AppuiLong()
{
// Fonction permettant de detecter si le bouton est maintenu longtemps
// On verifie 4 fois toutes les 500 ms si le bouton est en etat HIGH
for (int i = 1 ; i <= 4 ; i++)
{
if (digitalRead(bouton) == LOW)
{
return false;
break;
}
else if (i == 4)
{
return true;
}
delay(500);
}
}
void loop () {
// Chaque debut de boucle on verifie si le bouton est maintenu
if ( AppuiLong() == true )
{
do
{
// On eteint tout
digitalWrite(led, LOW);
// On met en veille profonde
attachInterrupt(0, wakeUp, RISING);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
detachInterrupt(0);
} while ( AppuiLong() == false ); // Un appui simple ne suffit pas pour reveiller, si on ne maintient pas l'appui on replonge en veille
}
// SUITE DU CODE (ici une led qui clignote)
for ( int i = 0 ; i < 5 ; i++ ) {
digitalWrite(led, LOW);
delay(50);
digitalWrite(led, HIGH);
delay(50);
}
}