可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am working on a project that has my computer communicating with an arduino board that reads the sensor output and put it on the serial port only if a "t" was received.the arduino code as shown below is working.
const int inputPin = 0;
void setup(){
Serial.begin(9600);
pinMode(13, OUTPUT);}
void loop(){
if (Serial.available() > 0){
char c=Serial.read();
if(c=='t'){
int value = analogRead(inputPin);
float celsius = (5.0 * value * 100.0)/1024.0;
Serial.println(celsius);
}
}
}
My problem is in the C code when Im trying to read what arduino puts on the serial port. My C code is:
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<fcntl.h>
int main(){
int STATE_OK=0;
int STATE_WARNING=1;
int STATE_CRITICAL=2;
char tempbuf[10];
int fd=open("/dev/ttyACM0",O_RDWR | O_NOCTTY | O_NONBLOCK);
if(fd == -1){
printf("Unable to open /dev/ttyACM0\n");
return STATE_WARNING;
} else {
fcntl(fd, F_SETFL, FNDELAY);
int w=write(fd, "t", 1);
printf("The number of bytes written to the serial port is %d \n",w);
fprintf(stderr, "fd = %d.\n", fd);
sleep(10);
int n=read(fd,tempbuf,5);
printf("%d,%s \n",n,strerror(errno));
if(n>0){
float temp=atof(tempbuf);
printf("Temperature is: %f Celsius\n", temp);
if (temp>27){
return STATE_CRITICAL;
}else{
printf("The temperature is %f Celsius and checked 10 seconds ago\n",temp);
return STATE_OK;
}
}
}
close(fd);
return 0;
}
n is always=0 and i can't figure out what is the problem.
Thanks in advance.
回答1:
i can't figure out what is the problem
One big problem is that the C program running on the "computer" is incomplete.
The Arduino's program does a serial port setup of at least the baud rate (and whatever else might be performed by default).
But the "computer's" C program never properly configures the serial port. The serial port will use whatever attributes (baud rate, data length, parity setting, canonical versus raw mode) previously configured, which will cause unpredictable reads and writes. (A loopback test would probably produce a false positive result.)
Use the POSIX Serial Port guide or this answer for sample code.
For canonical mode you probably need to add code like (assuming 8N1):
rc = tcgetattr(fd, &tty);
if (rc < 0) {
/* handle error */
}
savetty = tty; /* preserve original settings for restoration */
spd = B9600;
cfsetospeed(&tty, (speed_t)spd);
cfsetispeed(&tty, (speed_t)spd);
tty.c_cflag &= ~PARENB
tty.c_cflag &= ~CSTOPB
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS; /* no HW flow control? */
tty.c_cflag |= CLOCAL | CREAD;
tty.c_iflag |= IGNPAR | IGNCR;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_lflag |= ICANON;
tty.c_oflag &= ~OPOST;
rc = tcsetattr(fd, TCSANOW, &tty);
if (rc < 0) {
/* handle error */
}
You probably should delete the line
fcntl(fd, F_SETFL, FNDELAY);
as well as the O_NONBLOCK
option in the open()
call.
回答2:
try this
int n=read(fd,&tempbuf,sizeof(tempbuf));
instead of
int n=read(fd,tempbuf,5);
回答3:
Shouldn't you terminate the data sent with '\0'?
Serge
回答4:
Reading the description of read() (shown below) tells us that n = 0 when you reach the end of file. Since the serial is not sending a \0, the read will continue until the end of file is reached. Therefore I think n==0 is the result you want.
So, maybe your
if (n>0)
test should be
if (n==0)
Can you see the characters you expect in your buffer using the debugger?
read()
#include
int read( int handle, void *buffer, int nbyte );
The read() function attempts to read nbytes from the file associated with handle, and places the characters read into buffer. If the file is opened using O_TEXT, it removes carriage returns and detects the end of the file.
The function returns the number of bytes read. On end-of-file, 0 is returned, on error it returns -1, setting errno to indicate the type of error that occurred.
回答5:
Thank you for your answers. This is my final code:
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<fcntl.h>
#include<termios.h>
int main() {
int STATE_OK=0;
int STATE_WARNING=1;
int STATE_CRITICAL=2;
char tempbuf[10];
struct termios tty;
int fd=open("/dev/ttyACM1",O_RDWR | O_NOCTTY);
if(fd == -1){
printf("Unable to open /dev/ttyACM1\n");
return STATE_WARNING;
}else {
if(tcgetattr(fd, &tty)!=0){
perror("tcgetatt() error");
}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);
int w=write(fd, "t", 1);/*printf("%d\n",w);
fprintf(stderr, "fd = %d.\n", fd);*/
usleep(1000);
int n=read(fd,tempbuf,8);/*printf("%d \n",n);*/
tempbuf[9]=0;
float temp=atof(tempbuf);
if (temp>27){
printf("CRITICAL: %f celsius\n",temp);
return STATE_CRITICAL;
}else{
printf("Everything is OK and the temperature is %f Celsius\n",temp);
return STATE_OK;
}
}
}
close(fd);
return 0;
}