Code Structure - Switching Activities with Analog Buttons

I'm completely new to Arduino and I've been reading a lot but I'm starting to get stuck. I am trying to program an UNO to control an el wire sequencer. I also have an analog keypad and sound detector to control multiple actions. The goal is to turn it on and have all channels light up. Then, with the push of a button, switch between other modes. i.e. flashing, sound reactive, back to all on, etc. I got as far as turning on and changing to another mode. I couldn't figure out how to switch back. That is the first code. The second code is the start of another approach but it's not functional. I could use some guidance before I get discouraged.

const int Key_pin = A0;
const int Gate_pin = A1;
const int Envl_pin = A2;
const int Audio_pin = A3;
int Key_read;
int Previous_Key;
int Value;
String Key_id;
String Vol_id;

void setup() {

  Serial.begin(9600);

  pinMode(2, OUTPUT);  // channel A
  pinMode(3, OUTPUT);  // channel B
  pinMode(4, OUTPUT);  // channel C
  pinMode(5, OUTPUT);  // channel D
  pinMode(6, OUTPUT);  // channel E
  pinMode(7, OUTPUT);  // channel F
  pinMode(8, OUTPUT);  // channel G
  pinMode(9, OUTPUT);  // channel H

  pinMode(10, OUTPUT); // Escudo Status LED
  pinMode(13, OUTPUT); // Arduino Status LED

  pinMode(A0, INPUT);  // Button
  pinMode(A1, INPUT);  // Gate
  pinMode(A2, INPUT);  // Envelope
  pinMode(A3, INPUT);  // Audio
}

void loop()
{
  Value = analogRead(Envl_pin);
  if (not Value <= 9)
    if (Value >= 10 and Value <= 19) Vol_id = "Low";
  if (Value >= 20 and Value <= 29) Vol_id = "Moderate";
  if (Value >= 30) Vol_id = "High";

  if (Value >= 10) {
    Serial.print(Value);
    Serial.println(" - The volume is " + Vol_id);
    delay(100);
  }
  {
    Key_read = analogRead(Key_pin);
    if (not Key_read < 600)
      if (Key_read < 299) Key_id = "Blue";
    if (Key_read > 300 and Key_read < 349) Key_id = "Yellow", mode2();
    if (Key_read > 400 and Key_read < 449) Key_id = "Green";
    if (Key_read > 450 and Key_read < 499) Key_id = "Grey";
    if (Key_read > 500 and Key_read < 549) Key_id = "Red";

    if (Key_read != Previous_Key and Key_read < 600) {
      Serial.print(Key_read);
      Serial.println("  -  " + Key_id + " key pressed");
      Previous_Key = Key_read;
      delay(1000);
    }
    {
      digitalWrite(2, HIGH);   // turn on channel A
      digitalWrite(3, HIGH);   // turn on channel B
      digitalWrite(4, HIGH);   // turn on channel C
      digitalWrite(5, HIGH);   // turn on channel D
      digitalWrite(6, HIGH);   // turn on channel E
      digitalWrite(7, HIGH);   // turn on channel F
      digitalWrite(8, HIGH);   // turn on channel G
      digitalWrite(9, HIGH);   // turn on channel H
    }
  }
}

void mode2()
{
  int x;
  for (int x = 2; x <= 9; x++)
  {
    digitalWrite(x, HIGH);   // turn the EL channel on
    delay(100);              // wait for 1/10 second
    digitalWrite(x, LOW);    // turn the EL channel off
  }
  for (int x = 9; x >= 2; x--)
  {
    digitalWrite(x, HIGH);   // turn the EL channel on
    delay(100);              // wait for 1/10 second
    digitalWrite(x, LOW);    // turn the EL channel off
  }
  mode2();
}
const int Key_pin = A0;
const int Gate_pin = A1;
const int Envl_pin = A2;
const int Audio_pin = A3;
int Key_read;
int Previous_Key;
int Value;
int Mode_1;
int Mode_2;
String Key_id;
String Vol_id;

void setup() {

  Serial.begin(9600);

  pinMode(2, OUTPUT);  // channel A
  pinMode(3, OUTPUT);  // channel B
  pinMode(4, OUTPUT);  // channel C
  pinMode(5, OUTPUT);  // channel D
  pinMode(6, OUTPUT);  // channel E
  pinMode(7, OUTPUT);  // channel F
  pinMode(8, OUTPUT);  // channel G
  pinMode(9, OUTPUT);  // channel H

  pinMode(10, OUTPUT); // Escudo Status LED
  pinMode(13, OUTPUT); // Arduino Status LED

  pinMode(A0, INPUT);  // Button
  pinMode(A1, INPUT);  // Gate
  pinMode(A2, INPUT);  // Envelope
  pinMode(A3, INPUT);  // Audio
}

void loop()
{
  Keypad();
  Sound_detect();
  Mode_1();
  Mode_2();
}

void Keypad()
{
  Key_read = analogRead(Key_pin);
  if (not Key_read < 600)
    if (Key_read < 299) Key_id = "Blue";
  if (Key_read > 300 and Key_read < 349) Key_id = "Yellow", Mode_2();
  if (Key_read > 400 and Key_read < 449) Key_id = "Green";
  if (Key_read > 450 and Key_read < 499) Key_id = "Grey", Mode_1();
  if (Key_read > 500 and Key_read < 549) Key_id = "Red";

  if (Key_read != Previous_Key and Key_read < 600) {
    Serial.print(Key_read);
    Serial.println("  -  " + Key_id + " key pressed");
    Previous_Key = Key_read;
    delay(1000);
  }
}

void Sound_detect()
{
  Value = analogRead(Envl_pin);
  if (not Value <= 9)
    if (Value >= 10 and Value <= 19) Vol_id = "Low";
  if (Value >= 20 and Value <= 29) Vol_id = "Moderate";
  if (Value >= 30) Vol_id = "High";

  if (Value >= 10) {
    Serial.print(Value);
    Serial.println(" - The volume is " + Vol_id);
    delay(100);
  }

  void Mode_1()
  {
    digitalWrite(2, HIGH);   // turn on channel A
    digitalWrite(3, HIGH);   // turn on channel B
    digitalWrite(4, HIGH);   // turn on channel C
    digitalWrite(5, HIGH);   // turn on channel D
    digitalWrite(6, HIGH);   // turn on channel E
    digitalWrite(7, HIGH);   // turn on channel F
    digitalWrite(8, HIGH);   // turn on channel G
    digitalWrite(9, HIGH);   // turn on channel H
  }

  void Mode_2()
  {
    {
      int x;
      for (int x = 2; x <= 9; x++)
      {
        digitalWrite(x, HIGH);   // turn the EL channel on
        delay(100);              // wait for 1/10 second
        digitalWrite(x, LOW);    // turn the EL channel off
      }
      for (int x = 9; x >= 2; x--)
      {
        digitalWrite(x, HIGH);   // turn the EL channel on
        delay(100);              // wait for 1/10 second
        digitalWrite(x, LOW);    // turn the EL channel off
      }
    }
  }

Do your code in little chunks. Get a chunk working. Make it encapsulated. Eg light up mode. I see you are doing some functions in your code. Do it in separate sketches each saved with a sensible name. In one chunk do buttons and set a variable such as modeSelect. Your button can cycle through modes by adding 1 to a variable each time using modulus %. And dividing by the number of modes.
In loop you just need an if modeSelect=1 do x if 2 do y if 3 do z

You can combine sketches at the end. This helps you to picture things as objects and also leads to potential library creation so that your main code will look neat and easily understood

Your final sketch should read (in pseudo code like this)
PollButton()
If modeSelect = 1
LightUp()
If modeSelect = 2
Flash()
Else
DosomethingCool()

Get a timing setup for delays without delay! Think in loops

Never heard about analog keyboards or buttons, only digitally working. Analog button.. usually a potentiometer....

Keypad will be non-responsive while this is running.

Probably key switches on a resistive divider... standard way to save pins.

Possible for buttons but rather demanding for a matrix keyboard I think...

How does this work when I have five discreet buttons that I want to have assigned functions?

In what regard? I have some delays already.

Correct

...that you must get rid of, if you expect the buttons to respond!

And always include a schematic of your project when asking questions.

I don't know where to begin to provide that.

Remember that all your code really runs in loop being read again and again really fast. Any delay will change the loop from looping really fast to really slow so the chance of it noticing a button being pushed at exactly the right time is small.

Delay is a human time scale thing not a microcontroller time scale thing. While your code simply stops for however many seconds your delay has in it nothing else will happen. That’s why I said to think in loops. Everything you code should be fast and able to be read again and again while making sense. That means when you have a human interface such as a button your code will implement your button polling function so many times every second that a human couldn’t press the button quick enough not to be picked up. You will never miss a button press.

Look up blink without delay

Start with reading these discussions.


https://learn.sparkfun.com/tutorials/how-to-read-a-schematic


1 Like

If I'm going to switch to using timers over delays, I'm going to need some help wrapping my brain around it. For example, how would I rewrite this for() loop "Knight Rider" code?

      {
        int x;
        for (int x = 2; x <= 9; x++)
        {
          digitalWrite(x, HIGH);   // turn the EL channel on
          delay(100);              // wait for 1/10 second
          digitalWrite(x, LOW);    // turn the EL channel off
        }
        for (int x = 9; x >= 2; x--)
        {
          digitalWrite(x, HIGH);   // turn the EL channel on
          delay(100);              // wait for 1/10 second
          digitalWrite(x, LOW);    // turn the EL channel off
        }
      }

The problem that I particularly need to wrap my head around is the syntax/formatting/structure I need to compartmentalize these modes. I can set and save a button state in the main loop. As soon as I try to add a loop, function, whatever, I get 'undefined' errors. I can create working modes, like the "Knight Rider" sequence in the main loop. But I cannot figure out how to callback, let alone define elements. I don't know if my line of questioning even makes sense.

Get knight rider mode working in a sketch all on its own. Get rid of the delays by using a millis timer. A millis timer works exactly the same as a stop watch:

  1. When the action occurs that demands a timer check the millis stopwatch and record the time in a variable.
    Unsigned long timerStartTime = millis
  2. decide on the interval that you need.
    Int interval = 5000 for example
  3. check the clock regularly to see if that interval has elapsed
    If millis - timerStartTime >= interval {time is up do something}

All code above is pseudocode and is only a rough example. Blink without delay examples give you correct format and syntax.

Remember loop is looping fast so every fraction of a second it will loop back round and check the time and compare time elapsed with your interval. The important thing is that it can also attend to anything else in your code while it loops round which is completely different from a dirty big delay where the loop just stops dead for x seconds.

And that is the point - you do not add loops. You test and make decisions in the main loop and store the results in variables or "flags". Those flags then become part of the decisions the next time round the loop; the record the "state" of the system which is then called a "state machine".

See Blink without delay() explained line-by-line and Using millis() for timing. A beginners guide.

Thank you for the resources. I'm reading everything and researching terms and concepts. It just hasn't clicked yet for me. Does this make sense?

  • Have buttons create a variable state change. i.e. Press red button, Button State = Red
  • Add working 'modes' to the loop as functions
  • Create if statements for functions based on the Button State

Hello h27790

To get started take some time, study the IPO model and take a piece of paper plus a pencil and design a program structure. Identify modules could to be coded and tested separetly. Merge after sucessfull testing all modules together to the needed project.
It is highly recommented to take a view into some powerful C++ instructions like STRUCT, ENUM, ARRAY, CASE/SWITCH,UDT, RANGE-BASED-FOR-LOOP, etc, too.

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

p.s.
Some usefull examples can be found here:

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