When running the following program, it works as expected but adds an additional output for -38 as an input. It doesn't matter what input I use, it will print out for -38 as well.
int number;
void setup()
{
Serial.begin(9600);
}
void loop()
{
number=0;
Serial.flush();
while(Serial.available() == 0)
{
//just waiting while nothing entered
}
while (Serial.available()>0)
{
number = Serial.read() - '0';
// read the number in buffer and
//remove ASCII text for "0"
}
Serial.print("You entered: ");
Serial.println(number);
Serial.print(number);
Serial.print(" multiplied by two is ");
number = number * 2;
Serial.println(number);
}
Output looks like:
>You entered: 4
>4 multiplied by two is 8
>You entered: -38
>-38 multiplied by two is -76
Your problem might be the Serial.flush. As the documentation states, it
Waits for the transmission of outgoing serial data to complete. (Prior to Arduino 1.0, this instead removed any buffered incoming serial data.)
You seem to try to achieve the pre 1.0 behavior of flushing the incoming buffer. So basically Serial.flush does nothing in your sketch, which leads to the second run reading and calculating with the line feed character (which is 10 in ASCII).
You could clear the buffer like so:
while ( Serial.available() > 0 ) {
Serial.read();
}
But please note that this part
while (Serial.available()>0)
{
number = Serial.read() - '0';
// read the number in buffer and
//remove ASCII text for "0"
}
may not do exactly what you intend it to to. If for example you would send 12 via serial, it may only print the result for the last character (the 2). It would be equally possible for your program to only output the -38 result, because the last character always is a line feed. You basically just got lucky and the serial data wasn't sent fast enough for this to happen, but as soon as your loop gets longer it likely will happen.
I would rather suggest you moving the calculation part inside the loop too and checking the input data instead of flushing the buffer after the first character. Consider this:
while ( Serial.available() > 0 )
{
// read the number in buffer and
number = Serial.read();
// make sure the character is 0 - 9 in ASCII
if( number < '0' || number > '9' ){
// invalid character, skip
continue;
}
//remove ASCII text for "0"
number = number - '0';
Serial.print("You entered: ");
Serial.println(number);
Serial.print(number);
Serial.print(" multiplied by two is ");
number = number * 2;
Serial.println(number);
}
This would read your buffer byte by byte and would apply the multiplication to each (valid) character.
Related
I code a program for encode and decode a morse code, this code is for decode a morse code.
i use 2 arduino board, 1st Arduino is for encode the text into morse and 2nd is for receiving the morse and decode into text.Connection of 2 arduino board is using IR sensors.
in 1st arduino board
This ARDU INO is a input of my code,then convert like this .-|.-.|-..|..-| |..|-.|---|, in this | is a end of word. Then transmit this morse code
in 2nd Arduino board
it receives .-|.-.|-..|..-| |..|-.|---|, but its Decode like this "ARDUU INOO ",it print the same word twice which is before the space
why this happen? please help me
#define SIZE 26
const int btnPin=7;
String morseCode="";
String text="";
int characterAscii=0;
int startPos=0, endPos=0;
int startPos1=0, endPos1=0;
String characterCode="";
int btnState=0;
unsigned long int duration = 0;
//Array of MorseCode for letters of English Language A to Z
String letters[SIZE]={
// A to I
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..",
// J to R
".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.",
// S to Z
"...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."
};
void setup() {
pinMode(btnPin, INPUT_PULLUP);
Serial.begin(9600);
//Serial.println("*********************");
Serial.println(" Demonstration of Morse Code ");
Serial.println("********************* ");
//Serial.println("\nInstructions");
Serial.println("1. First Write Your Morse code");
Serial.println("2. When you are done Write 1 on above input box and Press Enter or click Send Button ");
Serial.println("3. For Space between letters write 2 and Press Enter ");
Serial.println("4. For Space between words write 3 and Press Enter ");
Serial.println("5. Thats all Translation of Morse Code will then be Shown ");
Serial.println("\n\nEnter Your Morse Code Here ");
}
void loop() {
while(Serial.available() > 0 ) {
int ascii=Serial.read();
switch(ascii)
{
case 49: // 49 is Ascii value of 1
Serial.print("\n");
morseCode.concat('#');// Placeing # at the end of morseCode to simplify further processing
Serial.print("\nYour Morse code Translation : ");
endPos1=morseCode.indexOf('#');
while(endPos1 < morseCode.length() ){
extractLetters(morseCode.substring(startPos1, endPos1)); // This function would extract Letter as name suggest and would convert code to text SIMPLE!
startPos1=endPos1+1;
if(startPos1 == morseCode.length() ){
break;
}
endPos1= morseCode.indexOf('#', startPos1);
}
startPos1=0;
endPos1=0;
text=""; // For New Translation
morseCode="";
Serial.println("\n\nEnter Your Morse Code Here ");
break;
}
process();
}
void process(){
while(digitalRead(btnPin) == LOW ) {
delay(150); //if you want more resolution, lower this number
duration = duration + 150;
}
switch(duration){
case 450:
morseCode.concat("-"); // Storing code in variable morseCode with the help of concatenation function
Serial.print("-");//Prints User entered Code
//Serial.print(duration);
break;
case 150:
morseCode.concat(".");
Serial.print(".");
//Serial.print(duration);
break;
case 300:
morseCode.concat("#");
Serial.print("|");
//Serial.println(duration);
break;
case 1050:
morseCode.concat("#");
Serial.print(" |");
//Serial.println(duration);
break;
}
duration = 0;
}
char convertIntoText(String characterCode)
{
characterAscii=65;
for(int index=0; index<SIZE; index++)
{
if(characterCode == letters[index])
{
return characterAscii;
}
characterAscii++;
}
}
void extractLetters(String words)
{
words.concat('#'); // Placeing # at the end of word to simplify further processing
endPos=words.indexOf('#');
//Loop to extracting single character morse Code from string of word
while( endPos<words.length() )
{
characterCode=words.substring(startPos, endPos);
//Now CharacterCode will now convert in text
text.concat(convertIntoText(characterCode));
startPos=endPos+1;
characterCode="";
// if condition is just to terminate loop when our extracting single character code is complete thats all
if(startPos == words.length() )
{
break;
}
endPos=words.indexOf('#', startPos);
}
Serial.print(text);
Serial.print(" ");
startPos=0;
endPos=0;
text="";
}
The issue seems to be in your extracting logic, there is no accounting for the # to break the words, then because convertIntoText does not have a default return path, when the input character is NOT in the expected 26 characters the response from the function used in the sketch is actually the previous response from that function call (this is an error state)
First rule, make sure all logic paths in your functions return a value, either inject a known error value, or deliberately raise an error. In this case a non-alpha character is good enough:
char convertIntoText(String characterCode)
{
characterAscii=65;
for(int index=0; index<SIZE; index++)
{
if(characterCode == letters[index])
{
return characterAscii;
}
characterAscii++;
}
return '!'; // error code
}
If you see any ! characters in your output, then you know that there is an issue mapping the input... but that doesn't help debugging, you should probably output the entire characterCode value, so maybe try this:
return "(" + characterCode + ")";
But you would also need to change the response type of this function to a String as well.
The actual issue, make sure you take # into account in extractLetters, there are a number of ways to do this, the easiest to fit into this current logic might be at the start of the loop, just check the next character:
//Loop to extracting single character morse Code from string of word
while( endPos<words.length() )
{
// check for word break
if(words.substring(startPos,startPos+1) == '#')
{
text.concat(' ');
// advance 1 char
startPos++;
}
characterCode=words.substring(startPos, endPos);
//Now CharacterCode will now convert in text
text.concat(convertIntoText(characterCode));
startPos=endPos+1;
characterCode="";
// if condition is just to terminate loop when our extracting single character code is complete thats all
if(startPos == words.length() )
{
break;
}
endPos=words.indexOf('#', startPos);
}
Some general code feedback:
When building morseCode you use # as a delimiter, but you output to the serial stream |. Having two meanings for the same thing makes parsing code and explaining to colleagues much more complicated than it needs to be. Try to avoid having an internal representation as well as a debugging or external one. Pick pipe or at and be consistent.
When testing this, it wasn't obvious at first, but your input to extractLetters is actually:
.-#.-.#-..#..-##..#-.#---#
(Actually this is more of the same) In process(), to simplify debugging, you should write the same characters that you are interpreting and processing to the serial out as you are recording internally.
I am trying to send integers over serial using the serial monitor in the ardunio IDE (then python from a raspberry pi after I debug using serial monitor), and can get single numbers to work with code below, but as soon as I use 10 or 100 it will automatically fill the next variable as 0. I have tried to use serial.readString then convert to an int afterwards, but this is throwing an error also.
int varX = 0;
int varY = 0;
int varZ = 0;
int varCounter = 0;
void setup() {
Serial.begin(115200);
grabNewVars();
}
void grabNewVars()
{
while (varCounter < 3)
{
if (Serial.available() > 0) {
if (varCounter ==0)
{
varX = Serial.parseInt();
}
if (varCounter ==1)
{
varY = Serial.parseInt();
}
if (varCounter ==2)
{
varZ = Serial.parseInt();
}
varCounter++;
}
}
}
void loop()
{
Serial.println("varX = " + String(varX));
Serial.println("varY = " + String(varY));
Serial.println("varZ = " + String(varZ));
Serial.println("variables received, run main loop");
delay(100000);
}
Let's think about what your functions are doing.
Serial.available() returns the number of bytes available in the receive buffer.
Serial.parseInt() reads any digit until a non-digit character is received or it times out if no digit is received within 1 second (default).
In that case it returns 0.
So, in your while loop you wait until something is in the receive buffer by checking Serial.available() > 0.
Note that You enter: 100 (without a line ending).
Now that “something” is in the receive buffer and varCounter is 0, you execute varX = Serial.parseInt();
parseInt will time out after 1 second and return the 100, that has been received within “that” 1 second.
The 100 is stored in varX and varCounter is incremented by 1.
Now you execute varY = Serial.parseInt();
As you most likely did not enter another number within a second, this will timeout and you'll store 0 in varY.
Terminate your number with a non digit character.
For example: by selecting a line ending in the serial monitor or by sending a newline or carriage return from Python code (Or any other single non-digit character).
That way, Arduino knows that the complete Integer has been received and it does not have to wait until it times out.
If you want your code to wait forever: for your next input, check Serial.available > 0 before your next call to parseInt.
You already read every number form the receive buffer so: calling parseInt right away doesn't make sense, unless you know for sure that you'll receive another number within a second.
I'm using Arduino to look for I2C addresses, and half way through this new glitch appeared, and I don't know if it's the IDE or if I'm going insane.
I know most of this probably isn't important, but I don't know what is going on so here is my entire loop.
void loop(){
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 0; address <= 255; address++ )
{
Wire.beginTransmission(address);
error = Wire.endTransmission();
Serial.print(address);
Serial.print("|");
Serial.println(error);
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknow error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
delay(200);
//Serial.println(address);
}
delay(150);
Serial.println("Exiting");
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(30000);
exit(0);
}
As you can see in the picture I included the for loop returns to address=0 without printing anything after it, or before it in the loop(). Why is this happening?
I'm sure it has to do with you declaring address as a byte which is can be the integer 255 at max. What happens is if you add 1 to a byte value of 255, it loops around again to 0.
What happens when address = 255 and when the for loop goes back up to check the conditioning, 255 passes and address++ adds 1 to address so now address = 0.
https://www.arduino.cc/en/reference/byte
Alternatively, you could use a while loop instead and increment the address counter at the very end of the loop, followed by a test to see if it has wrapped around to zero. On the first run through of the loop, the address counter will be 1, so the loop will continue until the counter has reached 255 when the increment will wrap it around to zero and execution reaches the break statement.
byte address = 0;
while( true ) // Creating an unconditional loop
{
// Run your test here
address++;
if( !address ) // If address has wrapped around to 0, exit the loop
{
break;
}
}
...or a do/while loop, which does the same thing but may be slightly larger in some cases.
byte address = 0;
do
{
// Run your test here
address++;
} while( address ); // The loop will continue until address becomes zero again
Depending on your microcontroller, this may take a few bytes more program space though it looks like the while-loop ends up the same size as the for-loop on an ATMega328. (YMMV, of course)
On 8-bit microcontrollers however, code to manipulate ints will be slower and take up more space, so depending on your code you may still be better off by being able to stick with using a byte for your address.
I want to turn ON and OFF, three LEDS connected to arduino, using a python GUI, thus I use pyserial. The state of the LEDs is described by a tuple
RGB = (Red On/Off, Green On/Off, Blue On/Off), e.g. (1,0,1)
Since pyserial.write() works only with strings, let's say that RGB = "101"
I want to sent to arduino the RGB string, split it to three values 1, 0 and 1, and set LOW or HIGH three output pins, depending on the incoming values.
The python code works fine:
import serial
ser = serial.Serial('/dev/ttyACM4', 9600)
ser.write('101')
This is the arduino code:
void setup() {
Serial.begin(9600);
Serial.println("Ready");
}
void loop() {
char input_data = ' ';
if(Serial.available()){
char input_data = {Serial.read()};
Serial.println(input_data);
}
delay(100);
}
The print line is only for inspection purpose.
Can I somehow split the input_data string, and retrieve its values, like:
int R = input_data[0];
int G = input_data[1];
int B = input_data[2];
Any suggestion would be appreciated.
OK, so one quick clarification here (as verified by your comment): input_data is not a string, it is a single char (one byte). Also, serial.read() returns a single byte (the next in the serial stream) and does so as an int, so you're implicitly casting int to char in your code. This is fine, just wanted to make that clear.
What you can do is make input_data an array of chars, and store each new byte in a new location in the array. Then you'll have all three numbers you're looking for. Then, all that's left is to turn input_data[i] into a LOW or HIGH value to be passed to each of your LED pins. What I would do is within your for loop, test each value read from the serial.read() function to see if it's value is '0' or '1' and then storing true or false in another array of bools. Finally, you can test that array and set the corresponding pin 'HIGH' or 'LOW' as necessary. Please keep in mind what I mentioned earlier in the comments, that you're going to want to test the received data as the characters 1 and 0 and not the numbers 1 and 0.
Here's a quick snippet as an example:
int[3] pins; //Initialize this to contain the numbers of the R, G, and B pins.
void setup() {
Serial.begin(9600);
Serial.println("Ready");
}
void loop() {
char[3] input_data;
bool[3] low_high;
if(Serial.available() >= 3){
for (int i=0; i<3; i++) {
input_data[i] = Serial.read();
if(input_data[i] == 48) //ASCII for 0
low_high[i] = false;
if(input_data[i] == 49) //ASCII for 1
low_high[i] = true;
//Serial.println(input_data);
}
}
for (int j=0; j<3; j++) {
if(low_high[j]) {
digital_write(pins[j],'HIGH');
} else {
digital_write(pins[j], 'LOW');
}
}
delay(100);
}
That should get you up and running. Please keep in mind that this example has very limited input checking, so you'll need to beef it up a bit (i.e. checking for more than 3 bytes ready, making sure you're getting char's and not gibberish, etc.).
I'm trying to read variable streams of characters and process them on the Arduino once a certain string of bytes is read on the Arduino. I have a sample sketch like the following, but I can't figure out how to compare the "readString" to process something on the Arduino. I would like the Arduino to process "commands" such as {blink}, {open_valve}, {close_valve}, etc.
// Serial - read bytes into string variable for string
String readString;
// Arduino serial read - example
int incomingByte;
// flow_A LED
int led = 4;
void setup() {
Serial.begin(2400); // Open serial port and set Baud rate to 2400.
Serial.write("Power on test");
}
void loop() {
while (Serial.available()) {
delay(10);
if (Serial.available() > 0) {
char c = Serial.read(); // Gets one byte from serial buffer
readString += c; // Makes the string readString
}
}
if (readString.length() > 0) {
Serial.println( readString); // See what was received
}
if (readString == '{blink_Flow_A}') {
digitalWrite(led, HIGH); // Turn the LED on (HIGH is the voltage level).
delay(1000); // Wait for one second.
digitalWrite(led, LOW); // Turn the LED off by making the voltage LOW.
delay(1000); // Wait for a second.
}
Some definitions first:
SOP = Start Of Packet (in your case, an opening brace)
EOP = End Of Packet (in your case, a closing brace)
PAYLOAD = the characters between SOP and EOP
PACKET = SOP + PAYLOAD + EOP
Example:
PACKET= {Abc}
SOP = {
EOP = }
PAYLOAD = Abc
Your code should process one character at a time, and should be structured as a state machine.
When the code starts, the parser state is "I'm waiting for the SOP character". While in this state, you throw away every character you receive unless it's equal to SOP.
When you find you received a SOP char, you change the parser state to "I'm receiving the payload". You store every character from now on into a buffer, until you either see an EOP character or exhaust the buffer (more on this in a moment). If you see the EOP char, you "close" the buffer by appending a NULL character (i.e. 0x00) so that it becomes a standard NULL-terminated C-string, and you can work on it with the standard functions (strcmp, strstr, strchr, etc.).
At this point you pass the buffer to a "process()" function, which executes the operation specified by the payload (1)
You have to specify the maximum length of a packet, and size the receive buffer accordingly. You also have to keep track of the current payload length during the "payload receive" state, so you don't accidentally try to store more payload bytes into the temporary buffer than it can hold (otherwise you get memory corruption).
If you fill the receive buffer without seeing an EOP character, then that packet is either malformed (too long) or a transmission error changed the EOP character into something else. In either case you should discard the buffer contents and go back to "Waiting for SOP" state.
Depending on the protocol design, you could send an error code to the PC so the person typing at the terminal or the software on that side knows the last command it sent was invalid or not received correctly.
Finally, the blink code in you snipped should be replaced by non-blocking "blink-without-delay"-style code (look at the example that come with the Arduino IDE).
(1) Example of a "process" function:
void process(char* cmd) {
if (strcmp(cmd, "open_valve") == 0) {
open_valve();
}
else if (strcmp(cmd, "close_valve") == 0) {
close_valve();
}
else {
print_error("Unrecognized command.");
}
}
It seems you are comparing the string in this statement:
if( readString == '{blink_Flow_A}' )
So I don't get your question re :
but I can't figure out how to compare the "readString" to process something
Are you really asking:
How do I extract the commands from an incoming stream of characters?
If that is the case then treat each command as a "packet". The packet is enclosed in brackets: {}. Knowing that the {} brackets are start and end of a packet, it is easy to write a routine to get at the command in the packet.
Once the command is extracted just go through a if-then-else statement to do what each command is supposed to do.
If I totally misunderstood your question I apologize :)
EDIT:
see http://arduino.cc/en/Tutorial/StringComparisonOperators
if( readString == "{blink_Flow_A}" ) should be correct syntax.
Since you have a statement
Serial.println( readString);
you should see the string received.