I'm trying to create an android app like ArduDroid that sends data via Bluetooth to and Arduino. So far I'm using appinventor for the android app. The app consists of about 12 buttons and 6 sliders. I'm looking at this info file to try and figure out what gets sent and how, from the android app:
/*
PROJECT: ArduDroid
PROGRAMMER: Hazim Bitar (techbitar at gmail dot com)
DATE: Oct 31, 2013
FILE: ardudroid.ino
LICENSE: Public domain
*/
#define START_CMD_CHAR '*'
#define END_CMD_CHAR '#'
#define DIV_CMD_CHAR '|'
#define CMD_DIGITALWRITE 10
#define CMD_ANALOGWRITE 11
#define CMD_TEXT 12
#define CMD_READ_ARDUDROID 13
#define MAX_COMMAND 20 // max command number code. used for error checking.
#define MIN_COMMAND 10 // minimum command number code. used for error checking.
#define IN_STRING_LENGHT 40
#define MAX_ANALOGWRITE 255
#define PIN_HIGH 3
#define PIN_LOW 2
String inText;
void setup() {
Serial.begin(9600);
Serial.println("ArduDroid 0.12 Alpha by TechBitar (2013)");
Serial.flush();
}
void loop()
{
Serial.flush();
int ard_command = 0;
int pin_num = 0;
int pin_value = 0;
char get_char = ' '; //read serial
// wait for incoming data
if (Serial.available() < 1) return; // if serial empty, return to loop().
// parse incoming command start flag
get_char = Serial.read();
if (get_char != START_CMD_CHAR) return; // if no command start flag, return to loop().
// parse incoming command type
ard_command = Serial.parseInt(); // read the command
// parse incoming pin# and value
pin_num = Serial.parseInt(); // read the pin
pin_value = Serial.parseInt(); // read the value
// 1) GET TEXT COMMAND FROM ARDUDROID
if (ard_command == CMD_TEXT){
inText =""; //clears variable for new input
while (Serial.available()) {
char c = Serial.read(); //gets one byte from serial buffer
delay(5);
if (c == END_CMD_CHAR) { // if we the complete string has been read
// add your code here
break;
}
else {
if (c != DIV_CMD_CHAR) {
inText += c;
delay(5);
}
}
}
}
// 2) GET digitalWrite DATA FROM ARDUDROID
if (ard_command == CMD_DIGITALWRITE){
if (pin_value == PIN_LOW) pin_value = LOW;
else if (pin_value == PIN_HIGH) pin_value = HIGH;
else return; // error in pin value. return.
set_digitalwrite( pin_num, pin_value); // Uncomment this function if you wish to use
return; // return from start of loop()
}
// 3) GET analogWrite DATA FROM ARDUDROID
if (ard_command == CMD_ANALOGWRITE) {
analogWrite( pin_num, pin_value );
// add your code here
return; // Done. return to loop();
}
// 4) SEND DATA TO ARDUDROID
if (ard_command == CMD_READ_ARDUDROID) {
// char send_to_android[] = "Place your text here." ;
// Serial.println(send_to_android); // Example: Sending text
Serial.print(" Analog 0 = ");
Serial.println(analogRead(A0)); // Example: Read and send Analog pin value to Arduino
return; // Done. return to loop();
}
}
// 2a) select the requested pin# for DigitalWrite action
void set_digitalwrite(int pin_num, int pin_value)
{
switch (pin_num) {
case 13:
pinMode(13, OUTPUT);
digitalWrite(13, pin_value);
// add your code here
break;
//...this continues for each respective pin
[\code]
I understand it needs to identify a * as start reading valid data and a # as an end to reading valid data. While working with the android app interface I quickly realized I also needed to distinguish between identifier data (which button got clicked) as well as value data (on or off, or an integer for pwm).
My questions are about Arduino though:
1). In the main loop they first check if the serial port is actually available using <1. If the value is <1 then the port is unavailable and so return to the loop. But I'm wondering, wouldn't execution return to the loop no matter what the value was? So is this here because if it's <1 it will stop it's linear execution of loop() and go back to the start of loop?
2). Then it actually gets the data, assuming linear execution continued since it did find data from the port. It checks to see if the character read is the START_CHR_CMD and if it isn't, it returns to the loop again. Does this mean it goes back to the beginning of loop or continues execution?
More questions to follow :-)
Thanks, Im reading through your post and have a couple of questions. Why in this second code snippet for reading several characters with only the end marker:
const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data
boolean newData = false;
void setup() {
Serial.begin(9600);
Serial.println("<Arduino is ready>");
}
void loop() {
recvWithEndMarker();
showNewData();
}
void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = '\n';
char rc;
// if (Serial.available() > 0) {
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
[color=red]if (ndx >= numChars) {
ndx = numChars - 1;
}[/color]
} else {
[color=red]receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;[/color]
}
}
}
void showNewData() {
if (newData == true) {
Serial.print("This just in ... ");
Serial.println(receivedChars);
newData = false;
}
}
When receiving characters and its not the end character, why do you set the ndx = numChars-1? Wouldnt this truncate the message?
Why when you DO reach the end marker, do you set the receivedChars[ndx] = '\0' if you have defined the end character to be '\n' instead?
At the end, why do you assure that this code reads at most 1 character at a time? I think ive read that one of the problems is that sometimes it could receive more than 1 character at a time and if your code is not ready to receive it, it just throws away the data.
because C uses zero-based arrays. Character number 1 is accessed as receivedChars[0]. When you have filled that array element, you only have 1 character stored.
because strings in C are terminated with a null character.
it doesn't. It uses while(Serial.available()) so it can read many chars. In practice, it will usually only have one available to read.
Yes, it is truncating the data. It must leave space for the '\0' terminating character
You are mixing up two different terminating concepts. '\n' is the character that marks the end of the message. '\0' is the character that marks the end of a string. You can send messages with any end-marker that you choose but standard C/C++ functions require strings to be terminated with '\0'
why do you assure that this code reads at most 1 character at a time?
If you are referring to this "It is important to notice that each time the function recvWithEndMarker() is called it reads at most one character from the input buffer." then I apologize, the text is not up to date with the code. Thanks for pointing it out.
In fact each call to the function now reads whatever characters happen to be in the serial input buffer. In the orginal version it did only read one character at a time.
So we are truncating the data. In that case if we are receiving truncated messages we would simply need to increase the const byte numChars to 64 or more.
Yes I see I confused the 2 terms, end character vs string-terminating character.
Ok, armed with your latest input where I should basically replace Serial.parseInt(), delay() with this new structure, I shall attempt to re-write the original code in my post.
I still have a few questions about that original code that I would like to clear up:
Why do this: if (Serial.available() < 1) return; which states that if incoming data is empty, then return to the loop?
Similarly: if (get_char != START_CMD_CHAR) return; if we dont get the start char, return to the loop?
So we are truncating the data. In that case if we are receiving truncated messages we would simply need to increase the const byte numChars to 64 or more.
Yes, you need to set that value a little bigger than the biggest item you expect to receive. The truncation is just an extra protection.
Why do this: if (Serial.available() < 1) return; which states that if incoming data is empty, then return to the loop?
Similarly: if (get_char != START_CMD_CHAR) return; if we dont get the start char, return to the loop?
Why test for something and return to the loop?
Because we don't return to loop() if the test fails - in other words, if there is data or if there is a start char.
I thought it would be obvious that one should return if there is no work to do. Keep in mind that this code was written to make the maximum time available for other parts of an Arduino program.
I wrote it that way so the entire code would not be within {} which it would be if I had used
if (Serial.available > 0) {
Logically it behaves the same.
return actually exits the loop() method and starts anew from the first line of the loop(). I thought it meant it would just keep traversing the loop() as it was doing so before reaching that line...in which case it seemed pointless.
So if there is no data to be read, execution of loop() stops and exits the loop() and starts loop() because loop() is called infinitely. So it doesn't waste time traversing the rest of the loop() method.
This far I understand.
So writing:
if (Serial.available > 0) {} //if data comes in, do something that takes a long time...blocking the main thread.
But by using:
if (Serial.available < 1) {} // if no data, skip the rest of loop(, break out and restart the loop() until there is data...great!
So about:
if (get_char != START_CMD_CHAR) return; // if not START_CHR_CMD then also skip the rest of the loop() and start a new.
In this case return1 will make it so only myFunction1 is executed but myFunction2 will never be executed?
In this case first name will be logged but then return2 will stop further execution of myFunction1 and return to the loop where return1 as mentioned before will stop execution of myFunction2?
loop() is a function with no different status from myFunction() so you can use return in loop() and it will direct the program back to the hidden main() function that called loop() in the first place.
All that return does is to return the code to the point immediately after the point at which the function (that contains the return) was called.
I don't understand what you are having difficulty with. Perhaps you can explain how you think it works - that may help me to give a more useful answer.
All that return does is to return the code to the point immediately after the point at which the function (that contains the return) was called.
According to the post I put in my previous reply, anything after return is not executed. But according to you everything after return is indeed executed executed. If that is the case, what is the return being used for?
Iow, if there is no data coming into the serial port then just keep running thru the loop method? But it's already doing that, it makes me think it's superfluous. So obviously it doesn't mean keep on going, does it?
Marciokoko:
According to the post I put in my previous reply, anything after return is not executed. But according to you everything after return is indeed executed executed. If that is the case, what is the return being used for?
No. you are mixing up "afters" in two different places.
All functions are called by another (parent) function.
When a return is encountered in a child function the code immediately returns to the parent function and it does not complete any other code that comes after (1) return within the child function.
When the action gets back to the parent function it continues with the instruction after (2) the instruction that called the child function.
void loop() {
myFunction1();
myFunction2();
}
void myFunction1() {
if there is nothing to do {
return;
}
do other stuff
}
In this example the "do other stuff" will not happen if there is nothing to do because it comes after return.
Whether or not myFunction1() completes the code will continue with myFunction2() because it comes after the call to myFunction1().
Maybe another way to think about it is that the closing } at the end of a function is an implicit return.