1

I am writing two Arduino Uno programs. One is a remote with a joystick and the other has five LED's indicating which direction the joystick is pointing. They are Bluetooth, so everything is sent and received through Serial. I am sending three variables by joining them into one string, separated by colons. Then I separate them back into three variables on the other arduino The joystick, Bluetooth, and LED's part of the programs work, I'm having trouble receiving the data and separating it. I have included both programs below. As it is now, it doesn't work. In the slave code, you can change the int xPosition = getValue(input, ':', 0).toInt(); to int xPosition = getValue(input2, ':', 0).toInt();( also change yPosition and buttonState) and everything works. What is the difference between that string and what I'm receiving?

Slave code:

#include <SoftwareSerial.h>  
#define RxD 7
#define TxD 6
SoftwareSerial BlueToothSerial(RxD,TxD);
char flag=1;
String input;
int xPosition;
int yPosition;
int buttonState;
char outstring[30];
char *input2 = "510:609:1\r\n";

void sendBlueToothCommand(char *Command)
{
  BlueToothSerial.print(Command);
  Serial.print(Command); 
  delay(100);
  while(BlueToothSerial.available())
  {    
     Serial.print(char(BlueToothSerial.read())); 
  }
}

String getValue(String data, char separator, int index)
{
 int found = 0;
  int strIndex[] = {0, -1  };
  int maxIndex = data.length()-1;
  for(int i=0; i<=maxIndex && found<=index; i++){
  if(data.charAt(i)==separator || i==maxIndex){
  found++;
  strIndex[0] = strIndex[1]+1;
  strIndex[1] = (i == maxIndex) ? i+1 : i;
  }
 }
  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}

void setup()
{
   pinMode(12, OUTPUT);
   pinMode(11, OUTPUT);
   pinMode(10, OUTPUT);
   pinMode(9, OUTPUT);
   pinMode(8, OUTPUT);
   Serial.begin(38400);     
   BlueToothSerial.begin(38400); 
   delay(500);
   Serial.println("Starting...");
}

void loop()
{
    if(BlueToothSerial.available())
    {
      input = char(BlueToothSerial.read());
      int xPosition = getValue(input, ':', 0).toInt();
      int yPosition = getValue(input, ':', 1).toInt();
      int buttonState = getValue(input, ':', 2).toInt();
      Serial.println("xPosition");
      Serial.println(xPosition);
      Serial.println("yPosition");
      Serial.println(yPosition);
      Serial.println("buttonState");
      Serial.println(buttonState);
      if ((xPosition == 507)&&(yPosition == 506)){
        clear();
        digitalWrite(8, HIGH);
      } else if ((xPosition == 507)&&(yPosition == 0)){
        clear();
        digitalWrite(12, HIGH);
      } else if ((xPosition == 507)&&(yPosition == 1023)){
        clear();
        digitalWrite(10, HIGH);
      } else if ((xPosition == 1023)&&(yPosition == 507)){
        clear();
        digitalWrite(11, HIGH);
      } else if ((xPosition == 0)&&(yPosition == 1023)){
        clear();
        digitalWrite(9, HIGH);
      }
    }      
}

void clear() {
  digitalWrite(12, LOW);
  digitalWrite(11, LOW);
  digitalWrite(10, LOW);
  digitalWrite(9, LOW);
  digitalWrite(8, LOW);
}

Master code:

#include <SoftwareSerial.h>  
#define RxD 7
#define TxD 6
SoftwareSerial BlueToothSerial(RxD,TxD);
int xPin = A1;
int yPin = A0;
int buttonPin = 2;
char outstring[30];
int xPosition = 0;
int yPosition = 0;
int buttonState = 0;

void sendBlueToothCommand(char *Command)
{
  BlueToothSerial.print(Command);
  Serial.print(Command); 
  delay(100);
  while(BlueToothSerial.available())
  {    
     Serial.print(char(BlueToothSerial.read())); 
  }
}

void setup()
{
   Serial.begin(38400);     
   BlueToothSerial.begin(38400); 
   delay(500);
   pinMode(xPin, INPUT);
   pinMode(yPin, INPUT);
   pinMode(buttonPin, INPUT_PULLUP); 
   BlueToothSerial.println("Hello");
}

void loop()
{
  joy();
  sprintf(outstring, "%d:%d:%d\r\n", xPosition, yPosition, buttonState);
  BlueToothSerial.println(outstring);
  Serial.println(outstring);
}

void joy() {
  xPosition = analogRead(xPin);
  yPosition = analogRead(yPin);
  buttonState = digitalRead(buttonPin);
}
0

The problem is you are only reading one character and trying to split that single character into other smaller units. It just isn't going to happen.

Instead you need to append each character to the end of a string until you receive the end-of-line characters (\r\n). Then you can split that entire string into parts.

Alternatively you can read numbers until you hit a : or a \r\n and build up the numbers directly without having to store anything.

My preferred method is the first, but I know Nick Gammon prefers the second, so I shall leave it to him to describe his favourite Finite State Machine for you.

To store all the data in a string I use a C string, not one of Arduino's dodgy String objects.

char input[15];
int ipos = 0;

Then you read the data:

if (BlueToothSerial.available()) {
    char c = BlueToothSerial.read();
    if (c == '\r') continue; // Skip the carriage return
    if (c == '\n') { // We have the line ending
        // Split the data on :
        char *xtxt = strtok(input, ":");
        char *ytxt = strtok(NULL, ":");
        char *btxt = strtok(NULL, ":");
        // Convert the text to integers
        if (xtxt) xPosition = atoi(xtxt);            
        if (ytxt) yPosition = atoi(ytxt);            
        if (btxt) buttonState = atoi(btxt);            
        ipos = 0; // Reset the string to the start
    } else {
        // If there is still room in the array
        if (ipos < 14) {
            // Add the incoming character
            input[ipos++] = c;
            // and terminate the string.
            input[ipos] = 0;
        }
    }
}
0

In the slave's loop(), when you say

input = char(BlueToothSerial.read());

I'd expect just the first character of the serial stream to be read and stored. Without further investigation, I don't know just what a String class does when you assign a character to it, but I doubt that any of the following code ever has more than one character at a time to work on. This will keep your getValue() calls from working like you want.

Instead of using String objects and your getValue() code, consider using code like the following to handle the serial input. The data format that this code expects is nnnxnnnynnnb, where each nnn is a series of digits, and x, y, b are literal characters.

This code shortens two of the overly-verbose parts of your code by:
• Use of an array and subscripting to replace the long list of if statements that sort out the combinations of low/medium/high x and y values.
• Use of Streaming.h (which you can install by unzipping Streaming5.zip from arduiniana.org into your sketchbook/libraries directory) to clean up long lists of Serial.println() statements, without increasing code size.

#include <Streaming.h>
int numVal = 0;

void doAction() {
  byte pins[] = { 9,0,0, 12,8,10, 0,11,0 };
  byte xy = 3*(x/500)+y/500;
  byte pin = pins[xy];
  if (pin) {
    clear();
    digitalWrite(pin, HIGH);
  }
  Serial << "xPosition =  " << xPosition << endl;
  Serial << "yPosition =  " << yPosition << endl;
  Serial << "buttonState = " << buttonState << endl;
  numVal = 0;
}

void loop() {
  while (BlueToothSerial.available()) {
    byte c = BlueToothSerial.read();
    if ('0' <= c && '9' >= c) {
        numVal = 10*numVal + c - '0';
    } else {
      switch (c) {
      case 'x':  xPosition = numVal;   break;
      case 'y':  yPosition = numVal;   break;
      case 'b':  buttonState = numVal; doAction(); break;
      }
      numVal = 0;
    }
  }
}

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.