시리얼제어 Linux Serial Port 2013년도과정 2013.09.11.
차례 통신방식 Linux Serial 통신 Serial Port 설정용구조체 Serial 통신프로그래밍기법 샘플프로그램작성 2
통신방식 Parallel 한번에 8bit 씩데이터를송수신 전송속도가빠르나케이블이굵음 주로프린터와의접속에이용 구현하기힘들고고가 거리에제한적임 Serial 1bit 씩데이터송수신 전송속도가느리지만케이블이단순 구현하기쉽고저가 거리제한을덜받음 3
RS232C 인터페이스 설명 미국 EIA(Electronic Industries Association) 에의해규격화 실명칭 : EIA-RS232C 전기적, 기계적특성, 인터페이스회로의기능등을규정 전송유효거리 일반적으로 15m, 고품질케이블사용시최장 3km 데이터단말장치와모뎀을접속을위한규격 1 대 1 접속 RS232C의규격을간략화하여 PC에적용 비동기 / 동기방식모두사용 통상 PC에서는비동기방식사용 4
Serial Port 거의모든 PC 본체에외부인터페이스를위해내장 초기마우스는모두시리얼포트만사용 RS232C, COM1 Serial communication 을통한응용예 PC-PC, PC-Modem 외부기판의 LED (Light Emitting Diode) 제어 패널의문자점등표시 전등 relay 스위치 on/off 제어 step 모터회전제어 센서신호의 A/D 값을 PC에서읽어들이는프로그램등 5
Linux 의 Serial 접근 /dev 디렉터리 Linux의장치제어용디렉터리 Linux는장치를파일로간주 Serial 포트번호와장치명 COM 1 : /dev/ttys0 COM 2 : /dev/ttys1 6
sturct termios 터미널인터페이스제어용구조체 POSIX가지정한표준인터페이스 System V : struct termio 터미널을제어하기위한모드 입력 출력 제어 로컬 특수제어문자 7
sturct termios field <asm/termbits.h> #define NCCS 19 struct termios { tcflag_t c_iflag; // input mode flags tcflag_t c_oflag; // output mode flags tcflag_t c_cflag; // control mode flags tcflag_t c_lflag; // local mode flags cc_t c_line; // line discipline cc_t c_cc[nccs]; // control characters }; 8
입력 : c_iflag 터미널에입력되는 Data 의전처리방법을명시 정의된매크로의 OR 연산사용 BRKINT: 브레이크조건이발견되면인터럽트발생 IGNBRK: 브레이크조건무시 ICRNL: 수신한캐리지리턴을줄바꿈으로변환 IGNCR: 수신한캐리지리턴을무시 INLCR: 수신한줄바꿈을캐리지리턴으로변환 IGNPAR: 패리티에러를가진문자를무시 INPCK: 수신한문자에대해패리티검사수행 PARMRK: 패리티에러를표기 ISTRIP: 모든들어오는문자를 Strip(7 비트로설정 ) IXOFF: 입력에대한소프트웨어흐름제어설정 IXON: 출력에대한소프트웨어흐름제어설정 9
출력 : c_oflag 터미널에 Data 출력시문자의전처리방법을명시 정의된매크로의 OR 연산사용 OPOST: 출력처리 ON ONLCR: 출력줄바꿈을캐리지리턴 / 라인피드쌍으로변환 ONOCR: 열 0 에어떤캐리지리턴도출력하지않음 ONLRET: 줄바꿈이캐리지리턴도수행 OFILL: 지연시키기위해채움문자전송 (Padding) OFDEL: 널이아니라델 (DEL) 을채움문자로사용 NLDLY: 줄바꿈지연선택 CRDLY: 캐리지리턴지연선택 TABDLY: 탭지연선택 BSDLY: 백스페이스지연선택 VTDLY: 수평탭지연선택 FFDLY5: 폼피드지연선택 OPOST 가설정되지않을경우다른모든플래그무시 10
제어 : c_cflag 하드웨어특성을제어 정의된매크로의 OR 연산사용 CLOCAL: 모뎀접속이아님을명시 CREAD: 문자형 Data 수신상태로설정 CS5: 송 / 수신 Data 의 5Bit 을사용 CS6: 송 / 수신 Data 의 6Bit 을사용 CS7: 송 / 수신 Data 의 7Bit 을사용 CS8: 송 / 수신 Data 의 8Bit 을사용 CSTOPB: 문자당한개가아닌두개의정지비트사용 HUPCL: 닫을때모뎀접속을끊음 PARENB: 패리티발생과감지를가능하게함 PARODD: 홀수패리티사용 11
로컬 : c_lflag 터미널의다양한특성제어 정의된매크로의 OR 연산사용 ECHO: 입력문자의로컬에코를설정 ECHOE: ERASE 를받았을때백스페이스, 스페이스, 백스페이스를수행 ECHOK: KILL 문자에대해줄지우기수행 ECHONL: 줄바꿈문자를에코 ICANON: Canonical 모드사용 IEXTEN: 특정함수의구현가능하게설정 ISIG: 신호사용가능하게설정 NOFLSH: 대기열에대한플러시불가능하게설정 TOSTOP: 쓰기시도시백그라운드프로세스에게신호전송 12
특수제어문자 : c_cc[nccs] 특수한방식으로동작하는제어문자에대한설정 Canonical Mode VEOF: EOF 문자 VEOL: EOL 문자 VERASE: ERASE 문자 VINTR: INTR 문자 VKILL: KILL 문자 VQUIT: QUIT 문자 VSUSP: SUSP 문자 VSTART: START 문자 VSTOP: STOP 문자 Non-Canonical Mode VINTR: INTR 문자 VMIN: MIN 문자 VQUIT: QUIT 문자 VSUSP: SUSP 문자 VTIME: TIME 문자 VSTART: START 문자 VSTOP: STOP 문자 13
특수제어문자 : 제어문자 문자 의미 INTR QUIT ERASE KILL EOF SUSP STOP START SIGINT 신호발생 SIGQUIT 신호발생마지막문자제거 1 라인삭제 1 라인의모든문자를응용프로그램에게전달모두전달하였을경우 read() 는 0을반환 SIGSUSP 신호발생터미널에대한출력정지 XON/XOFF 흐름지원을지원하기위해사용보통 ASCII 의 XOFF 문자 ([Ctrl] + [S]) 로지정터미널에대한출력재개보통 ASCII 의 XON 문자로지정 14
특수제어문자 : TIME 값과 MIN 값 Non-Canonical Mode 의 read() 를지원하기위한설정 설정값 read() 상태 MIN = 0 TIME = 0 즉시반환 MIN = 0 TIME > 0 시간제한에의한반환 MIN > 0 TIME = 0 읽어들인문자가 MIN 개이상일경우에만반환 MIN > 0 TIME > 0 읽어들인문자가 MIN 개이상일경우에만반환 15
Serial Port 설정용구조체 4/4 struct termios { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t c_line; cc_t c_cc[nccs]; }; c_cc : 제어문자배열 EOF(End of File), STOP 등의제어동작들을어떤문자로정의할것인가를설정 제어문자의디폴트문자는 <asm/termios.h> 에정의됨 c_line POSIX 호환시스템에서사용되지않음 16
시리얼통신프로그래밍기법 Canonical Non-Canonical Asynchronous Multi Flexing 17
Canonical 터미널의기본처리방법 한줄단위로통신 한줄 NL(New Line, ASCII는 LF) - 디폴트 EOF(End of File) EOL(End of Line) 에의해종료되는문자열 CR(Carriage Return) 종료문자로인식되지않음 NL 문자로변환처리 18
Non-Canonical 한번에정해진크기의데이터만읽어들임 타이머의사용 대기시간설정가능 응용 항상정해진크기의문자들만을읽을때 대량의문자들을전송하고자할때 19
Asynchronous read 의조건이만족될때까지 block 되는방식 모든 API 에디폴트로설정 호출한프로그램에게 signal 전송 전송된 signal 은 signal handler 이처리 20
Multi Flexing 여러개의장치들을다루고자할때유용 개념이다소복잡 select() 사용 입력을기다리는동안 CPU 에부하를주지않음 polling 방식 입력이들어왔는지루프를돌면서체크 시스템부하에의한수행속도를저하야기 21
Canonical Sample Program 1/4 #include <stdio.h> #include <fcntl.h> #include <termios.h> #include <sys/types.h> #include <sys/stat.h> #define SPEED #define SPORT B19200 "/dev/ttys1" 22
Canonical Sample Program 2/4 main() { char cbuff[255]; int idev = 0; int iret = 0; struct termios stoldstate; struct termios stnewstate; // 수신용버퍼 // 장치데스크립션 // 반환값 // 기존 Serial Port 상태정보 // 새로운 Serial Port 상태정보 idev = open(sport, O_RDWR O_NOCTTY); // Serial Port Open if (0 > idev) { perror(sport); exit(-100); } // 시리얼포트 Open Error 23
Canonical Sample Program 3/4 tcgetattr(idev, &stoldstate); // 현재 Serial Port 상태저장 bzero(&stnewstate, sizeof(stnewstate)); // 구조체초기화 // SPEED : 전송속도, cfsetispeed(), cfsetospeed() 로도설정가능 // CS8 : 8N1 (8bit, no parity, 1 stop bit) // CLOCAL : Local connection. 제어를하지않음 // CREAD : 문자수신가능 stnewstate.c_cflag = SPEED CRTSCTS CS8 CLOCAL CREAD; // IGNPAR : Parity 에러가있는문자바이트무시 // ICRNL : CR 문자를 NL 문자로변환처리 stnewstate.c_iflag = IGNPAR ICRNL; stnewstate.c_oflag = 0; // 수신된데이터를그대로출력 24
Canonical Sample Program 4/4 stnewstate.c_lflag = ICANON; bzero(stnewstate.c_cc, NCCS); stnewstate.c_cc[vmin] = 1; // Canonical 통신기법사용 // 제어문자초기화 // read시리턴되기위한최소문자개수지정 tcflush(idev, TCIFLUSH); tcsetattr(idev, TCSANOW, &stnewstate); // 시리얼포트수신큐초기화 // 시리얼포트에새속성적용 iret = read(idev, cbuff, 255); cbuff[iret]=0; printf("[%s]:[%d]\n", cbuff, iret); // 시리얼포트로부터데이터수신 tcsetattr(idev, TCSANOW, &stoldstate); // 시리얼포트의원래속성복귀 close(idev); // 시리얼포트닫음 } // End main() 25
Non-Canonical Sample Program 1/2 두변수에의한처리방법변화 c_cc[vtime] : 타이머시간설정 c_cc[vmin] : read 시리턴되기위한최소문자개수지정 VMIN > 0, VTIME = 0 TIME = 0 이면문자가들어오기전까지는무한대기 VMIN = 0, VTIME > 0 VTIME 은 time-out 값으로사용 Time-out = VTIME * 0.1Sec Time-out 이일어나기전에한문자라도들어오면 read 는리턴 VMIN > 0, VTIME > 0 VTIME 은 time-out 이아닌 inter-character 타이머로동작 리턴조건 최소 MIN 개의문자수신 두문자사이의시간이 TIME 값을넘으면리턴 문자가수신될때마다재시작 VMIN = 0, VTIME = 0 read 는바로리턴 현재읽을수있는문자의개수나요청한문자개수가반환 26
Non-Canonical Sample Program 2/2 stnewstate.c_lflag = 0; // Non Canonical bzero(stnewstate.c_cc, NCCS); // 밑의값을바꾸어가며테스트 stnewstate.c_cc[vtime] = 0; // 문자입력까지무한대기 stnewstate.c_cc[vmin] = 5; // 최소 5 문자받을때까진 blocking 27
Asynchronous Sample Program 1/6 #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <termios.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/signal.h> #define SPEED #define SPORT B19200 "/dev/ttys1 volatile int ibreak = 0; 28
Asynchronous Sample Program 2/6 main() { char cbuff[255]; int idev = 0; int iret = 0; struct termios stoldstate; struct termios stnewstate; struct sigaction stsigact; // 수신용버퍼 // 장치데스크립션 // 반환값 // 기존 Serial Port 상태정보 // 새로운 Serial Port 상태정보 // 시그널액션설정 idev = open(sport, O_RDWR O_NOCTTY O_NONBLOCK); if (0 > idev) { perror(sport); exit(-100); } // 시리얼포트 Open Error 29
Asynchronous Sample Program 3/6 // 시리얼포트설정전에시그널핸들러등록 bzero(&stsigact, sizeof(stsigact)); stsigact.sa_handler = Handle_Serial_Sig; sigaction(sigio, &stsigact, NULL); // SIGIO signal 을수신하도록설정 fcntl(idev, F_SETOWN, getpid()); // file descriptor 를비동기로설정 fcntl(idev, F_SETFL, FASYNC); 30
Asynchronous Sample Program 4/6 tcgetattr(idev, &stoldstate); // 현재 Serial Port 상태저장 bzero(&stnewstate, sizeof(stnewstate)); // 구조체초기화 stnewstate.c_cflag = SPEED CRTSCTS CS8 CLOCAL CREAD; stnewstate.c_iflag = IGNPAR ICRNL; stnewstate.c_oflag = 0; // 수신된데이터를그대로출력 stnewstate.c_lflag = ICANON; stnewstate.c_cc[vmin] = 1; // read시리턴되기위한최소문자개수지정 stnewstate.c_cc[vtime]=0; tcflush(idev, TCIFLUSH); tcsetattr(idev, TCSANOW, &stnewstate); // 시리얼포트수신큐초기화 // 시리얼포트에새속성적용 31
Asynchronous Sample Program 5/6 while(1) { if (1 == ibreak) { iret = read(idev, cbuff, 255); // 시리얼포트로부터데이터수신 cbuff[iret]=0; printf("[%s]:[%d]\n", cbuff, iret); break; } else { sleep(2); } printf("go Sleep\n"); } 32
Asynchronous Sample Program 6/6 tcsetattr(idev,tcsanow,&stoldstate); // 시리얼포트의원래속성복귀 close(idev); // 시리얼포트닫음 } // End main() void Handle_Serial_Sig(int Arg) { printf("receive SIGIO Signal\n"); ibreak = 1; } 33
Multi Flexing Sample Program 1/6 #include <stdio.h> #include <unistd.h> #include <termios.h> #include <fcntl.h> #include <sys/time.h> #include <sys/types.h> #define SPEED #define COMPORT1 #define COMPORT2 B19200 "/dev/ttys0" "/dev/ttys1" void Input_Incomming(int); char cbuff[255]; 34
Multi Flexing Sample Program 2/6 main() { int imaxfd = 0; //maximum file descriptor used int icom1 = 0; int icom2 = 0; struct termios stoldst1; struct termios stoldst2; struct termios stnewst1; struct termios stnewst2; fd_set strfd; // file descriptor set icom1 = open(comport1, O_RDWR O_NOCTTY); if (0 > icom1) { perror(comport1); exit(-1); } 35
Multi Flexing Sample Program 3/6 icom2 = open(comport2, O_RDWR O_NOCTTY); if (0 > icom2) { perror(comport2); exit(-1); } tcgetattr(icom1, &stoldst1); tcgetattr(icom1, &stoldst2); bzero(&stnewst1, sizeof(stnewst1)); 36
Multi Flexing Sample Program 4/6 stnewst1.c_cflag = SPEED CRTSCTS CS8 CLOCAL CREAD; stnewst1.c_iflag = IGNPAR ICRNL; stnewst1.c_oflag = 0; stnewst1.c_cc[vmin] = 1; // blocking read until 1 character arrives stnewst2 = stnewst1; tcflush(icom1, TCIFLUSH); tcsetattr(icom1, TCSANOW, &stnewst1); tcflush(icom2, TCIFLUSH); tcsetattr(icom1, TCSANOW, &stnewst2); imaxfd = icom2 + 1; 37
Multi Flexing Sample Program 5/6 while (1) { // Set Descriptor FD_ZERO(&stRFd); FD_SET(iCom1, &strfd); FD_SET(iCom2, &strfd); // block until input select(imaxfd, &strfd, NULL, NULL, NULL); } if (FD_ISSET(iCom1, &strfd)) { Input_Incomming(iCom1); } if (FD_ISSET(iCom2, &strfd)) { Input_Incomming(iCom2); } 38
Multi Flexing Sample Program 6/6 } tcsetattr(icom1,tcsanow,&stoldst1); tcsetattr(icom2,tcsanow,&stoldst2); close(icom1); close(icom2); void Input_Incomming(int iport) { int iret = read(iport, cbuff, 255); } cbuff[iret]=0; printf("[%s]:[%d]\n", cbuff, iret); 39
정리 컴퓨터통신 Serial 통신용구조체및플래그 Linux에서의 Serial Port 접근 Serial 통신기법 Canonical Non-Canonical Asynchronous Multi Flexing 샘플프로그램 40