Go Down

Topic: Serial Read, String, Convert ATOI (Read 53375 times) previous topic - next topic

T86157

I feel like I'm in the middle of an arguement. In any case, I am still having problems from getting from point A to point B-my code worked two years ago with Arduino but there have been a lot of updates since then. I was going to use my old class programs as reference for a project I am contributing to as part of a club.


Explaining how to capture data in an array, that can be printed out to validate that it was received correctly, and then how to use proven library methods like strtok() and atoi() to newbies seems a more useful technique than showing, but not explaining, code that uses pointers, bit operations, magic numbers, etc.


I take it strtok() is conversion of string to integer?

This is the whole code of what I was trying to use bits of for referencing which now this code is obsolete. I am sure it is changing a little bit in the code but I tried searching the forums and google about this alternate version and cannot find what I am looking for. It may be because I read somewhere that Arduino now has a string library with the software so I do not need to unzip and drag a WString library to the arduino library. If that is the case, I know .append does not work but this is to show the original code. .concat or .indexOf I believe is the substitute but even then the code does not work.

I must be doing some very simple programming in my Matlab class if I cannot understand my own code in Arduino and why now it does not work anymore on top of the error message not making any sense to me either.

Code: [Select]
//Servo control #2 by [color=yellow]Anonymous[/color]
//The way this program works is by when a pushbutton is pressed once, it will prompt the
//user to enter in a angle from 0 to 180 degrees. The angular change is approx. 45 deg/s
//Once the angle is reached, the screen should prompt user to enter in a new angle value
//If angle value is outside of 0 to 180 it displays an error message
//If angle value is 999 it deactivates the system
//The system can also be deactivated by pushing the button a 2nd time

#include <Servo.h>
#include <WString.h> //Make sure to download this if your arduino did not come with it at http://arduino.cc/en/uploads/Tutorial/String.zip
String readString = String(100);

const int  buttonPin = 2;    
const int motorPin = 3;      


int buttonPushCounter = 0;  
int buttonState = 0;        
int lastButtonState = 0;    

short timer= 20;
short timer2 = 100;

Servo myservo;
void setup() {
 pinMode(buttonPin, INPUT);
 pinMode(motorPin, OUTPUT);

 Serial.begin(9600);
 myservo.attach(3);
}
void loop() {
 buttonState = digitalRead(buttonPin);
 if (buttonState != lastButtonState) {
   if (buttonState == HIGH) {
     buttonPushCounter++;
   }
   else {
   }
   lastButtonState = buttonState;
 }
 
if(buttonPushCounter % 2 == 1){
 if(buttonState == HIGH){
     Serial.println("System ACTIVE");
     myservo.write(90);
     delay(timer2*10);
     Serial.print("Enter in a value between 0 and 180 degrees: ");
     delay(timer2);
 }
 else{

 while (Serial.available()) {
 delay(10);  
   if (Serial.available() >0) {
 char c = Serial.read();  //gets one byte from serial buffer
 readString.append(c); } //makes the string readString
 }

       if(readString.length() >0) {

int n;
n = atoi(readString); //convert string to number
       if (n != 999){
Serial.println(readString);
             if((n > myservo.read()) && (n<= 180)){
         for (int i= myservo.read(); i<= n; i+=1){
         myservo.write(i);
         delay(timer);
         if (i == n) {Serial.print("Enter in a value between 0 and 180 degrees: "); break;  
         }
         }
             }
             else if((n < myservo.read()) && (n>=0)){
         for (int i= myservo.read(); i>= n; i-=1){
         myservo.write(i);
         delay(timer);
         if (i == n) {Serial.print("Enter in a value between 0 and 180 degrees: "); break;  
         }
         }
             }
             else if((n>180 || n <0) && n!=999){
         Serial.print("Error\nEnter in a value between 0 and 180 degrees: ");
         delay(timer2);
             }
             else if(n == myservo.read()){
             Serial.print("The servo is already set at this angle.\nEnter in a value between 0 and 180 degrees: ");
             delay(timer2);
             }
       }
       if (n == 999){ //if 999 is entered, it turns off and centers servo
       myservo.write(90);
       Serial.println("\n\n\n");
       Serial.println("System DEACTIVATED");
       Serial.println("\n\n\n\n\n\n\n\n\n\n\n\n\n");
       buttonPushCounter++;
       delay(timer2);
       }

readString="";
}      
 }
}
if (buttonPushCounter % 2 == 0){//turns off and centers servo
   if(buttonState == HIGH){
       myservo.write(90);
       Serial.println("\n\n\n");
       Serial.println("System deactivated");
       Serial.println("\n\n\n\n\n\n\n\n\n\n\n\n\n");
     delay(timer2);      
}
}


}
 

PaulS

Quote
Where we seem to disagree appears (to me) to have more to do with "easy" than with building software problem-solving skills.

Once can never get to the point of being able to create robust code like you do without a lot of experience. Some of that experience comes from producing working code. When one gets comfortable doing that, then one can explore what the libraries/functions that are taken for granted are doing. I prefer to help people get something going. You prefer to offer alternatives to the standard library routines. Wile I have no problem with that, showing a Ferrari to a kid who keeps falling off a tricycle is probably not going to turn them into a competent vehicle operator. Learning to ride the tricycle first, then the bicycle with training wheels, then without the training wheels, etc. is necessary, in my opinion.
The art of getting good answers lies in asking good questions.

PaulS

Quote
I feel like I'm in the middle of an arguement.

There's no yelling, name calling, etc. going on. It's just a discussion about the best way to help you.

Quote
I take it strtok() is conversion of string to integer?

No. The strtok() function is a string parsing function. The atoi() function converts a string to an integer value.

Quote
It may be because I read somewhere that Arduino now has a string library with the software so I do not need to unzip and drag a WString library to the arduino library.

Case is important. The Arduino has a String library. While it is a good idea, the implementation leaves a lot to be desired on such a memory-constrained platform. Even if it didn't have a String library, unzipping and dragging a WString library to the Arduino would probably not be a good idea.

Code: [Select]
String readString = String(100);
One of the changes between the old WString class and the new String class is what the constructor does. Now, the value in the parentheses is converted to a string, and wrapped in the String object. The value no longer reserves space.

Code: [Select]
  readString.append(c); } //makes the string readString
The += operator is much easier to use and understand, in my opinion.
Code: [Select]
readString += c; // Append c onto the end...

Code: [Select]
n = atoi(readString); //convert string to number
atoi() doesn't know anything about Strings, which are not the same as strings. There are three or more ways to deal with the issue. One, the best, is to ditch the String class altogether. Storing data in a NULL terminated char array is simple. That string can then be passed to atoi(). The second way is to use the String::toInt() method, and let it make the call to atoi() on the string is wraps. The third way would be to use String::toCharArray() to extract the wrapped string, and pass that to atoi().

There's Morris' method, too. It's a great approach, if you understand it.

Without knowing exactly what issues you are having with the code, I'll leave it at this, for now.
The art of getting good answers lies in asking good questions.

T86157

The issue I was having was during compilation:

error: cannot convert 'String' to 'const char*' for argument '1' to 'int atoi(const char*)

It sounds like what you are explaining relates directly to the error I get when compiling.

Can you provide an example of the second and third method you mentioned? The first method sounds like a basic talor series function I can use with an array. The only problem I may have is knowing which number would be placed in array first. Let's say I enter in 142 degrees. I am guessing that "1" would be entered into the first, "4" into the 2nd and "2" in the 3rd. So then I could do something similar to in a loop...

Code: [Select]
numFromPort = numFromPort + (data[i]) * pow(10, 6-i);

mrdovey

Since you're pointed in this direction, in your loop you might want

   num = 10 * num + digit_value;

In order to make that work, num will need to be set to zero before looping and each digit character will need to be converted to that digits binary value.

A way to convert an ASCII digit character to its corresponding binary value is to subtract an ASCII zero from it so that

   '0' - '0' -> 0
   '1' - '0' -> 1
   '2' - '0' -> 2
   ...
   '9' - '0' -> 9

If you incorporate this into the assignment in the loop, it comes out:

   num = 10 * num + digit_char - '0';

Does this make sense to you?

Marek080

#20
Apr 11, 2012, 10:55 pm Last Edit: Apr 11, 2012, 11:01 pm by Marek080 Reason: 1
Quote
Can you provide an example of the second and third method you mentioned?


The second method is a single line (assuming you stored the string with the number in readString - same as in your initial post, of type String)
Code: [Select]
long nReadLong= readString.toInt();
Too bad it is not documented now on the reference page.

For the third method I have posted the example here http://arduino.cc/forum/index.php/topic,100803.msg755891.html#msg755891

Now choose your weapon  ;)

zoomkat

I didn't read all the noise, but below is some simple servo test code that gets a string from the serial port, breaks it into two parts, and converts each part into a number for a servo control position.

Code: [Select]

// zoomkat 12-13-11 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 1.0
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550
// use serial monitor to test

#include <Servo.h>
String readString, servo1, servo2;
Servo myservo1;  // create servo object to control a servo
Servo myservo2;

void setup() {
  Serial.begin(9600);
  myservo1.attach(6);  //the pin for the servo control
  myservo2.attach(7);
  Serial.println("two-servo-test-1.0"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    delay(3);  //delay to allow buffer to fill
    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
     
      // expect a string like 07002100 containing the two servo positions     
      servo1 = readString.substring(0, 4); //get the first four characters
      servo2 = readString.substring(4, 8); //get the next four characters
     
      Serial.println(servo1);  //print to serial monitor to see parsed results
      Serial.println(servo2);

      int n1 = servo1.toInt();
      int n2 = servo2.toInt();

      Serial.println("the numbers are :");
      Serial.println(n1);  //print to serial monitor to see number results
      Serial.println(n2);
           
      myservo1.writeMicroseconds(n1); //set servo position
      myservo2.writeMicroseconds(n2);
    readString="";
  }
}

Google forum search: Use Google Search box in upper right side of this page.
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

T86157

Thank you, guys. All these examples helped out. When I become more proficient, I will try out Morris' first example but for now these latter examples are understandable for me.

nickstotle

Code: [Select]

void loop ()
{
  int y = Serial.available();
  Serial.println(y);
  int cont=0;
  int suffix=0;   
  //--------------------------------------
  while (cont!=y && cont<n)
  {
    Byte_received = Serial.read();
    text[cont]=Byte_received;
    cont++;
  }
  //--------------------------------------
  if (y>0)
  {
    suffix = (atoi(&text[1]));
    Serial.print(text[0]);
    Serial.print("-");
    Serial.println(suffix);
 
    switch (text[0])
    {
      case 'M':           
        if(suffix >65 && suffix < maximum)
        {
          change_speed(suffix);
        }
        break;
      case '0':
         change_speed(minimum);
        break;           
        default:
        break; 
    }
  }


can somebody specify me the output at each stage by adding comments to the above code??
after " suffix = (atoi(&text[1]));" this instruction what will be the data in suffix if i send "M78" to arduino
How many characters or length of the string can i receive by using serial.read ???
can i send "A2000" to arduino via bluetooth??
how can i break it into two parts "A" and "2000" how to seperate it by using above program???

PaulS

Quote
can somebody specify me the output at each stage by adding comments to the above code??
I could, but I won't. You can RTFM, and add Serial.print() statements to confirm/refute what you think you learned.

Quote
after " suffix = (atoi(&text[1]));" this instruction what will be the data in suffix if i send "M78" to arduino
Why didn't you run the code and find out?

Quote
How many characters or length of the string can i receive by using serial.read
Serial.read() returns one int that contains one useful byte in the low byte, and an error code in the high byte. If the high byte is 0, the low byte can be used.

Quote
can i send "A2000" to arduino via bluetooth??
If you have a bluetooth device, and it is paired to something that can send data, yes.

Quote
how can i break it into two parts "A" and "2000" how to seperate it by using above program???
If the first part is always one letter, then the above code does that.
The art of getting good answers lies in asking good questions.

nickstotle

@Pauls don't get angry bro but i don't have bluetooth module i have ordered it online it will be available soon...so first i am confirming that i can send and decode the sequence using bluetooth..thank you for support bro...i have tested above code on my friends device...it works fine...
i have few questions for you...
1) can i send "*A1000*B1000*C1000*D1000*" these 25 characters via bluetooth???
2) thus arduino will receive this much characters(25) ??? By using Serial.read??
3)and how can i decode 25 serial bit into A and its value...B and its value...c and its value and d and its value???i have used * for seperation?
4) one option in my mind that i will use AND logical bitwise function...means for decoding A and its respective value i will use

Code: [Select]

void loop ()
{
  int y = Serial.available();
  Serial.println(y);
  int cont=0;
  int suffix=0;   
  //--------------------------------------
  while (cont!=y && cont<n)
  {
    Byte_received = Serial.read();
    text[cont]=Byte_received;
    cont++;
  }
  //--------------------------------------
  if (y==25)
  {
String decode=( Byte_received & 011111000000000000000000);//it will remove *carries A1000 and                       ///////////////////////////////////////////////////////////////////////////remove all char ahead
suffix = (atoi(&decode));
    Serial.print(text[0]);
    Serial.print("-");
    Serial.println(suffix);
}


it will help or not??

PaulS

Quote
1) can i send "*A1000*B1000*C1000*D1000*" these 25 characters via bluetooth???
With the right app on the sending end, yes.

Quote
2) thus arduino will receive this much characters(25) ??? By using Serial.read??
If they do not get lost in the ether, or mangled, yes. NOT all at once, though. Sending start and end markers is a much better idea. "<A1000*B1000*C1000*D1000>".

The delimiters you have are not useful delimiters. There is no way, using the * to tell the start of a packet from the end of a packet from data that is reasonably IN the packet.

Quote
3)and how can i decode 25 serial bit into A and its value...B and its value...c and its value and d and its value???i have used * for seperation?
Save all the data in a NULL terminated array of chars, and use strtok() to extract each token.

Seria input basics - updated

Code: [Select]
String decode=( Byte_received & 011111000000000000000000);//it will remove *carries A1000 and                       ///////////////////////////////////////////////////////////////////////////remove all char ahead

Masking the last 16 bits received with a 24 digit octal constant does not make sense. Storing the result in a String does not make sense.

Passing atoi() the address of a String does not make sense.

Quote
it will help or not??
Not in the slightest.
The art of getting good answers lies in asking good questions.

nickstotle

@pauls i have tried my code and it work successfully but if the byte gets mangled then problem will occur as per u say...so i would like to go with u and decode  "<A1000*B1000*C1000*D1000>".  please help me to design the code using strtok()... i want indivual output and error checkung for the recieved byte..

valasoft

i am coming from vb6 to Arduino C , i Have big trouble with C:
my question is exactly like {T8615 } User
this is a very simple matter in vb but here i spend so many hours for converting a String extracted from serial  terminal to a number and after reading your Deals i understand Nothing.
in fact i need to recognize numbers from the serial and get they pure value to a Integer value
Truly C is very weak at String Manipulation.

Robin2

#29
Mar 24, 2017, 07:16 pm Last Edit: Mar 24, 2017, 07:18 pm by Robin2
Truly C is very weak at String Manipulation.
Then I have bad news for you :)   It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

Quote
n fact i need to recognize numbers from the serial and get they pure value to a Integer value
And some good news ...
Have a look at the parse example in Serial Input Basics

If that does not help solve your problem then please describe if completely. This is a very old Thread you have joined.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Go Up