Record a sequence of pushButtons on A0 and play them back using digitalWrite.

Hello,

I’m a complete noob at programming. I have an arduinoUno.

I need help with a project I’m working on which is basically recording a sequence of push buttons to automate something.

I have 12 pushbuttons going into analog A0 and I’m using a resistor chain to read a voltage difference between button 1 and button 12.

The code I have is based on this site:

5 pushButtons on A0

I can get an accurate analogRead from every button, but I hit a wall with recording.

I set a counter to see how many times A0 has been pressed.
I also set a value for each of the 12 pushButtons in an int buttonValue.

My question is the following:

I want to be able to record this in an array, myArray[counter,buttonValue];
and then have it play back in the correct order.

For now I will be using LEDs on 12 digital outputs without the serial monitor to see if it works, but I
just can’t seem to get my head around recording which button was pressed, along with the counter, and if possible I’d also like to record how long a button has been pressed.

Then send the recorded information to each one of the 12 digital outputs in the order they were recorded.

I’ve been looking at 2D arrays but I still can’t figure out how to do what I need.

Unfortunately the code I have only deals with reading pushbuttons and assigning them a value. The code is simplified down to two buttons, and the recording and playback buttons are on digitalInputs, and two LEDs on digitalOutputs. Eventually the recButton and playButton will be on A1 and A2, so I have enough room for the 12 solenoids on the digital pins.

I only need to have two solenoids on at the same time (max) and I will be using an external power supply and some transistors (or whatever you guys suggest).

I’d love to know if this is possible. Thanks.

            // these constants won't change:

const int  buttonPin = 0;   // the pin that the pushbutton is attached to
const int ledPin1 = 4;       // the pin that the LED is attached to
const int ledPin2 = 5;

const int RECBUTTON = 7;
const int PLAYBUTTON = 8;

const int BUTTON1 = 1;
const int BUTTON2 = 2;

const int BUTTON1LOW = 1000;
const int BUTTON1HIGH = 1024;
const int BUTTON2LOW = 900;
const int BUTTON2HIGH = 950;


// this bunch of code manages the counter, recording, and playback for the buttons that lead to the solenoids

int lastButtonState = 0;     
int lastRecState = 0;
int lastPlayState = 0;
int buttonCount = 0;		 
int buttonValue = 0;
bool isRec = false;
bool isPlay = false;

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  pinMode(RECBUTTON, INPUT);
  pinMode(PLAYBUTTON, INPUT);
  
  // initialize the LED as an output:
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  
  
    
  // initialize serial communication:
  Serial.begin(9600);
}

void loop() {
  
  int reading = analogRead(buttonPin);
  int play = digitalRead(PLAYBUTTON);
  int rec = digitalRead(RECBUTTON);
  int tmpButtonState = LOW;
  
  
//  Serial.println(reading);
    
    // compare the buttonState to its previous state
    
    if (reading != lastButtonState) {
    
    // if the state has changed, increment the counter
    
    if (reading > 1) {
    buttonCount++;
    Serial.println("on");
    Serial.print("counter:  ");
    Serial.println(buttonCount);
    } 
      
    if (reading > BUTTON1LOW && reading < BUTTON1HIGH){
 	tmpButtonState = BUTTON1;
      	buttonValue = 1;
        Serial.println(buttonValue);
    }
    else if	(reading > BUTTON2LOW && reading < BUTTON2HIGH){
    	tmpButtonState = BUTTON2;
      	buttonValue = 2;
        Serial.println(buttonValue);
    }      
    else
        
    {
    	tmpButtonState = LOW;
    }
    
// if (reading > 100)Serial.println(buttonValue);
        
    // Delay a little bit to avoid bouncing
    
    delay(100);
  }
  
  // save the current state as the last state,//
  //for next time through the loop
  
  lastButtonState = reading;
  if(buttonCount>=20)buttonCount=0;
  
  
  }

What happens when multiple buttons are down at once?

I'm curious as to the wiring and would like to see a schematic as I don't understand the BUTTON LOW vs HIGH values.

Help is only possible with understanding!

lloyddean:
What happens when multiple buttons are down at once?

Exactly, that's part of the problem. I know based on the math, and resistor values, that I can tell which combination of two buttons are pressed at any point. I can assign a value for that situation. But I'll deal with that problem after I figured out the basics of recording on analog and outputting to digital.

The code for the digital out needs to know which button was pressed at which value of buttonCounter along with millis(), (if possible), but again, I'd like to simplify it as much as possible so I can expand.

lloyddean:
I’m curious as to the wiring and would like to see a schematic as I don’t understand the BUTTON LOW vs HIGH values.

Help is only possible with understanding!

Yup, you can check out the site I posted to understand the basic schematic.

5 pushButtons through A0

Basically I’m sending voltage 5v to the twelve buttons interrupted by resistors. The different resistor values will change the reading of each button on the serial monitor depending on their resistance. Then I simply give a range of values which will tell arduino which button is pressed.

So if buttonOneValue is > than 900 but < 1023 {buttonOneValue = button1} etc…

I know I can map and I intend to do so later on. Like I said, trying to keep it simple.

Much as I thought.

Since that don't reflect your actual ladder tree and I'm to lazy to do the math so without the info..., can you provide a complete list of UP/DOWN values for all 12 buttons?

lloyddean:
Much as I thought.

Since that don't reflect your actual ladder tree and I'm to lazy to do the math so without the info..., can you provide a complete list of UP/DOWN values for all 12 buttons?

Yes, basically I divided 1023 by 12 and got a value of 85.25 so I had the ranges separated by 85.

const int BUTTON1LOW = 938;
const int BUTTON1HIGH = 1023;
const int BUTTON2LOW = 853;
const int BUTTON2HIGH = 937;
const int BUTTON3LOW = 768;
const int BUTTON3HIGH = 852;
const int BUTTON4LOW = 683;
const int BUTTON4HIGH = 767;
const int BUTTON5LOW = 598;
const int BUTTON5HIGH = 766;
const int BUTTON6LOW = 513;
const int BUTTON6HIGH = 597;
const int BUTTON7LOW = 428;
const int BUTTON7HIGH = 512;
const int BUTTON8LOW = 343;
const int BUTTON8HIGH = 427;
const int BUTTON9LOW = 258;
const int BUTTON9HIGH = 342;
const int BUTTON10LOW = 173;
const int BUTTON10HIGH = 257;
const int BUTTON11LOW = 88;
const int BUTTON11HIGH = 172;
const int BUTTON12LOW = 1;
const int BUTTON12HIGH = 87;

OK, thanks and just in case how about the resister values -

                        +5v
                         |
R1   R2   R3   R4   R5   R6   R7   R8   R9  R10  R11  R12
o____o____o____o____o____o____o____o____o____o____o____o
|    |    |    |    |    |    |    |    |    |    |    |
/    /    /    /    /    /    /    /    /    /    /    /
\    \    \    \    \    \    \    \    \    \    \    \
/    /    /    /    /    /    /    /    /    /    /    /
\    \    \    \    \    \    \    \    \    \    \    \
|    |    |    |    |    |    |    |    |    |    |    |
o    o    o    o    o    o    o    o    o    o    o    o
/    /    /    /    /    /    /    /    /    /    /    /
o    o    o    o    o    o    o    o    o    o    o    o
|____|____|____|____|____|____|____|____|____|____|____|________o A0
                         o
                         |
                         /
                         \  R0
                         /
                         \
                         |
                     _________
                     / / / / /

And the value for NO button pressed?

And do you consider HIGH as button DOWN or button UP?

My guess is button DOWN!

lloyddean:
And do you consider HIGH as button DOWN or button UP

LOW and HIGH are the limits of the ranges of values for the arduino to tell if the button is PUSHED or not.

If you're talking about the record and play button which are using digital inputs (temporarily), then yes, HIGH is button pressed and LOW is not.

lloyddean:
And the value for NO button pressed?

The value for no button being pressed is analogRead = 0.

lloyddean:
OK, thanks and just in case how about the resister values -

The values of the resistors can be from 1k Ohm to 100k Ohm or more. I haven't gone out and bought the resistors yet because I didn't have time. The values of the resistors should make it so that the fluctuations of the reading of the serial monitor land within the ranges I specified. If you get high enough tolerance resistors, I'm sure the number of buttons on one analog pin could be multiplied, but I plan on getting 5% tolerance resistors and just making this thing work.

Thanks for the information.

Some time to think ...

By the way for anyone wondering why I'm using LEDs in the code, it's just for testing. These will eventually be swapped for signals going to transistors or something which will get the job done.

As to how to store them - are you familiar wit the concept of a stack?

While I’m still working on reducing the button presses to 0 = NONE, 1 - 12

Some untested example code for storing, removing and reporting items into, out-of and on a stack.

It is untested but should work.

Questions are expected but I’ll be back a little latter so please excuse the absence.

#include <stddef.h>

const size_t  MAXSTACK    = 10;
const int     EMPTYSTACK  = -1;

struct stack_t
{
    int     m_top;
    size_t  m_count;
    char    m_v[MAXSTACK];
};

typedef stack_t    stack_t;

size_t stackCount(stack_t& stack)
{
    return stack.m_count;
}

void stackClear(stack_t& stack)
{
    stack.m_count   = 0;
    stack.m_top     = EMPTYSTACK;
}

void stackPush(stack_t& stack, int value)
{
    stack.m_v[++stack.m_top] = value;
    stack.m_count++;
}

int stackPop(stack_t& stack)
{
    stack.m_count--;
    return stack.m_v[stack.m_top--];
}

int stackIsFull(stack_t& stack)
{
    return stack.m_top + 1 == MAXSTACK;
}

int stackIsEmpty(stack_t& stack)
{
    return stack.m_top == EMPTYSTACK;
}

int stackAt(stack_t& stack, size_t index)
{
    if ( (index > EMPTYSTACK) && (index < MAXSTACK) )
    {
        return stack.m_v[index];
    }

    return EMPTYSTACK;
}


stack_t     stack;

void loop()
{   }

void setup()
{
    Serial.begin(9600);

    // ... push 0 to 9 on stack ...
    for ( size_t i = 0; ! stackIsFull(stack); i++ )
    {
        stackPush(stack, i);
    }

    // ... no-destructively report all items on the stack ...
    for ( size_t i = stackCount(stack); i--; )
    {
        Serial.print(stackAt(stack, i));
    }

    // ... pull all items from the stack ...
    while ( ! stackIsFull(stack) )
    {
        Serial.print(stackPop(stack));
    }
}

No, this is the first time I hear of stacks,

I'll look into it.

Thanks :slight_smile:

Note, we are programming in C++.

You should lookup C++ 'references' as well since the code uses them.

Unless you have very high percision resisters you are unlikely to hit those voltage windows expected for the buttons!

EDIT: And C/C++ structures as well.

lloyddean:
Note, we are programming in C++.

You should lookup C++ 'references' as well since the code uses them.

Unless you have very high percision resisters you are unlikely to hit those voltage windows expected for the buttons!

EDIT: And C/C++ structures as well.

Yes, like I said, I haven't got the resistors yet, but I know it is do-able.

It looks like STACKS is a last in first out (lifo) type of structure, so if I have a list of button pushes along with the counter,

count: 1 button1
count: 2 button4
count: 3 button8
count: 4 button2

etc...

the output will look something like this,

count: 4 button2
count: 3 button8
count: 2 button4
count: 1 button1

so it outputs the sequence in reverse. I would like it to output in the same order as the sequence was originally recorded. I see that there's also a structure called Queue, which is Stacks but in reverse (first in, first out, or last in last out if you prefer).

As for the resistors, I can always get 1% tolerance resistors.

Thanks for giving me something to study, I had no idea about these structures. :smiley:

Stacks can contain structures as well.

I’m not going to work out finished code for button presses but simply give you something to think about.

Some things we know -

const int       ADC_NUM_BITS            = 10;
const int       ADC_RANGE               = 1 << ADC_NUM_BITS;
const int       ADC_MIN                 = 0;
const int       ADC_MAX                 = ADC_RANGE - 1;

const size_t    NUM_BUTTONS             = 12;

const int       BUTTTON_UP_DOWN_RANGE   = ADC_MAX / NUM_BUTTONSl

int button  = (ADC_MAX / analogRead(A0))

Once the button presses are reduced to integers you can use them as indexes into an arrays of counts and increment/decrement them as you wish!

You should be able to use the BUTTON_UP_DOWN_RANGE as a window with which to classify the button as HIGH or LOW. Perhaps a mid-point of some type?

I vaguely understand the code you gave me.

Could you give me a more concrete example with say button 1, the record button, and the play button? I’m not sure how to set the array so that the counter AND the buttonValues go in the array as they’re being pressed.

const int ADC_NUM_BITS = 10; // I don’t understand this
const int ADC_RANGE = 1 << ADC_NUM_BITS; // or this (<<)

int button = (ADC_MAX / analogRead(A0)) // would this eliminate the need to set the
// ranges for the resistors on each button?

Like I said in my original post, I just began programming a few months ago.

So STACKS is the way to go. I’m looking at the QUEUE library right now to see how it works.

Thanks for your help.

From my reading of your requirements every time a button is pressed you need to store the button number and when it was pressed. When the button is released you need to store that time to calculate the duration of the button press.

Here is some code that stores the min and max button value readings in one array and button press info in another array. Typing the ‘p’ key into the serial monitor prints out the button press values.

This is assuming that you will press and release one button at a time. If you want to record that a button is pressed when another is also down it gets much more complicated.

This code compiles, test it with your hardware setup if you like.

// analog reading values for each button
typedef struct buttonvalue {
  int minReading;
  int maxReading;
};

const int NUMBUTTONS = 2;    // # of buttons

// array holding button reading values
buttonvalue bVals[] = {
  1002, 1024, 900, 950};

// iformation about one button press
typedef struct buttonPress {
  byte buttonNum;
  unsigned long pressStart;
  unsigned long pressEnd;
};

// all recored button presses
buttonPress bPress[20];

const int  buttonPin = 0;   // the pin that the pushbutton is attached to
int lastButtonState = 0;   

int pressIdx = 0;  // index of button pressed

void setup()
{
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);

  Serial.begin(9600);

}

void loop()
{
  int reading = analogRead(buttonPin);

  if (reading != lastButtonState) {

    // if button went up
    if( reading == LOW )
    {
      // record end time
      bPress[pressIdx++].pressEnd = millis();

    } 
    else {

      // button went down

      // look at each button
      for(int i = 0; i < NUMBUTTONS; i++)
      {
        // if this button is down
        if( (reading >= bVals[i].minReading) && (reading <= bVals[i].maxReading) )
        {
          // record button pressed, start time
          bPress[pressIdx].buttonNum = i;              // record button #
          bPress[pressIdx].pressStart = millis();      // record start time

          break; // stop looking

        }// if


      } // for

    } // else

  } // if

  lastButtonState = reading;
}

void serialEvent(){

  // type 'p' into serial monitor to show button press values
  if(Serial.read() == 'p')
  {
    for(int i = 0; i < 20; i++)
    {
      Serial.print("Button: ");
      Serial.println(bPress[i].buttonNum);
      Serial.print("Start: ");
      Serial.println(bPress[i].pressStart);
      Serial.print("End: ");
      Serial.println(bPress[i].pressEnd);

    }
  }




}