Using Serial imput to run a code

      while (toggleButton[1] == 0) {
        color();
        mandmColor();
        if (buttonState == LOW) {
          toggleButton[1] = 1;
          delay(500);
        }
      }

What will cause the value in buttonState to change, while this loop is running? Hint: Not a damned thing.

@DH12043, do not cross-post. Threads merged.

My problem is that color() and mandmColor() only run once instead of until the button is pushed again like i want.

pinMode(out, INPUT);

Well, that looks real smart.

"out" is simply the name of a color sensor pin.

you are not using the internal pullup resistor. Why not?

because the external one is more powerful.

if (toggleButton[1] = 0) {

= is the assignment operator, NOT the equality operator.

It has been changed in my last reply.

What will cause the value in buttonState to change, while this loop is running?

It should check if the button is pressed.

if (buttonState == LOW) {

"out" is simply the name of a color sensor pin.

Why? The fact that it is "out" from the sensor's perspective is NO excuse for naming it "out" on the Arduino end of the connection. colorSensorPin would make a LOT more sense.

because the external one is more powerful.

And you need a "more powerful" (whatever the hell that means) one because?

It should check if the button is pressed.

buttonState doesn't check squat. Try again. What ACTUALLY checks to see of the pin is HIGH or LOW?

And you need a "more powerful" (whatever the hell that means) one because?

It cuts down on interference and makes it less likely to randomly read LOW when it is not pressed.

buttonState doesn't check squat. Try again. What ACTUALLY checks to see of the pin is HIGH or LOW?

Does this look good?

  else if (buttonState == LOW) {
    Serial.println("<Button>");
    progState = digitalRead(buttonPin);
    if (toggleButton[1] == 1) {
      Serial.println ("-Paused-");
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print ("-Paused-");
      while (toggleButton[1] == 1) {
        if (buttonState == LOW) {
          toggleButton[1] = 0;
          delay(500);
        }
      }
    }
    progState = digitalRead(buttonPin);
    else if (toggleButton[1] == 0) {
      mandmStart();
      while (toggleButton[1] == 0) {
        color();
        mandmColor();
        if (buttonState == LOW) {
          toggleButton[1] = 1;
          delay(500);
        }
      }
    }
  }

Does this look good?

No. You still don't seem to understand that EVERY time you want to know the state of a pin, you MUST call digitalRead().

Until you get that, DO NOT ASSIGN THE RESULT OF digitalRead() TO A VARIABLE.

I changed it so that it uses digital read every time now.

EVERY time you want to know the state of a pin, you MUST call digitalRead()

Here is the current code:

  else if (buttonState == LOW) {
    Serial.println("<Button>");
    buttonState = digitalRead(buttonPin);
    if (toggleButton[1] == 1) {
      Serial.println ("-Paused-");
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print ("-Paused-");
      delay(500);
      while (toggleButton[1] == 1) {
        buttonState = digitalRead(buttonPin);
        if (buttonState == LOW) {
          toggleButton[1] = 0;
        }
      }
    }
    buttonState = digitalRead(buttonPin);
    if (toggleButton[1] == 0) {
      mandmStart();
      while (toggleButton[1] == 0) {
        color();
        mandmColor();
        buttonState = digitalRead(buttonPin);
        if (buttonState == LOW) {
          toggleButton[1] = 1;
          delay(500);
        }
      }
    }
  }

It now working to some extent, the problem is that when pausing, sometimes it takes two presses to get it to pause, and sometimes it doesent regiser at all. I assume it has something to do the delays stopping the code from reading the button but i am not sure how to fix this problem. I will look into BWoD but i dont now how that will work seeing i dont completelly understand it yet and i am not sure if that would fix the problem anyways.

--DH

It's advisable to post the complete sketch so if someone wants to look at it, he/she does not have to go through the exercise of looking for the different pieces and stitching it together.

#include <LiquidCrystal.h>
#include <stdio.h>
#include <string.h>
#include <Servo.h>
#include <SPI.h>

const int s0 = 4;
const int s1 = 5;
const int s2 = 6;
const int s3 = 7;
const int out = 3;

const int buttonPin = 2;

int red = 0;
int green = 0;
int blue = 0;

int mandmcount = 0;

int buttonState;    // LOW or HIGH
int progState = 0;  // progState is used as a state variable
int toggleButton[] = {0, 0, 0, 0, 0};

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];
boolean newData = false;
char key[] = "start";
char buffer[80];

char messageFromPC[numChars] = {0};
int integerFromPC = 0;
float floatFromPC = 0.0;

int pos = 0;

Servo bottomservo;
Servo topservo;

LiquidCrystal lcd(10);
//===========================================================
void setup() {
  Serial.begin(9600);
  Serial.flush();
  delay(2);
  Serial.println("<Initializing...>");
  bottomservo.attach(9);
  topservo.attach(1);
  pinMode(buttonPin, INPUT);
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  pinMode(out, INPUT);
  digitalWrite(s0, HIGH);
  digitalWrite(s1, HIGH);
  bottomservo.write(0);
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("<Initializing..>");
  lcd.setCursor(0, 1);
  lcd.print("M&M Sorter - DH");
  delay(1000);
  Serial.println("M&M Sorter - D.H.");
  lcd.clear();
  delay(50);
  Serial.println("- Awaiting Start Command Prompt -");
  lcd.setCursor(0, 0);
  lcd.print("Awaiting Start");
  lcd.setCursor(0, 1);
  lcd.print("Command Prompt");
  delay(2);
}
//===========================================================
void loop() {
  buttonState = digitalRead(buttonPin);
  recvWithEndMarker();
  if (newData == true) {
    strcpy(tempChars, receivedChars); //Example 5 Serial Input Basics-Robin2
    // this temporary copy is necessary to protect the original data
    // because strtok() used in parseData() replaces the commas with \0
    parseData();
    showParsedData();
    newData = false;
    if (strcmp (key, receivedChars) == 0) { //start command is given
      Serial.println("<Serial>");
      mandmStart();
      for (;;) {
        color();
        mandmColor();
      }
    }
    else { //if wrong command is given
      Serial.println("<INNCORRECT> - Wait 10 Seconds");
      lcd.setCursor(0, 0);
      lcd.print("<INNCORRECT>");
      lcd.setCursor(0, 1);
      lcd.print("Wait 10 Seconds");
      delay(10000);
      Serial.println("Accepting new imput");
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Accepting new");
      lcd.setCursor(0, 1);
      lcd.print("imput");
      delay(5);
    }
  }
  else if (buttonState == LOW) {
    Serial.println("<Button>");
    buttonState = digitalRead(buttonPin);
    if (toggleButton[1] == 1) {
      Serial.println ("-Paused-");
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print ("-Paused-");
      delay(500);
      while (toggleButton[1] == 1) {
        buttonState = digitalRead(buttonPin);
        if (buttonState == LOW) {
          toggleButton[1] = 0;
        }
      }
    }
    buttonState = digitalRead(buttonPin);
    if (toggleButton[1] == 0) {
      mandmStart();
      while (toggleButton[1] == 0) {
        color();
        mandmColor();
        buttonState = digitalRead(buttonPin);
        if (buttonState == LOW) {
          toggleButton[1] = 1;
          delay(500);
        }
      }
    }
  }
}
//===========================================================
void mandmStart() {
  Serial.println("M&M Sorter - Start!");
  lcd.setCursor(0, 0);
  lcd.print("M&M Sorter");
  lcd.setCursor(0, 1);
  lcd.print("- Start!");
  delay(500);
  lcd.clear();
  delay(2);
}
//===========================================================
void mandmColor() {
  Serial.print(" R:  ");
  Serial.print(red, DEC);
  Serial.print("   | G:  ");
  Serial.print(green, DEC);
  Serial.print("   | B:  ");
  Serial.print(blue, DEC);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("R:");
  lcd.print(red, DEC);
  lcd.print("  G:");
  lcd.print(green, DEC);
  lcd.print("  B:");
  lcd.print(blue, DEC);
  lcd.setCursor(0, 1);

  if (red >= 17 && red <= 23 && green >= 23 && green <= 28 && blue >= 23 && blue <= 28)  {
    Serial.println("  - (Yellow)");
    lcd.print(" - (Yellow)");
    bottomservo.write(30);
    mandmcount = mandmcount + 1;
  }

  else if (red >= 23 && red <= 30 && green >= 38 && green <= 49 && blue >= 26 && blue <= 34)  {
    Serial.println("  - (Red)");
    lcd.print(" - (Red)");
    bottomservo.write(60);
    mandmcount = mandmcount + 1;
  }

  else if (red >= 30 && red <= 40 && green >= 27 && green <= 39 && blue >= 25 && blue <= 31)  {
    Serial.println("  - (Green)");
    lcd.print(" - (Green)");
    bottomservo.write(90);
    mandmcount = mandmcount + 1;
  }

  else if (red >= 38 && red <= 45 && green >= 32 && green <= 42 && blue >= 17 && blue <= 26)  {
    Serial.println("  - (Blue)");
    lcd.print(" - (Blue)");
    bottomservo.write(120);
    mandmcount = mandmcount + 1;
  }

  else if (red >= 18 && red <= 22 && green >= 36 && green <= 47 && blue >= 28 && blue <= 34)  {
    Serial.println("  - (Orange)");
    lcd.print(" - (Orange)");
    bottomservo.write(150);
    mandmcount = mandmcount + 1;
  }

  else if (red >= 31 && red <= 39 && green >= 40 && green <= 48 && blue >= 28 && blue <= 35)  {
    Serial.println("  - (Brown)");
    lcd.print(" - (Brown)");
    bottomservo.write(180);
    mandmcount = mandmcount + 1;
  }

  else {
    Serial.println("  - (No M&M)");
    lcd.print(" - (No M&M)");
    //bottomservo.write(0);
  }
  lcd.setCursor(12, 1);
  lcd.print("#");
  lcd.print(mandmcount);
  delay(1000);
}
//===========================================================
void color()
{
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  //count OUT, pRed, RED
  red = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH);
  digitalWrite(s3, HIGH);
  //count OUT, pBLUE, BLUE
  blue = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH);
  digitalWrite(s2, HIGH);
  //count OUT, pGreen, GREEN
  green = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH);
}
//===========================================================
void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
    }
  }
}
//===========================================================
void showNewData() {
  if (newData == true) {
    Serial.println(receivedChars);
    newData = false;
  }
}
//===========================================================
void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}
//===========================================================
void parseData() {      // split the data into its parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars, ",");     // get the first part - the string
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  integerFromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  floatFromPC = atof(strtokIndx);     // convert this part to a float
}
//===========================================================
void showParsedData() {
  //Serial.print("Message ");
  Serial.println(messageFromPC);
  //Serial.print("Integer ");
  //Serial.println(integerFromPC);
  //Serial.print("Float ");
  //Serial.println(floatFromPC);
}

The question is why you have those 'long' delays? What are you trying to achieve with each of them? Do they have a function to prevent the screen from flickering? Do you want the servo to be in a position for a certain time?

You also have an array for toggleButton but you only have one button pin; what is the future plan?

Blink-without-delay is the wrong example to look at in my opinion. Look at the debounce example.

You have two ways to start the sorting (serial and button) but only one way to pause it (button); is this intentionally? What I would do is read the serial port and the buttons and keep a flag (you already do that for the button, re-use it for the serial port).

In a very simplistic form

void loop()
{
  static int state = 0;
  if(Serial.available() > 0)
  {
    Serial.read();
    state = !state;
  }

  if(digitalRead(buttonPin) == HIGH)
  {
    state = !state;
  }

  if(state == 1)
  {
    // sort
  }
}

It needs more than that; this is only to show how you can use one variable that is controlled by both the serial port and the button.

The question is why you have those 'long' delays? What are you trying to achieve with each of them? Do they have a function to prevent the screen from flickering? Do you want the servo to be in a position for a certain time?

I have not had any problems with my screen flickering, i am not sure how that would happen anyways.
I have a delay after the color determining and sorting of the M&Ms to allow the old and new M&M's to fall into place before it re-runs. The only other delay that is not in Initialization is the one for if an incorrect command is given in the Serial Monitor so that should not interfere in any way.

Look at the debounce example.

I did and adjusted my code accordingly, or at least i tried to, not sure if i did it correct.

You have two ways to start the sorting (serial and button) but only one way to pause it (button); is this intentionally?

I did notice this and finally just got around to adding it. Thanks for the tip!

There is one question outstanding :wink: What is the future plan (why do you have an array of toggle buttons)? The design of your code highly depends on what it all has to do. It's useless to suggest an approach (or design software) if it's not clear what all functionalities of the code need to be.

I did and adjusted my code accordingly, or at least i tried to, not sure if i did it correct.
...
I did notice this and finally just got around to adding it.

By now, you should have learned ( :wink: ) that you should post updated code. If in doubt if you did it correct, does it work? If so, you probably did do it correctly :wink:

I have not had any problems with my screen flickering, i am not sure how that would happen anyways.

This will flicker the screen

void loop()
{
  lcd.Clear();
  lcd.print("Hello world");
}

With above, you're writing faster to the screen than the screen can update. With your long delays, you will not have that problem.

Unfortunately, i don't know if it will work or not because it won't compile. It says that my functions "was not declared in this scope. I looked through it and it wont accept it. I even tried closing down the program and restarting it but it wont work. I am not sure what to do with it.

I will post a link to a copy of the code because the strait copy is too long to post due to character limit.
https://drive.google.com/open?id=1ojsd7MrdJVKGfpK3I9gauFjDjhRO9i9U

--DH

sorry about not posting the code earlier, was trying to decide how to post it because it was over sized. I will have to post links in the future due to the character limit.

Scroll down and Attach it. Links to potentially virus infected hosting sites stink.

Here is my code:

MM_Sorter_shift_toggle_servo_count5.ino (9.64 KB)

Never mind, i fixed the problem by doing this in the in the area outside setup and loop before it runs:

void checkToggle();
void checkSerial();
void checkButton();
void mandmStart();
void mandmColor();
void color();
void recvWithEndMarker();
void recvWithStartEndMarkers();
void showNewData();
void parseData();
void showParsedData();

So my serial imput is now working flawlessly, however, my checkButton() function is working less than desirable. It will occasionally trigger the code but very rarely will it register no matter what i try. I have tried two different iterations of the code, #7 has debounce, and #6 does not. Neither is working.

Here is the code snippets of the function in both sketches:

#6

void checkButton() {
  int reading = digitalRead(buttonPin);
  buttonState = digitalRead(buttonPin);
  if (buttonState == LOW) {
    Serial.println("<Button>");
    if ((toggle [1] == 1) || (toggle [1] == 2)) {
      toggle [1] = 0;
    }
    else if (toggle [1] == 0) {
      toggle [1] = 1;
    }
  }
}

#7

void checkButton() {
  int reading = digitalRead(buttonPin);
  buttonState = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == LOW) {
        Serial.println("<Button>");
        if ((toggle [1] == 1) || (toggle [1] == 2)) {
          toggle [1] = 0;
        }
        else if (toggle [1] == 0) {
          toggle [1] = 1;
          delay(500);
        }
      }
    }
  }
  lastButtonState = reading;
}

Below i will attach the full codes.

MM_Sorter_shift_toggle_servo_count7.ino (10.4 KB)

MM_Sorter_shift_toggle_servo_count6.ino (10.1 KB)

Your function is a little wrong. If you look at the debounce example, there is only one digitalRead. From your code

  int reading = digitalRead(buttonPin);
  buttonState = digitalRead(buttonPin);

and

    if (reading != buttonState) {

Chances are slim that they differ after the debounce period.

The readButton function in below code is basically the debounce example placed in a function; I've stripped the things that don't relate to the button.

Note that the code does not use LOW and HIGH but ISPRESSED; makes it easier to read. LOW does not mean much, ISPRESSED a lot more. I think that you use an external pull-up; if not, add one or change the pinMode statement to use the internal pull-up. If you use an external pull-down, change LOW in the first line to HIGH.

For demonstration purposes, I've added loop and setup.

#define ISPRESSED LOW

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2;    // the number of the pushbutton pin

// Variables will change:
int buttonState = !ISPRESSED;       // the current reading from the input pin
int lastButtonState = !ISPRESSED;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup()
{
  Serial.begin(57600);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop()
{
  static int lastState = !ISPRESSED;
  int state = readButton();

  if (state != lastState)
  {
    Serial.print(millis());
    Serial.print(": Button state = ");
    Serial.println(state == ISPRESSED ? "Pressed" : "Released");
    lastState = state;
  }
}

/*
  read button
  Returns:
    last statble state
*/
int readButton()
{
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState)
  {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay)
  {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState)
    {
      buttonState = reading;
    }
  }

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;

  // return the last stable button state
  return buttonState;
}

The loop contains the state change detection.

I suggest that you use the readButton function, move the functionality of loop to checkButton and take it from there.

I have been trying to work through the code but i have hit a wall, it just won't work. It starts fine but it will rarely pause correctly. I think the problem is that it cant check it except while it is not running the sorter code. Is there any way to fix it?

Here is my current code:

MM_Sorter_shift_toggle_servo_count8.ino (10.7 KB)