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!
const char **commands
orconst char *commands[]
since you are using an array of pointers.ReadSerialPort(output,MAX_DATA_LENGTH);
I doubt that the function:ReadSerialPort()
terminates the input with a NUL byte, so any following calls that are expecting a NUL terminated array of characters will not work. I would expect that function returns a count of the number of characters read, which can be used to insert a NUL byte into the arrayoutput[]
ReadSerialPort(output,MAX_DATA_LENGTH);
The posted code does not check the returned value fromReadSerialPort()
AND the actual function:ReadSerialPort()
fails to return an error status when (for instance) the port is not connectedprintf("PC: Now writing: ");
this data will stay in the output stream until something happens (like another call to printf() that (properly) has a '\n' as part of the data (perferably the last character output) forces the data to be passed to the terminalread()
will let the code know if anything is there to read. Waiting some arbitrary time is not a good method. Much better to keep callingReadSerialPort()
until some data is seen