리눅스에서 직렬 포트 읽기 및 쓰기
FTDI를 사용하여 USB 포트를 통해 데이터를 송수신하려고 하므로 C/C++을 사용하여 직렬 통신을 처리해야 합니다.저는 리눅스(우분투)에서 일하고 있습니다.
기본적으로 수신 명령을 수신하는 장치에 연결되어 있습니다.저는 그 명령들을 보내고 장치의 응답을 읽어야 합니다.명령과 응답은 모두 ASCII 문자입니다.
GtkTerm을 사용하면 모든 것이 정상적으로 작동하지만 C 프로그래밍으로 전환하면 문제가 발생합니다.
내 코드는 다음과 같습니다.
#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
/* Open File Descriptor */
int USB = open( "/dev/ttyUSB0", O_RDWR| O_NONBLOCK | O_NDELAY );
/* Error Handling */
if ( USB < 0 )
{
cout << "Error " << errno << " opening " << "/dev/ttyUSB0" << ": " << strerror (errno) << endl;
}
/* *** Configure Port *** */
struct termios tty;
memset (&tty, 0, sizeof tty);
/* Error Handling */
if ( tcgetattr ( USB, &tty ) != 0 )
{
cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << endl;
}
/* Set Baud Rate */
cfsetospeed (&tty, B9600);
cfsetispeed (&tty, 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_lflag = 0; // no signaling chars, no echo, no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // 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
tty.c_iflag &= ~(IXON | IXOFF | IXANY);// turn off s/w flow ctrl
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
tty.c_oflag &= ~OPOST; // make raw
/* Flush Port, then applies attributes */
tcflush( USB, TCIFLUSH );
if ( tcsetattr ( USB, TCSANOW, &tty ) != 0)
{
cout << "Error " << errno << " from tcsetattr" << endl;
}
/* *** WRITE *** */
unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'};
int n_written = write( USB, cmd, sizeof(cmd) -1 );
/* Allocate memory for read buffer */
char buf [256];
memset (&buf, '\0', sizeof buf);
/* *** READ *** */
int n = read( USB, &buf , sizeof buf );
/* Error Handling */
if (n < 0)
{
cout << "Error reading: " << strerror(errno) << endl;
}
/* Print what I read... */
cout << "Read: " << buf << endl;
close(USB);
무슨 일이 일어날까요?read()
0(바이트를 전혀 읽지 않음) 또는 시간 초과될 때까지 블록을 반환합니다(VTIME
) 제 생각에 이런 일이 일어나는 것 같습니다.write()
아무 것도 보내지 않습니다.이 경우 장치가 명령을 수신하지 못하고 응답을 수신할 수 없습니다.실제로 프로그램 읽기가 차단된 상태에서 장치를 끄면 응답이 표시됩니다(장치가 종료되는 동안 무언가를 전송함).
이상한 것은 이것을 추가한다는 것입니다.
cout << "I've written: " << n_written << "bytes" << endl;
바로 뒤에write()
통화, 수신:
I've written 6 bytes
그게 바로 제가 기대하는 바입니다.장치가 포트에서 실제로 쓰고 있는 내용을 수신할 수 없는 것처럼 프로그램만 제대로 작동하지 않습니다.
데이터 유형과 관련하여 다양한 방법과 솔루션을 시도했습니다(std::string을 사용해 보았습니다.cmd = "INIT \r"
또는const char
하지만 아무 것도 효과가 없었습니다.
누가 내가 어디가 틀렸는지 말해줄 수 있나요?
잘 부탁드립니다.
EDIT: 사용된 이 코드의 이전 버전
unsigned char cmd[] = "INIT \n"
그리고 또한cmd[] = "INIT \r\n"
장치에 대한 명령 sintax가 다음과 같이 보고되어 변경했습니다.
<command><SPACE><CR>
.
저는 또한 그것을 피하려고 노력했습니다.O_NONBLOCK
읽다가 플래그를 세우면 영원히 차단할 뿐입니다.사용해 보았습니다.select()
하지만 아무 일도 일어나지 않습니다.데이터를 사용할 수 있을 때까지 대기 루프를 만들었지만 코드는 루프를 벗어나지 않습니다.BTW, 대기 또는usleep()
제가 피해야 할 것입니다.보고된 것은 제 코드의 발췌본일 뿐입니다.완전한 코드는 실시간 환경(특히 OROCOS)에서 작동해야 하므로 저는 수면과 같은 기능을 별로 원하지 않습니다.
저는 제 문제를 해결했기 때문에 누군가 유사한 것이 필요할 경우를 대비하여 여기에 올바른 코드를 게시합니다.
개항장
int USB = open( "/dev/ttyUSB0", O_RDWR| O_NOCTTY );
매개 변수 설정
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);
/* Error Handling */
if ( tcgetattr ( USB, &tty ) != 0 ) {
std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::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) {
std::cout << "Error " << errno << " from tcsetattr" << std::endl;
}
쓰기
unsigned char cmd[] = "INIT \r";
int n_written = 0,
spot = 0;
do {
n_written = write( USB, &cmd[spot], 1 );
spot += n_written;
} while (cmd[spot-1] != '\r' && n_written > 0);
바이트당 바이트를 쓸 필요도 없었습니다.int n_written = write( USB, cmd, sizeof(cmd) -1)
잘 작동했습니다.
마지막으로 다음을 읽습니다.
int n = 0,
spot = 0;
char buf = '\0';
/* Whole response*/
char response[1024];
memset(response, '\0', sizeof response);
do {
n = read( USB, &buf, 1 );
sprintf( &response[spot], "%c", buf );
spot += n;
} while( buf != '\r' && n > 0);
if (n < 0) {
std::cout << "Error reading: " << strerror(errno) << std::endl;
}
else if (n == 0) {
std::cout << "Read nothing!" << std::endl;
}
else {
std::cout << "Response: " << response << std::endl;
}
이건 저한테 효과가 있었어요.여러분 감사합니다.
하며, 으로 두 문자인 EOL 시퀀스를 합니다.\r\n
그러니 코드를 입력해 보세요 라인을 교체하세요.
unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'};
와 함께
unsigned char cmd[] = "INIT\r\n";
그나저나, 위의 방법이 아마도 더 효율적일 것입니다.모든 문자를 인용할 필요는 없습니다.
init 뒤에 /n을 추가합니다. 즉, write(USB, "init\n", 5);
직렬 포트 구성을 다시 확인합니다.아마 뭔가 잘못된 것 같습니다.^Q/^S 또는 하드웨어 흐름 제어를 사용하지 않는다고 해서 상대방이 기대하지 않는 것은 아닙니다.
가능성이 가장 높습니다.write() 뒤에 "ussleep(100000);"을 추가합니다.파일 설명자는 차단하거나 기다리지 않도록 설정되어 있죠?호출 읽기를 호출할 수 있을 때까지 응답을 받는 데 얼마나 걸립니까?(읽기 전에 시스템 하드웨어 인터럽트를 통해 커널에서 수신하고 버퍼링해야 합니다.)select()를 사용하여 읽을 내용을 기다리는 것을 고려해 보셨습니까?아마도 시간이 초과되면요?
추가하도록 편집됨:
DTR/RTS 라인이 필요합니까?다른 쪽에 컴퓨터 데이터를 전송하도록 지시하는 하드웨어 흐름 제어(예:
int tmp, serialLines;
cout << "Dropping Reading DTR and RTS\n";
ioctl ( readFd, TIOCMGET, & serialLines );
serialLines &= ~TIOCM_DTR;
serialLines &= ~TIOCM_RTS;
ioctl ( readFd, TIOCMSET, & serialLines );
usleep(100000);
ioctl ( readFd, TIOCMGET, & tmp );
cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl;
sleep (2);
cout << "Setting Reading DTR and RTS\n";
serialLines |= TIOCM_DTR;
serialLines |= TIOCM_RTS;
ioctl ( readFd, TIOCMSET, & serialLines );
ioctl ( readFd, TIOCMGET, & tmp );
cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl;
언급URL : https://stackoverflow.com/questions/18108932/reading-and-writing-to-serial-port-in-c-on-linux
'programing' 카테고리의 다른 글
WordPress 사이트를 위한 침입 탐지 시스템 (0) | 2023.06.14 |
---|---|
"DNS_BLOCK_ASSERTION"(C 컴파일러 플래그)은 무엇입니까? (0) | 2023.06.14 |
python: excel 워크북을 만들고 csv 파일을 워크시트로 덤프합니다. (0) | 2023.06.14 |
compileSdkVersion과 targetSdkVersion의 차이점은 무엇입니까? (0) | 2023.06.14 |
C: 할당되지 않은 포인터가 NULL이 아닌 예측 불가능한 메모리를 가리키는 이유는 무엇입니까? (0) | 2023.06.14 |