본문 바로가기

Software/Network

[serial] 16C550 UART

(Universal Asynchronous Receiver/Transmitter)
병렬 제어기 또는 데이타 단말기의 단어를 순서적인 비트 통신망에 접속시키는 장치. 수신기는 송신된 단어의 시작에 원하는 수의 개시 비트를 넣고 끝에 종료 비트를 넣어 입력된 직렬 데이타를 병렬 데이터로 출력시킨다. 패리티 비트도 삽입될 수 있다. 데이타는 전송 데이타 클록에 의하여 정해진 보율 (baud rate) 로 전송된다. 수신기 부분은 순서적인 데이타의 개시 비트의 정당성을 체크하고 입력 데이타를 병렬 단어로 출력시킨다. 수신기는 패리티와 오버런 오류를 체크한다.
 

7

6

5

4

3

2

1

0

x

x

x

x

x

x

x

x

 
Register
레지스터 0 - 수신 버퍼 레지스터(RHR:Receiver Holding Register)
한 문자의 데이터가 16550 UART의 수신 버퍼 레지스터(RBR)에서 조합이 된다. 수신 버퍼 레지스터는 이 UART의 첫 번째 레지스터로서, 직렬 포트의 기본 레지스터 포트를 읽어서 주소가 지정된다. 수신 버퍼 레지스터는 항상 8비트 값이 들어 있지만 한 문자당 8비트 미만을 사용하는 데이터 링크에서는 사용되지 않는 비트가 나타나지 않도록 주의해야 한다.

0

들어오는 문자의 비트 0

1

들어오는 문자의 비트 1

2

들어오는 문자의 비트 2

3

들어오는 문자의 비트 3

4

들어오는 문자의 비트 4

5

들어오는 문자의 비트 5. 5개의 데이터 비트를 사용하는 경우에는 정의 되지 않을 수 있다.

6

들어오는 문자의 비트 6. 5 또는 6개의 데이터 비트를 사용하는 경우에는 정의 되지 않을 수 있다.

7

들어오는 문자의 비트 7. 5나 6또는 7개의 데이터 비트를 사용하는 경우에는 정의 되지 않을 수 있다.

 
레지스터 0 - 전송 대기 레지스터(THR:Transmitter Holding Register)
이 UART의 전송 대기 레지스터(THR)는 직렬 인터페이스를 통해 한 문자의 데이터를 전송하는 데 사용된다. 이것은 이 UART의 첫 번째 레지스터를 수신 버퍼 레지스터(RBR)와 함께 사용하며, 해당 직렬 포트의 기본 레지스터 포트에 기록함으로써 주소가 지정된다.

0

나가는 문자의 비트 0

1

나가는 문자의 비트 1

2

나가는 문자의 비트 2

3

나가는 문자의 비트 3

4

나가는 문자의 비트 4

5

나가는 문자의 비트 5

6

나가는 문자의 비트 6

7

나가는 문자의 비트 7

 
레지스터 1 - 인터럽트 가능 레지스터(IER:Interrupt Enable Register)
이 UART의 인터럽트 가능 레지스터(IER)는 인터럽트를 가능하게 하는 데 사용된다. 이 것은 직렬 포트의 기본 레지스터 포트 + 1번지에서 읽거나 씀으로써 주소가 지정된다.

0

RxRDY : 이 비트가 1이면 16550 UART는 수신 버퍼 레지스터에 문자 데이터가 준비될 때마다 인터럽트를 생성한다.

1

TBE : 이 비트가 1이면 16550 UART는 문자 데이터가 전송 대기 레지스터에서 이 UART의 내부 전송 시프트 레지스터로 이동될 때마다 인터럽트를 생성한다.

2

이 비트가 1이면 16550 UART는 한 문자의 데이터를 수신하는 동안에 패리티 에러, 오버런 에러, 프레임 에러, 또는 BREAK 조건이 인식 될 때마다 인터럽트를 생성한다.

3

이 비트가 1이면 16550 UART는 RS-232 입력 라인중 상태를 변경하는 것이 있을 때마다 인터럽트를 생성한다.

4

항상 0 이다.

5

항상 0 이다.

6

항상 0 이다.

7

항상 0 이다.

 
레지스터 2 - 인터럽트 인식 레지스터(IIR:Interrupt Identification Register)
이 UART의 인터럽트 인식 레지스터(IIR)는 인터럽트가 발생했는지의 여부와 FIFO 버퍼가 사용 가능한지의 여부를 판단하는 데 사용된다. 이것은 직렬 포트의 기본 레지스터 포트 + 2번지부터 읽어서 주소가 지정된다.

0

이 비트가 1이면 어떤 인터럽트도 인식되지 않은 상태이다. 이 비트가 0이면 인터럽트가 발생했음을 나타낸다.

1

비트 0이 0이면 비트 3, 비트 2, 비트 1은 다음과 같은 인터럽트의 종류를 나타낸다.

2

3

비트 3 비트 2 비트 1

0 0 0

0 0 1

0 1 0

0 1 1

1 1 0

인터럽트의 종류

모뎀 상태 변화.

전송 대기 레지스터(THR)가 비어 있음.

수신 버퍼 레지스터(RBR)가 가득 찾음.

직렬화 에러 또는 BREAK.

수신 버퍼 레지스터(RBR)가 하나이상 찾고 최소한 4문자 시간 동안 문자가 읽히지 않고 지나갔음.

4

항상 0 이다.

5

항상 0 이다.

6

이 비트가 1이면 FIFO가 사용 가능한 상태이다.
이 비트가 0이면 FIFO가 사용 불가능한 상태임을 나타낸다.

7

이 비트가 1이면 FIFO가 사용 가능한 상태이다.
이 비트가 0이면 FIFO가 사용 불가능한 상태임을 나타낸다.

 
레지스터 2 - FIFO 제어 레지스터(FCR:FIFO Control Register)
이 UART의 FIFO 제어 레지스터(FCR)는 FIFO 버퍼를 제어하는 데 사용된다. 이것은 직렬 포트의 기본 레지스터 포트 + 2번지에 기록함으로써 주소가 지정된다.

0

FIFO 가능 : 이 비트가 1이면 16550 UART의 FIFO 버퍼가 사용 가능한 상태이다. 그러나 이 비트가 0이면 16550 UART의 FIFO 버퍼가 사용 불가능한 상태이며 이 칩은 16450 UART 처럼 동작한다.

1

수신기 FIFO 리셋 : 이 비트가 1이면 수신기 FIFO 버퍼를 클리어 한다.

2

전송기 FIFO 리셋 : 이 비트가 1이면 전송기 FIFO 버퍼를 클리어 한다.

3

DMA 모드 선택 : IBM PC와 그 호환 기종에서는 이 비트는 항상 0으로 세트되어야 한다.

4

예약

5

예약

6

FIFO가 사용 가능한 상태이면 비트 7과 비트 6은 수신기 FIFO 버퍼에 대한 수신기의 경계를 지정한다. 간단히 말해서, 수신기 경계는 UART가 수신 버퍼 레지스터(RBR)가 가득찾다는 인터럽트를 생성하기 전에 FIFO 버퍼에 넣을 바이트의 수를 말한다. 수신기 경계는 다음 값 중 하나로 지정 할수 있다.

7

비트 7 비트 6

0 0

0 1

1 0

1 1

수신기 경계

1 바이트

4바이트

8 바이트

14 바이트

 
레지스터 3 - 라인 제어 레지스터(LCR:Line Status Register)
이 UART의 라인 제어 레지스터(LCR)는 데이터 비트의 수, 정지 비트의 수, 패리티 세팅 등을 지정하는 데 사용된다. 이것은 직렬 포트의 기본 레지스터 + 3번지부터 읽거나 씀으로써 주소가 지정된다.

0

비트 1과 비트 0은 다음과 같이 사용되는 데이터 비트의 수를 지정한다.

1

비트 1 비트 0

0 0

0 1

1 0

1 1

데이터 비트의 수

5

6

7

8

2

이 비트가 0이면 1개의 정지 비트가 사용된다.

이 비트가 1이면 2개의 정지 비트가 생성된다.

주의 : 5개의 데이터 비트가 사용될 때 이 비트가 1이면 이 UART는 1개 반의 정지 비트를 사용한다.

3

비트 5, 비트 4, 비트 3은 다음과 같이 사용되는 패리티 비트를 지정한다.

4

비트 5 비트 4 비트 3

0 0 0

0 0 1

0 1 1

1 0 1

1 1 1

패리티

없음(NONE)

홀수(ODD)

짝수(EVEN)

표시(MARK)

공백(SPACE)

5

P align=center>6

BREAK : 이 비트가 1이면 이 UART는 TD 라인을 논리적 0의 상태로 만든다. 완전한 한 문자를 전송하게 되며, 데이터 라인 반대쪽 끝의 직렬 장치는 그것을 BREAK 조건이 필요한 경우 외에는 언제나 0 이어야 한다.

7

DLAB(Divisor Latch Access Bit) : 이 비트가 1이면 이 UART의 수신 버퍼 레지스터(RBR)/전송 대기 레지스터(THR)는 보드율 제수 래치(Baud Rate Divisor Latch)의 하위 바이트 레지스터(DLL)로서 작동하며, 이 UART의 인터럽트 가능 레지스터(IER)는 보드율 제수 래치의 상위 바이트 레지스터(DLM)로서 작동한다. 보드율이 지정되어 있지 않은 경우에는 이 비트는 언제나 0이어야 한다. 그렇지 않으면, 수신 버퍼 레지스터(RBR)/전송 대기 레지스터(THR)와 인터럽트 가능 레지스터(IER)를 엑세스 할 수가 없다.

 
레지스터 4 - 모뎀 제어 레지스터(MCR:Modem Control Register)
이 UART의 모뎀 제어 레지스터(MCR)는 RTS(Request To Send) 라인이나 DTR(Data Terminal Ready) 라인을 세트하거나 이 UART를 인터럽트 가능으로 세트하는 등에 사용된다. 이것은 직렬 포트의 기본 레지스터 + 4번지부터 읽거나 씀으로써 주소가 지정된다.

0

P>DTR(Data Terminal Ready) : 이 비트가 1이면 RS-232 직렬 인터페이스의 DTR 라인은 논리적 1로 세트된다. 이 비트가 0이면 RS-232 직렬 인터페이스의 DTR 라인은 논리적 0으로 세트된다.

1

RTS(Request To Send) : 이 비트가 1이면 RS-232 직렬 인터페이스의 RTS 라인은 논리적 1로 세트 된다. 이 비트가 0이면 RS-232 직렬 인터페이스의 RTS 라인은 논리적 0으로 세트된다.

2

GP01(General Purpose Output #1) : 이것은 사용자 정의 출력이다. IBM PC에서 이 비트를 1로 세트하면 몇몇 내부 모뎀이 리셋된다.

3

GP02(General Purpose Output #2) : 이것은 사용자 정의 출력이다. IBM PC에서는 인터럽트 가능 레지스터(IER)에 의해 가능하게 된 이 UART의 인터럽트가 유효하게 되기 전에 반드시 이 비트를 1로 세트해 두어야 한다. 실제로, PC에서 이 UART의 인터럽트 작업둁는 이외에도 몇몇 단계가 필요하다.

4

로컬 룩백 테스트(Local Loopback Test) : 이 비트를 1로 세트하면 8250 UART는 로컬 룩백 상태(local lookback state)가 된다. UART에 의해 이 전송기를 통해 전송되는 데이터는 수신되는 문자처럼 반환된다. 일반적인 조작에서는 이 비트는 항상 0으로 세트되어야 한다.

5

항상 0 이다.

6

항상 0 이다.

7

항상 0 이다.

 

라인 상태 레지스터(LSR:Line Status Register)

이 UART의 라인 상태 레지스터(LSR)는 수신된 데이터의 유효성, 에러, 그리고 데이터 전송 완료 등을 보고하는 데 사용된다. 이것은 직렬 포트의 기본 레지스터 + 5번지부터 읽음으로써 주소가 지정된다.

0

RxRDY : 이 비트가 1이면 이 UART의 수신 버퍼 레지스터(RBR)에 들어 있는 한 문자 데이터를 사용할 수 있다. 수신 버퍼 레지스터와 FIFO가 둘 다 비면 이 비트는 리셋된다.

1

이 비트가 1로 세트되면 수신기 오버런 에러가 발생한 것이다. 수신기 오버런 에러는 FIFO 버퍼가 가득 찬 상태에서 새 문자 데이터가 수신 버퍼 레지스터에 들어올 때 발생한다. 이 비트는 라인 상태 레지스터(LSR)가 읽혀질 때 리셋된다.

2

이 비트가 1이면 패리티 에러가 발생한 것이다. 패리티 에러는 들어오는 문자의 패리티 비트가 예상과 다를 때 발생한다. 이 비트는 라인 상태 레지스터(LSR)가 읽혀 질 때 리셋된다.

3

이 비트가 1이면 프레이밍 에러(framing error)가 발생한 것이다. 프로에밍 에러는 문자의 정지 비트가 논리적 0으로 들어올 때 발생한다. 이 비트는 라인 상태 레지스터(LSR)가 읽혀질 때 리셋된다.

4

이 비트가 1이면 BREAK가 인식된 것이다. BREAK는 RD(수신된 데이터) 라인에 최소한 한 문자 길이의 시간 동안 논리적 0 가 들어 있을 때 발생한다.

5

TBE(Transmitter Buffer Empty) : 이 비트가 1이면 이 UART는 전송 대기 레지스터(THR)의 이전 내용을 그 송신기의 시프트 레지스터로 옮긴 것이다. 그러므로, 전송 대기 레지스터는 다른 문자 데이터를 수신할 준비가 된 것이다. 이 비트가 0인 상태. 즉 전송 대기 레지스터의 이전 내용이 알맞게 전송되지 않은 상태에서 전송 대기 레지스터에 데이터를 넣어서는 안 된다.

6

TXE(Transmitter Empty) : 이 비트가 1이면 이 UART의 전송 FIFO 버퍼와 전송 시프트 레지스터가 둘 다 비어 있는 것이다. 그러므로, 이 비트가 세트되어 있다면 이 UART는 문자 데이터를 모두 전송한 것이다.

7

수신기 FIFO 에러 : 이 비트가 1이면 수신기 FIFO 버퍼에 최소한 하나의 패리티 에러, 프레임 에러, 또는 BREAK가 있는 것이다. 이 비트는 라인 상태 레지스터(LSR)가 읽혀질 때 리셋된다.

 
모뎀 상태 레지스터(MSR:Modem Status Register)
이 UART의 모뎀 상태 레지스터(MSR)는 전화 신호가 들어오거나 캐리어가 있을 때 CTS(전송 해제)와 DSR(데이터 세트 준비 완료) 라인의 현재 상태 등을 보고하는 데 사용된다. 이것은 직렬 포트의 기본 레지스터 + 6번지부터 읽음으로써 주소가 지정된다.

0

델타 CTS : 이 비트가 1로 세트되면 모뎀 상태 레지스터(MSR)가 마지막으로 읽힌 이후로 RS-232 직렬 인터페이스의 CTS(전송 해제) 라인의 상태가 변경된 것이다. 이 비트는 모뎀 상태 레지스터가 읽힐 때 리셋된다.

1

델타 DSR : 이 비트가 1로 세트되면 모뎀 상태 레지스터(MSR)가 마지막으로 읽힌 이후로 RS-232 직렬 인터페이스의 DSR(데이터 세트 준비 완료) 라인의 상태가 변경된 것이다. 이 비트는 모뎀 상태 레지스터가 읽힐 때 리셋된다.

2

델타 Ring Indicator : 이 비트가 1로 세트되면 모뎀 상태 레지스터(MSR)가 마지막으로 읽힌 이후로 RS-232 직렬 인터페이스의 RI(전화 신호 인식) 라인의 상태가 변경된 것이다. 이 비트는 모뎀 상태 레지스터가 읽힐 때 리셋된다.

3

델타 DCD : 이 비트가 1로 세트되면 모뎀 상태 레지스터(MSR)가 마지막으로 읽힌 이후로 RS-232 직렬 인터페이스의 DCD(데이터 캐리어 인식) 라인의 상태가 변경된 것이다. 이 비트는 모뎀 상태 레지스터가 읽힐 때 리셋된다.

4

CTS(전송 해제) : 이 비트는 이 UART가 CTS 라인의 현재 상태를 인식하는 데 따라 세트되거나 리셋된다.

5

DSR(데이터 세트 준비 완료) : 이 비트는 이 UART가 DSR 라인의 현재 상태를 인식하는 데 따라 세트되거나 리셋된다.

6

RI(전화 신호 인식) : 이 비트는 이 UART가 RI 라인의 현재 상태를 인식하는 데 따라 세트되거나 인식된다.

7

DCD(데이터 캐리어 인식) : 이 비트는 이 UART가 DCD 라인의 현재 상태를 인식하는 데 따라 세트되거나 리셋된다.

 
레지스터 7 - 스크래치 패드(Scratch Register)
이 레지스터는 16550 UART에서는 사용되지 않으며 8250 UART의 전체 버전에 존재하지도 않는다. 따라서 무시하는 것이 좋다.
 
레지스터 8 - DLL:Divisor Latch(보드율 제수 하위 래치 레지스터)

이 UART의 DLL(보드율 제수 하위 래치 레지스터)은 이 UART 보드율 제수의 하위 바이트를 세트하는 데 사용된다. 이 레지스터에서 읽고 쓰려면 우선 라인 제어 레지스터(LCR)의 DLAB(Divisor Latch Access Bit) 비트를 1로 세트해 두어야 한다. 즉, DLAB 비트를 1로 세트하면 DLL은 그 직렬 포트의 기본 레지스터에서 읽고 씀으로써 주소가 지정된다.

이 UART의 보드율 제수는 단순히 115,200을 원하는 보드율을 나눔으로써 계산된다. 그리고 그 결과의 하위 8비트가 DLL에 놓이게 된다.

0

보드율 제수(divisor)의 비트 0

1

보드율 제수(divisor)의 비트 1

2

보드율 제수(divisor)의 비트 2

3

보드율 제수(divisor)의 비트 3

4

보드율 제수(divisor)의 비트 4

5

보드율 제수(divisor)의 비트 5

6

보드율 제수(divisor)의 비트 6

7

보드율 제수(divisor)의 비트 7

 
레지스터 9 - 보드율 제수 상위 래치 레지스터(DLM)

이 UART의 DLM(보드율 제수 상위 래치 레지스터)은 이 UART 보드율 제수의 상위 바이트를 세트하는 데 사용된다. 이 레지스터에서 읽고 쓰려면 우선 라인 제어 레지스터(LCR)의 DLAB(Divisor Latch Access Bit) 비트를 1로 세트해 두어야 한다. 즉 DLAB 비트를 1로 세트하면 DLM은 그 직렬 포트의 기본 레지스터 + 1번지에서 읽고 씀으로써 주소가 지정된다.

이 UART의 보드율 제수는 단순히 115,200을 원하는 보드율로 나눔으로써 계산된다. 그리고 그 결과의 상위 8비트가 DLM에 놓이게 된다.

0

보드율 제수(divisor)의 비트 8

1

보드율 제수(divisor)의 비트 9

2

보드율 제수(divisor)의 비트 10

3

보드율 제수(divisor)의 비트 11

4

보드율 제수(divisor)의 비트 12

5

보드율 제수(divisor)의 비트 13

6

보드율 제수(divisor)의 비트 14

7

보드율 제수(divisor)의 비트 15


(Universal Asynchronous Receiver/Transmitter)
FIFO(First In First Out)
UART의 속도와 CPU 속도는 큰 차이를 내기 때문에 UART쪽에 FIFO라는 buffer을 내장해서 CPU의 부담을 덜도록 설계했다. 16450은 FIFO가 없고, 16550은 FIFO가 있다. 총 16 바이트의 버퍼가 있으나, 2개는 예비 버퍼로 활용하고 있고, FIFO의 총 가능 버퍼는 14byte 이다. FIFO Control Register 에서 제어한다.
 
16550 초기화(Initialization)

1. Line Control Register(LCR)의 7비트(DLAB)를 1로 세트
2. baud 세팅(DLL, DML 세팅)
3. 다시 LCR 7비트 0으로 프로그램 리셋
4. FIFO Contorl Register(FCR) 데이터 xx00 0001 로 설정.(RX, TX FIFO clear)
5. Line Status Register과 Modem Status Register를 읽는다. (LSR 인터럽트, MSR 인터럽트 clear)
6. 인터럽트 시그널을 UART에서 시스템 하드웨어(COM1 ~ COM4)로 enable 시킨다.
7. 0F를 보내서 Interrupt Enable Register가 모든 UART 인터럽트 가능하게 한다.

 
16C550 UART Register 요약본
1. Line Status Register
(0. 수신 1. over run 2. parity error 3. framing error. 4. break 5. THR->shifr 6. THR, FIFO empty 7. FIFO error )
2. Line Control Register
(0-1. 비트 데이터 1. 정비 비트 3-5. parity 비트 지정 6. break 7. DLAB = 1(분주율))
3. Modem Status Register
(델타 0. CTS 1. DSR 2. RI 3. DCD 보통 4. CTS 5. DSR 6. RI 7. DCD )
4. Modem Control Register
(0. DTR 1. RTS 2. GP01(모뎀 리셋) 3. GP02(인터럽트) 4. loopback 5-7. 0 )
5. Interrupt Identification Register
(0. 인터럽트0 1-3. MSR, THR empty, Trigger lovel 도달, over run외3 4-5. 0 6-7. 1 1 FIFO )
6. Interrupt Enable Register
(0. Trigger level 1. THE->shift 2. over run외3 3. MSR 4-7. 0)
7. FIFO Control Register
(0. FIFO 1 1. 수신 FIFO 0 2. 송신 FIFO 0 3. DMA 0 4-5. 예약 6-7. FIFO 수신 경계)
 
프로그램 소스

UART와 RS232C 통신하는 프로그램 소스를 여기에 싫도록 하겠다.
COM1, 9600, NONE, 8, 1 로 설정했다. 컴퓨터가 2대가 없다면, Serial Port의 2, 3번을 전기가 잘 통하는 구리선등으로 바로 연결하면 된다.
다른 것은 건드릴 필요도 없다. 2번 TXD -> 3번 RXD 로 연결하는 것이다.
참고로, RS232C의 최고 전력 +-12V. COM1-3F8, COM2-2F8, COM3-3E8, COM4-2E8.

Interrupt 방식이 아닌, polling 방식이다.

컴파일러는 볼랜드 C++ 3.1 이다. 도스용이다.

// programming by Oh, Seong-Min.

#include "stdio.h"

#include "conio.h"

#define COM1_BASE 0x03F8

#define DLAB 0x00

#define LCR 0x03

#defineLCR_8_DB 0x03

#define LCR_NO_PARITY 0x00

#define LCR_1_STOP 0x00

#define LSR 0x05

#define LSR_0_MASK 0x01 //LSR 0's bit Masking

int rl, tl, rt, tt; // rt=receive top, tt=transmitte top

char port_read, port_write;

void receive_port();

void transmitte_port();

void clear_screen();

void main()

{

outportb( (COM1_BASE + LCR), 0x80); //set DLAB=1

outport( (COM1_BASE + DLAB), 12); //set 9600 baud

// set none, 8, 1

outportb((COM1_BASE + LCR),(LCR_8_DB|LCR_NO_PARITY|LCR_1_STOP));

inport(COM1_BASE + LSR);

clrscr();

printf("\n\t========================================================");

printf("\n\t This is a receiver & transmitter Test program for UART.");

printf("\n\t=========================================================\n");

gotoxy(1,7);

printf("\n<- Transmitte start!!\n");

gotoxy(1,16);

printf("\n<- Receive start!!\n");

rl = tl = 1;

rt = 18;

tt = 9;

while(1) {

receive_port();

transmitte_port();

// ESC - halt program

if (port_write == 27) {

printf("\n\n=== Thank you for test. Good bye!! ===");

break;

}

}

}

void receive_port() {

while((inport(COM1_BASE + LSR) & LSR_0_MASK) == 1) {

port_read=inport(COM1_BASE);

gotoxy(rl,rt);

if (port_read == 13) {

clear_screen();

rl=0; rt=18;

}

putch(port_read);

rl++;

if (rl > 80) { rl=1; rt++; }

if (rt > 21) { rl=1; rt=18; }

}

}

void transmitte_port() {

if (kbhit()) {

port_write = getche();

if (port_write == 13) {

clear_screen();

tl=0; tt=9;

}

outportb( (COM1_BASE), port_write );

tl++;

if (tl>80) { tl=1; tt++; }

if (tt>12) { tl=1; tt=9; }

}

}

void clear_screen() {

clrscr();

gotoxy(1,1);

printf("\n\t\t------------------------------------------");

printf("\n\t\t\tPress ""ESC"" for halt program.");

printf("\n\t\t------------------------------------------");

gotoxy(1,7);

printf("\n<- Transmitte start!!\n");

gotoxy(1,16);

printf("\n<- Receive start!!\n");

}

// End the source program.



[출처:http://blog.naver.com/woosung807/10133730]