The Arduino code should listen to serial port and make decision according what it receives. If it receives 4 digits value (for example, 1131), it does one thing, but if it receives 5 digits value, it does the other thing. Could anyone recommend how I could do it? C++ code would send those values on the other side of the connection. Thank you.
Serial data arrives slowly. How do you know how many characters there will be?
You really need to define start and end markers, then read until the end marker arrives.
#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 is says "Process the packet", convert the string to an int, and test the value of the int, or just test the length of the string.
If it receives 4 digits value (for example, 1131), it does one thing, but if it receives 5 digits value, it does the other thing.
What is the data to consist of? Why would "happy" cause different behavior from "slop"?
Arduino code should get two types of messages: 3 digits-message (not 4, as I wrote before) and 5 digits-message
3 digits-message has data in itself: pin number(2 digits 00-13) + value (1 digit 1/0)
5 digits-message has data: pin number(2 digits) + value(3 digits 000-255)
Arduino code should get two types of messages: 3 digits-message (not 4, as I wrote before) and 5 digits-message
3 digits-message has data in itself: pin number(2 digits 00-13) + value (1 digit 1/0)
5 digits-message has data: pin number(2 digits) + value(3 digits 000-255)
If you have a choice in the matter, add a delimiter between the values. Makes parsing a lot easier. The strtok() function, combined with the atoi(0 function, will let you get the pin number and value.
It will also not require that you send exactly 3 or exactly 5 digits. <4,0> or <11,140>
Thank you. Could you pleas give example of how to do it? I am really new to this
Could you pleas give example of how to do it?
Sure.
What is "it" that you need an example for?
Using strok and atoi functions for this case.
Let's assume sketch is listening to serial port and waiting for messages. Each message is within markers "<" and ">".
When the code reads the packet after "<", and sees next character "1", it "understands" that this is digitalWrite(second character, third character). For example, if it gets packet <1,4,0>, it performs action digitalWrite(4,0).
When the code reads the next packet and sees that after "<", "0' goes, it understands that this is analogWrite(second character, third character).
For example, if it gets <0,11,140>, it performs analogWrite(11,140).
For example, if it gets packet <1,4,0>, it performs action digitalWrite(4,0).
I'd think that <D,4,0> would make more sense to people. The computer (PC or Arduino) doesn't care, but neither of them need to debug or enhance code later.
For example, if it gets <0,11,140>, it performs analogWrite(11,140).
Or <A,11,140>.
Hm...What am I doing wrong?
bool started = false;
bool ended = false;
char inData[5];
byte index;
void setup()
{
Serial.begin(9600);
}
void loop()
{
while (Serial.available() > 0)
{
char inChar = Serial.read();
if (inChar == '<')
{
index = 0;
started = true;
ended = false;
}
else if (inChar == '>')
{
ended = true;
break;
}
else
{
if (index <= 4)
{
inData[index] = inChar;
index++;
}
}
if (started && ended)
{
if (inData[0] == 'A')
{
pinMode(inData[2],OUTPUT);
analogWrite(inData[2],inData[4]);
}
else if (inData[0] == 'D')
{
if (inData[4] == 1)
{
pinMode(inData[2],OUTPUT);
digitalWrite(inData[2],HIGH);
}
else if (inData[4] == 0)
{
pinMode(inData[2],OUTPUT);
digitalWrite(inData[2],LOW);
}
}
started = false;
ended = false;
index = 0;
}
}
}
flighttothemoon:
Hm...What am I doing wrong?
Since you haven't said what actually happens ... who knows? Do you expect us to test it for you?
What should happen:
The program listen to messages from serial port in the form <D,9,1> or <A,11,255> where first character (A or D) means analog or digital, the 2nd character - pin, the 3rd character - 1/0 or from 0 to 255. The markers < and > show the beginning and the end of packet.
For example, if packet <D,13,1> is received, the light is turned on by digitalWrite(13,1)
OK, and what actually happens?
Nothing happens. When I send via serial monitor, for instance: <D,13,1> light is supposed to blink but it does not. The same with analogue outputs.
What happens within your sketch when you send that input?
(Hint: the easiest way to find out is by adding print statements to tell you what's happening.)
Hm...What am I doing wrong?
You received something like "A,4,0".
You store that so that
inData[0] = 'A'
inData[1] = ','
inData[2] = '4'
inData[3] = ','
inData[4] = '0'
Then, since inData[0] is 'A', you set the mode of pin '4' to OUTPUT and set pin '4' to '0'.
Since there is no pin '4', and '0' is NOT HIGH or LOW, it's not surprising that nothing happened.
You are supposed to use strtok() and atoi() after started and ended are both true. You are not parsing the input correctly.
I updated the code by adding strtok_r and atoi functions but now i get "ISO C++ forbids comparison between pointer and integer" about the line "if (tokens[0] == "A").
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
bool started = false;
bool ended = false;
char inData[10];
byte index;
void setup()
{
Serial.begin(9600);
}
void loop()
{
while (Serial.available() > 0)
{
char inChar = Serial.read();
if (inChar == '<')
{
index = 0;
started = true;
ended = false;
}
else if (inChar == '>')
{
ended = true;
break;
}
else
{
if (index <= 10)
{
inData[index] = inChar;
index++;
}
}
if (started && ended)
{
char *p = inData;
char *tokens[50];
int i = 0;
while (i < 50) {
tokens[i] = strtok_r(p, ",", &p);
if (tokens[i] == NULL) {
break;
}
i++;
}
if (tokens[0] == 'A'){
pinMode(tokens[1],OUTPUT):
analogWrite(atoi(tokens[1]),inData[2]);
}
else if (tokens[0] == 'D')
{
if (atoi(tokens[2]) == 1)
{
pinMode(atoi(tokens[1]),OUTPUT);
digitalWrite(atoi(tokens[1]),HIGH);
}
else if (atoi(tokens[2]) == 0)
{
pinMode (atoi(tokens[1]),OUTPUT);
digitalWrite(atoi(tokens[1]),LOW);
}
}
started = false;
ended = false;
index = 0;
}
}
Serial.println("Sending");
}
Okay, I fixed the previous problem but it still does not work. =( Lights do no not blink when I send something like <D,13,1> or <A,9,255> (led attached to the pin 9).
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
bool started = false;
bool ended = false;
char inData[10];
byte index;
void setup()
{
Serial.begin(9600);
}
void loop()
{
while (Serial.available() > 0)
{
char inChar = Serial.read();
if (inChar == '<')
{
index = 0;
started = true;
ended = false;
}
else if (inChar == '>')
{
ended = true;
break;
}
else
{
if (index <= 10)
{
inData[index] = inChar;
index++;
}
}
if (started && ended)
{
char *p = inData;
char *tokens[50];
int i = 0;
while (i < 50) {
tokens[i] = strtok_r(p,",",&p);
if (tokens[i] == NULL) {
break;
}
i++;
}
if (atoi(tokens[0]) == 'A'){
pinMode(atoi(tokens[1]),OUTPUT);
analogWrite(atoi(tokens[1]),atoi(tokens[2]));
}
else if (atoi(tokens[0]) == 'D')
{
if (atoi(tokens[2]) == 1)
{
pinMode(atoi(tokens[1]),OUTPUT);
digitalWrite(atoi(tokens[1]),HIGH);
}
else if (atoi(tokens[2]) == 0)
{
pinMode (atoi(tokens[1]),OUTPUT);
digitalWrite(atoi(tokens[1]),LOW);
}
}
started = false;
ended = false;
index = 0;
}
}
Serial.println("Sending");
}
Start over at the start of this thread. Where did anyone recommend using strtok_r()? The function that was recommended was strtok(). The strtok_r() function is the thread-safe version of strtok(). Fins for use in a multi-threaded application, but your sketch is not multi-threaded. The strtok_r() function is much more complicated than the strtok() function, and the resulting code size is larger.
char inData[10];
So, the indices are 0 to 9. The terminating NULL goes in position 9 or less.
if (index <= 10)
{
inData[index] = inChar;
index++;
}
Hmmm. What happened to the terminating NULL? How can you store a value in inData[10], when the largest valid index is 9?
char *tokens[50];
Suppose that you fix the issue with the terminating NULL, and that you correctly limit writing to the array to when index is less than 9. Then, inData might contain "A,1,2,3,4". That's a maximum of 5 tokens, when inData is full AND the tokens are the smallest they can be. 50 seems like overkill.
if (atoi(tokens[0]) == 'A'){
The atoi() function expects the string passed to it to be composed of characters from the set "0123456789". How do you expect it to convert the string "A" or the string "D" to an int? It will fail, and return the value 0. 0 is NOT 'A' and it is not 'D'.
OK, so, now we know why nothing happens in your code.