본문 바로가기
코스웨어/15년 스마트컨트롤러

2015-12-07 Linux Serial 통신개인업무일지 - 천정호

by 알 수 없는 사용자 2015. 12. 8.
728x90
반응형

Linux Serial 통신의 모습

가상 Linux의 가상 포트와 Windows의 실제 포트와 매칭을 시킨 후  Hyper Terminal과 연결된 포트와 연결시키면 Linux에서 보내는 데이터를 Hyper Terminal에 나타나게 된다. 


가상의 Linux에 Serial 포트 추가 방법


1. 가상 Linux를 종료한다.


2. 설정에 들어간다.


3. 하드웨어에서 추가를 누른다.

4. Serial Port 선택 후 다음을 누른다.

5. Use physical serial port on the host를 선택 후 다음을 누른다.

6. 물리적 시리얼 포트를 Auto Detect로 선택한 후 종료한다.

위와 같은 방법으로 필요한 만큼의 시리얼 포트를 추가해준다.


Linux Serial 통신에는 여러가지가 있는데 Canonical, Non-Canonical, Asynchronous, Multi Flexing의 방식이 있다.


Canonical

터미널의 기본 처리 방법이며 한 줄 단위로 통신을 한다.

한 줄이란 의미는 New Line, End Of File, End Of Line으로 구분이 된다.


#include <stdio.h>

#include <fcntl.h>

#include <termios.h>

#include <sys/types.h>

#include <sys/stat.h>


// 속도의 설정은 숫자만 적는게 아니고 B를 꼭 입력해야지만 Define값이 적용된다.

#define SPEED   B19200

// 사용할 Port의 위치 지정

#define SPORT   "/dev/ttyS9"


int main() {

int iDev = 0;

int iRet = 0;


// 수신용 버퍼

char cBuff[255];


// 원본값 복사를 위해서 Old, New가 존재

struct termios ST_OldState;

struct termios ST_NewState;


// Serial Port Open

// O_NOCTTY는 제어문자를 현재 프로그램 내에서만 적용하라는 의미

iDev = open(SPORT, O_RDWR | O_NOCTTY);


// Open 오류 검사

if (iDev < 0) {

perror(SPORT);

exit(-100);

}


// 현재 Serial Port 상태 저장

// TC - Terminer Control

// Terminer Control 백업을 위해서 Get 한다.

tcgetattr(iDev, &ST_OldState);

// 구조체 초기화

bzero(&ST_NewState, sizeof(ST_NewState));


// Control Flag

// SPEED    : 전송속도, cfsetispeed(), cfsetospeed()로도 설정가능

// CS8      : 8N1 (8Bit, No Parity, 1 Stop Bit)

// CLOCAL   : Local Connection. 제어를 하지 않음

// CREAD    : 문자 수신 가능

ST_NewState.c_cflag = SPEED | CRTSCTS | CS8 | CLOCAL | CREAD;


// Input Flag

//IGNPAR    : Parity Error가 있는 문자 Byte 무시

// ICRNL    : CR 문자를 NL 문자로 변환 처리

ST_NewState.c_iflag = IGNPAR | ICRNL;


// Output Flag

// 수신된 데이터 그대로 출력

ST_OldState.c_oflag = 0;


// Canonical 통신 기법 사용

ST_NewState.c_lflag = ICANON;

// 제어문자 초기화

bzero(ST_NewState.c_cc, NCCS);

// Read시 Return되기 위한 최소 문자 개수 지정

ST_NewState.c_cc[VMIN] = 1;


// Serial Port 수신 Queue 초기화

tcflush(iDev, TCIFLUSH);

// Serial Port에 새 속성 적용

tcsetattr(iDev, TCSANOW, &ST_NewState);


// Data가 1개 이상이되지 않으면 Blocking

// Serial Port로부터 데이터 수신

iRet = read(iDev, cBuff, 255);

cBuff[iRet] = 0;

printf("[%s] : [%d]\n", cBuff, iRet);


// Serial Port의 원래 속성의 복귀

tcsetattr(iDev, TCSANOW, &ST_OldState);

// Serial Port Close

close(iDev);


return 0;

}


Non-Canonical

한 번에 정해진 크기의 데이터만 읽어 들인다.

타이머의 사용이 가능하다.


Asynchronous

read의 조건이 만족될 때까지 Blocking 되는 방식이다.

호출한 프로그램에게 Signal을 전송한다.

전송된 Signal은 Signal Handler로 처리가 된다.


#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <termios.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <sys/signal.h>


#define SPEED   B19200

#define SPORT   "/dev/ttyS1"


volatile int iBreak = 0;


void Handle_Serial_Sig(int);


int main() {

// 장치 Description

int iDev = 0;

// Return Value

int iRet = 0;


// 수신용 버퍼

char cBuff[255];


// 기존 Serial Port 상태 정보

struct termios ST_OldState;

// 새로운 Serial Port 상태 정보

struct termios ST_NewState;

// Signal Action 설정 (Software Interrupt 방식)

struct sigaction ST_SigAct;


// Serial Port Open

iDev = open(SPORT, O_RDWR | O_NOCTTY | O_NONBLOCK);


if (iDev < 0) {

perror(SPORT);

exit(-100);

}


// Serial Port 설정 전 Signal Handler 등록

// Interrupt가 발생 할때마다 Handle_Serial_Sig 함수 호출

bzero(&ST_SigAct, sizeof(ST_SigAct));

ST_SigAct.sa_handler = Handle_Serial_Sig;

sigaction(SIGIO, &ST_SigAct, NULL);


// SIGIO Signal 수신 설정

// GETID() : 현재 실행중인 프로그램의 번호

fcntl(iDev, F_SETOWN, getpid());


// File Description 비동기 설정

fcntl(iDev, F_SETFL, FASYNC);


// 현재 Serial Port 상태 저장

tcgetattr(iDev, &ST_OldState);

// 구조체 초기화

bzero(&ST_NewState, sizeof(ST_NewState));


// SPEED    : 전송속도, cfsetispeed(), cfsetospeed()로도 설정가능

// CS8      : 8N1 (8Bit, No Parity, 1 Stop Bit)

// CLOCAL   : Local Connection. 제어를 하지 않음

// CREAD    : 문자 수신 가능

ST_NewState.c_cflag = SPEED | CRTSCTS | CS8 | CLOCAL | CREAD;


//IGNPAR    : Parity Error가 있는 문자 Byte 무시

// ICRNL    : CR 문자를 NL 문자로 변환 처리

ST_NewState.c_iflag = IGNPAR | ICRNL;

// 수신된 데이터 그대로 출력

ST_OldState.c_oflag = 0;


// Canonical 통신 기법 사용

ST_NewState.c_lflag = ICANON;


// Read시 Return되기 위한 최소 문자 개수 지정

ST_NewState.c_cc[VMIN] = 1;

ST_NewState.c_cc[VTIME] = 0;


// Serial Port 수신 Queue 초기화

tcflush(iDev, TCIFLUSH);

// Serial Port에 새 속성 적용

tcsetattr(iDev, TCSANOW, &ST_NewState);


while (1) {

if (iBreak == 1) {

// Serial Port로 데이터 수신

iRet = read(iDev, cBuff, 255);

cBuff[iRet] = 0;

printf("[%s] : [%d]\n", cBuff, iRet);

break;

}

else {

sleep(2);

}

printf("Go Sleep\n");

}

tcsetattr(iDev, TCSANOW, &ST_OldState);

close(iDev);


return 0;

}


void Handle_Serial_Sig(int Arg) {

printf("Receive SIGIO Signal\n");

iBreak = 1;

}

Multi Flexing

여러 개의 장치들을 다루고자 할 때 유용하다.

Select() 사용방식과 같다.


#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <termios.h>

#include <sys/time.h>

#include <sys/types.h>


#define SPEED       B19200

#define COMPORT1    "/dev/ttyS0"

#define COMPORT2    "/dev/ttyS1"


char cBuff[255];


void Input_Incomming(int);


int main() {

int iMaxFD = 0;

int iCom1 = 0;

int iCom2 = 0;


struct termios ST_OldST1;

struct termios ST_OldST2;

struct termios ST_NewST1;

struct termios ST_NewST2;


// File Descriptor Set

fd_set ST_RFD;


iCom1 = open(COMPORT1, O_RDWR | O_NOCTTY);


if (iCom1 < 0) {

perror(COMPORT1);

exit(-1);

}


iCom2 = open(COMPORT2, O_RDWR | O_NOCTTY);


if (iCom2 < 0) {

perror(COMPORT2);

exit(-1);

}


tcgetattr(iCom1, &ST_OldST1);

tcgetattr(iCom2, &ST_OldST2);


bzero(&ST_NewST1, sizeof(ST_NewST1));


ST_NewST1.c_cflag = SPEED | CRTSCTS | CS8 | CLOCAL | CREAD;

ST_NewST1.c_iflag = IGNPAR | ICRNL;

ST_NewST1.c_oflag = 0;

// Blocking Read Until 1 Charactor Arrives;

ST_NewST1.c_cc[VMIN] = 1;


ST_NewST2 = ST_NewST1;


tcflush(iCom1, TCIFLUSH);

tcsetattr(iCom1, TCSANOW, &ST_NewST1);

tcflush(iCom2, TCIFLUSH);

tcsetattr(iCom1, TCSANOW, &ST_NewST2);


iMaxFD = iCom2 + 1;


tcsetattr(iCom1, TCSANOW, &ST_OldST1);

tcsetattr(iCom2, TCSANOW, &ST_OldST2);

close(iCom1);

close(iCom2);


return 0;

}


void Input_Incomming(int iPort) {

int iRet = read(iPort, cBuff, 255);


cBuff[iRet] = 0;

printf("[%s] : [%d]\n", cBuff, iRet);

}


728x90