C의 시리얼 포트에서 열기, 읽기 및 쓰기는 어떻게 합니까?
시리얼 포트의 판독과 쓰기가 조금 혼란스럽습니다.Linux에서 FTDI USB 시리얼 디바이스 컨버터 드라이버를 사용하는 USB 디바이스가 있습니다.플러그를 꽂으면 /dev/tttyUSB1이 생성됩니다.
C로 열어서 읽고 쓰는 것은 간단하다고 생각했습니다.보레이트 및 패리티 정보는 알고 있습니다만, 기준이 없는 것 같습니다.
제가 뭘 놓치고 있는 건가요? 아니면 누가 저를 올바른 방향으로 인도해 줄 수 있나요?
저는 오래 전에 이 글을 썼고(1985년부터 1992년까지 몇 가지 수정만 거쳤지만) 각 프로젝트에 필요한 부분을 복사하여 붙여넣기만 하면 됩니다.
전화해야 합니다.cfmakeraw
에서tty
에서 얻은tcgetattr
. 를 제로 아웃 할 수 없습니다.struct termios
를 설정하고 나서,tty
와 함께tcsetattr
제로 아웃 방법을 사용하면, 특히 BSD나 OS X에서 원인을 알 수 없는 간헐적인 장해가 발생합니다.「설명할 수 없는 간헐적인 장해」는, 계속 행업 하는 것을 포함합니다.read(3)
.
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int
set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tcgetattr", errno);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
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_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
error_message ("error %d from tcsetattr", 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)
{
error_message ("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
error_message ("error %d setting term attributes", errno);
}
...
char *portname = "/dev/ttyUSB1"
...
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
error_message ("error %d opening %s: %s", errno, portname, strerror (errno));
return;
}
set_interface_attribs (fd, B115200, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (fd, 0); // set no blocking
write (fd, "hello!\n", 7); // send 7 character greeting
usleep ((7 + 25) * 100); // sleep enough to transmit the 7 plus
// receive 25: approx 100 uS per char transmit
char buf [100];
int n = read (fd, buf, sizeof buf); // read up to 100 characters if ready to read
속도 값은 다음과 같습니다.B115200
,B230400
,B9600
,B19200
,B38400
,B57600
,B1200
,B2400
,B4800
, 등. 패리티 값은 다음과 같습니다.0
(즉, 패리티 없음),PARENB|PARODD
(패리티를 유효하게 하고 홀수 사용),PARENB
(패리티를 활성화하고 짝수 사용),PARENB|PARODD|CMSPAR
(마크 패리티), 및PARENB|CMSPAR
(공간 패리티).
'블로킹'은 다음 중 하나가read()
지정된 수의 문자가 도착할 때까지 대기합니다.no blocking은 no blocking이read()
는 버퍼 제한까지 더 이상 기다리지 않고 사용할 수 있는 문자의 수를 반환합니다.
부록:
CMSPAR
마크와 스페이스 패리티를 선택하는 경우에만 필요합니다.이것은 드문 일입니다.대부분의 응용 프로그램에서는 생략할 수 있습니다.내 헤더 파일/usr/include/bits/termios.h
의 정의를 가능하게 하다CMSPAR
프리프로세서 기호가 있는 경우에만__USE_MISC
정의되어 있습니다.이 정의는 (에서) 발생합니다.features.h
)와 함께
#if defined _BSD_SOURCE || defined _SVID_SOURCE
#define __USE_MISC 1
#endif
의 도입 코멘트<features.h>
다음과 같이 말합니다.
/* These are defined by the user (or the compiler)
to specify the desired environment:
...
_BSD_SOURCE ISO C, POSIX, and 4.3BSD things.
_SVID_SOURCE ISO C, POSIX, and SVID things.
...
*/
터미널 모드 올바른 설정 및 POSIX 운영 체제용 시리얼 프로그래밍 가이드에 설명된 대로 POSIX 표준을 준수하는 데모 코드는 다음과 같습니다.
이 코드는 x86 위의 Linux 및 ARM(또는 CRIS) 프로세서를 사용하면 올바르게 실행됩니다.
기본적으로 다른 답변에서 파생된 것이지만 부정확하고 오해의 소지가 있는 코멘트가 수정되었습니다.
이 데모 프로그램은 가능한 한 휴대 가능한 비표준 모드용 115200 보에서 시리얼 단자를 열고 초기화합니다.
프로그램은 하드코드된 텍스트 문자열을 다른 단말기로 전송하고 출력이 실행되는 동안 지연시킵니다.
그 후 프로그램은 무한 루프에 들어가 시리얼 단말기로부터 데이터를 수신하고 표시합니다.
기본적으로는 수신된 데이터는 16진수 바이트 값으로 표시됩니다.
프로그램에서 수신한 데이터를 ASCII 코드로 처리하려면 DISPLAY_STRING 기호로 프로그램을 컴파일합니다.
cc -DDISPLAY_STRING demo.c
수신된 데이터가 (이진수 데이터가 아닌) ASCII 텍스트이고 이를 줄 바꿈 문자로 끝나는 라인으로 읽으려면 샘플 프로그램에 대한 이 답변을 참조하십시오.
#define TERMINAL "/dev/ttyUSB0"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
void set_mincount(int fd, int mcount)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error tcgetattr: %s\n", strerror(errno));
return;
}
tty.c_cc[VMIN] = mcount ? 1 : 0;
tty.c_cc[VTIME] = 5; /* half second timer */
if (tcsetattr(fd, TCSANOW, &tty) < 0)
printf("Error tcsetattr: %s\n", strerror(errno));
}
int main()
{
char *portname = TERMINAL;
int fd;
int wlen;
char *xstr = "Hello!\n";
int xlen = strlen(xstr);
fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
printf("Error opening %s: %s\n", portname, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(fd, B115200);
//set_mincount(fd, 0); /* set to pure timed read */
/* simple output */
wlen = write(fd, xstr, xlen);
if (wlen != xlen) {
printf("Error from write: %d, %d\n", wlen, errno);
}
tcdrain(fd); /* delay for output */
/* simple noncanonical input */
do {
unsigned char buf[80];
int rdlen;
rdlen = read(fd, buf, sizeof(buf) - 1);
if (rdlen > 0) {
#ifdef DISPLAY_STRING
buf[rdlen] = 0;
printf("Read %d: \"%s\"\n", rdlen, buf);
#else /* display hex */
unsigned char *p;
printf("Read %d:", rdlen);
for (p = buf; rdlen-- > 0; p++)
printf(" 0x%x", *p);
printf("\n");
#endif
} else if (rdlen < 0) {
printf("Error from read: %d: %s\n", rdlen, strerror(errno));
} else { /* rdlen == 0 */
printf("Timeout from read\n");
}
/* repeat read to get full message */
} while (1);
}
수신 데이터의 버퍼링을 제공하면서도 바이트 단위로 입력을 처리할 수 있는 효율적인 프로그램의 예를 보려면 다음 답변을 참조하십시오.
언급URL : https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
'programing' 카테고리의 다른 글
구성 vue js의 머리글 설정 (0) | 2022.06.02 |
---|---|
#ifdefinside #dispossible (0) | 2022.06.02 |
동적으로 등록된 모듈에서 vuex 변환에 액세스할 수 없음 (0) | 2022.06.02 |
fs.readdir는 기다릴 수 있지만 이유는 알 수 없습니다. (0) | 2022.06.02 |
vuex 작업에서 bootstrap-vue 모달 및 토스트를 호출하는 방법은 무엇입니까? (0) | 2022.06.02 |