printf()는 표준 출력을 사용하는 출력함수이다.
임베디드 환경에서는 printf()를 UART 등으로 재정의하여 사용할 수 있다.
따라서, UART를 이용해서 출력을 콘솔 창이 아닌 다른 파일에 하는 것을 할 것이다.
UART 통신이란 비동기 모드로서 사용되는 Serial 통신으로,
데이터 송신(TX), 수신(RX) 핀이 하나인 통신이다.
한 번에 1byte씩 보내며 각 bit는 직렬로 전송된다.
클럭신호는 필요 없어서 송신,수신 핀만 필요하고,
데이터 전송 속도는 상대적으로 느리다
USART 통신이란 동기 모드로서 사용되는 Serial 통신이다.
동기모드에서는 클럭신호가 필요하므로 송수신핀 말고도 추가적인 클럭라인이 필요하다.
데이터 전송속도는 동기모드에서 빠른 전송이 가능하다.
디버깅용으로는 115200정도로는 맞춰줘야 함
| Start Bit (1bit) | Data Bits (5~9bits) | Parity Bit (0~1bit) | Stop Bit (1~2bits) |
|---|
오류 검출을 위한 비트 (Odd / Even / None)
송신 측과 수신 측이 데이터를 구분하는 역할 (1비트 또는 2비트 설정 가능)
HAL_UART_Transmit(), HAL_UART_Receive()
CPU가 직접 UART 상태를 확인하며 데이터를 송수신하는 방식
쉬운 구현 가능하지만 CPU 사용률 증가
HAL_UART_Transmit_IT(), HAL_UART_Receive_IT()
특정 이벤트 발생 시 CPU가 데이터를 처리하는 방식
다른 작업을 수행하면서 데이터 수신 가능
HAL_UART_Transmit_DMA(), HAL_UART_Receive_DMA()
CPU 개입 없이 데이터를 메모리로 직접 송수신
가장 효율적이지만 설정이 복잡함
FTDI 모듈은 마이크로컨트롤러(MCU)와 PC 간의 데이터 통신을 가능하게 한다.
보드에서 UART로 전송된 데이터를 USB 형식으로 변환하고, PC는 이를 USB 데이터로 받아서 처리합니다.
📌 기본 동작 흐름
즉, MCU(임베디드 보드)에서는 UART로 데이터를 전송하지만, PC에서는 USB 포트로 받아들인다는 것이 핵심입니다.

GND : 그라운드
CTS
VCC : 전원 - USB로 전원을 받기 때문에 연결 필요 없음
TX : 송신부 - (보드에서는 RX)
RX : 수신부 - (보드에서는 TX)
DTR
5V - 3.3V 스위치가 있으니 맞는 전원으로 스위치 옮겨주기
PC에서는 기본적으로 USB 통신을 처리할 수 있는 기능이 있지만, FTDI 모듈에서 변환된 UART-to-USB 신호를 해석하기 위해서는 전용 드라이버가 필요합니다.
✅ USB 신호를 PC에서 인식할 수 있는 형태로 변환
✅ PC가 FTDI 모듈을 가상의 COM 포트(직렬 포트)로 인식하도록 설정
✅ 사용자가 Xshell, PuTTY 같은 터미널 프로그램에서 COM 포트를 열어 통신할 수 있도록 함
즉, 드라이버가 설치되지 않으면, FTDI 모듈을 연결해도 PC가 이를 USB 장치로만 인식할 뿐, UART 데이터 통신이 불가능합니다.
MCU에서 HAL_UART_Transmit() 같은 함수로 TX(송신) 핀을 통해 데이터를 보냄.
FTDI 모듈의 RX(수신) 핀이 이 데이터를 받아들임.
FTDI 칩셋이 UART 데이터를 USB 데이터 포맷으로 변환하여 PC로 전달.
USB 프로토콜을 사용하여 송수신을 처리.
FTDI 드라이버가 USB 데이터를 가상의 직렬 포트(COM 포트)로 변환
장치 관리자(Device Manager)에서 "USB Serial Port(COMx)"으로 표시됨.
프로그램(Xshell, Tera Term 등)에서 COM 포트를 선택하면 실제 UART 데이터를 확인 가능.
Xshell, Tera Term, PuTTY 같은 터미널 프로그램이 가상 COM 포트를 통해 데이터를 출력.
UART로 전송된 데이터가 화면에 나타남.
장치 관리자 - 포트 - USB Serial Port(COM5)

*COM 포트
: PC에서 FTDI 모듈을 통해 UART 데이터를 송수신하는 가상의 직렬 포트

| 모듈 | 보드 |
|---|---|
| GND | GND |
| CTS | |
| VCC | 전원 - USB로 전원을 받기 때문에 연결 필요 없음 |
| FTDI_TX | PA10 (USART_RX) |
| FTDU_RX | PA9 (USART_TX) |
| DTR |



Baud Rate : 115200Bits/s
Word Length : 한번 데이터를 보낼 때 8bit 씩 보내겠다
Parity : 없음
Stop Bits : 1
Data Direction : 송신, 수신
Over Sampling
: 터미널 프로그램, COM포트를 통해 데이터를 확인하는 프로그램




이 터미널에는 아스키 코드로만 출력된다.
HAL_UART_Transmit(huart, pData, Size, Timeout);
->
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
huart = *handler
pData = 보낼 데이터
Size = 보낼 데이터 사이즈
Timeout =
char senddata[15] = "hello world\r\n";
while (1)
{
HAL_UART_Transmit(&huart1, senddata, strlen(senddata), 1000);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

숙제
PA9, GND를 오실로스코프로 찍어보면 파형이 나올 것이다.
'h' = 아스키 코드 71 = 1101000
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int _write(int file,char *p,int len){
HAL_UART_Transmit(&huart1,(uint8_t *)p,len,10);
return len;
}
/* USER CODE END 0 */
printf() 안에 _write()가 정의되어 있다.
_write()를 재정의 해주면서 printf 가 uart로 출력되도록 바꿔주는 것이다.
/* USER CODE BEGIN WHILE */
while (1)
{
printf("hello ~~~ !!!\r\n")
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}


/* USER CODE BEGIN WHILE */
float ff = 0.7;
while (1)
{
printf("hello ~~~ !!!\r\n");
printf("f = %f\r\n",ff);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
