0

I'm trying to connect to an arduino Mega At2560 unit connected via usb serial port in my linux based PC. Using C code, I'm trying to send and receive simple text strings, just I'm able to send and receive on both sides.

On arduino:

int incomingByte = 0;    // for incoming serial data

void setup() {
    Serial.begin(19200);    // opens serial port, sets data rate to 9600 bps
}

void loop() {
  // send data only when you receive data:
  if (Serial.available() > 0) {

    // read the incoming byte:
    incomingByte = Serial.read();

    // say what you got:
    Serial.print((char)incomingByte);
  }

}

basically just a loop that checks if there is serial data, and if so reads it and prints it back. there's a (char) conversion so I'll see right away the sent data is what I got back (linux side)

For the linux code I use the pretty standard code for opening a port which I found here

I call the Arduino "Table" as it will eventually operate a moving table through USB commands.

C file:

#include "TableFunctions.h"

bool connected=false;
int fd;
char *portname;


int set_interface_attribs (int fd, int speed, int parity)
{
        connected=false;
        struct termios tty;
        struct termios tty_old;
        memset(&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        {
                printf("PC: Error %d from tcgetattr  \n", errno);
                return -1;
        }
        tty_old = tty;

        cfsetospeed (&tty, (speed_t)B19200);
        cfsetispeed (&tty, (speed_t)B19200);

        //tty.c_cflag |= B19200;
        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;                  // 
        tty.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines
        cfmakeraw(&tty);
        tcflush( fd, TCIFLUSH );

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
        {
                printf("PC: Error %d from tcsetattr  \n", errno);
                return -1;
        }
        return 0;
}

void set_blocking(int fd, int should_block)
{
        struct termios tty;
        memset(&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        {
                printf("PC: Error %d from tggetattr  \n", errno);
                return;
        }

        tty.c_cc[VMIN]  = should_block ? 1 : 0;
        tty.c_cc[VTIME] = 10;            // 0.5 seconds read timeout

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
                printf("PC: Error %d setting term attributes  \n", errno);
}


void OpenSerialPort()
{
    char *portname = "/dev/ttyACM0";

    printf("PC: Opening port to table \n");

    int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);

    usleep(2000000);
    if (fd < 0)
    {
        printf("PC: Error %d opening %s: %s  \n", errno, portname, strerror(errno));
        return;
    }

    set_interface_attribs(fd, B19200, 0);  // set speed to 19,200 bps, 8n1 (no parity)
    set_blocking(fd, 0);                // set no blocking
    printf("PC: Connected\n");
    connected = true;
}
void PrepareWriteCommand(int numberOfCommands, const char *commands[numberOfCommands])
{
    if(connected) //check if arduino still connected
    {
        for(int i = 0; i<numberOfCommands; i++) //go through commands 
        {
            int bufferSize = strlen(commands[i]); //get the buffer size needed for this command
            char charArray[bufferSize]; //helper char array
            memcpy(charArray,commands[i],bufferSize);//copy command to the char array
            charArray[bufferSize]=0; //make sure there is a stop symbok at the end
            WriteSerialPort(charArray); //command is ready to be sent, send it.
        }
    }
}
int WriteSerialPort(const char *buffer)
{
    printf("PC: Now writing: ");
    int n_written = 0; //how many bytes were written

    n_written = write(fd, buffer, strlen(buffer)); //write the command and return how many bytes were written

    printf("\n");

    //check bytes send and return ouput (error, nothing or x bytes sent)
    if(n_written<0)
    {
        printf("PC: Error %d from %s \n",errno, strerror(errno));
    }
    else if(n_written == 0)
    {
        printf("PC: Nothing was written  \n");
    }
    else
    {
        printf("PC: Written %i bytes  \n", n_written);
    }

}

int ReadSerialPort(char *buffer, unsigned int buff_size)
{
    //check if arduino still connected
    if(connected)
    {
        //read the serial data
        if(read(fd,buffer,buff_size))
            return sizeof(buffer); //return how much bytes were read
        else
        {
            //else print nothing received
            printf("PC: Arduino not Connected (ReadSerialPort) \n");
        }
    }
}

in OpenSerialPort I basically open a new fd, and call the functions that set the communication settings. I use PrepareWriteCommand to make sure commands input from users are with a stop symbol and send them to WriteSerialPort where I use write() and print how many bytes were sent.

H file:

#include <errno.h>
#include <fcntl.h> 
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>


#define MAX_DATA_LENGTH 256

int set_interface_attribs (int fd, int speed, int parity);
void set_blocking(int fd, int should_block);
void OpenSerialPort();
void PrepareWriteCommand(int numberOfCommands, const char *commands[numberOfCommands]);
int WriteSerialPort(const char *buffer);
int ReadSerialPort(char *buffer, unsigned int buff_size);

Main:

#include "TableFunctions.h"
#include <stdio.h>
#include <stdlib.h>    
int main(int argc, char *argv[])
    {
        char output[MAX_DATA_LENGTH]; //char array to hold arduino output
        int received = 0; // check if read() got any bytes
        const char* commands[]={"test"}; //test command

        OpenSerialPort(); // open serial port

        PrepareWriteCommand((sizeof(commands)/sizeof(commands[1])),commands); //prepare command for sending

        usleep(500000); //wait for arduino response

        while(true)
        {
            ReadSerialPort(output,MAX_DATA_LENGTH);//check serial port for response
            if(strlen(output)>0) //if anything received
            {
                printf("PC: received %i\n",received); //if yes, how many bytes
                printf("PC: %s\n",output); //and what was received
                usleep(500000);
            }
            else if(strlen(output)<=0) //else print nothing received
            {
                printf("PC: Nothing received\n");
            }
        }
        return 0; //finish program
    }

I tried tweaking the tty flags settings with no success. Each time I run the C code I see the arduino resets (and after opening a new fd I give it some time for bootloading) but no communication is sent between the two.

Output:

PC: Opening port to table 
PC: Connected
testPC: Now writing: 
PC: Written 4 bytes  

PC: received 0
PC: 

Any help with understanding why the C code can't communicate with the Arduino will be highly appreciated!

  • Are you waiting for the bootloader to finish executing before you try sending ... ? – Majenko Jan 14 at 11:37
  • @Majenko yep: int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); usleep(2000000); was told I never assign received again in ReadSerialPort(), so I fixed it and now I get: PC: received 8 PC: I send only 4 bytes so arduino might be sending twice the data in the given time untill PC reads it. It doesn't matter though, right now PC still shows nothing in buffer after I call read() – Jordan Jan 14 at 11:45
  • I might be wrong and the 8 bytes are the size of the pointer (sizeof(buf)) – Jordan Jan 14 at 11:58
  • This makes no sense: void PrepareWriteCommand(int numberOfCommands, const char *commands[numberOfCommands]) – Majenko Jan 14 at 12:10
  • 1
    Yes, but you can't use a parameter to set the size of a parameter. It makes no sense. You should be using const char **commands or const char *commands[] since you are using an array of pointers. – Majenko Jan 14 at 12:18
0

Problem was in OpenSerialPort(). I set another variable fd which is local, thus given priority. then when OpenSerialPort() is done, it is deleted, and the global fd remain unset. This is why I can't send anything from or to the PC.

Thanks.

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.