programing

C의 시리얼 포트에서 열기, 읽기 및 쓰기는 어떻게 합니까?

prostudy 2022. 6. 2. 21:28
반응형

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

반응형