Serial.read() getting random characters from exact same input

Good afternoon,
I created a simple Android app using the MIT App Inventor. I have a button on the app that sends the following data to the Arduino via the HC-06 BlueTooth module:

When I push the button quickly and output the command string to the serial monitor, I can see that most of the time the proper string is present, but randomly, I'll get garbage, or I'll get one character changed.
In the below screenshot, I did not change any values of the sliders and the expected command string is "1,148,128". However, when i clicked the button quickly several times, you can see that the second time, the "2" in "128" was translated as "b" and the 6th click yielded a bunch of garbage characters.

The issue is easily replicable. I followed this article schematic to pull down the tx/rx to 3.3V that the HC-06 requires - Arduino and Bluetooth module HC-06 • AranaCorp. The wiring diagram looks like this:

And this is the Arduino code in the loop:

void loop(){
  //Read data from HC06
  while(hc06.available()>0){
    cmd += (char)hc06.read();
  }

  if(cmd!=""){
    Serial.print("Command received : ");
    Serial.println(cmd);

        while (((index) < cmd.length()) && ((isDigit(cmd[index])) || (cmd[index] == ','))) {
        char byteIn = cmd[index];
        if (byteIn == ',') {
       count++;
     } 

     if ((byteIn != ',')) {
       if (count == 1) {
         mode += byteIn;
       } else if (count == 2) {
         brightness += byteIn;
     } else if (count == 3) {
       color += byteIn;
     }
   }


      index++;
        }
int COLOR = color.toInt();
int BRIGHTNESS = brightness.toInt();
Serial.print("COLOR: ");
Serial.println(COLOR);
Serial.print("BRIGHTNESS: ");
Serial.println(BRIGHTNESS);
if (BRIGHTNESS > 0) {
        fill_solid(leds, NUM_LEDS, CHSV(COLOR, 255, BRIGHTNESS));
}
    if(mode=='OFF'){
        Serial.println("LEDs are off");
        fill_solid(leds, NUM_LEDS, CRGB::Black);
    }  else if (mode=='1') {
      } else  {
        Serial.println("unknown command");
    }

    count=1; //reset count
    index=0; //reset index
    mode="";
    color="";
    brightness="";
    FastLED.show();
 
  }
    cmd=""; //reset cmd } 
}

I'm hoping someone can point me in the right direction regarding cleaning the signal up. It's currently wired via a breadboard. I'm not sure if my issue is physical, or a chip issue, or a speed thing, but I can say that the code works fine when the command received is proper.

Thanks for all your help!

I would recommend using the techniques of the Serial Input Basics tutorial.

You will be sending the data in this format with start/end markers
"<1,148,128>"
and reading and parsing with the techniques of the tutorial.

1 Like

Thanks. I'm not having any issue with parsing. I'm either receiving incorrect data from the Tx/Rx from the BlueTooth module, or the bits are being misread by the Arduino. I'm not having any issue with the start/end of the command string. Referencing my code, line 4 reads the characters into the string. Line 7 just makes sure the string isn't empty and then prints the command. As you can see in my output, the text printed into the serial monitor changes. That's before my code processes the command.

Why not post the whole code? Just the loop() leave a lot out.

What is the software serial baud rate? The fastest that I have been able to use SoftwareSerial, reliably, is 38400 baud.

Is cmd a String? Do you know of the problems that the String class can cause? The evils of arduino Strings.

+1 for serial input basics tutorial.

1 Like

Sorry about that. Below is the whole code. I apologize for the formatting :frowning:

#include <SoftwareSerial.h>
#include <FastLED.h>

SoftwareSerial hc06(2,3);
String cmd="";
float sensor_val=0;
#define ledPin 12
#define NUM_LEDS 20
#define FRAMES_PER_SECOND  120
#define LED_TYPE    WS2811
#define COLOR_ORDER GRB
int state = 0;
int index = 0;
int count = 1;
int commacount = 0;
String color;
String brightness;
String mode;
CRGB leds[NUM_LEDS];

void setup(){
  //Initialize Serial Monitor
  Serial.begin(115200);
  Serial.println("ENTER AT Commands:");
  //Initialize Bluetooth Serial Port
  hc06.begin(115200);
  FastLED.addLeds<WS2812B, ledPin, GRB>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(255);
}

typedef void (*SimplePatternList[])();
SimplePatternList gPatterns = { rainbow, rainbowWithGlitter, confetti, sinelon, juggle, bpm };

uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
uint8_t gHue = 0; // rotating "base color" used by many of the patterns

void loop(){
  //Read data from HC06
  while(hc06.available()>0){
 //   char temp = (char)hc06.read();
 //   if (isDigit(temp) || (temp ==',')) {
    cmd += (char)hc06.read();
 //   } 
  }

  //Select function with cmd
  if(cmd!=""){
    Serial.print("Command recieved : ");
    Serial.println(cmd);

        while (((index) < cmd.length())&& ((isDigit(cmd[index])) || (cmd[index] == ',')) ) {
        char byteIn = cmd[index];
        if (byteIn == ',') {
       count++;
     } 

     if ((byteIn != ',')) {
       if (count == 1) {
         mode += byteIn;
       } else if (count == 2) {
         brightness += byteIn;
     } else if (count == 3) {
       color += byteIn;
     }
   }


      index++;
        }
int COLOR = color.toInt();
int BRIGHTNESS = brightness.toInt();
Serial.print("COLOR: ");
Serial.println(COLOR);
Serial.print("BRIGHTNESS: ");
Serial.println(BRIGHTNESS);

    if(cmd=="OFF"){
        Serial.println("Function is off");
        fill_solid(leds, NUM_LEDS, CRGB::Black);
    }  else if (mode=="1") {
          if (BRIGHTNESS > 0) {
            fill_solid(leds, NUM_LEDS, CHSV(COLOR, 255, BRIGHTNESS));
          }
      } else if (mode=="3") {
          // Call the current pattern function once, updating the 'leds' array
            gPatterns[gCurrentPatternNumber]();

            // send the 'leds' array out to the actual LED strip
            FastLED.show();  
            // insert a delay to keep the framerate modest
            FastLED.delay(1000/FRAMES_PER_SECOND); 

            // do some periodic updates
            EVERY_N_MILLISECONDS( 20 ) { gHue++; } // slowly cycle the "base color" through the rainbow
            EVERY_N_SECONDS( 10 ) { nextPattern(); } // change patterns periodically
      }
      
      else  {
        Serial.println("unknown command");
    }

    count=1; //reset count
    index=0; //reset index
    mode="";
    color="";
    brightness="";
    FastLED.show();
 
  }
    cmd=""; //reset cmd } 
}
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))

void nextPattern()
{
  // add one to the current pattern number, and wrap around at the end
  gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns);
}

void rainbow() 
{
  // FastLED's built-in rainbow generator
  fill_rainbow( leds, NUM_LEDS, gHue, 7);
}

void rainbowWithGlitter() 
{
  // built-in FastLED rainbow, plus some random sparkly glitter
  rainbow();
  addGlitter(80);
}

void addGlitter( fract8 chanceOfGlitter) 
{
  if( random8() < chanceOfGlitter) {
    leds[ random16(NUM_LEDS) ] += CRGB::White;
  }
}

void confetti() 
{
  // random colored speckles that blink in and fade smoothly
  fadeToBlackBy( leds, NUM_LEDS, 10);
  int pos = random16(NUM_LEDS);
  leds[pos] += CHSV( gHue + random8(64), 200, 255);
}

void sinelon()
{
  // a colored dot sweeping back and forth, with fading trails
  fadeToBlackBy( leds, NUM_LEDS, 20);
  int pos = beatsin16( 13, 0, NUM_LEDS-1 );
  leds[pos] += CHSV( gHue, 255, 192);
}

void bpm()
{
  // colored stripes pulsing at a defined Beats-Per-Minute (BPM)
  uint8_t BeatsPerMinute = 62;
  CRGBPalette16 palette = PartyColors_p;
  uint8_t beat = beatsin8( BeatsPerMinute, 64, 255);
  for( int i = 0; i < NUM_LEDS; i++) { //9948
    leds[i] = ColorFromPalette(palette, gHue+(i*2), beat-gHue+(i*10));
  }
}

void juggle() {
  // eight colored dots, weaving in and out of sync with each other
  fadeToBlackBy( leds, NUM_LEDS, 20);
  uint8_t dothue = 0;
  for( int i = 0; i < 8; i++) {
    leds[beatsin16( i+7, 0, NUM_LEDS-1 )] |= CHSV(dothue, 200, 255);
    dothue += 32;
  }
}


I did take the time to read the tutorial. However, just for an example, I did:

// Example 2 - Receive with an end-marker

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

void setup() {
    Serial.begin(115200);
    Serial.println("<Arduino is ready>");
}

void loop() {
    recvWithEndMarker();
    showNewData();
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
    
    while (hc06.available() > 0 && newData == false) {
        rc = hc06.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.print("Received Command: ");
        Serial.println(receivedChars);
        newData = false;
    }
}

And my serial output was like this - again, with the random garbage and characters popping up:
image

Software Serial is not reliable at that baud rate. Use 9600. 38400 is the max, and it can be flakey at times.

1 Like

Sorry for the delay. Thank you very much for the information! Once I reduced the baud rate, the amount of random character changes and garbage diminished drastically. Unfortunately the issue is still there, but definitely much, much less frequent. It really only happens now when I drag the color or brightness slider in the Android app very quickly. Silly me for thinking that a faster baud rate would yield faster communication between the modules. I guess, at the end of the day, it doesn't really matter because I'm not sending much information at all.

In addition, I am taking your twos' advice and restructuring the code to have functions like seen in the tutorial and also to stop using strings and instead use a character array. My hope is that this will also lead to more reliability in the communication (translating the bits and bytes into characters) and maybe remove the swapped characters/garbage completely. I will need to learn how to "unset" a character array so that I can clear it after each command, but I'm sure I can find some examples of this syntax. Strings are super easy hehe string="";!

Once I've updated the code (at least a week with my current schedule), I'll update you here to hopefully aid another individual like myself running into a similar issue. Updates to follow, and again, thank you for your time to help me :slight_smile:

Typically when using Null terminated character arrays, there is no need to clear receive buffers, as they will be overwritten, and then you only deal with the values before the terminating Null.

However, if you do wish to clear a buffer, you can use memset().


memset(readArray, '\0', sizeof(readArray));//initialize read buffer

1 Like

Im typing on my phone, so apologies, but i was trying in my loop funtion to print the character array (so the whole "new" command) but it got stuck after the first command. Ill work on it more and post the update functioning.
I havent programmed in C++ since high school. Im much more used to higher level languages like PHP, javascript, and bash

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.