I'm using Ubuntu 16 (although i have the same problem on Debian) Arduino Mega 2560, 2 versions of Arduino IDE: 2:1.0.5+dfsg2-4.1 and 1.8.9.
I'm working on a connecting a C program with Arduino via COM-port.
For example, I have following code; a PC program sends some text to Arduino, while Arduino receives and prints it.
pc.c:
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
int openPort(char port_name[], speed_t speed)
{
int F_ID = open(port_name, O_RDWR | O_NOCTTY);
fcntl(F_ID, F_SETFL, 0);
//printf("%s\n", port_name);
if(F_ID == -1)
{
return -1;
}
struct termios options;
tcgetattr(F_ID, &options);
cfsetispeed(&options, speed);
cfsetospeed(&options, speed);
options.c_cc[VTIME] = 20;
options.c_cc[VMIN] = 0;
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_lflag = 0;
options.c_oflag &= ~OPOST;
tcsetattr(F_ID, TCSANOW, &options);
return F_ID;
}
void closePort(int id)
{
close(id);
return;
}
int sendData(int id, unsigned char* buf, int len)
{
int n = write(id, buf, len);
if(n == -1)
{
char *errmsg = strerror(errno);
printf("%s\n",errmsg);
}
return n;
}
int main(int argc, char * argv[])
{
int port=openPort("/dev/ttyUSB0", B9600);
if ( (port) == -1){
//char *errmsg = strerror(errno);
printf("Cannot open port: %s\n",strerror(errno));
return -1;
}
sendData(port, "Hello, Arduino!*", 16);
closePort(port);
return 0;
}
ard.ino:
int stage = 0;
String recv;
char* line;
char* get_line(void)
{ // '*' is a terminal character
if (Serial.available() > 0)
{
char c = Serial.read();
if (c=='*')
{
char* res = (char*)malloc((recv.length()+1)*sizeof(char));
recv.toCharArray(res, recv.length()+1);
stage=1;
recv="";
return res;
}
else { recv += c; }
} // if (Serial.available() > 0)
}
void setup()
{
Serial.begin(9600);
}
void loop()
{
if (stage==0)
{
line = get_line();
}
else
{
Serial.print("Got line: ");
Serial.println(line);
stage = 0;
}
}
To check, if my program works fine, I'm using Port Monitor in the IDE.
I have following problem:
I prefer to use Arduino IDE 1.8.9, but when I open Port Monitor and run my PC program - nothing works, PC-prog can't access the port and send information (it says Bad file descriptor);
while with Arduino 2:1.0.5+dfsg2-4.1 everything works fine and i can see on Port Monitor:
Got line: Hello, Arduino!
So I'm asking, what I have to do with Arduino IDE 1.8.9 parameters or with /dev/ttyUSB* for it to work fine with each other?
Related
I'm relatively new to embedded linux so apologies if there's a simple answer to this question or if I'm not providing the necessary information.
And if there's a concept here that I clearly don't understand please point it out as I'm doing all of this as a learning exercise.
I recently need to use GPS receiver neo-6m and 3-axis accelerator adxl345 to collect GPS data
and acceleration on Raspberry Pi 3 for the project I currently working on.
Individually both work fine.
However when my program runs them together only one of them will receive data.
Below are my code to setup both of them:
int setup_for_acc_impl(void) {
// Create I2C bus
int file;
char *bus = "/dev/i2c-1";
if ((file = open(bus, O_RDWR)) < 0) {
printf("Failed to open the bus. \n");
exit(1);
}
// Get I2C device, ADXL345 I2C address is 0x53(83)
ioctl(file, I2C_SLAVE, 0x53);
// Select Bandwidth rate register(0x2C)
// Normal mode, Output data rate = 100 Hz(0x0A)
char config[2] = {0};
config[0] = 0x2C;
config[1] = 0x0A;
write(file, config, 2);
// Select Power control register(0x2D)
// Auto-sleep disable(0x08)
config[0] = 0x2D;
config[1] = 0x08;
write(file, config, 2);
// Select Data format register(0x31)
// Self test disabled, 4-wire interface, Full resolution, range = +/-2g(0x08)
config[0] = 0x31;
config[1] = 0x08;
write(file, config, 2);
return file;
}
and set up for gps:
void gps_setup(void){
int uart0_filestream = -1;
uart0_filestream = open(PORTNAME, O_RDWR | O_NOCTTY | O_NDELAY);
if (uart0_filestream == -1)
{
printf("Failed to open the ttyS0. \n");
exit(1);
}
struct termios options;
tcgetattr(uart0_filestream, &options);
options.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
options.c_iflag = IGNPAR;
options.c_oflag = 0;
options.c_lflag = 0;
tcflush(uart0_filestream, TCIFLUSH);
tcsetattr(uart0_filestream, TCSANOW, &options);
}
and how I read data from both of them:
//read data from adxl345,simply read
read(obu->i2c_fd, data, 6) ;
//read data from gps module
void serial_read_for_gps(char *buffer, int len)
{
char c;
char *b = buffer;
int rx_length = -1;
while(1) {
rx_length = read(uart0_filestream, (void*)(&c), 1);
if (rx_length <= 0) {
//wait for messages
printf("didn't receive any data\n");
sleep(1);
} else {
if (c == '\n') {
*b++ = '\0';
break;
}
*b++ = c;
}
}
}
I'm not sure where the problem is coming from, any help would be great.
Thanks
I wrote common functions in order to manage serial ports, based on the following structure:
typedef struct
{
int PHandle;
unsigned int Port;
unsigned int BaudRate;
unsigned char Parity;
unsigned char FlowControl;
char Device[MAX_SIZE];
} Tst_SPort;
I am calling these functions (see below) in another file in order to test an RS232 serial port. The flow control needs to be enabled.
int iInit(Tst_SPort *port, const char *device, int baudRate, unsigned char parity, unsigned char flowControl)
{
strncpy(port->Device, device, MAX_SIZE);
port->PHandle = iOpen(port);
port->Port = -1;
port->BaudRate = baudRate;
port->Parity = parity;
port->FlowControl = flowControl;
if(port->PHandle > 0)
{
setuart(port, port->BaudRate);
}
return port->PHandle;
}
int iOpen(Tst_SPort *port)
{
port->PHandle = open(port->Device, O_RDWR | O_NOCTTY);
if(port->PHandle < 0)
{
perror("open:");
return (-1);
}
return (port->PHandle);
}
void setuart(Tst_SPort *port, int baudRate)
{
struct termios opt, optCmp;
struct serial_struct info;
if(port->PHandle > 0)
{
bzero(&opt, sizeof(opt));
bzero(&optCmp, sizeof(optCmp));
if(ioctl(port->PHandle, TIOCGSERIAL, &info) == 0)
port->Port = info.port;
fcntl(port->PHandle, F_SETFL, O_NONBLOCK);
if (tcgetattr(port->PHandle, &opt) < 0)
perror("tcgetattr Get:");
if(baudRate > 0)
{
cfsetospeed (&opt, baudRate);
cfsetispeed (&opt, baudRate);
}
opt.c_iflag = IGNPAR;
opt.c_oflag &= ~OPOST
opt.c_oflag &= ~ONLCR;
opt.c_lflag = 0;
opt.c_cflag |= (CLOCAL | CREAD);
opt.c_cflag &= ~(PARENB | PARODD);
opt.c_cflag |= port->Parity;
opt.c_cflag &= ~CSTOPB;
opt.c_cflag &= ~CSIZE;
opt.c_cflag |= CS8;
if(!port->FlowControl)
opt.c_cflag &= ~CRTSCTS;
else
opt.c_cflag |= CRTSCTS;
opt.c_cc[VMIN] = 0;
opt.c_cc[VTIME] = 50;
if(tcsetattr(opt->PHandle, TCSANOW, &opt) < 0)
perror("tcgetattr Update :");
if (tcgetattr(opt->PHandle, &optCmp) < 0)
perror("tcgetattr Read:");
/* Compare */
if (memcmp((void *)&opt, (void *)&optCmp, sizeof(opt)) != 0)
printf("Conf failed");
tcflush(port->PHandle, TCIFLUSH);
}
}
int iRead(Tst_SPort *port, char *buffer, unsigned long buffLength)
{
struct timeval tv;
fd_set recv;
int s32Read = 0;
int s32Offset = 0;
int s32SRes = 0;
tv.tv_sec = 0;
tv.tv_usec = 100000; /* 100ms */
if ((port) && (port->PHandle > 0))
{
while (s32Offset < buffLength)
{
FD_ZERO(&recv);
FD_SET(port->PHandle, &recv);
s32SRes = select(port->PHandle + 1, &recv, NULL, NULL, &tv);
if ((s32SRes == -1) && (errno == EINTR))
{
continue;
}
else if(s32SRes > 0)
{
if (FD_ISSET(port->PHandle, &recv))
{
s32Read = read(port->PHandle, buffer + s32Offset, buffLength - s32Offset);
if(s32Read > 0)
{
tv.tv_sec = 0;
tv.tv_usec = 5000;
s32Offset += s32Read;
continue;
}
}
}
break;
}
}
return s32Offset;
}
int iClose(Tst_SPort *port)
{
return (close(port->Phandle));
}
In order to validate the implementation, the pinouts Tx and Rx have been connected together, idem for CTS and RTS. Everything works fine, the message sent can be read correctly. In addition, when Tx is disconnected from the Rx nothing is reading as expected.
But when the CTS is unplugged from the RTS the test blocks after the port closing step (~20 seconds).
However, if the function setuart() is called with flowControl == 0, the test does not block and returns the exepected error code without delay.
I probably understood something wrongly especially in port configuration. Is it the good way to do ?
The problem you are facing is a correct behaviour.
Leaving CTS unconnected with flow control enabled, means DTE (AKA PC) cannot send data to DCE (slave device).
When you try to write to the UART output buffer it, probably, is full and application temporarily stops running and waits until some buffer space becomes available.
I am using fgets in a small C program - running under Ubuntu - to read data coming from Arduino via its FTDI USB/Serial converter.
I am using low level I/O function from GNU libc (since I want - in the future - be able to control baud rate etc) and then promoting from descriptor to stream in order to use higher leve I/O functions.
The observed behaviour of my program suggests that the fgets function does not block until the line terminator is acquired (as in my opinion it should do).
Any explanation?
The codes of my programs are here
-> PC side:
#include <stdio.h> /* Standard input/output definitions */
#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 */
#define bufLen 81
int main(void) {
int fd; /* File descriptor for the port */
FILE * f; /* port will be identified also as stream 'f'*/
char buf[bufLen];
fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
if (fd == -1) {perror(""); return errno;}
else {
f = fdopen(fd, "r+t");
while (1) {
if (fgets(buf,bufLen,f)) {
printf("{%s}\n",buf);
sleep(1);
} else {
{perror("ahhhh! ");}
}
}
}
return 0;
}
-> Arduino side:
char ar[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
int k1 = 0, k2 = 0;
void setup() {
// initialize serial:
Serial.begin(9600);
}
void loop() {
Serial.print(ar[k1]);
k1 = (++k1) % 26;
k2 = (++k2) % 5;
if (k2==0) {Serial.println();}
delay(300);
}
And the result of run..
xxx#RevoR3600:~/CProg$ ./SerialPort
ahhhh! : Success
ahhhh! : Success
ahhhh! : Success
...
... (many identical lines...)
...
ahhhh! : Success
ahhhh! : Success
{AP}
{A}
{BCD}
{E
}
{FGHIJ
}
^C
xxx#RevoR3600:~/CProg$
After sleeping one night on it and two more hours of digging this site (and testing) I finally came across a solution right here; sorry I was not able to find it before posting (I can't figure out why); now it is matter for me to study exactly why the found solution is working (and why there is still a minor problem: some strange characters acquired on starting).
Thanks (and apology) to everybody has read my post.
Here is the working (test) code:
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<fcntl.h>
#include<termios.h>
#define bufLen 81
int main() {
char buf[bufLen];
struct termios tty;
FILE * f;
int fd=open("/dev/ttyACM0",O_RDWR | O_NOCTTY);
if(fd == -1) {
perror("Unable to open /dev/ttyACM1\n");
return -1;
} else {
if(tcgetattr(fd, &tty)!=0) {perror("tcgetatt() error"); return -1;}
else {
cfsetospeed(&tty, B9600);
cfsetispeed(&tty, B9600);
tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= CLOCAL | CREAD;
tty.c_iflag |= IGNPAR | IGNCR;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_lflag |= ICANON;
tty.c_oflag &= ~OPOST;
tcsetattr(fd, TCSANOW, &tty);
if (!(f = fdopen(fd, "r+t"))) {perror("fdopen() error"); return -1;}
while (1) {
fgets(buf,bufLen,f);
printf("%s--\n",buf);
}
}
}
close(fd);
return 0;
}
I want to read data frames sent by a GPS XBee protocol. The USB XStick receives the following data:
CHARS : 15931 SENTENCES = 0 CHECKSUM : 58
Heading : 55 Tilt: -46 Roll:2
CHARS : ....
and so on ... I can read by typing in the terminal control :
$ screen /dev/ttyUSB0
I'd like to see these details in the same way, but with a program written in C. Here's what I do :
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include "serial_port.h"
void read_Serial_Port(const char* DEVICE_PORT)
{
int file;
struct termios options;
char message[100];
unsigned int nCountMax = 60;
bool b;
file = open(DEVICE_PORT, O_RDONLY | O_NOCTTY | O_NDELAY);
if(file == -1){perror("Unable to open the serial port\n");}
printf("Serial port open successful\n");
tcgetattr(file, &options);
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag |= PARENB; //No parity
options.c_cflag |= PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8; //8 bits
options.c_iflag |= (INPCK | ISTRIP);
tcsetattr(file, TCSANOW, &options);
fcntl(file, F_SETFL, FNDELAY);
printf("Reading serial port ...\n\n");
b = readMessage(file, message, nCountMax);
if (b == 0){printf("Error while reading serial port\n");}
else printf("Serial port read successful\n");
close(file);
printf("Serial port closed\n");
};
bool readMessage(int file, char *message, unsigned int nCountMax)
{
int nbCharToRead;
char data[100];
int i;
if (file != 0)
{
i = 0;
while (i<nCountMax && data != ".")
{
if (read(file,&data,1) == -1)
{
printf("reception error\n");
return false;
}
else
{
message[i] = *data;
printf("%c", message[i]);
i++;
}
}
message[i] = 0;
return true;
}
}
But it does not work, I get "reception error", corresponding to:
read(file,&data,1) == -1
Where am I going wrong?
My program is the following:
bool readMessage(int file, unsigned int nCountMax)
{
int i;
size_t nbytes;
ssize_t bytes_read;
if (file != -1)
{
i = 0;
char message[100];
char data[100];
while (i<nCountMax && data != ".")
{
if (read(file, data, 1) == -1)
{
printf("reception error\n");
printf("code errno = %d\n", errno);
return false;
}
else
{
nbytes = sizeof(data);
bytes_read = read(file, data, nbytes);
message[i] = *data;
printf("%c", message[i]);
i++;
}
}
message[i] = 0;
return true;
}
}
This time there are no more errors, but the characters shown are wrong:
$$$$QUC
U$C
$$$$JQMJ' J$Cz(HSQ'Q'y
UKUNiQUMJ
the dollar signs $$$$ represent numbers in groups of four... I repeat that what I would like to have is
CHARS : 15931 SENTENCES = 0 CHECKSUM : 58
Heading : 55 Tilt: -46 Roll:2
CHARS : .....
I have tried using %c, %d, %x in the format string, but obviously none of them worked properly ...
Thank you!
In my code, I only change c_cflag, as follows:
// Enable the receiver and set local mode...
options.c_cflag |= (CLOCAL | CREAD);
// Set 8-bit mode
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
I'll post more code tomorrow, but give that a shot (and don't modify c_iflag).
I have problem in sending data serially using RS-232 from linux OS to uc 8051.
8051 setting:
baudrate = 9600;
comport = port1.
parity = none
stop bit = one
// my code for receiving data on 8051 uc
#include <reg51.h>
unsigned char value;
int i,j;
void ini()
{
TMOD=0x20; //Timer1, mode 2, baud rate 9600 bps
TH1=0XFD;
SCON=0x50;
TR1=1;
}
void delay()
{
for(i=0;i<=1000;i++)
for (j=0;j<=300;j++);
}
void recieve()
{
unsigned char value;
while(RI==0);
value=SBUF;
P1=value;
RI=0;
}
void main()
{
while(1)
{
ini();
recieve();
}
}
// and code which run on linux is as following
#include <stdio.h> // standard input / output functions
#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 definitionss
#include <time.h> // time calls
int open_port(void)
{
int fd; // file description for the serial port
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) // if open is unsucessful
{
//perror("open_port: Unable to open /dev/ttyS0 - ");
printf("open_port: Unable to open /dev/ttyS0. \n");
}
else
{
fcntl(fd, F_SETFL, 0);
printf("port is open.\n");
}
return(fd);
} //open_port
int configure_port(int fd) // configure the port
{
struct termios port_settings; // structure to store the port settings in
cfsetispeed(&port_settings, B9600); // set baud rates
cfsetospeed(&port_settings, B9600);
port_settings.c_cflag &= ~PARENB; // set no parity, stop bits, data bits
port_settings.c_cflag &= ~CSTOPB;
port_settings.c_cflag &= ~CSIZE;
port_settings.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &port_settings); // apply the settings to the port
return(fd);
} //configure_port
int query_modem(int fd) // query modem with an AT command
{
char n;
fd_set rdfs;
struct timeval timeout;
// initialise the timeout structure
timeout.tv_sec = 10; // ten second timeout
timeout.tv_usec = 0;
// Create byte array
unsigned char send_bytes[] = { 0x00, 0xff};
write(fd, send_bytes, 2); //Send data
printf("Wrote the bytes. \n");
// do the select
n = select(fd + 1, &rdfs, NULL, NULL, &timeout);
// check if an error has occured
if(n < 0)
{
perror("select failed\n");
}
else if (n == 0)
{
puts("Timeout!");
}
else
{
printf("\nBytes detected on the port!\n");
}
return 0;
} //query_modem
int main(void)
{
int fd = open_port();
configure_port(fd);
query_modem(fd);
return(0);
} // main
But I have problem .. so plz help me out and tell me in which format linux sends data through rs-232. Also receiving format of 8051 micro-controller.
Need sample code in C.
I recomment basic fault finding
make sure you use correct cables (2 & 3 crossed out, no handshake lines to start with)
seperate the devices, i.e. connect your Linux machine to a PC running a terminal
program and try to establish 2-way communication - work on the Linux / C code until you achieve
connect your 8051 to a PC running a terminal program ....
connect Linux and 8051 only if they both work against a known and proven device
If your 8051 code sample represents all code .... how would the 8051 respond to the AT .... it can only receive.
good luck