Trying to recieve numbers vis serial from pc.

Ok, I have a analog gauge that shows from 0 to 30, im controlling it via PWM. Ive built an array holding the different PWM values needed for the gauge. Now I want to be able to send a value 0-30 from my pc (via arduino compiler serial or telnet etc) and the gauge will display that value.

Here is my code:

int gauge = 10;
int val = 0;
int econVals[] = {0, 12, 14, 17, 19, 22, 26, 29, 32, 35, 38};

void setup()
{
  Serial.begin(9600);
pinMode(gauge, OUTPUT);
}

void loop()
{
  val = (Serial.available());
  analogWrite(gauge, econVals[val]);
}

It semi works, say if I send "5" to the arduino the gauge will show 1, if I send "10" the gauge will show 8, if I enter "5" again the gauge wont move back, it will just increase to 10.

I dont think it is recieving the right values, does Serial.Avaliable return a byte when analogWrite is expecting a decimal/integer?

I have also tried Serial.read with the same results.

If I enter the value I want to display manually into analogWrite, e.g analogWrite(gauge, econVals[10); it works perfectly.

The reason I want to do this is so that I can map the rest of the gauge and find the rest of the PWM values easily, before I was just changing the PWM value in my code and writing it to the arduino and seeing what the gauge displayed and then adjust the PWM and write it to the arudino again until I got it right, thats how I got the first 10 values, but it is very slow doing it that way :)

serial.available() tells you how much data is available to be read.

serial.read() reads the data, but it's going to return an ASCII character (since that's what you are feeding it). The character '5' isn't the same thing as the number 5.

A two digit character will be two characters - you'll have to read them both and convert the characters to a single number.

-j

Ok thanks. Any hints on converting ASCII to a number like I am trying to do?

I'm really confused by your question.

You mention a gauge. I infer that this is something that shows a number when you send the right thing to it from the Arduino.

If that's what's going on, why the use of "serial.available"?

And why the use of PWM? Was that just "what (sort of) worked"?

Details (http for data sheet, or at least on-line ad) for the gauge would probably help us help you.

Does the gauge have just one wire for input? For the "message" to say what to display?

If so, it is possible that it wants serial data.

If so, the first question is what data rate the gauge needs. If it can accept something "nice", like 9066, then Serial.begin(9600) tells the ARduino to send at that speed.

Once you've done Serial.begin(9600), then you can use

Serial.print(15)

to send the number 15 out on the Ardino's pin 1

Serial.print("15")

would send the ASCII for 1, then the ASCII for 5 out on pin 1.

To (not) answer your question about converting ASCII to other... it can be done, but is probably not necessary... the Serial.print command caters for various relevant needs already.

Although not directly related to the issues above, you might find my programming tutorials useful.....

http://sheepdogsoftware.co.uk/pltut.htm

Hope that helps, or at least will help you to frame a supplementary question...

You mention a gauge. I infer that this is something that shows a number when you send the right thing to it from the Arduino.

If that's what's going on, why the use of "serial.available"?

And why the use of PWM?

I assume the original poster means an analogue gauge with a moving needle, something like this.

--Phil.

Here is some code that expects digits followed by an enter. You can modify it for your needs.

-j

Orac, if your PC can send your values as raw bytes ranging from 0 to 30 then your Arduino code can be a simple as:

if(Serial.available()) Val = Serial.read();

if your PC can send your values as raw bytes

The computer can, but he specified he's using a terminal window (e.g. the Arduino IDE console). Typing non-printable characters may be problematic there.

now if we're talking about an application doing the character generation instead of a keyboard, then that would be an efficient and simple way to do it (as long as you make sure software flow control is off).

-j

j, I completely agree with you. However if Orac just wants to get test values into the Arduino than sending a single letter from A through Z will provide the values from 0 to 25 if the Arduino code is:

Val = Serial.read() – ‘A’;

Values from 26-30 are the ascii chars: “^_”

Your suggestion is a good choice if ascii strings are the only thing that can be sent or if there is a benefit of having the data human readable. But Orac would need to either ensure he always sent two chars or implement a terminating character to indicate the end of the value.

Orac, over to you?

Theres some confusion here/

The gauge is a analog one, it is driven via PWM.

The code I posted is a bad example, I was using serial.available and serial.read I was experimenting with both as I couldnt get it to work.

What I want to do, is send a number to the arduino from the pc, either via hyperterminal or the built in arduino IDE terminal. The number would be from 0 - 110. The number I sent from the pc would be what the ardunio used as the PWM value for the gauge.

This is so that I can send a value to the arduino and see where the gauge moves to so I can easily map PWM values to what the gauge will show.

RecievedData = Serial.read(); analogWrite(gauge, RecievedData);

Something like that I geuss, but Serial.read will return ASCII characters?

Off to work now, Ill check out those links some people posted when I get back.

Either of the suggestions should do what you want. Kg4wsv posted a routine that returns an integer that is sent as ascii characters terminated by a carriage return.

Or if you are after a quick a dirty test, you could use the following two lines of code that will set Val to be a number proportional to the ascii value of the letter typed where A is 0, B is 1, C is 2 etc if(Serial.available()) Val = Serial.read() – 'A';

google ascii table to see what letter to press to get any value in the range you want. Val will be the ascii value of the letter minus 65

If that is as clear as mud then just use KG4wsv's method ;)

I tryed KG4wsv's function, but I get errors when compiling.

 In function 'int read_int()':
error: 'crlf' was not declared in this scope

So I commented out that line, it was just a Serial.print anyway. Then I got this error,

 In function 'int read_int()':
error: 'isdigit' was not declared in this scope

Which is this line:

 if (isdigit(c))

Is (isdigit(c) another function I need to include in my code?

Heres the code:

int read_int()
{
  static byte c;
  static int i;

  i = 0;
  while (1)
  {
    while (!Serial.available())
    {;}

    c = Serial.read();
    Serial.print(c, BYTE);
  
    if (c == '\r')
    {
      Serial.print(crlf);
      return i;
    }
    if (isdigit(c))
    {
      i = i * 10 + c - '0';
    }
    else
    {
      Serial.print("\r\nERROR: \"");
      Serial.print(c, BYTE);
      Serial.print("\" is not a digit\r\n");
      return -1;
    }-65
  }
}

Mem: I understand your method except the part about the ASCII value -65, why is it minus 65?

add these to your sketch:

#include <ctype.h> // this is for isdigit
#define crlf “\r\n” // this is a carriage return and line feed.

also, you have -65 near the end of that code, this should be removed.


Mem: I understand your method except the part about the ASCII value -65, why is it minus 65?

each byte you receive on the serial port has a value. The letter A is a byte with the value of 65, B has a value of 66 etc. So subtracting 65 from the letter you recieve results in a value from 0 on up

Oops, isdigit() and crlf are defiend elsewhere:

#define isdigit(X) (((X) >= '0') && ((X) <= '9'))

char crlf[] = "\r\n";

Sorry about that!

-j