Displaying button press order

Ok so lets call this a tamper alarm, it has 3 sensors (reed switches) so that when the object is moved the state of the input changes permanently. I need the display to (in real time) display the order in which the objects have been tampered with

so if the objects are 1,2,3 and someone moves 3, then 1, then 2 the display should just read 3 1 2
if they move 2 then 3 then 1, then the display should just read 2 3 1

I’ve got a code together but the characters overwrite eachother on the display so i loose the order in which they’ve been tampered with and i can’t seem to get a working “button press” to reset everything. Can anyone help?

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 5
Adafruit_SSD1306 display(OLED_RESET);
 
 #define buttonone 2 
 #define buttontwo 3 
 #define buttonthree 4 
 int state = 1; 
 void setup()   
 { 
  Serial.begin(9600); 
  pinMode(buttonone, INPUT_PULLUP); 
  pinMode(buttontwo, INPUT_PULLUP); 
  pinMode(buttonthree, INPUT_PULLUP);
 
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
 
  digitalWrite(buttonone, 1);   
  digitalWrite(buttontwo, 1);   
  digitalWrite(buttonthree, 1);   
  delay(200); 
 } 
 void loop()   
 {
  state = digitalRead(buttonone); 
  if (state != 1) { 
  display.setTextSize(3);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("1");
  display.display();
  }
 
  state = digitalRead(buttontwo); 
  if (state != 1) { 
    display.setTextSize(3);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("2");
  display.display();; 
  }


  state = digitalRead(buttonthree); 
  if (state != 1) { 
    display.setTextSize(3);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("3");
  display.display();; 
  }   
 }

the characters overwrite eachother on the display

You are always print them starting at the same place on the display.

I understand that, but how do i get the cursor to move on so that it displays the order they're pressed. I get how i can always make the #2 appear in a certain place but that's not what i need, i need the process to be "aware" of whats going on and automatically move the cursor along so that i get the display in press order. I can't get my head around how to do that

Set your cursor position with a variable instead of a constant.

tommoore:
I've got a code together but the characters overwrite each other on the display so i loose the order in which they've been tampered with

That would be because you have redundant and identical code for each button and this code only places the indicator on the display always in the very same position. Not only that, it does it again and again forever because it is in the loop().

tommoore:
and i can't seem to get a working "button press" to reset everything. Can anyone help?

Well, in that code there is neither a reset button nor anything to reset!

You clearly have not thought out that process at all but have just written random code. :astonished:

If you wish to record whether a button has been pressed, you need to record that fact. To do that, you use variables to record each item. For a "yes/ no" record you generally use a boolean (bool) but a byte is often simpler. So you have three buttons, to record the state of three buttons you need three variables.

Now when a button is pressed, if you go and read it again, it will be pressed (or actually not, because of contact bounce). So you do not - in this case - want to read it again. So each time you pass through the loop, you check to see (using your variable) if the button was previously (ever) pressed and if so, you can safely ignore it.

So your routine in the loop is - for each button, was it already pressed? If not, is it now pressed? If so, record that it was pressed in the matching variable and tell the display. That's it. :grinning:

What about the display?

Well, everything about setting the display - text size, colour, cursor position - is set up in setup(). the only thing you do in a button routine is to "print" the button number - and in the process the cursor is moved. That should automatically happen using the "display.println()" function though it should probably be "display.print()" as I don't think you want to go to a new line, just continue on the one. Apparently you then need "display.display()" - I don't know that display so I don't know if or why.

As for reset, suffice to say that the reset button will do that quite well. :roll_eyes: If you want some other way of doing it, that can wait until the main part is sorted.

Thanks for those pointers; i’ve got it working and doing what i want. I don’t have any need to store what happened to the inputs or re-use the data so setting up an an array and reading it / printing it a) seems like overkill and b) is something i’ve never managed to get my head around before so using the screen as “memory” seems like a more appropriate solution here? I’m trying to make it as simple and bomb-proof as possible.

I’ve cracked the screen reset / wipe also.

Here’s my code - any pointers for how i can improve it

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 5
Adafruit_SSD1306 display(OLED_RESET);
 
 #define buttonone 2 
 #define buttontwo 3 
 #define buttonthree 4 
 #define buttoneleven 11
 int state = 1; 
 void setup()   
 { 
  Serial.begin(9600); 
  pinMode(buttonone, INPUT_PULLUP); 
  pinMode(buttontwo, INPUT_PULLUP); 
  pinMode(buttonthree, INPUT_PULLUP);
  pinMode(buttoneleven, INPUT_PULLUP);
 
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(4);
  display.setTextColor(WHITE);
 
  digitalWrite(buttonone, 1);   
  digitalWrite(buttontwo, 1);   
  digitalWrite(buttonthree, 1);
  digitalWrite(buttoneleven, 1);   
  delay(200); 
 } 
 void loop()   
 {
  state = digitalRead(buttonone); 
  if (state != 1) { 
  display.print("1");
  display.display();
  }
 
  state = digitalRead(buttontwo); 
  if (state != 1) { 
  display.print("2");
  display.display();
  }

  state = digitalRead(buttonthree); 
  if (state != 1) { 
  display.print("3");
  display.display();
  }   
  state = digitalRead(buttoneleven); 
  if (state != 1) { 
  display.clearDisplay();
  display.display();
  display.setCursor(0, 0);
  }   
 }

This is redundant with pinMode( ,INPUT_PULLUP):

  digitalWrite(buttonone, 1);   
  digitalWrite(buttontwo, 1);   
  digitalWrite(buttonthree, 1);
  digitalWrite(buttoneleven, 1);

tommoore:
Thanks for those pointers; I've got it working and doing what I want.

OK, well if you think it does, I suppose that is what counts! :roll_eyes:

Paul__B:
OK, well if you think it does, I suppose that is what counts! :roll_eyes:

We as i said - pointers as to what I should be doing better would always be appreciated. Sarcastic comments that don't help anyone learn how to improve their arduino coding are not so useful....

It's such a short piece of code, that if it works, be happy.

There are a few minor things I'd change, but realistically, only to develop good habits for the future, not because it would help much here.

#define has its place, but for defining pins, use const byte instead.

This:

  state = digitalRead(buttontwo); 
  if (state != 1) { 
  display.print("2");
  display.display();
  }

Appears in almost identical form three times. That's a sign that you should have a function to do it that takes the two things that vary as parameters.

I cannot see that it does work, but I gave a didactic (which is to say, complete) explanation of how to perform the stated task.

That was the "pointers". If you think parts of that design were superfluous, then - so be it! :grinning:

ok i’ve been through a few revisions, tried putting it into an array, testing all the separate bits of code things work on their own but when i lump them all together it just doesn’t work (display not showing anything)

Here’s my code

const byte inputs[] = {5, 6, 7, 8, 9};
const byte NUMBER_OF_INPUTS = sizeof(inputs) / sizeof(inputs[0]);  //calculate number of elements in the array
const char * messages[][2] =
{
  {"1" , "-1" },
  {"2" , "-2" },
  {"3" , "-3" },
  {"4" , "-4" },
  {"5" , "-5" },
};

byte previousStates[NUMBER_OF_INPUTS];
byte action;

#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

void setup(void){
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
        for (int switchPin = 0; switchPin < NUMBER_OF_INPUTS; switchPin++)
      previousStates[switchPin] = digitalRead(inputs[switchPin]);
}

void loop(){ 
  
  display.clearDisplay();
  display.setCursor (10,5); // position the cursor
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.display();


  for (int switchPin = 0;switchPin < NUMBER_OF_INPUTS; switchPin++)
  {
    byte currentState = digitalRead(inputs[switchPin]);
    if (currentState != previousStates[switchPin])
    {
      if (currentState == HIGH)
      {  
        action = 1;
        // mySwitch.send(messages[switchPin][action]);
      }
      else
      { 
        action = 0;
        // mySwitch.send(messages[switchPin][action]);
      }
      display.print(messages[switchPin][action]);
      display.display();
      // mySwitch.send(messages[switchPin][action]);
      delay(400);
    }
    previousStates[switchPin] = currentState;
  }
  }

I’m using a Nano
I2C display on A4 & A5 (SDA, SCL)
“switches” on D2-D5

If i just run sketches to print stuff on the LCD it works so i know that’s operational.

What’s the really stupid mistake i’ve made in the code which is making it not all work together?

Current Sketch

const byte inputs[] = {5, 6, 7, 8, 9};
const byte NUMBER_OF_INPUTS = sizeof(inputs) / sizeof(inputs[0]);  //calculate number of elements in the array
const char * messages[][2] =
{
  {"1" , "-1" },
  {"2" , "-2" },
  {"3" , "-3" },
  {"4" , "-4" },
  {"5" , "-5" },
};

byte previousStates[NUMBER_OF_INPUTS];
byte action;

#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#define OLED_RESET -1

Adafruit_SSD1306 display(OLED_RESET);

void setup(void){
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setCursor (10,5); // position the cursor
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.display();
  
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
        for (int switchPin = 0; switchPin < NUMBER_OF_INPUTS; switchPin++)
      previousStates[switchPin] = digitalRead(inputs[switchPin]);
}

void loop(){ 
  
  for (int switchPin = 0;switchPin < NUMBER_OF_INPUTS; switchPin++)
  {
    byte currentState = digitalRead(inputs[switchPin]);
    if (currentState != previousStates[switchPin])
    {
      if (currentState == HIGH)
      {  
        action = 1;
        // mySwitch.send(messages[switchPin][action]);
      }
      else
      { 
        action = 0;
        // mySwitch.send(messages[switchPin][action]);
      }
      display.print(messages[switchPin][action]);
      display.display();
      // mySwitch.send(messages[switchPin][action]);
      delay(400);
    }
    previousStates[switchPin] = currentState;
  }
  }

If i upload this to an Uno it works perfectly

If i upload this to a Nano the screen doesn’t initialise.

I’m using the same components on the same pins.

Is there a compatibility / pinout / coding issue i’m missing as to why it works on one but not the other?

Can you get the display to work on the Nano with the basic examples from the library?

frustratingly, yes,

running this sketch

//Include library
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
void setup()
{
    //Initialize display by providing the display type and its I2C address.
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    //Set the text size and color.
    display.setTextSize(1);
    display.setTextColor(WHITE);
}
void loop()
{
    //Clear previous image.
    display.clearDisplay();
    display.setCursor(0, 15);
    display.print("Hello World.");
    //Display changes if any were made.
    display.display();
    delay(1);
}

gets “hello world” on the screen exactly as it should and with no changes to the wiring

I can't see anything obviously wrong. I'd take the obvious but boring route and comment everything in that code out that doesn't get the display set up and make it display a hello world message. Then add your code back a bit at a time until it breaks.

I've added a "Serial.Write" to my sketch immediately before the display.print command - when i run it on the uno i get serial output correct and screen output correct.

When i run it on the uno i get no screen output and no serial output so that suggests that there's a problem that's stopping my sketch from running properly on the nano?

Id there some known issue with arrays or pullups on nanos?

tommoore:
I've added a "Serial.Write" to my sketch immediately before the display.print command - when i run it on the uno i get serial output correct and screen output correct.

When i run it on the uno i get no screen output and no serial output so that suggests that there's a problem that's stopping my sketch from running properly on the nano?

Id there some known issue with arrays or pullups on nanos?

Not that I know of. Uno and Nano are identical except for their physical packaging and the fact that the Nano has a couple more Analog pins accessible. I would guess that your wiring isn't actually the same or the Nano is defective.

I've tried just using a jumper straight from Pin 4 Gnd to short direct to pin 5/6/7/8 so that there's no wiring / switch errors.

On the UNO it works exactly as needed, on the Nano - nada