본문 바로가기
Embedded/STM32

[STM32] UART통신에서 printf() 함수 사용

by Gordon_ 2024. 9. 11.

1. printf()를 사용하고자 하는 이유

1.1. 코드 길이 축소

  UART 통신은 데이터를 송수신 할때 자주 사용하는 통신으로 디버깅이나 현재 로그를 출력하기 위해 자주 사용된다.

기본적으로 STM32에서 UART를 이용하여 데이터를 PC에 전송할 때 HAL_UART_Transmit() 함수를 사용하지만, 필요한 인수가 4개(통신할 UART, 전송할 메세지, 메세지 길이, 타임아웃 시간) 이므로 자주 사용하는 함수임에도 사용이 매우 불편하다. 그러므로, C언어를 사용할 때 부터 자주 사용하였던 printf()함수로 대체하여 기본 HAL_UART_Transmit() 함수보다 편하게 사용하고자 한다.

 

// 기존 UART 통신 함수 사용
char* Message = "Hello world";

HAL_UART_Transmit(&huart3, Message, strlen(Message),5);

 

// printf() 함수 사용하여 UART 통신
printf("Hello world");

 

위 코드를 에서 확인 할 수 있듯이 코드의 크기를 많이 줄일 수 있다.

 

1.2. 기존 printf() 함수의 포멧 기능 사용

  printf()를 사용하는 가장 중요한 이유라고 할 수 있다. 가끔 특정 상황에서 디버깅하기 위해 변수의 값을 출력 하고자 할 때, 기존  HAL_UART_Transmit() 함수로는 출력하기에 많이 불편하다. 그러므로, printf() 함수를 통해 변수의 값을 출력을 편하게 하고자 한다.

 

int num = 10;
    
// num변수의 값을 UART로 출력
printf("num : %d", &num);

2. 사전 작업

2.1. PC와 통신하는 UART 확인

 PC와 통신하는 UART는 사용하는 Board에 따라 다르게 설정되어 있을 수 있다. 제가 사용하는 Nucleo-F429ZI 보드는 UART3가 PC와 통신하고 있음을 확인 할 수 있다.

Nucleo-F429ZI는 UART3를 통해 PC와 통신하기 위해 CubeMX에서 설정 확인

 

대부분 많이 사용하는 Nucleo-F103RB 보드는 UART2를 통해 PC와 통신하고 있음을 확인 할 수 있다.

Nucleo-F103RB는 UART2를 통해 PC와 통신하기 위해 CubeMX에서 설정 확인

 

 

2.2.  __io_putchar() 함수 작성

  printf() 함수 내에서 __io_putchar() 함수가 호출되지만, STM32 프로젝트 내에서 __io_putchar() 함수가 작성되어 있지 않다. 해당 함수가 작성되어 있지 않음을 "{프로젝트 경로}/Core/Src/syscalls.c" 폴더 내에서 확인 할 수 있다.

syscalls.c 파일 위치
__io_putchar() 함수가 선언되어 있지만 몸체가 없다.

 

  위에서 확인 할 수 있듯이, __io_putchar() 함수가 선언은 되어 있지만 동작을 위한 몸체가 없는 것을 확인할 수 있다. 또한 함수 선언에 extern이 붙어 있어 다른 파일에서 해당 함수를 작성 할 수 있도록 한 것을 확인 할 수 있다. 그러므로 해당 함수를 main.c 파일에서 작성 해 줄 것이다.

 

여기서 제일 중요한 것은 2.1. 에서 확인한 UART를 사용해야한다는 것이다.

저는 UART3 이므로 huart3를 사용하였다.

 

__io_putchar() 함수

  입력 번수 ch : 출력 하고자 하는 문자

  반환 값 : 출력 성공 시 출력한 문자, 출력 실패시 0

 

main.c에 작성된 __io_puthchar() 함수

/* USER CODE BEGIN 4 */
int __io_putchar(int ch){
  // UART3에 ch에 있는 문자 1개를 1ms내 전송
  if(HAL_UART_Transmit(&huart3, &ch, 1 ,1) != HAL_OK)
    return 0; //출력 실패 시 0 리턴

  return ch; //출력 성공 시 출력한 데이터 리턴
}
/* USER CODE END 4 */

3. 테스트

  /* USER CODE BEGIN WHILE */
  size_t count = 0;

  while (1)
  {
    printf("[%d] Hello world\r\n", count);
    ++count;
    
    HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

 

위 코드 실행 시 정상적 출력 되는 것을 확인 할 수 있다.

 

태스트 코드 출력 화면


4. 참고 사항

4.1. C++ 에서 printf() 함수 사용

https://littlebitodd-developer.tistory.com/11