I'm using snippets of code to try to read accelerometer data from an android phone through bluetooth. I have attached my code and a screenshot of the string values sent to the serial monitor. I would like to be able to use the values in the string separately. For instance, I would like to capture the left and right data separately and continuously. Is that what is called parsing? int motorLeft = L41:;
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
int led = 9;
char myChar = 'a';
String string;
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(57600);
pinMode(led, OUTPUT);
Serial.println("Goodnight moon!");
// set the data rate for the SoftwareSerial port
mySerial.begin(57600);
}
void loop() // run over and over
{
string = "";
while (true) {
myChar = mySerial.read();
if (32 <= myChar && myChar <= 127) {
string += myChar;
}
if (myChar == ':') {
break;
}
delay(10);
}// While End
Serial.println(string);
}
You really need to stop using Strings. They have no place on an Arduino. You know how much data you are using. Create a char array and an index. Store the incoming characters in the array, at the index location. Add a NULL after every character is added.
Then, use strtok() to parse the string and atoi() to convert the tokens to ints.
First, I don't understand why all this is in the setup function. Secondly, when I check the serial monitor, it's blank. Thirdly, I don't understand where these values come from: char instring[] = "R39:L147:"; I just took them randomly from the values that came from the android using previous sketch.
My goal is to get int leftVal and int rightVal from R39:L147:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
int led = 9;
int androidValue;
char myChar = 'a';
void setup() {
char instring[] = "R39:L147:"; //
char delimiters[] = "!:,";
char* valAccel;
//This initializes strtok with our string to tokenize
valAccel = strtok(instring, delimiters);
while (valAccel != NULL) {
Serial.println(androidValue);
androidValue = atoi (valAccel);
valAccel = strtok (NULL, delimiters);
}
// Open serial communications and wait for port to open:
Serial.begin(57600);
pinMode(led, OUTPUT);
// set the data rate for the SoftwareSerial port
mySerial.begin(57600);
}
void loop() // run over and over
{
myChar=mySerial.read();
}
First, I don't understand why all this is in the setup function.
Because it is demonstration code
Secondly, when I check the serial monitor, it's blank.
Possibly because your Serial.begin() should be before the very first Serial.print() / Serial.println()
Thirdly, I don't understand where these values come from: char instring[] = "R39:L147:"; I just took them randomly from the values that came from the android using previous sketch.
You have to populate instring with data from the serial port (in your case the software serial port). Read the link that PaulS provided, it shows you how to read serial data into a nul terminated character array and how to parse it. Although the code uses the serial port, the principles equally apply to reading from the software serial port (or from a SD card or from a network connection or ...).
// Example 5 - Receive with start- and end-markers combined with parsing
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0};
int pwmLeftFromAndroid = 0;
int pwmRightFromAndroid = 0;
float floatFromPC = 0.0;
boolean newData = false;
//============
void setup() {
Serial.begin(57600);
Serial.println("This demo expects 2 pieces of data");
Serial.println("the first is the motorLeft pwm value");
Serial.println("next is motorRight pwm value");
Serial.println();
}
//============
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
showParsedData();
newData = false;
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars,",");
pwmLeftFromAndroid = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
pwmRightFromAndroid = atoi(strtokIndx); // convert this part to an integer
}
//============
void showParsedData() {
Serial.print("Left Motor ");
Serial.println(pwmLeftFromAndroid);
Serial.print("Right Motor ");
Serial.println(pwmRightFromAndroid);
}
I tried to modify the example 5 of the tutorial that Paul S. suggested. The only thing that appears in my serial monitor is the message from void setup(); It's not printing any data sent from my android. The data the arduino receives from the android should look something like this: <12,255> Both of these numbers will be a value of 0 to 255 depending on how the phone is tilted. I want to use the number on the left as the pwmLeftFromAndroid number and the number on the right as the pwmRightFromAndroid.
Anybody see what I'm doing wrong? I'm pretty sure I'm not doing something right in the void parseData(); function.
I also added the SoftwareSerial library to the sketch so I can have my bluetooth plugged in to my arduino while it is also using the 0, 1 tx/rx pins for the serial monitor.
// Example 5 - Receive with start- and end-markers combined with parsing
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
int pwmLeftFromAndroid = 0;
int pwmRightFromAndroid = 0;
boolean newData = false;
int motorPinL = 5;
int motorPinR = 6;
//============
void setup() {
pinMode(motorPinL, OUTPUT);
pinMode(motorPinR, OUTPUT);
Serial.begin(57600);
}
//============
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
newData = false;
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ",");
pwmLeftFromAndroid = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
pwmRightFromAndroid = atoi(strtokIndx); // convert this part to an integer
analogWrite(motorPinL, pwmLeftFromAndroid);
analogWrite(motorPinR, pwmRightFromAndroid);
}
//============
I removed the serial.print functions and added two led's for debugging and for simulating a left motor and a right motor. When I tilt the phone the two led's light up according to the pwm from the tilt.
Your code in reply #4 works as expected when using the serial port.
This demo expects 2 pieces of data
the first is the motorLeft pwm value
next is motorRight pwm value
L12,R3
Left Motor 0
Right Motor 0
12,3
Left Motor 12
Right Motor 3
I added one additional Serial.println in the code so I could see what was actually received.
Initially I did send a L and a R in front of the numbers and that resulted in 0 for the printed values as letters are not valid for numbers Once I understood that I did not have to send that, the code happily showed what was entered.
So can't say what went wrong in your code. I did not use a bluetooth module connected to the hardware serial.
If you want to use bluetooth as well on software serial, configure the sofware serial with the correct baudrate (in setup()) and read from software serial instead of from hardware serial in recvWithStartEndMarkers().
I would like to add to my sketch in my reply #5 above some incoming data from the android. The data would be either of two characters . 'a' or 'b' to turn an led on or off on the arduino. Right now, the android constantly sends two sets of numbers over the bluetooth connection to the arduino. I'm just at a loss on where to start. I think I would start here to have the arduino look for a single char coming from the android as opposed to the stream of two sets of numbers.
Can you tell me if I am on the right track? I won't be able to test this for a few days until I get some parts in the mail.
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
char ledData; //new char to receive 'a' or 'b' from android.
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
ledData = Serial.read(); //read bluetooth android data. I don't know how to proceed without mixing up the data
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
It looks like it was copied from Robin2's thread and butchered. We have no idea where you call the function, what serial data you are sending, or what you do with the data that the function collects.
If you are not sending < or >, then the code isn't going to work.
I added this to the loop of my code to try to simply allow the arduino to receive a 1 or 0 to turn on/off the led:
if (Serial.available()>0){
ledData = Serial.read();
if (ledData = 0){
digitalWrite(led, LOW);
}
if (ledData = 1){
digitalWrite(led, HIGH);
}
}
The led does not light up when I press the button on the android. Here is the full sketch:
// Example 5 - Receive with start- and end-markers combined with parsing
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
char ledData;
// variables to hold the parsed data
int pwmLeftFromAndroid = 0;
int pwmRightFromAndroid = 0;
boolean newData = false;
int motorPinL = 5;
int motorPinR = 6;
int led = 4;
//============
void setup() {
pinMode(motorPinL, OUTPUT);
pinMode(motorPinR, OUTPUT);
Serial.begin(57600);
}
//============
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
if (Serial.available()>0){
ledData = Serial.read();
if (ledData = 0){
digitalWrite(led, LOW);
}
if (ledData = 1){
digitalWrite(led, HIGH);
}
}
parseData();
newData = false;
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ",");
pwmLeftFromAndroid = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
pwmRightFromAndroid = atoi(strtokIndx); // convert this part to an integer
analogWrite(motorPinL, pwmLeftFromAndroid);
analogWrite(motorPinR, pwmRightFromAndroid);
}
If someone could point me in the right direction, I would greatly appreciate it.
e.g. function:data
For the motorControl, it can be
<M:speedL,speedR>; example <M:41,33>
For the led(s), it can be
<L:whichLed,onoffStatus>; example <L:3,0> to switch the 3rd led (or the led on pin 3 depending on implementation) off.
The parsing of the incoming message will now involve splitting on the colon first to determine which function needs to be called.
Thanks for your reply. I know you have spent a lot of time and I appreciate it. Here is the sketch so far for reference:
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
int pwmLeftFromAndroid = 0;
int pwmRightFromAndroid = 0;
boolean newData = false;
int motorPinL = 5;
int motorPinR = 6;
//============
void setup() {
pinMode(motorPinL, OUTPUT);
pinMode(motorPinR, OUTPUT);
Serial.begin(57600);
}
//============
void loop()
{
recvWithStartEndMarkers();
if (newData == true)
{
processData();
newData = false;
}
}
void processData()
{
// if the first character is 'a' or 'b', control the led
if(receivedChars[0] == 'a' || receivedChars[0] == 'b') {
ledControl();
}
// else control the motors
else
{
motorControl();
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void motorControl() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ",");
pwmLeftFromAndroid = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
pwmRightFromAndroid = atoi(strtokIndx); // convert this part to an integer
analogWrite(motorPinL, pwmLeftFromAndroid);
analogWrite(motorPinR, pwmRightFromAndroid);
}
what is the ndx in void recvWithStartEndMarkers() function? I don't understand its meaning or purpose. Especially this statement: receivedChars[ndx] = rc;
and is the motorControl function is looking for receivedChars?
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
int pwmLeftFromAndroid = 0;
int pwmRightFromAndroid = 0;
boolean newData = false;
int motorPinL = 5;
int motorPinR = 6;
int led = 9;
//============
void setup() {
pinMode(led, OUTPUT);
pinMode(motorPinL, OUTPUT);
pinMode(motorPinR, OUTPUT);
Serial.begin(57600);
}
//============
void loop()
{
recvWithStartEndMarkers();
if (newData == true)
{
processData();
newData = false;
}
}
void processData()
{
// if the first character is 'a' or 'b', control the led
if (receivedChars[0] == 'a' || receivedChars[0] == 'b') {
ledControl();
}
// else control the motors
else
{
motorControl();
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void motorControl() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ",");
pwmLeftFromAndroid = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
pwmRightFromAndroid = atoi(strtokIndx); // convert this part to an integer
analogWrite(motorPinL, pwmLeftFromAndroid);
analogWrite(motorPinR, pwmRightFromAndroid);
}
void ledControl()
{
if (receivedChars[0] == 'a')
{
digitalWrite(led, LOW);
Serial.println(receivedChars);
}
if (receivedChars[0] == 'b')
{
digitalWrite(led, HIGH);
Serial.println(receivedChars);
}
}
I think I spoke too soon about the code working. Here is the code I'm using. I have attached a screenshot of the serial monitor that shows the result of the parsing is 0 for both the pwmLeftFromAndroid and the pwmRightFromAndroid. I should see numbers from 0 to 9 (with or without a negative sign). When I send the 'a' or 'b' from Android, I do see that on the serial monitor. Can anybody spot any errors?
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
int pwmLeftFromAndroid = 0;
int pwmRightFromAndroid = 0;
boolean newData = false;
int motorPinL = 5;
int motorPinR = 6;
int led = 8;
//============
void setup() {
pinMode(led, OUTPUT);
pinMode(motorPinL, OUTPUT);
pinMode(motorPinR, OUTPUT);
Serial.begin(57600);
}
//============
void loop()
{
recvWithStartEndMarkers();
if (newData == true)
{
processData();
newData = false;
}
}
void processData()
{
// if the first character is 'a' or 'b', control the led
if (receivedChars[0] == 'a' || receivedChars[0] == 'b') {
ledControl();
}
// else control the motors
else
{
motorControl();
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void motorControl() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ",");
pwmLeftFromAndroid = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
pwmRightFromAndroid = atoi(strtokIndx); // convert this part to an integer
analogWrite(motorPinL, pwmLeftFromAndroid);
Serial.print("Left: ");
Serial.println(pwmLeftFromAndroid);
Serial.println();
analogWrite(motorPinR, pwmRightFromAndroid);
Serial.print("Right: ");
Serial.println(pwmRightFromAndroid);
Serial.println();
}
void ledControl()
{
if (receivedChars[0] == 'a')
{
digitalWrite(led, LOW);
Serial.println(receivedChars);
Serial.println();
}
if (receivedChars[0] == 'b')
{
digitalWrite(led, HIGH);
Serial.println(receivedChars);
Serial.println();
}
}