Arduino Gemma with 8x8 LED Matrix backpack button press to change picture

Hi everyone,
Just started with Arduino and made a few small projects but since I am no programmer I hit a dead end pretty quick on my current project involving a 8x8 LED Matrix backpack driven by Gemma from Adafruit.

Project description: press a button; wake up the 8x8 LED Matrix; display a picture for 5 sec. and go back to sleep. If the button is pressed again before the sleep mode (5 sec.) go to next picture in library and show it on the matrix and so on so forth. Basically is changing the picture after every button press.

Schematics:

Full project description:
=https://learn.adafruit.com/trinket-slash-gemma-space-invader-pendant/overview

My post on Adafruit forum with no response except mine:
=https://forums.adafruit.com/viewtopic.php?f=51&t=77191

So my biggest problem is the coding side, if any one could help/advice I would greatly appreciate it.

Thanks!
Catalin

My code:

/*************************************************** 
  This is a library for our I2C LED Backpacks

  Designed specifically to work with the Adafruit LED Matrix backpacks 
  ----> http://www.adafruit.com/products/872
  ----> http://www.adafruit.com/products/871
  ----> http://www.adafruit.com/products/870

  These displays use I2C to communicate, 2 pins are required to 
  interface. There are multiple selectable I2C addresses. For backpacks
  with 2 Address Select pins: 0x70, 0x71, 0x72 or 0x73. For backpacks
  with 3 Address Select pins: 0x70 thru 0x77

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

// Button pin
const int buttonPin = 1;

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

void setup() {
  Serial.begin(9600);
  //Serial.println("8x8 LED Matrix Test");
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  matrix.begin(0x70);  // pass in the address
}

static const uint8_t PROGMEM
  smile_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10100101,
    B10011001,
    B01000010,
    B00111100 },
  neutral_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10111101,
    B10000001,
    B01000010,
    B00111100 },
  frown_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10011001,
    B10100101,
    B01000010,
    B00111100 };

void loop() {
  
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);
  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
  bitmap_count = bitmap_count +1;
if (bitmap_count == 3){bitmap_count = 1;}
}
switch (bitmap_count){
case 1:
// bitmap 1 code here
matrix.clear();
  matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
break;
case 2:
//bitmap 2 code here
matrix.clear();
  matrix.drawBitmap(0, 0, neutral_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
break;
case 3:
//bitmap 3 code here
matrix.clear();
  matrix.drawBitmap(0, 0, frown_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
break;
}  // end switch
} // end void loop

So my biggest problem is the coding side

That's where the problem is. That is NOT what the problem is.

You need to look at the state change detection example. You do not want to change the image when the switch IS pressed. You want to change the image when the switch BECOMES pressed.

Thanks! PaulS for the tip ...

Here is my new version of code that works in a way by switching the images in a way
that I can make no logic out of it.
The only clear picture I get is the Smile_bmp, then I have a mix of Smile with Flower
and then a "scrambled animation" and the cycle repeats after button presses.
It has something to do with the MODULO operator ...

Can someone point me on the right direction with my code? any tip or advice ...

Another unknown I am facing is this message after I compile:
Sketch uses 5,192 bytes (97%) of program storage space. Maximum is 5,310 bytes.
Global variables use 125 bytes of dynamic memory.

Any tip how can I reduce the code so I clear memory ... I see codes with more lines than mine running on the same GEMMA with no issue regarding the "storage space"

I followed this for the "state change detection"
=https://opensourcehardwaregroup.com/tutorial-18-state-change-detection-and-the-modulo-operator-old-version/

well and here is the code:

/*
This example code is in the public domain.
    
 http://arduino.cc/en/Tutorial/ButtonStateChange
 
 */

#include <TinyWireM.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

const int buttonPin = 1;    // button pin set on Gemma Pin #1

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  matrix.begin(0x70);     // pass in the address
}

static const uint8_t PROGMEM   // X and square bitmaps
  hearth_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10100101,
    B10011001,
    B01000010,
    B00111100 },
  smile_bmp[] =
  { B00100100,
    B01011010,
    B10011001,
    B10000001,
    B10000001,
    B01000010,
    B00100100,
    B00011000 },
  flower_bmp[] =
  { B11000011,
    B10100101,
    B01100110,
    B00011000,
    B01111011,
    B10101110,
    B11001100,
    B00001000 };

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH && lastButtonState == LOW) {
      // if the current state is HIGH then the button
      // went from off to on:
      buttonPushCounter++;
    } else {
      // if the current state is LOW then the button
      // went from on to off: 
    }
  }
  // save the current state as the last state, 
  //for next time through the loop
  lastButtonState = buttonState;

  // turns on the LED every four button pushes by 
  // checking the modulo of the button push counter.
  // the modulo function gives you the remainder of 
  // the division of two numbers:
  if (buttonPushCounter % 4 == 0) {
    matrix.clear();
      matrix.drawBitmap(0, 0, hearth_bmp, 8, 8, LED_ON);
      matrix.writeDisplay();
      buttonState = HIGH;
       
  if (buttonPushCounter % 1 == 0){
    matrix.clear();
      matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
      matrix.writeDisplay();
      buttonState = HIGH;
  
  if (buttonPushCounter % 2 == 0){
    matrix.clear();
      matrix.drawBitmap(0, 0, flower_bmp, 8, 8, LED_ON);
      matrix.writeDisplay();
      buttonState = HIGH;
  } else {
    matrix.clear();
}
}
}
}

Thanks for help!
Catalin

  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH && lastButtonState == LOW) {

If the current state is not the same as the previous state, that indicates that a change has occurred. If the state is now HIGH, is there ANY possible way that the previous state is NOT LOW?

  if (buttonPushCounter % 4 == 0) {
    matrix.clear();
      matrix.drawBitmap(0, 0, hearth_bmp, 8, 8, LED_ON);
      matrix.writeDisplay();
      buttonState = HIGH;
       
  if (buttonPushCounter % 1 == 0){
    matrix.clear();
      matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
      matrix.writeDisplay();
      buttonState = HIGH;
  
  if (buttonPushCounter % 2 == 0){
    matrix.clear();
      matrix.drawBitmap(0, 0, flower_bmp, 8, 8, LED_ON);
      matrix.writeDisplay();
      buttonState = HIGH;
  } else {
    matrix.clear();
}
}
}

What a mess. Put every { on a new line. Use Tools + Auto Format to properly indent the code.

Then, try to explain what you are doing. It's completely wrong, but I am interested in your explanation.

The correct way:

   switch(buttonPushCounter % 3)
   {
      case 0:
         // Do the 0 stuff
         break;
      case 1:
         // Do the 1 stuff
         break;
      case 2:
         // Do the 2 stuff
         break;
   }

You've got three things to do:
0) Draw the hearth bitmap

  1. Draw the smile bitmap
  2. Draw the flower bitmap

The modulo function (%) returns the remainder of integer division.
0 / 3 = 0 with a remainder of 0
1 / 3 = 0 with a remainder of 1
2 / 3 = 0 with a remainder of 2
3 / 3 = 1 with a remainder of 0
and so forth. It is only the remainder that matters.

Dear PaulS,

Sorry for the late replay and at the same time thanks for your guidance.
The code snippet you provided with Switch Case worked and I am very happy that it did.
Also I had no idea how to properly indent the code and thanks to your tip I did that also.
Can you elaborate a bit on this so I can give you better answer:
"Then, try to explain what you are doing. It's completely wrong, but I am interested in your explanation."

Another question: to make the display turn off after x seconds do I need some timer library? or how do I implement a "time counter" ? do I need some hardware to track time ? any advice is welcomed ...

Regards,
Catalin

Can you elaborate a bit on this so I can give you better answer:
"Then, try to explain what you are doing. It's completely wrong, but I am interested in your explanation."

You'll notice in my code that the value following the % operator never changes. In your code, it jumps all over the place. I'm curious what you were thinking when you did that.

Hi Paul,
To answer your question now that I understand it:
1-st I did not completely understood the modulo function (%); not that I understand it better now
so in my code I had %4 %2 %1 because I just played with the (%) values to see if the resoult would be what I wanted to but unfortunately it did not worked

2-nd here is the pseudo code (sort of my logic) I had in mind:

when system starts put 0 into Counter variable and clear the screen
if button pressed put 1 into Counter and display the first image
else if button pressed again then add 1 to Counter (Counter becomes 2)
if Counter = 2 then display the 2 image
else if button pressed again then add 1 to Counter (Counter becomes 3)
if Counter = 3 then display the 3-rd image
else if button pressed again then add 1 to Counter (Counter becomes 4)
if Counter = 4 then display the first image
else put 0 into Counter

so that is what I had in mind just that it is the first time I tinker with Arduino and Arduino sketches (C++) and I had (have) no idea how I should write the code from my head with the proper syntax; but hey I am a hard learner and I am happy with my small steps.
I really do appreciate your help ad guidance.
I do read really a lot trying to find the information's by myself before I post and I do modify code snippets found over the internet to see how it works ...

Will you tell me why it has been better to use Case method instead of nested if-s ? if written properly the if's would form a loop and will work right ? Are you still willing to guide me into this Arduino coding stuff ?

Question for everyone: to count "time" so I can turn off the LED matrix after x sec. do I need extra hardware or is a C++ function to be used ?

Thanks,
Catalin Anesia

Will you tell me why it has been better to use Case method instead of nested if-s ?

Using the switch statement, with cases, is not a replacement for nested ifs. It IS an alternative to a series of if/else if/else statements.

Notice that I said alternative. The compiler can generate more efficient code from a switch statement than from a series of if/else if/else statements, but in general that does not matter. What matters is which construct you can understand and write. If you are more comfortable with switch, use it. If you are more comfortable with if/else if/else, use them.

if written properly the if's would form a loop and will work right ?

Loop isn't the proper term. But, the if/else if/else combination WILL work. In some cases (such as the one I showed code for), the switch statement feels more logical and the cases more obvious. In other cases, if/else if/else makes more sense.

Are you still willing to guide me into this Arduino coding stuff ?

Of course. We all are. That's why we waste time here.

Question for everyone: to count "time" so I can turn off the LED matrix after x sec. do I need extra hardware or is a C++ function to be used ?

The Arduino has a built in "clock". It starts when the Arduino starts, and counts microseconds. There is a function, micros() to get that count. There is another function, millis(), that gets the count of milliseconds. Either of those functions are useful for making now vs. then decisions, such as turning an LED (or matrix of them) off after some period of time.

They are lousy at making things happen at some absolute time. For relative times, though, they work great.

The blink without delay example shows how to use millis().

Good day PaulS,

Of course. We all are. That's why we waste time here.

I hope people are not "wasting" time around here; any way for me all your informations are with great value and my project is moving on due to your help.

Nice if/else vs case scenarios explanation you gave me; it was my mind setted up on the if/else scenarios for some reason, probably because I had more contact with them during my reading session and code analysis from others.

The blink without delay example shows how to use millis().

I am looking in to this and add that functionality to my LED Matrix.

Meanwhile the big problem I have is with Arduino Gemma memory, it keeps saying that I am out of memory and my sketch is fairly small in terms of code lines ...

Sketch uses 5,192 bytes (97%) of program storage space. Maximum is 5,310 bytes.
Global variables use 125 bytes of dynamic memory.
Any tip how can I reduce the code so I clear memory ... I see codes with more lines than mine running on the same GEMMA with no issue regarding the "storage space"

Here is what I tried unsuccessfully: I made another TAB in Arduino IDE to hold my Bitmap codes and saved it as Images.h after that I declared this at the beginning of the main sketch #include "Images.h" but it didn't work.

Am I on the right direction by splitting the sketch in separate tabs? to clear memory on Gemma?

Thanks!

Am I on the right direction by splitting the sketch in separate tabs? to clear memory on Gemma?

If you go to the airport with a 75# suitcase, and the airline is going to charge you an overweight luggage fee, can you save money by putting the luggage in two suitcases, instead?

Ok PaulS,
no money saving on the Airline case and you are saying that I reached the mem. space limit.
This example makes me think otherwise:
=https://learn.adafruit.com/trinket-slash-gemma-space-invader-pendant/source-code

I was hoping the solution is to use this PROGMEM thing: "static const uint8_t PROGMEM reorder[]"
I do not completely understand what it does is just that they are using it and have the main sketch and animation sketch separated for some reasons and PROGMEM is used and I do not have it in my sketch ...

Ok, so I have no choice but to move on a bigger Arduino (I tried to avoid that because of the size of the hardware). Well I will compile to Adafruit FLORA then and see when I reach the limit :frowning:

Thanks!

The amount of code that you have, and the amount of memory you need, does not change because you use multiple files, any more than the weight changes because you use two or more suitcases.

All arrays and variables are stored in flash memory. At run time, some stuff is copied to SRAM. By using the PROGMEM directive, you tell the compiler to not generate code to copy the variable/array to SRAM at run time.

While that saves on SRAM, it has two drawbacks which may, or may not, be a problem. One is that access to the data in PROGMEM is different from access to the data in SRAM. Most code is written to access data in SRAM. Libraries, in particular, rarely are written to access data in PROGMEM.

The other, and the one that usually determines whether PROGMEM is suitable or not, is that data in PROGMEM is read-only. There is no way to change that data.

There are Arduino-like designs, that have more memory, etc. in the Uno footprint, that can be programmed using the Arduino IDE.

Meaning,
that if I load my Images in PROGMEM I will not be able to modify them later on, this is fine for me.
So I will be able to ask for them to be displayed on the LED Matrix but will not be able to modify them at run time.

Any way I am to much of a NEWBIE at this point to tinker with that, ill move on with a bigger Arduino (Flora) so at least I'll be able to have a finished working project and concentrate my self on learning rather than optimising at this point.

Have a great day!

So I will be able to ask for them to be displayed on the LED Matrix

Maybe. It depends on whether the code that sends data to the display knows that it has to read from PROGMEM (instead of SRAM), or not.

Back to my code and timer to switch off the LED,
Ill need to include this probably to make the power-off

#include <avr/power.h>
#include <avr/sleep.h>

and use it somehow like this :

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    sei();                 // Keep interrupts disabled
    sleep_mode();          // Power down CPU (pin 1 will wake)

well ill test and see where it goes ...