serial.read to array (16 ints)

0
Hi :slight_smile:

I’m working on a audio-reactive lightinstallation with 16 LED lights. In Max MSP I analyse my audio and split the frequencies in 16 ‘parts’. I store these parts in a message of 16 ints, either 1 or 0 (on of off). Every time a new frequency is detected the message updates and puts out a new int from 16 numbers (for exampe 1000100100110101).

I receive this number in my serial monitor of my Arduino Uno. I want to put this ‘incomingValues’ in an array so I can check if a number/frequency is 0 or 1. When it’s 1 I can turn on my relay/ light. The ‘incomingValues’ is changing quite quickly but that shouldn’t be a problem right?

I tried multiple things to create an array and update this every time a new serial message is coming in but I’m not used to work with Arduino so I could need some help.

Thanks! :slight_smile:

Here is my code:

int counter;
int incomingValues = 0;
int lights[16];


void setup() {
  Serial.begin(9600);
  counter = 0;
  pinMode(13, OUTPUT);
}

void loop() {

  boolean newValue = false;

  while (Serial.available() > 0) {

    incomingValues = Serial.read();
    Serial.print(incomingValues);
    counter = counter + 1;

    newValue = true;
  }


  if (newValue) {
//    delay(50);
//    lights[counter] = incomingValues;
//
//
//    Serial.print(lights[0]);
//
//    for (int i = 0 ; i < 16 ; i ++) {
//      Serial.print(lights[i]);
//    }
//    Serial.println("");
//    newValue = false;
  }

  if (counter > 15) {
    counter = 0;
    Serial.print("\n");
  }

  if (incomingValues == 1) {
    digitalWrite(13, HIGH);
  } else if (incomingValues == 0) {
    digitalWrite(13, LOW);
  }
}

Every time a new frequency is detected the message updates and puts out a new int from 16 numbers (for exampe 1000100100110101).

Do you mean that you are using an int to store a value of 0 or 1 ?

Serial.read() returns one char, not an entire array. You will have to read them in one at a time and store them in your array as they arrive. It is also not clear to me if the incoming data stream contains '1' and '0' which are asciii values or just a 1 and a 0 (numbers).

You might want to read this thread Serial Input Basics to get a more robust method.

To make things more clear:

This is what I get as serial input

UKHeliBob:
Do you mean that you are using an int to store a value of 0 or 1 ?

I'm not storing the values yet, the only come in with serial (I posted a picture to make things more clear).
I need to find a way to store these numbers individually but I didn't succeed...

Why are you using an int to hold a value of 0 or 1 when a byte would do ?
Even better, you could get 16 values in a singe int

Perhaps I don't understand what you're trying to do, but I think it would be easier to use:

// in loop
char values[17];
int state;
int i;

  while (Serial.available() > 0) {
     i = Serial.readBytesUntil('\n', values, sizeof(values) - 1);
     values[i] = '\0';                 // Now it's a string, so
     Serial.println(values);           // ...show it
   }
   i = 0;
   while (values[i]) {
      state = (int) values[i++];       // turn '1' or '0' into int
      digitalWrite(13, state);         // Maybe on...maybe off     
      delay(500L);                     // wait a half second...
      if (state)                       // if on, turn it off
         digitalWrite(13, LOW); 
   }

This assume a newline '\n' character terminates input stream.

UKHeliBob:
Even better, you could get 16 values in a singe int

I think that’s what the OP is actually doing

message updates and puts out a new int from 16 numbers (for exampe 1000100100110101).

My inclination is the opposite of yours. As it seems that the OP wants to use the individual bits my suggestion would be to send the data as a string - for example Serial.println("<10000100101010101>"); as then the individual parts can be dealt with by iterating over the received data - something like

for (byte n = 0; n < 16; n++) {
   digitalWrite(ledPins[n], receivedChars[n] - '0');
}

assuming that there is an array called ledPins that has the list of I/O pins for the leds.

…R

Thanks for the answers!
I didn't knew the Serial.readBytesUntil() function.

I tried the following code:

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

void loop() {

  char values[17];
  int state;
  int i;

  while (Serial.available() > 0) {
    i = Serial.readBytesUntil('\n', values, sizeof(values) - 1);
    values[17] = i;   
    Serial.println(i);
  }
    i = 0;
    while (values[i]) {
      state = (int) values[i++];    
      Serial.print(values);
      digitalWrite(13, state);         
      delay(20);                     
      if (state)                      
      digitalWrite(13, LOW);
    }
}

Serial.println(i) gives me "16".
Maybe I miss something but the sixteen incoming values aren't stored in an array yet right?

digitalWrite(13, state) is working to turn the relay on or off (when I change the serial input first number).
But I'm not sure how I can use the other values of the incoming numbers, I'm trying to figure it out now :slight_smile:

@Robin2 is right about using the bits individual.
Every number of "10000100101010101" represents one pin on the arduino (HIGH or LOW).

I just have to check if the first number is a 0 or 1, if the second is a 0 or 1, etc...

sjoerdmol:
I just have to check if the first number is a 0 or 1, if the second is a 0 or 1, etc...

In the code snippet I posted in Reply #7 there is not even a need to check.

...R

Robin2:
as then the individual parts can be dealt with by iterating over the received data

Ah now I get it :slight_smile:
That’s great!

I now have it working (code below).
Now I can use your piece of code to make it better :slight_smile:

const byte bufferSize = 16;
char inputBuffer[bufferSize + 1];
int myDelay = 20;

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

void loop(){

  if(Serial.available() > 0){
    byte bytesRead = Serial.readBytesUntil('\n', inputBuffer, bufferSize);
    if(bytesRead == 16){
      for(byte i = 0; i < 16; i++){
        if(inputBuffer[0] == 1){
          digitalWrite(13, HIGH);
          delay(myDelay);
        }
        else{
          digitalWrite(13, LOW);
        }
        if(inputBuffer[1] == 1){
          digitalWrite(12, HIGH);
          delay(myDelay);
        }
        else{
          digitalWrite(12, LOW);
        }
      }
      Serial.println();
    }
    else{
      Serial.println("Invalid data length.");
    }
  }
}

Check my code. I did NOT write:

   // missing code...

    values[17] = i;   // Read it again.

   // more missing code

Programming usually requires paying close attention to the details.