Planning and Implementing an Arduino Program

CHAPTER 7 - QUESTION FOR USER

Now we will deal with getting information from the user. I have left this to last because we will be using some of the techniques we have already explored. The timing of a user's response is unpredictable - he or she may provide an answer immediately or not until after they have finished a telephone conversation. And we don't want this part of the code to interfere with the rest of things.

The concept here is very basic - just enough to show the principles involved. The Arduino will print a message on the Arduino Serial Monitor and then listen for a reply. While it is listening it will continue flashing the LEDs and controlling the servo.

When the reply comes it will say "Thank you" and repeat the response. It will then wait 5 seconds before asking the question again.

This chapter just deals with asking the question. We'll deal with the response in the next chapter.

We will store our question and the response in standard C/C++ strings (note the small s). A string is simply a char array with a 0 to mark the end of the text. NB this is the number 0, not the character '0' which has a number of 48.

const char question[] = "Please type some text and press ENTER";
const byte buffSize = 31;
char userResponse[buffSize];

The compiler will automatically allocate enough space for the text within double quotes followed by a 0.
The array userResponse has space for 30 characters plus a 0.

We need a constant and a variable to manage the time between a response and a question - similar to the way we managed the flashing LEDs.

const unsigned long questionInterval = 5000;
unsigned long prevResponseMillis = 0;

The code for askForUserInput() has to check if it is the correct time and then send the question. Importantly, it also has to check whether a response has been received so we need another variable to record that.

boolean waitingForResponse = false;

By starting with this "false" the question will be asked first time around.

And, of course, we need to start the Serial communication in setup() with

Serial.begin(9600);

I am using a baudrate of 9600 but you can use any value you wish as long as the Serial Monitor is set to use the same rate.

I find it useful to print the name of the program in case you have forgotten what program is uploaded onto your Arduino. It also shows that the Arduino is working up to that point in the code.

Serial.println("Starting LessonF.ino");

This is the code for askForUserInput()

if (waitingForResponse == true) {
  return;
}
if (currentMillis - prevResponseMillis >= questionInterval) {
  Serial.println(question);
  waitingForResponse = true;
}

If waitingForResponse is already true the function just returns without doing anything.

If waitingForResponse is false and the time has elapsed the question is printed and waitingForResponse is changed to true so we can wait for the response.

Note that, unlike the code for flashing the LEDs, the value of prevResponseMillis is not updated. That will only happen when the response is received.

Note that we could use an else clause as in

if (waitingForResponse == true) {
  return;
}
else {
  // the rest of the code
}

but it is unnecessary because of the use of return;.

The full code at this stage is in LessonF.ino

// LessonF.ino
// Program with servo, potentiometer, led flashes, switch buttons and question


//======for the servo==========
#include <Servo.h>
Servo myServo;
const byte servoPin = 5;
const byte servoMin = 20;
const byte servoMax = 160;
byte servoPosition = servoMin;

//======for the potentiometer===
const byte potPin = A0;
int potValue;

//======for the LEDs============
const unsigned long ledOnMillis = 300;
const unsigned long ledAbaseInterval = 500;
const unsigned long ledBbaseInterval = 1000;
unsigned long ledAInterval = ledAbaseInterval;
unsigned long ledBInterval = ledBbaseInterval;
byte ledAstate = HIGH;
byte ledBstate = HIGH;
unsigned long prevLedAMillis;
unsigned long prevLedBMillis;
unsigned long currentMillis;
const byte ledApin = 13;
const byte ledBpin = 12;
unsigned long ledAoffMillis = ledAbaseInterval;
unsigned long ledBoffMillis = ledBbaseInterval;

//======for the switch buttons===
const byte button0pin = 8;
const byte button1pin = 9;
byte button0state;
byte button1state;

//======for user question========
const char question[] = "Please type some text and press ENTER";
const unsigned long questionInterval = 5000;
unsigned long prevResponseMillis = 0;
boolean waitingForResponse = false;

//=====for user response=========
const byte buffSize = 31;
char userResponse[buffSize];


void setup() {
  myServo.attach(servoPin);
  myServo.write(servoPosition);
  
  pinMode(ledApin, OUTPUT);
  pinMode(ledBpin, OUTPUT);
  digitalWrite(ledApin, HIGH);
  digitalWrite(ledBpin, HIGH);
  
  pinMode(button0pin, INPUT_PULLUP);
  pinMode(button1pin, INPUT_PULLUP);
  
  Serial.begin(9600);
  Serial.println("Starting LessonF.ino");
  
  delay(5000);
}

void loop() {
 
    currentMillis = millis();

    checkButtons();
    setFlashPeriod();
    flashLedA();
    flashLedB();
    
    askForUserInput();
    getUserResponse();
    
    readPotentiometer();
    setServoPosition();
    moveServo();
}

void flashLedA() {
  if (currentMillis - prevLedAMillis >= ledAInterval) {
    prevLedAMillis += ledAInterval;
    ledAstate = ! ledAstate;
    if (ledAstate == HIGH) {
      ledAInterval = ledOnMillis;
    }
    else {
      ledAInterval = ledAoffMillis;
    }
    digitalWrite(ledApin, ledAstate);
  }
}

void flashLedB() {
  if (currentMillis - prevLedBMillis >= ledBInterval) {
    prevLedBMillis += ledBInterval;
    ledBstate = ! ledBstate;
    if (ledBstate == HIGH) {
      ledBInterval = ledOnMillis;
    }
    else {
      ledBInterval = ledBoffMillis;
    }
    digitalWrite(ledBpin, ledBstate);
  }
}

void checkButtons() {
  button0state = digitalRead(button0pin);
  button1state = digitalRead(button1pin);
}

void setFlashPeriod() {

  if (button0state == LOW && button1state == LOW) {
    return; // if both buttons are pressed do nothing
  }
  
  if (button0state == LOW) {
     ledAoffMillis = ledAbaseInterval;
     ledBoffMillis = ledAbaseInterval;
  }

  if (button1state == LOW) {
     ledAoffMillis = ledAbaseInterval >> 1;
     ledBoffMillis = ledAbaseInterval >> 1;
  }
}

void askForUserInput() {
  if (waitingForResponse == true) {
    return;
  }
  
  if (currentMillis - prevResponseMillis >= questionInterval) {
    Serial.println(question);
    waitingForResponse = true;
  }
}

void getUserResponse() {

}

void moveServo() {
  myServo.write(servoPosition);
}

void readPotentiometer() {
  potValue = analogRead(potPin);
}

void setServoPosition() {
  servoPosition = (servoMax - servoMin) * (long) potValue / 1023 + servoMin;
}

...R