ISR and void loop working together ?

Hi everyone, I'm working on a Tetris minigame on Arduino UNO for a class.

Teachers want us to use an ISR (TimerOne). They told us we should use the ISR for event handling (detect the press of a button for example), and then use the void loop for every thing display-related.

Except I feel like this is slowing me down. The fact that ISR interrupts void loop every 25ms makes the display kinda slow, and not very reactive to the player input.

I tried to put the display in the ISR too (linked to TimerOne), and the game is way more fluid. But I know that using display functions in an ISR is dangerous, as it could slow it down and overlap with the previous iteration.

Is there a way to make an ISR and void loop work together in order to avoid the game slowing down ?

Thanks for your help :slight_smile:

Welcome to the forum

Please post your sketch so that we can see why the ISR is slowing things down

using an ISR for button detection is generally not good practice

ISR processing should be minimal. when using it as a timer, it might just set a flag that is checked in loop(). but loop() could just as easily check millis(). that timing can be used to update the display

ISRs are needed for very short term events such as encoder signals from motors spinning quickly.

button presses require recognizing a change in button status and waiting for debounce. your finger will hold the button for as long as necessary to be detected. it's difficult for me to imagine how to do button detection with an ISR. such real-time processing, when necessary is often not trivial

suggest you use the ISR just to set a flag for when to do things in loop()

1 Like

Here is the full sketch, it's a bit lengthy and commented in French.

/*******************************************************
Nom ......... : deplacerPiece.ino
Rôle ........ : Permettre le déplacement horizontal d'une pièce
Auteur ...... : Raphaël Boulocher
Version ..... : V1
Licence ..... : GNU GPLv3
Contraintes . : Ne pas laisser les pièces sortir de la matrice
Arguments ... : 
Norme ....... : 
********************************************************/

#include <TimerOne.h>
#include <Wire.h>
#include <Arduino.h>
#include "ht1632.h"
#include <avr/pgmspace.h>

//Formes

const byte formes[8] = {
  B01101100,  // Z
  B01100011,  // S
  B11001100,  // carré
  B11110000,  // I
  B00010111,  // L à l'envers
  B01110001,  // L
  B01110010,  // T
};

byte mat[32][16]={0}; // Création de la matrice pour l'affichage

//Buzzer

#define BUZZER 3

//Joystick

#define XPIN A0
#define YPIN A1
#define BTPIN 2

//Etats

#define APPUYE LOW
#define RELACHE HIGH

// Positions neutres

#define BORNE_GAUCHE 1020
#define BORNE_DROITE 3

#define COULEUR GREEN

//Structures

typedef struct { // Coordonnées
  int x; 
  int y;
} T_coord;

typedef struct { // Pièce
	char forme;
	T_coord currentPos;
	T_coord lastPos;
	byte speed;
	byte sens;
  byte active;
} T_piece;

T_piece p; // Création d'une pièce

enum { // Différents sens de déplacement
  GAUCHE, DROITE, AUCUN
};

enum { // Etats du jeu
  INIT, NOIR, E1, E2, FIN, NONE
};

volatile byte mode = E1; //////////////// <<<<<<<<<<
volatile byte lastMode = NONE; // Etat précédent

volatile byte direction = AUCUN; // Direction initiale

volatile char sens;
volatile long compteur = 0;
volatile boolean etatBouton;

//Prototypes
void fnPeriodique();
byte testForme(byte x, byte y, byte forme, byte couleur, char sens);
void afficherForme(byte x, byte y, byte forme, byte couleur, char sens);
void afficherMatrice();

volatile int periodeAppui;
volatile int x,y;
volatile byte lastStateBtn = HIGH;
volatile byte stateBtn;
volatile char lastSens;

void setup()
{
  pinMode(BTPIN,INPUT); //BTPIN est un input
  digitalWrite(BTPIN, HIGH); //Si bouton relaché, HIGH
  ht1632_setup();      // Initialisation de la librairie
  Serial.begin(9600);  // Lancement du Serial Monitor
  Wire.begin();        //ISP
  setup7Seg();         //Initialiser le 7 segments
  cls(); // Vider l'écran

  Timer1.initialize(25000); // 25ms
  Timer1.attachInterrupt(fnPeriodique);

  p.currentPos.x = 31;
  p.currentPos.y = 3;
  p.active = 0;
}

void loop() {
  //Serial.println("loop");
  switch (mode) {
    case INIT: // Affichage du logo
      for(x = 0; x <= 31; x++) {
        for(y = 0; y <= 15; y++) {
          if((x >= 12 && x <= 15 && y >= 6 && y <= 9) || (x >= 16 && x <= 19 && y >= 2 && y <= 13)) {
            ht1632_plot(x,y, RED);
          } 
          else if ((x >= 15 && x <= 20 && (y == 1 || y == 14)) || (((y >= 2 && y <= 5) || (y >= 10 && y <= 13))&& x == 15) || (y >= 2 && y <= 14 && x == 20) || (y >= 6 && y <= 9 && x == 11) || (x >= 11 && x <= 14 && (y == 5 || y == 10))) {
            ht1632_plot(x,y,ORANGE);
          } else {
            ht1632_plot(x,y,GREEN);
          }
        }
      }
    break;

    case NOIR: // Affichage écran début du jeu
      afficherMatrice();

      if(compteur%4 == 0) {
        mode=E1;
      }
      break;

    case E1:
      if (p.active == 0) {
        // Création pièce
        p.forme = random(7);
        p.currentPos.x = 31;
        p.currentPos.y = 3;
        p.lastPos.x = 31;
        p.lastPos.y = 3;
        //p.speed= ??
        p.sens = 1;
        p.active = 1;

      }else{    
          // La pièce descend    
        if (p.currentPos.x > 0) {
          afficherForme(p.currentPos.x, p.currentPos.y, formes[p.forme], BLACK, p.sens); // Effacer position actuelle
          p.lastPos = p.currentPos; // Mettre à jour la dernière position

          //if(testForme(p.currentPos.x+1, p.currentPos.y+1, formes[p.forme], BLACK, p.sens) == 1) {
            p.currentPos.x--; // Mettre à jour la position actuelle
          //}
        }
      }
      afficherForme(p.currentPos.x, p.currentPos.y, formes[p.forme], COULEUR, p.sens); // Insérer nouvelle position
      afficherMatrice();
      
      switch (direction) {
          case GAUCHE :
            if (p.currentPos.y > 0) {
              afficherForme(p.currentPos.x, p.currentPos.y, formes[p.forme], BLACK, p.sens); // Effacer position actuelle
              p.lastPos = p.currentPos;
              p.currentPos.y--; // MàJ position
              afficherForme(p.currentPos.x, p.currentPos.y, formes[p.forme], COULEUR, p.sens); // Insérer nouvelle position
              //afficherMatrice();
              direction = AUCUN;
            }
          break;

          case DROITE :
            if (p.currentPos.y < 13) {
              afficherForme(p.currentPos.x, p.currentPos.y, formes[p.forme], BLACK,p.sens); // Effacer position actuelle
              p.lastPos = p.currentPos;
              p.currentPos.y++; // MàJ position
              afficherForme(p.currentPos.x, p.currentPos.y, formes[p.forme], COULEUR, p.sens); // Insérer nouvelle position
              //afficherMatrice();
              direction = AUCUN;
            }
          break;
        }
        afficherMatrice();
      break;

      case E2:
      break;

      case FIN:
      break;
  }
}

int i = random(7);


///////////////////////////////////
void fnPeriodique() {
  

  switch (mode) {
    case INIT:
      stateBtn = digitalRead(BTPIN);
        if ((lastStateBtn == LOW && stateBtn == HIGH)){// && ((compteur - periodeAppui) > 40)) {
          mode = NOIR;
        }

      // if ((lastStateBtn != stateBtn) && (stateBtn == LOW) ) {
      //   periodeAppui = compteur;
      // }
      lastStateBtn = stateBtn;
    break;

    case E1:
      //if(compteur % 3 == 0) {

        int x = analogRead(XPIN);
        etatBouton = digitalRead(BTPIN);

        if(x > BORNE_GAUCHE) {
          Serial.println("Gauche");
          direction = GAUCHE;
        }
        if(x < BORNE_DROITE) {
          direction = DROITE;
        }

        if(etatBouton == LOW) {
          afficherForme(p.currentPos.x,  p.currentPos.y, formes[p.forme], BLACK, p.sens);
          p.sens++;
          if(p.sens == 5){
            p.sens=1;
          }
          afficherForme(p.currentPos.x,  p.currentPos.y, formes[p.forme], COULEUR, p.sens);
        }
      //}


    break;

    case E2:
    break;

    case FIN:
    break;
  }
  compteur++;
}

void afficherForme(byte x, byte y, byte forme, byte couleur, char sens) {
  int i;
  switch(sens) {
    case 1:
      for (i = 0; i <= 7; i++) {
        if (bitRead(forme, 7 - i) == 1) {
          mat[x + i / 4][y + (i % 4)]=couleur;
          //ht1632_plot(x + i / 4, y + (i % 4), couleur);
        }
      }
    break;

    case 2:
      if(forme == formes[0] || forme == formes[3]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x - (i % 4) + 1][y + i / 4 + 1]=couleur;
            //ht1632_plot(x - (i % 4) + 1, y + i / 4 + 1, couleur);
          }
        }
      }
      else if (forme == formes[1]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x - (i % 4) + 2][y + i / 4 + 2]=couleur;
            //ht1632_plot(x - (i % 4) + 2, y + i / 4 + 2, couleur);
          }
        }
      }
      else if (forme == formes[4]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x - (i % 4) + 3][y + i / 4 + 1]=couleur;
            //ht1632_plot(x - (i % 4) + 3, y + i / 4 + 1, couleur);
          }
        }
      }
      else if (forme == formes[5] || forme == formes[6]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x - (i % 4) + 2][y + i / 4 + 2]=couleur;
            //ht1632_plot(x - (i % 4) + 2, y + i / 4 + 2, couleur);
          }
        }
      }
      else if (forme == formes[2]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x + i / 4][y + (i % 4)]=couleur;
            //ht1632_plot(x + i / 4, y + (i % 4), couleur);
          }
        }
      }
    break;

    case 3:
      if(forme == formes[0] || forme == formes[3]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x - i / 4][y - (i % 4) + 2]=couleur;
            //ht1632_plot(x - i / 4, y - (i % 4) + 2, couleur);
          }
        }
      }
      else if (forme == formes[1]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x - i / 4 + 1][y - (i % 4) + 4]=couleur;
            //ht1632_plot(x - i / 4 + 1, y - (i % 4) + 4, couleur);
          }
        }
      }
      else if (forme == formes[4]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x - i / 4 + 2][y - (i % 4) + 4]=couleur;
            //ht1632_plot(x - i / 4 + 2, y - (i % 4) + 4, couleur);
          }
        }
      }
      else if (forme == formes[5] || forme == formes[6]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x - i / 4][y - (i % 4) + 4]=couleur;
            //ht1632_plot(x - i / 4, y - (i % 4) + 4, couleur);
          }
        }
      }
      else if (forme == formes[2]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x + i / 4][ y + (i % 4)]=couleur;
            //ht1632_plot(x + i / 4, y + (i % 4), couleur);
          }
        }
      }
    break;

    case 4:
      if(forme == formes[0] || forme == formes[3]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x + (i % 4) - 1][y - i / 4 + 1]=couleur;
            //ht1632_plot(x + (i % 4) - 1, y - i / 4 + 1, couleur);
          }
        }
      }
      else if (forme == formes[1]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x + (i % 4) - 2][y - i / 4 + 3]=couleur;
            //ht1632_plot(x + (i % 4) - 2, y - i / 4 + 3, couleur);
          }
        }
      }
      else if (forme == formes[4]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x + (i % 4) - 1][y - i / 4 + 3]=couleur;
            //ht1632_plot(x + (i % 4) - 1, y - i / 4 + 3, couleur);
          }
        }
      }
      else if (forme == formes[5] || forme == formes[6]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x + (i % 4) - 2][y - i / 4 + 2]=couleur;
            //ht1632_plot(x + (i % 4) - 2, y - i / 4 + 2, couleur);
          }
        }
      }
      else if (forme == formes[2]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            mat[x + i / 4][y + (i % 4)]=couleur;
            //ht1632_plot(x + i / 4, y + (i % 4), couleur);
          }
        }
      }
    break;
  }
}

byte testForme(byte x, byte y, byte forme, byte couleur, char sens) {
  int i;
  switch(sens) {
    case 1:
      for (i = 0; i <= 7; i++) {
        if (bitRead(forme, 7 - i) == 1) {
          if(mat[x + i / 4][y + (i % 4)] != 0) {
            p.active==0;
            return(0);
          }
        }
        return(1);
      }
    break;

    case 2:
      if(forme == formes[0] || forme == formes[3]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x - (i % 4) + 1][y + i / 4 + 1] != 0) {
              p.active==0;
              return(0);
            }
            //ht1632_plot(x - (i % 4) + 1, y + i / 4 + 1, couleur);
          }
        }
        return(1);
      }
      else if (forme == formes[1]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x - (i % 4) + 2][y + i / 4 + 2] != 0) {
              p.active==0;
              return(0);
            }
            //ht1632_plot(x - (i % 4) + 2, y + i / 4 + 2, couleur);
          }
        }
        return(1);
      }
      else if (forme == formes[4]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x - (i % 4) + 3][y + i / 4 + 1] != 0) {
              p.active==0;
              return(0);
            }
            //ht1632_plot(x - (i % 4) + 3, y + i / 4 + 1, couleur);
          }
        }
        return(1);
      }
      else if (forme == formes[5] || forme == formes[6]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x - (i % 4) + 2][y + i / 4 + 2] != 0) {
              p.active==0;
              return(0);
            }
            //ht1632_plot(x - (i % 4) + 2, y + i / 4 + 2, couleur);
          }
        }
        return(1);
      }
      else if (forme == formes[2]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x + i / 4][y + (i % 4)] != 0) {
              p.active==0;
              return(0);
            }
            //ht1632_plot(x + i / 4, y + (i % 4), couleur);
          }
        }
        return(1);
      }
    break;

    case 3:
      if(forme == formes[0] || forme == formes[3]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x - i / 4][y - (i % 4) + 2] == 0) {
              p.active==0;
              return(0);
            } else {
              return(1);
            }
            //ht1632_plot(x - i / 4, y - (i % 4) + 2, couleur);
          }
        }
      }
      else if (forme == formes[1]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x - i / 4 + 1][y - (i % 4) + 4] == 0) {
              p.active==0;
              return(0);
            } else {
              return(1);
            }
            //ht1632_plot(x - i / 4 + 1, y - (i % 4) + 4, couleur);
          }
        }
      }
      else if (forme == formes[4]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x - i / 4 + 2][y - (i % 4) + 4] == 0) {
              p.active==0;
              return(0);
            } else {
              return(1);
            }
            //ht1632_plot(x - i / 4 + 2, y - (i % 4) + 4, couleur);
          }
        }
      }
      else if (forme == formes[5] || forme == formes[6]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x - i / 4][y - (i % 4) + 4] == 0) {
              p.active==0;
              return(1);
            } else {
              return(0);
            }
            //ht1632_plot(x - i / 4, y - (i % 4) + 4, couleur);
          }
        }
      }
      else if (forme == formes[2]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x + i / 4][y + (i % 4)] == 0) {
              p.active==0;
              return(1);
            } else {
              return(0);
            }
            //ht1632_plot(x + i / 4, y + (i % 4), couleur);
          }
        }
      }
    break;

    case 4:
      if(forme == formes[0] || forme == formes[3]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x + (i % 4) - 1][y - i / 4 + 1] == 0) {
              p.active==0;
              return(1);
            } else {
              return(0);
            }
            //ht1632_plot(x + (i % 4) - 1, y - i / 4 + 1, couleur);
          }
        }
      }
      else if (forme == formes[1]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x + (i % 4) - 2][y - i / 4 + 3] == 0) {
              p.active==0;
              return(1);
            } else {
              return(0);
            }
            //ht1632_plot(x + (i % 4) - 2, y - i / 4 + 3, couleur);
          }
        }
      }
      else if (forme == formes[4]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x + (i % 4) - 1][y - i / 4 + 3] == 0) {
              p.active==0;
              return(1);
            } else {
              return(0);
            }
            //ht1632_plot(x + (i % 4) - 1, y - i / 4 + 3, couleur);
          }
        }
      }
      else if (forme == formes[5] || forme == formes[6]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x + (i % 4) - 2][y - i / 4 + 2] == 0) {
              p.active==0;
              return(1);
            } else {
              return(0);
            }
            //ht1632_plot(x + (i % 4) - 2, y - i / 4 + 2, couleur);
          }
        }
      }
      else if (forme == formes[2]) {
        for (i = 0; i <= 7; i++) {
          if (bitRead(forme, 7 - i) == 1) {
            if(mat[x + i / 4][y + (i % 4)] == 0) {
              p.active==0;
              return(1);
            } else {
              return(0);
            }
            //ht1632_plot(x + i / 4, y + (i % 4), couleur);
          }
        }
      }
    break;
  }
}


void afficherMatrice() {
  int c;
  int l;
  for (c = 0 ; c < 32 ; c++) {
    for (l = 0 ; l < 16 ; l++) {
        ht1632_plot(c, l, mat[c][l]);
    }
  }
}

Yes, for shure.

Dismiss the interrupt handling and use the millis() function for realtime tasks like button debouncing and event handling.

Have a nice day and enjoy coding in C++.

p.s. gcjr was faster again

1 Like

If you must use the TimerOne library for the button, can you make a ISR of about three lines of code ?
An interrupt routine should be very short and fast.
Read the button, put it in a buffer or variable. Perhaps do some basic debouncing. But no more. The rest has to be done in the loop().

1 Like

Thank you all for your help ! I realise that despite trying to keep it as short as possible, my ISR may be too long, and I could use flags to make the ISR even shorter ! I'll try going down this way and put everything I can in the loop()

Have a great day

 Timer1.initialize(25000); // 25ms

It was you that told the ISR to fire every 25 milliseconds so you could easily change that if you wanted to but first you should concentrate on making the ISR as short as possible, perhaps by only reading the button input and storing its state to be processed in loop()

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.