Pages: 1 [2]   Go Down
Author Topic: Serial Read, String, Convert ATOI  (Read 10621 times)
0 Members and 1 Guest are viewing this topic.
Ca, USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 95
Slow learner, ME in a programmers world
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
//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);      
}
}


}
  
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
  readString.append(c); } //makes the string readString
The += operator is much easier to use and understand, in my opinion.
Code:
readString += c; // Append c onto the end...

Code:
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.
Logged

Ca, USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 95
Slow learner, ME in a programmers world
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
numFromPort = numFromPort + (data[i]) * pow(10, 6-i);
Logged

West Des Moines, Iowa USA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 428
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

There's always a better way!

Germany
Offline Offline
Jr. Member
**
Karma: 0
Posts: 89
Walking on Nails
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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  smiley-wink
« Last Edit: April 11, 2012, 04:01:21 pm by Marek080 » Logged

loved the 68000 assembler back then and now I have to deal with THIS 8 bit thingy

0
Offline Offline
Tesla Member
***
Karma: 141
Posts: 9470
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
// 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="";
  }
}

Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Ca, USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 95
Slow learner, ME in a programmers world
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Pages: 1 [2]   Go Up
Jump to: