Serial.read an aray

Hi
I am trying to read an array from the serial monitor (in future vb)
What I would like to be able to do is set the pin (LED) to whatever 25 say and then a value of either 1 or 0 to turn it on or off. So I would type 25 press enter then type 1 and press enter to turn pin 25 high.

I can read it fine with the following code.

int LED;    //Used to control outputs
int State;  //Used to control the state of outputs
int On_Off;      //Used to read array from Serial data

unsigned char bytes[2];  //Array to store values from Serial data

void setup(){
  Serial.begin (9600);  //Start Serial at 9600
  pinMode(13, OUTPUT);  //Set output (only useing pin 13 with onboard LED for testing purposes)
  }

void loop(){
  ReadSerial();
  //digitalWrite(13,HIGH);
  digitalWrite(LED, State);   
  
    Serial.print(LED);
    Serial.print(", ");
    Serial.println(State);   
}

void ReadSerial(){
  while(Serial.available()<2){} // wait for 2 bytes to be available
   
  for(int n=0;n<2;n++)
    bytes[n] = Serial.read();
   
  int L1 = bytes[0];  //L1 used for LED (Set pin)
  int D1 = bytes[1];  //D1 used to set hi or low
      
  LED = L1-'0';        
  On_Off = D1-'0';
   
  if(On_Off==1) {
    State = HIGH;
  }
  else if(On_Off==0){
  State = LOW;
  }  
}

However if LED is above 9 it does not work. For example if I enter 20 then 1. It thinks that 2 is the LED value and 0 is the On_Off value then 1 would start to fill the next buffer, 0.

Any ideas???

Simple serial test code that uses an added comma , as a delimiter to signify the end of the data packet being sent.

//zoomkat 3-5-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port
//send on, or off, from the serial monitor to operate LED

int ledPin = 13;
String readString;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT); 
  Serial.println("serial LED on/off test with , delimiter"); // so I can keep track
}

void loop() {

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      Serial.println(readString); //prints string to serial port out
      //do stuff with the captured readString
      if(readString.indexOf("on") >=0)
      {
        digitalWrite(ledPin, HIGH);
        Serial.println("LED ON");
      }
      if(readString.indexOf("off") >=0)
      {
        digitalWrite(ledPin, LOW);
        Serial.println("LED OFF");
      }       
      readString=""; //clears variable for new input
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

if I were to do it that way (with the ,) how would I then read the 2 values sent 13,1, to turn on led 13

grantastley:
So I would type 25 press enter then type 1 and press enter to turn pin 25 high.

Note that you type 3 characters… 2, 5, 1

Comments in the code… Assuming you type 2, 0, 1

void ReadSerial(){
  while(Serial.available()<2){} // wait for 2 bytes to be available
    // you type 3 bytes, wait for two. At this point, you have at least two bytes, and
   // most likely, ONLY two bytes.
   
  for(int n=0;n<2;n++)
    bytes[n] = Serial.read();
   // bytes[0] contains  '2'
   // bytes[1] contains '0'

  int L1 = bytes[0];  //L1 used for LED (Set pin)
  int D1 = bytes[1];  //D1 used to set hi or low
  // L1 now equals '2' and D1 now equals '0'
      
  LED = L1-'0';        
  On_Off = D1-'0';
   // L1 now equals 2, and D1 now equals 0

  if(On_Off==1) {
    State = HIGH;
  }
  else if(On_Off==0){
  State = LOW;
  }  
  // and the above does exactly what you said, rather than what you meant.
  // AND the 1 you typed will still be in the serial buffer, 
}

So, you can fix it by simply making it wait for 3 bytes. in the while(), and converting the first two bytes to an integer, and the third byte can be checked while it is still a char.

By the way, in your for loop, you don’t use curlies {}. While some might disagree with me, I do think it’s ALWAYS best to use them, even if your loop only has a single statement. The reason for this is that it generates a good habit, making it less likely you’ll forget to put them in, and it also means that if you add a statement later, with the intention of putting it within the loop, you will be less likely to just add it and forget the {}. The same goes for an if that has the conditional statement on a separate line. I usually leave out the {} if the if and the statement are on a single line. And finally, I think it improves readability

grantastley:
if I were to do it that way (with the ,) how would I then read the 2 values sent 13,1, to turn on led 13

Not sure of the character string you are sending, so you need to show specific examples. If you send a command like 131 to set pin 13 high and 130 to set pin 13 low, then you would use something like below.

if(readString.indexOf("131") >=0)
if(readString.indexOf("130") >=0)

Well I got it to work with the following

int LED;    //Used to control outputs
int State;  //Used to control the state of outputs
int On_Off; //Used to read array from Serial data
int LED1;   //Used to construct LED
int LED2;   //Used to construct LED

unsigned char bytes[3];  //Array to store values from Serial data

void setup(){
  Serial.begin (9600);  //Start Serial at 9600
  pinMode(13, OUTPUT);  //Set output (only useing pin 13 with onboard LED for testing purposes)
  }

void loop(){
  ReadSerial();
  //digitalWrite(13,HIGH);
  digitalWrite(LED, State);   //Write pin to value coming across serial data
  
}

void ReadSerial(){
  while(Serial.available()<3){} // wait for 3 bytes to be available
   
  for(int n=0;n<3;n++)
    bytes[n] = Serial.read();
   
  int L1 = bytes[0];  //L1 used for LED (Set pin)
  int L2 = bytes[1];  //L2 used for LED (Set pin)
  int D1 = bytes[2];  //D1 used to set hi or low
   
  LED1 = L1-'0';        
  LED2 = L2-'0';
  LED = ((LED1*10) + LED2);  
  On_Off = D1-'0';
   
  if(On_Off==1) State = HIGH; 
  else if(On_Off==0) State = LOW;
}

lar3ry - Im not sure of your reasoning with the curly brackets. I used them on the if statements that only had 1 line of code as it did have serial.prints there as well used for debugging and the For loop does not require them. I would have thought that if you are going to advise to use them for 1 situation (the For loop) than you should do it for all situations (Ifs, Whiles, etc) to keep code uniform.
Please do not get me wrong though I am very grateful for your help, which has led to me getting the code to work :slight_smile:

unsigned char bytes[3];  //Array to store values from Serial data

Now, suppose that you want to send pin 11 and 150 as thePWM value.

Using delimiters between the values, and start and end-of-packet markers makes reading and parsing much easier. Using the following code, you could send “<11, 150>”.

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

Where it says “Process the packet”, you could call strtok() and atoi() to get the two tokens (“11” and “150”) and convert them to ints (11 and 150).

grantastley:
lar3ry - Im not sure of your reasoning with the curly brackets. I used them on the if statements that only had 1 line of code as it did have serial.prints there as well used for debugging and the For loop does not require them. I would have thought that if you are going to advise to use them for 1 situation (the For loop) than you should do it for all situations (Ifs, Whiles, etc) to keep code uniform.
Please do not get me wrong though I am very grateful for your help, which has led to me getting the code to work :slight_smile:

Ummm… I did say

The same goes for an if that has the conditional statement on a separate line. I usually leave out the {} if the if and the statement are on a single line. And finally, I think it improves readability.

In case my meaning wasn’t clear, let me show a few examples. Bear in mind that there is no difference to the actual code generated, and I recommend this only because it helps to avoid traps when you (later) read, maintain, or mofify uour code.

I would write these conditionals this way:

    for (i =0; i < 3; i++)  buf[i] = x;

    for (n =0; n < 3; n++) {
        str[n]  = s;
    }

    if ( dataFound) return result;
    else toggleLED();

    if ( j == 10 ) {
        ( j = x);
    }
    else {
        j++;
    }

It’s not a big deal, but I’ve been bitten by the trap, and have seen many others bitten as well, sio i mention it when I see it.