1

I am experimenting with the serial monitor in an Arduino Uno. My project consists in a simple LED turning on and off at will with the commands "ON" and "OFF" respectively.

To achieve this, I use an HC-06 Bluetooth module, but because of the nature of the test I decided to disconnect it and 'debug' my project using the serial monitor as an equivalent.

The circuit has the following connection table:

LED +: Pin 12 on my Arduino. LED -: GND on my Arduino.

...as you can see, I have tried to simplify as much as I can the circuit, as I wanted to make sure I didn't have wire problems.

Here's the code:

char command;
String string;
#define led 12 

void LEDOn()
    { 
          digitalWrite(led, HIGH);
    }

void LEDOff()
    {
      digitalWrite(led, LOW);
    }

void setup() 
{
      Serial.begin(9600);
      pinMode(led, OUTPUT);
}

void loop()
{
     if (Serial.available() > 0)
           {string = "";}

     while(Serial.available() > 0)
    {
           command = ((byte)Serial.read());

           if(command == ':')
           {
                  break;   
           }  

           else
           {
                  string += command;
           }

           delay(1);
    }

    if(string == "LO")
    {
           LEDOn();
     }   

   if(string == "LF")
    {
           LEDOff();
    }

The problem comes when I type the commands. Normally, an LED in the board will react (I think it's the RX one), but the LED in pin 12 will not react at all. After testing ten times with each command alternatively, I calculated the serial needs an average of 6 command repetitions in order to react. Exactly the same happens when the HC-06 is connected.

Is there a reason for this?

  • Does the problem occur at higher BPS? For example, try changing Serial.begin(9600); to Serial.begin(115200); (and change serial monitor BPS also). Note, you should do string = ""; only in setup() and after processing :, LO, or LF, or something like that, since it perhaps could be loop() loops before getting a complete command – James Waldby - jwpat7 Dec 29 '16 at 21:20
  • Please read and digest this, then re-write your code accordingly: hackingmajenkoblog.wordpress.com/2016/02/01/… – Majenko Dec 29 '16 at 21:26
  • @jwpat7 There's no response at all if I set a baudrate higher than 9600. – xvlaze Dec 29 '16 at 21:32
  • There is a problem with your code: Serial.available() > 0 might be false at your if test, but true at your while loop condition, which means that string has a chance of not being correctly initialized to "" before you start chaining characters to it. I would also add some sanity check on the input stream, because as it is now any failure is silent. When you exit the loop, either string == "LO" or string == "LF". If not, then you could print the content of string to Serial and see why the command was not taken. What's the point of delay(1)? – Patrick Trentin Dec 29 '16 at 21:53
  • The baudrate needs to be changed both within the Arduino program and on the serial client you use on your pc, otherwise they can't talk to one another. I doubt that's the cause of it, though. – Patrick Trentin Dec 29 '16 at 21:54
0

Your problem is, amongst other things, that you are assuming that all the serial data arrives at once, which doesn't necessarily happen at all.

I have a discussion about this sort of thing.

Rewriting your sketch using the ideas presented there we get this:

#define led 12

void LEDOn()
{
  digitalWrite(led, HIGH);
}

void LEDOff()
{
  digitalWrite(led, LOW);
}

// how much serial data we expect before a newline
const unsigned int MAX_INPUT = 50;

void setup ()
{
  Serial.begin (9600);
  pinMode(led, OUTPUT);
} // end of setup

// here to process incoming serial data after a terminator received
void process_data (const char * data)
{

  if (strcmp (data, "ON") == 0)
    LEDOn ();
  else if (strcmp (data, "OFF") == 0)
    LEDOff ();
  else
    {
    Serial.print (F("Unexpected command: "));
    Serial.println (data);
    }
}  // end of process_data

void processIncomingByte (const byte inByte)
{
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
  {

    case '\n':   // end of text
      input_line [input_pos] = 0;  // terminating null byte

      // terminator reached! process input_line here ...
      process_data (input_line);

      // reset buffer for next time
      input_pos = 0;
      break;

    case '\r':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;

  }  // end of switch

} // end of processIncomingByte

void loop()
{
  // if serial data available, process it
  while (Serial.available () > 0)
    processIncomingByte (Serial.read ());

  // do other stuff here like testing digital input (button presses) ...

}  // end of loop

with the commands "ON" and "OFF" respectively.

I changed the test to be for "ON" and "OFF" not "LO" and "LF" which seems a weird way of meeting your requirements.

For this to work you need a delimiter (which tells the Arduino when you have finished sending a command). I have used linefeed which you can automatically send in the IDE's serial monitor (see bottom RH corner).

Serial monitor

I also put in code to show "Unexpected command: " if you don't get ON or OFF (note that "on" is not the same as "ON").

  • Nice! Now it works perfectly from the serial monitor. But if I wanted to send this command from an external device via Bluetooth (a smartphone, for example). how could I force the newline after the command? Using ON\n or ON"\n" does not return anything. – xvlaze Dec 30 '16 at 14:25
  • Sending "ON\n" should work. You could of course use a different delimiter. Instead of checking for \n in the code you could check for :. – Nick Gammon Dec 30 '16 at 20:39
  • It worked with ':'. Is there a reason why it's not working with '\n'? – xvlaze Dec 31 '16 at 14:35
  • No, not unless you didn't send "\n" properly. – Nick Gammon Dec 31 '16 at 21:05
0

It worked fine for me, if I typed the entire command, "LO:" or LF:" (without the quotes of course). However, if I typed and sent one character at a time, it failed. The problem is quite likely the code:

   if (Serial.available() > 0)
         {string = "";}

If you send all of the characters at once, the while( Serial.available() ) loop will get the whole line and match it. But if there is any pause between characters, what does that if statement do? (Hint: loop() executes way faster than you can type!)

I was using the serial terminal built into the Eclipse IDE. Different terminal software might behave differently when you type a string and send it. Remember, any gaps between characters, and that first if statement gets time to do its dirty work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.