UART 컨트롤러는 자체적으로 흐름 제어(Flow Control) 신호를 처리할 수 있는 기능을 포함하고 있다. 여기서 흐름제어란 데이터가 수신 측의 처리 속도보다 너무 빠르게 들어와서 버퍼 오버플로우가 발생하는 걸 막는 매커니즘을 말한다.
1. 과거의 UART 흐름제어
과거 RS-232 통신 규격이 정립되던 시기에는 DTE 장치(PC)가 DCE 장치(모뎀)에 연결되는 것이 기본이었다. 데이터 송수신 자체는 DTE, DCE 모두 할 수 있지만 데이터 전송을 시작하고 종료하는 쪽은 DTE 였으며, 이러한 역할 구분에 따라 TXD, RXD를 포함한 각 신호 핀의 용도가 정의되었다.
- DTE (Data Terminal Equipment) : 단말기, 컴퓨터
- DCE (Data Circuit-terminating Equipment) : 모뎀 등 통신 장비

1.1. 하드웨어 흐름 제어 (Hardware Flow Control)
전용 물리 회선을 사용하여 송수신 가능 상태를 알리는 방식이다.
1.1.1. RTS / CTS
- RTS (Request To Send) : DTE 입장에서 출력 신호이고, DTE가 DCE에게 데이터를 보내도 될 지 묻는 신호
- CTS (Clear To Send) : DTE 입장에서 입력 신호이고, DCE가 보내도 된다고 응답하는 신호
1.1.2. DTR / DSR
DTR/DSR은 보통 흐름제어는 아니고 통신 세션을 시작하기 전 서로의 존재를 확인하는 연결 상태 표시 용도로 사용했다.
- DTR (Data Terminal Ready) : DTE 입장에서 출력 신호이고, DTE가 전원이 켜져 있고 통신할 준비가 되었음을 나타냄
- DSR (Data Set Ready) : DTE 입장에서 입력 신호이고, DCE가 네트워크에 연결되어 동작할 준비가 되었음을 나타냄
1.2. 소프트웨어 흐름 제어 (Software Flow Control)
별도의 제어선 없이 데이터 스트림 내에 특수 제어 문자를 삽입하여 흐름을 제어하는 방식이다.
1.2.1. XON & XOFF
- XOFF (Transmit Off) : 수신 측의 버퍼가 가득 차서 더 이상 데이터를 받을 수 없을 때, 송신 측에 ASCII 19 (Ctrl+S) 문자를 보낸다. 송신 측은 이 문자를 받으면 전송을 일시 중단한다.
- XON (Transmit On) : 수신 측 버퍼에 여유가 생기면 송신 측에 ASCII 17(Ctrl+Q) 문자를 보낸다. 송신 측은 이 문자를 확인하고 다시 전송을 재개한다.
추가 배선이 필요 없어 경제적이지만, 바이너리 데이터 전송 시 제어 문자와 데이터가 혼동될 위험이 있었고, 제어문자로 인해 처리량(Throughput)이 떨어져서 요새는 거의 쓰지 않는다.
1.3. 과거의 배선 방식
과거 DTE와 DCE를 연결할 때는 DB9 Male to DB9 Female 스트레이트 케이블을 사용해 모든 신호 핀을 1:1로 연결했다.
TX와 RX는 교차해야 한다는 일반적인 생각과 다르게 TXD와 RXD도 다이렉트로 연결하는데, 이는 표준 규격상 TX와 RX의 의미는 DTE 입장에서 정의되어 있기 때문이다.
즉, TXD는 'DTE의 출력/DCE의 입력'이고, RXD는 'DTE의 입력/DCE의 출력'으로 정의된다.
- PC (DTE):
- 2번: RX
- 3번: TX
- 시리얼 장비 (DCE):
- 2번: TX
- 3번: RX

그래서 DTE와 DTE간 혹은 DCE와 DCE간 연결이 필요할 때는 각 신호를 교차해주는 널-모뎀 케이블이나 크로스오버 케이블을 사용해야 했다.


2. 현재의 UART 흐름제어 및 사용 사례
2.1. 배선 방식의 변화
현재는 모뎀을 거치지 않고 PC와 PC, PC와 계측기, PC와 MCU, MCU와 MCU 등 장치 간 직접 통신하는 경우가 대부분이다.
특히 PC에 사용하는 USB to RS232 컨버터 끝단이 DB9 Male 커넥터를 가지므로, PC와 통신해야하는 시리얼 장비를 개발한다면 DB9 Female 커넥터를 채택하고 2번이 TX, 3번이 RX가 되도록 설계하면 별도의 크로스 케이블 없이 컨버터와 직결이 가능하다.
또한 배선을 간소화하기 위해 흐름제어 핀을 사용하지 않고 데이터핀(TX/RX)과 GND만 연결하여 사용하는 방식이 일반적이다.
2.2. 흐름제어의 의미 변화
일단 고전적인 의미의 RTS/CTS, DTR/DSR가 사용되는 경우는 거의 없다.
그리고 하드웨어 흐름제어를 사용하더라도 요즘은 장치간 통신이 대부분이다 보니, RTS/CTS의 의미가 과거와는 완전히 달라졌다.
RTS는 내가 데이터를 받을 준비가 되었음을 알리는 신호로 쓰이며, CTS 핀을 통해 상대방이 데이터를 받을 준비가 되었는지를 확인하는 용도로 쓴다.
- RTS (Ready to Receive) : 내 수신 버퍼에 여유가 있으니, 데이터를 보내도 좋다는 신호
- CTS : 교차 연결에 의해 상대 RTS 신호가 입력되는 핀으로, 상대가 데이터를 받을 준비가 되었는지 확인하는 용도
2.3. 실제 설정 사례
윈도우에서 범용 시리얼 터미널 프로그램을 개발한다면, 일반적으로 다음과 같이 HW Flow Control을 비활성화하고 사용하면 된다.
DTR과 RTS은 흐름제어를 쓰지 않더라도 ENABLE로 켜주는 이유는, 혹시 상대 장치가 해당 신호에 의미를 부여해 사용하는 경우를 고려하여 내가 터미널이 연결되어 준비된 상태이고(DTR active), 데이터를 받을 준비가 됐음(RTS active)을 알려주기 위함이다.
DCB dcb = { 0, };
// ...
GetCommState(m_handle, &dcb);
// ...
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
// ...
SetCommState(m_handle, &dcb);
그리고 리눅스 터미널 에뮬레이터인 minicom에서 배선이 올바른데도 통신이 되지 않는다면, 설정에서 Hardware Flow Control이 켜져 있는지 확인해볼 필요가 있다. 해당 옵션이 켜져 있으면 상대 CTS 신호 상태에 따라 송신이 차단될 수 있으므로, 흐름제어를 사용하지 않는 환경에서는 끄는 게 정상적인 동작을 보장한다.

2.4. 특수 케이스
흐름 제어 핀을 특수 용도로 사용하는 케이스도 몇 가지 있다.
Arduino 계열은 USB to UART bridge IC의 DTR 핀이 MCU(ATmega*)리셋 핀에 연결되어 있고, 아두이노 IDE에서 프로그램 업로드를 하거나 시리얼 터미널 연결하는 순간 DTR을 토글해서 아두이노가 리셋되도록 설계되어 있다.

한편, RS-485 Half Duplex 통신에서 RTS 핀을 송수신 방향 제어에 사용하기도 한다.
485 트랜시버는 일반적으로 데이터 라인 방향제어를 위한 DE(Driver Enable) 핀이랑 /RE(Receiver Enable) 가지고 있는데, 보통 DE랑 /RE는 묶고 UART 컨트롤러의 RTS 핀을 485 트랜시버 DE에 연결해서 송신 직전과 송신 직후에 RTS를 제어함으로써 송수신 방향을 전환하는 용도로 쓰는 케이스가 있다.

'임베디드 개발 > 펌웨어' 카테고리의 다른 글
| 1553B (MIL-STD-1553) (0) | 2026.06.07 |
|---|---|
| TL16C752C, Dual UART (16550 호환 칩) (0) | 2026.05.31 |
| 리셋 신호가 Low Active인 이유 (0) | 2026.05.14 |
| PCA9555, I2C 16-bit I/O Expander (0) | 2026.05.10 |
| VxWorks 셸에서 부트 파라미터 확인 및 설정 방법 (0) | 2026.04.06 |