2

I want to read the analog values of my ardunio uno into a separate c++ program. On the Arduino I have a serial port initialized for 9600 baud:

int sensorPin = A0;    // select the input pin for the potentiometer

int sensorValue = 0;  // variable to store the value coming from the sensor

void setup() {
Serial.begin(9600);
}

void loop() {
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);
  Serial.println(sensorValue);
} 

The output value should be right around 390, given the current settings. My serial port reading code seems to read the port fine, but only displays some of the characters sometimes.... some of the time, it reads the value fine. other times I get one or 2 of the characters, such as 3, or 39.

#include <stdio.h>      // standard input / output functions
#include <stdlib.h>
#include <string.h>     // string function definitions
#include <unistd.h>     // UNIX standard function definitions
#include <fcntl.h>      // File control definitions
#include <errno.h>      // Error number definitions
#include <termios.h>    // POSIX terminal control definitions
#include <iostream>     
using namespace std;

int main(){
    const char* device ="/dev/ttyACM0";
/* Open File Descriptor */
//int USB = open( device, O_RDWR| O_NONBLOCK | O_NDELAY );
int USB = open( device, O_RDWR| O_NOCTTY );

/* Error Handling */
if ( USB < 0 ){
cout << "Error " << errno << " opening " << device << ": " << strerror (errno) << endl;
}

/* *** Configure Port *** */
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);

/* Error Handling */
if ( tcgetattr ( USB, &tty ) != 0 ) {
   cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << endl;
}

/* Save old tty parameters */
tty_old = tty;

/* Set Baud Rate */
cfsetospeed (&tty, (speed_t)B9600);
cfsetispeed (&tty, (speed_t)B9600);

/* Setting other Port Stuff */
tty.c_cflag     &=  ~PARENB;            // Make 8n1
tty.c_cflag     &=  ~CSTOPB;
tty.c_cflag     &=  ~CSIZE;
tty.c_cflag     |=  CS8;

tty.c_cflag     &=  ~CRTSCTS;           // no flow control
tty.c_cc[VMIN]   =  1;                  // read doesn't block
tty.c_cc[VTIME]  =  5;                  // 0.5 seconds read timeout
tty.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines

/* Make raw */
cfmakeraw(&tty);

/* Flush Port, then applies attributes */
tcflush( USB, TCIFLUSH );
if ( tcsetattr ( USB, TCSANOW, &tty ) != 0) {
   cout << "Error " << errno << " from tcsetattr" << endl;
}


if ( tcsetattr ( USB, TCSANOW, &tty ) != 0){
cout << "Error " << errno << " from tcsetattr" << endl;
}


/* Allocate memory for read buffer */
char buf [1024];
memset (&buf, '\0', sizeof buf);

/* *** READ *** */
int n = read( USB, &buf , sizeof buf );
cout << "buffer: " << &buf << endl; 
/* Error Handling */
if (n < 0)
{
     cout << "Error reading: " << strerror(errno) << endl;
}

/* Print what I read... */
cout << "Read: " << buf << endl;

close(USB);
 return 0;
}

How can I read the correct value being sent every time?

8
  • 1
  • 1
    It's odd that you don't care about Serial.print(), since it is the sort of thing Arduino gives to allow conveying data over a serial connection. You mention "stable connection"; does this mean you have found your serial connection to be unstable?
    – timemage
    Jul 24 at 14:27
  • 1
    I know how to set the arduino to send data on the serial port, its the receiving it elsewhere that I am struggling with. My interpretation of the results I am getting lead me to believe there is a stability issue.
    – j0h
    Jul 24 at 22:02
  • Would capturing the Serial.print() output with a terminal emulator that supports logging output do, then post processing that file? At least it would confirm (or not) that the data being sent is correct (or not). If it's being sent correctly, your problem isn't with the Arduino or its code.
    – JRobert
    Jul 24 at 23:21
  • 1
    Your core problem is the way you're using read, as Edgar notes. You must read a line not just a random number of bytes.
    – Majenko
    Jul 25 at 17:41
4

There are a few issues at play here. One is that the Arduino resets every time you open the serial connection on the PC side. You can prevent this by putting a 1 µF (or more) capacitor between 5V and RESET. A second issue is that the tty driver may be keeping old data in its buffer, and you get this data when you open the connection. The third issue is that read() returns as soon as it is able to read some data: it doesn't wait until it has got sizeof buf bytes.

To fix those issues, I suggest:

  1. Have some form of handshake, where the PC sends a request to the Arduino, and then the Arduino acknowledges and starts to send the data. The PC program would then discard everything preceding the acknowledgement.
  2. On the PC, repeatedly read() until you have a full line (which ends with CRLF). You may want to use a line-oriented stream if you want the libc to handle this for you: see fdopen(3) setlinebuf(3).

Edit: A very simple example of handshake: the PC sends S (for “start”), then the Arduino sends OK, then it starts sending the data. On the Arduino side:

void setup() {
    Serial.begin(9600);

    // Wait for the 'S' (start) command from the computer.
    while (Serial.read() != 'S')
        /* wait */ ;

    // Send acknowledgement.
    Serial.println("OK");
}

A longer “start” command would be more robust, but a bit more complex to handle on the Arduino. The PC should wait a bit before sending the command (in case the Arduino is restarting), or maybe send it multiple times until it gets an answer.

3
  • have any good refference material for this?
    – j0h
    Jul 25 at 14:51
  • 1
    @j0h: For what? About line buffering, the notation “fdopen(3), setlinebuf(3)” is a horthand for “see man 3 fdopen 3 setlinebuf. Jul 25 at 16:20
  • the handshaking bit, I'm not clear on. is that Serial.read() reading from the serial port to the computer, or from the Arduino? Im thinking maybe I can send a character to the arduino, pc say, hey arduino, you there rsvp to char 42. arduino listens for char 42, gets it, and responds with a string of values or something, and posts a hangup sign, and goes back to listening for the next rsvp from the PC. ... or something like that, is how I'm imagining it going
    – j0h
    Jul 25 at 17:20
1

A USB connection is actually very complex. And serial communications (or the CDC class of USB) is only 1 of over a dozen protocols used over USB. Most cheap embedded processors save money by leaving out this feature. Most Arduino's use cheap embedded processors. For instance, the classic Arduino Uno needs a second chip (search for New USB in this link) to even talk Serial over the USB port. Fortunately this is what Serial.print() does. It takes care of setting up the Serial protocol over the USB port for you. And will send your data over that connection.

How you pick up that data at the other end of the USB connection is usually beyond the discussion range of this stack exchange site. But if you are on a windows machine it will probably be one of the COM ports. And on Linux it will probably be something like /dev/ttyUSB0 or 1.

6
  • 1
    You don't have to, but comments are appreciated when ever there is a vote. In either direction. The objective is to edit and improve both the questions and the answers.
    – st2000
    Jul 24 at 17:17
  • 1
    I might have to repost this, as it is now closed. But I appreciate the answer.
    – j0h
    Jul 24 at 22:00
  • You can edit this question to be more focused. That should trigger a message to person who closed it so that they can reconsider the edited version of the new more focused question. Hint: It's always good to try something on your own first then ask when things don't go as expected.
    – st2000
    Jul 24 at 22:06
  • 1
    yeah, I edited it, but its still closed. every vote to reopen helps. hint hint
    – j0h
    Jul 24 at 22:25
  • 2
    Thanks @Juraj for responding. I see your point. But since @ Edgar Bonet gave such a complete answer I don't see a benefit in repeating even a part of what he said. So as to mitigate confusion I'm going to leave things as they are.
    – st2000
    Jul 25 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.