Pages: [1] 2   Go Down
Author Topic: [Résolu] Une pause avec une interruption  (Read 1741 times)
0 Members and 1 Guest are viewing this topic.
Toulouse
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour.

Je souhaiterais que mon programme Arduino se mette en pause lors de l'appui sur un bouton, à n'importe-quel moment de l’exécution.
Le programme reprendrait lors d'un nouvel appui sur le bouton.

J'ai donc naturellement pensé aux interruptions, mais toutes mes tentatives pour faire cela ont échouées...

Voici mon dernier programme :

Code:
const int buttonPin = 2;

void setup()
{
  Serial.begin(9600);
  attachInterrupt(0, onRelease, FALLING); // Lance onRelease() lorsque on relache le bouton
  pinMode(buttonPin, INPUT);
}

void loop()
{
  for(int i=0; i<100; i++) { // Programme simple pour vérifier l’exécution du programme principal
    Serial.println(i);
    delay(500);
  }
}

void onRelease()
{
  Serial.println("\nInterruption");
  state();
  
  while(digitalRead(buttonPin) == LOW) { // On attend le nouvel appui sur le bouton
    Serial.print(".");
  }
  
  state();
}

void state() // Imprime l'état actuel du bouton
{
  if (digitalRead(buttonPin) == HIGH)
    Serial.println("Hight");
  else
    Serial.println("Low");
}
« Last Edit: September 07, 2013, 05:36:54 pm by roipoussiere » Logged

N'attendez pas de savoir pour entreprendre.
Drawall, le robot qui dessine : http://drawall.cc/

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Est ce que ce ne serait pas plus simple un truc du style :

Code:
const int buttonPin = 2;
boolean state = 0 ;

void setup()
{
  Serial.begin(9600);
  attachInterrupt(0, onRelease, FALLING); // Lance onRelease() lorsque on relache le bouton
  pinMode(buttonPin, INPUT);
}

void loop()
{
Serial.println(state);
  if(state){
  for(int i=0; i<100; i++) { // Programme simple pour vérifier l’exécution du programme principal
    Serial.println(i);
    delay(500);
  }
  }
}

void onRelease()
{
state = !state ;
}

« Last Edit: September 05, 2013, 07:51:38 pm by Jean-François » Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Toulouse
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Merci pour ta réponse J.F.

Quote
Code:
void loop()
{
  if(state){
  for(int i=0; i<100; i++) { // Programme simple pour vérifier l’exécution du programme principal
    Serial.println(i);
    delay(500);
  }
  }
}

Alors non ça ne va pas.
1. : Si on j'appuie sur le bouton, le programme se mettra en pause lors de la fin du for(), alors que je voudrais une pause immédiatement
Edit : En fait non après test, le programme ne se met pas en pause du tout, ça affiche "1" et reprend le comptage.
Il faut par contre modifier la 2eme ligne :
volatile boolean state = HIGH ;

2. : En réalité mon programme est beaucoup plus long que les quelques lignes ici, je ne peux pas me permettre de tout regrouper dans un if{}.
« Last Edit: September 05, 2013, 12:02:50 pm by roipoussiere » Logged

N'attendez pas de savoir pour entreprendre.
Drawall, le robot qui dessine : http://drawall.cc/

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ben non justement pas, si "state" est à 0, la boucle for n'est jamais executée.

Inverse la valeur du boléen lors de la déclaration.

et rien ne t'empèche de faire :

Code:
if (state)
{
1ère foncction()
2ème fonction()
etc()
}
« Last Edit: September 05, 2013, 12:03:02 pm by Jean-François » Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Toulouse
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Mais le soucis c'est que avec ce que tu me propose, l'appui sur le bp n'a aucune action immédiate, vu que le test de state se fait en dehors de la boucle...

PS : Je suppose que pour changer l'état de la variable tu voulais écrire : state = !state ;
Logged

N'attendez pas de savoir pour entreprendre.
Drawall, le robot qui dessine : http://drawall.cc/

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Et comme ça :

Code:
const int buttonPin = 2;
boolean state = 0 ;

void setup()
{
  Serial.begin(9600);
  attachInterrupt(0, onRelease, FALLING); // Lance onRelease() lorsque on relache le bouton
  pinMode(buttonPin, INPUT);
}

void loop()
{
Serial.println(state);

  for(int i=0; i<100; i++) { // Programme simple pour vérifier l’exécution du programme principal
    Serial.println(i);
    delay(500);
  }
}

void onRelease()
{
state = !state ;
while (state);
}
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

France
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3547
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Avec la librairie Sleep_n0m1

J'ai extrait le code d'un bout de programme que j'avais utilisé pour tester cette librairie sur une carte Seeduino Film.

Code:
#include <avr/pgmspace.h>
#include <Sleep_n0m1.h>

Sleep sleep;
volatile boolean aulit=false;

void goSleep(void){
  aulit=true;
}

void goToSleep(void){
  aulit=false;
  detachInterrupt(0);
  ADCSRA &= ~_BV(ADEN);     // turns ADC off
  delay(200);
//  while(digitalRead(2)==0);
  sleep.pwrDownMode(); //set sleep mode
  sleep.sleepInterrupt(0,FALLING); //sleep for: sleepTime
  ADCSRA |=_BV(ADEN);      // turns ADC on
  delay(200);
//  while(digitalRead(2)==0);
  attachInterrupt(0,goSleep,FALLING);
}

void setup(void) {
  pinMode(2, INPUT);  // bouton poussoir
  // autres initialisation
  attachInterrupt(0,goSleep,FALLING);
}

void loop(void) {
// picture loop 
//  u8g.firstPage();
  if (aulit) goToSleep();
 
  // L'application est là
 
 }

Je voulais garder le contrôle du moment où la mise en sommeil se produisait ce qui explique l'utilisation de goSleep et goToSleep.
Tu dois pouvoir appeler directement goToSleep par attachInterrupt.
La mise en veille et le réveil se font par appui sur un bouton connecté à l'entrée 2.
La mise en veille de l'ADC est un facteur important pour la réduction de la consommation.
Logged

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Code:
[...]
void onRelease()
{
state = !state ;
while (state);
}

En faisant ça, tu restes bloqué à vie dans l'ISR dès que state est à '1'

C'est également ce qu'il me semblait, mais sans en avoir la certitude  smiley-mr-green
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Toulouse
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Je ne sais pas comment est câblé ton BP mais j'imagine au GND avec une pull-up, en fait peu importe.

Oui, j'ai mis aussi un condo en // avec l'inter pour faire un anti-rebond, étant donné que je ne peux pas le faire dans le prgm puisque l'interruption désactive le timer.



En faisant ça, tu restes bloqué à vie dans l'ISR dès que state est à '1'
Oui, je peux confirmer smiley

==> il faut en fait, en entrant dans l'ISR, attendre de relâcher le BP, pour ensuite attendre un nouvel appui, puis encore un nouveau relâchement ...

Pourquoi ? L’interruption est déclenchée au moment où on relâche le bouton.
Comment faire alors?

fdunews, je vais d'abord voir si j'y arrive sans librairie, je ne sais pas de toute façon si elle me sera utile car je cherche pas a mettre en veille l'Arduino, la pause n'est jamais très longue (max 1min).
« Last Edit: September 06, 2013, 11:41:28 am by roipoussiere » Logged

N'attendez pas de savoir pour entreprendre.
Drawall, le robot qui dessine : http://drawall.cc/

France
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3547
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
fdunews, je vais d'abord voir si j'y arrive sans librairie, je ne sais pas de toute façon si elle me sera utile car je cherche pas a mettre en veille l'Arduino, la pause n'est jamais très longue (max 1min).
Si tu avais seulement pris le temps de regarder la librairie en question, tu aurais vu qu'il y a le mode IDLE qui est une simple mise en pause du processeur soit pour un temps donné soit en l'attente d'une nouvelle interruption.
Logged

Toulouse
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Si tu avais seulement pris le temps de regarder la librairie en question, tu aurais vu qu'il y a le mode IDLE qui est une simple mise en pause du processeur soit pour un temps donné soit en l'attente d'une nouvelle interruption.


Ok, j'avoue avoir parcouru un peu trop vite la librairie.
Alors j'ai fait ceci :
Code:
#include <Sleep_n0m1.h>
Sleep sleep;

void setup()
{
  Serial.begin(9600);
  attachInterrupt(0, onRelease, RISING); // Lance onRelease() lorsque on relache le bouton
}

void loop()
{
  for(int i=0; i<100; i++) { // Programme simple pour vérifier l’exécution du programme principal
    Serial.println(i);
    delay(500);
  }
}

void onRelease()
{
  sleep.pwrDownMode(); //set sleep mode
  sleep.sleepInterrupt(0, RISING);  // sleep until interrupt
}

Résultat : Le programme s’exécute,
on appuie/relâche le bouton, le programme se met en pause,
on appuie/relâche le bouton à nouveau, le programme reprends son exécution,
Et là (hélas!), quand on appuie/relâche le bouton ça ne fait rien.

J'ai essayé en mode idle mais là rien ne se passe du tout.

5_cylindre : Déjà merci pour l'explication sur l'anti-rebond, j'ai l'impression qu'il marche un peu mieux (mais pas tout a fait encore, certains appuis sont encore comptés 2 fois).

Sinon j'ai mis le changé en RISING et j'ai attendu les différents états mais on reste toujours bloqué dans la pause.
« Last Edit: September 06, 2013, 07:47:19 pm by roipoussiere » Logged

N'attendez pas de savoir pour entreprendre.
Drawall, le robot qui dessine : http://drawall.cc/

Toulouse
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

J'ai réalisé ceci :
Code:
void onRelease()
{
  EIMSK = 0;
  state = !state;
  digitalWrite(13, state);
  Serial.println("début 1er while");
  while(digitalRead(buttonPin) == 1)
  { // On attend le nouvel appui sur le bouton
    Serial.print(".");
  }
  Serial.println("fin 1er while");
  while(digitalRead(buttonPin) == 0)
  { // On attend le relachement
    Serial.print("-");
  }
  Serial.println("fin 2eme while");
  EIMSK = 1;
}

C'est étrange, Dès que j'appuie/relâche le BP, le programme est bloqué et il n'y a aucune des phrases ci-dessus qui s'affichent.
Logged

N'attendez pas de savoir pour entreprendre.
Drawall, le robot qui dessine : http://drawall.cc/

Toulouse
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I did it !!!
Merci à fdufnews pour sa solution avec la librairie Sleep_n0m1.

En fait le pb était que à l'appel de sleep.sleepInterrupt(0, RISING); la librairie désactive l'interruption. J'ai donc fait un nouvel appel de attachInterrupt() pour la réactiver.

Voici le code :

Code:
#include <Sleep_n0m1.h>
Sleep sleep;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  attachInterrupt(0, onRelease, RISING); // Lance onRelease() lorsque on relache le bouton
  digitalWrite(2, HIGH); // set internal pullup
  digitalWrite(13, LOW);
}

void loop()
{
  for(int i=0; i<100; i++) { // Programme simple pour vérifier l’exécution du programme principal
    Serial.println(i);
    delay(500);
  }
}

void onRelease()
{
  digitalWrite(13, HIGH);
  sleep.pwrDownMode(); //set sleep mode
  sleep.sleepInterrupt(0, RISING);  // sleep until interrupt
  attachInterrupt(0, onRelease, RISING); // Lance onRelease() lorsque on relache le bouton
  digitalWrite(13, LOW);
}

Il doit y avoir plus propre, mais bon ça marche, c'est déjà ça smiley
« Last Edit: September 07, 2013, 07:06:06 am by roipoussiere » Logged

N'attendez pas de savoir pour entreprendre.
Drawall, le robot qui dessine : http://drawall.cc/

France
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3547
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
En fait le pb était que à l'appel de sleep.sleepInterrupt(0, RISING); la librairie désactive l'interruption. J'ai donc fait un nouvel appel de attachInterrupt() pour la réactiver.
En fait la librairie Sleep_n0m1 utilise attachInterrupt pour ces propres besoins. Elle attache sa propre fonction de gestion de l'interruption (celle qui est appelée au réveil) et du coup au retour la fonction que l'on avait attachée est perdue.
Logged

Toulouse
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yeaaah !
Ça marche du feu de dieu ! Merci pour ce dernier message !
Un topic, 2 solutions smiley

Ça me donne de plus en plus envie de coder en avr pur sans passer par arduino, on comprends bien mieux ce qu'on fait smiley

J'ai réécris en Arduino-like pour que ça compile avec l'IDE, je me permet de poster ce code pour que les prochains qui cherchent a faire un truc identique s'y retrouvent.

Edit : Il y a un moyen de mettre ce topic en évidence ou de le recenser quelque part ? Je trouve ce code très utile, je ne dois pas être le seul à avoir ce besoin.

Code:
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>

void setup()
{
  SREG |= 128 ; // INTERRUPTIONS GLOBALES OK
  EIMSK   = 1 ; // INT0 OK
  EICRA   = 3 ; // FRONT MONTANT INT0
  // POUR UN FRONT DESCENDANT : EICRA = 2 ;
 
  Serial.begin(9600);
  digitalWrite(2, HIGH); // set internal pullup
}

void loop()
{
  // Compteur pour vérifier l’exécution du programme
  for(int i=0; i<100; i++) {
    Serial.println(i);
    delay(500);
  }
}

// ROUTINE D'INTERRUPTION
ISR (INT0_vect)
{
  EIMSK = 0 ; // BLOQUER INT0

  while ( PIND & 4 ) { } ; // ON ATTEND TANT QUE LA BROCHE EST À '1'
  while ( ! ( PIND & 4 ) ) { } ; // ON ATTEND TANT QUE LA BROCHE EST À '0'
  // POUR UN FRONT DESCENDANT IL FAUT INVERSER CES 2 LIGNES

  EIMSK = 1 ; // RÉAUTORISER INT0
  EIFR = 1 ; // ET REMETTRE SON FLAG À '0'
};
Logged

N'attendez pas de savoir pour entreprendre.
Drawall, le robot qui dessine : http://drawall.cc/

Pages: [1] 2   Go Up
Jump to: