게시글 상세

목록으로

STM32 printf 사용 방법

조회수: 72
작성자: june9152
등록일: 2025-08-21 16:01 수정일: 2025-12-20 19:45
STM32F103RCT6 Printf 사용 가이드

STM32F103RCT6 Printf 사용 가이드

UART를 통한 디버그 출력 구현하기

소개

STM32F103RCT6 마이크로컨트롤러에서 printf 함수를 사용하려면 UART를 통해 출력을 리다이렉션해야 합니다. 이 가이드에서는 Standard Peripheral Library와 HAL 라이브러리 두 가지 방법을 모두 다룹니다.

필요한 하드웨어:
  • STM32F103RCT6 개발보드
  • USB-to-Serial 변환기 (FTDI, CH340 등)
  • 점퍼 와이어

1. UART 초기화 및 printf 리다이렉션

Standard Peripheral Library를 사용한 UART1 초기화 및 printf 리다이렉션 구현입니다.

#include "stm32f10x.h"
#include <stdio.h>

// UART1 초기화 함수
void UART1_Init(void) {
    // 클럭 활성화
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
    
    // GPIO 설정 (PA9: TX, PA10: RX)
    GPIO_InitTypeDef GPIO_InitStruct;
    
    // TX 핀 설정 (PA9)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // RX 핀 설정 (PA10)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // UART 설정
    USART_InitTypeDef USART_InitStruct;
    USART_InitStruct.USART_BaudRate = 115200;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    
    USART_Init(USART1, &USART_InitStruct);
    USART_Cmd(USART1, ENABLE);
}

// printf 리다이렉션을 위한 함수
int fputc(int ch, FILE *f) {
    // UART1로 한 문자 전송
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, (uint8_t)ch);
    return ch;
}

// 대안: _write 함수 재정의 (GNU ARM 툴체인)
int _write(int file, char *ptr, int len) {
    int i;
    for(i = 0; i < len; i++) {
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        USART_SendData(USART1, ptr[i]);
    }
    return len;
}
💡 팁: fputc 함수는 Keil MDK-ARM에서 주로 사용되고, _write 함수는 GCC 기반 툴체인에서 사용됩니다.

2. 메인 함수 예제

printf를 사용한 간단한 예제 프로그램입니다.

int main(void) {
    // 시스템 클럭 설정 (옵션)
    SystemInit();
    
    // UART1 초기화
    UART1_Init();
    
    // printf 사용 예제
    printf("STM32F103RCT6 Printf Example\r\n");
    printf("System Clock: %ld Hz\r\n", SystemCoreClock);
    
    int counter = 0;
    float voltage = 3.3;
    
    while(1) {
        // 다양한 형식의 printf 사용
        printf("Counter: %d\r\n", counter);
        printf("Voltage: %.2f V\r\n", voltage);
        printf("Hex value: 0x%04X\r\n", counter);
        
        counter++;
        
        // 딜레이 (간단한 방법)
        for(volatile int i = 0; i < 1000000; i++);
    }
}

3. HAL 라이브러리 사용 시 (CubeMX)

STM32CubeMX와 HAL 라이브러리를 사용하는 경우의 구현 방법입니다.

#include "main.h"
#include <stdio.h>

UART_HandleTypeDef huart1;

// printf 리다이렉션 (HAL 버전)
int __io_putchar(int ch) {
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}

// 또는 _write 함수 재정의
int _write(int file, char *ptr, int len) {
    HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 0xFFFF);
    return len;
}

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    
    printf("STM32F103RCT6 HAL Printf Example\r\n");
    
    while(1) {
        printf("System Tick: %ld\r\n", HAL_GetTick());
        HAL_Delay(1000);
    }
}
📌 참고: CubeMX에서 USART1을 설정할 때 다음 설정을 사용하세요:
  • Mode: Asynchronous
  • Baud Rate: 115200
  • Word Length: 8 Bits
  • Parity: None
  • Stop Bits: 1

4. 컴파일러 설정

Keil MDK-ARM

  1. Project → Options for Target 메뉴 선택
  2. Target 탭으로 이동
  3. "Use MicroLIB" 체크박스 선택
  4. OK 클릭하여 저장

STM32CubeIDE / GCC

다음 중 하나의 방법을 선택하세요:

  • syscalls.c 파일에 _write 함수 구현
  • 프로젝트 속성 → C/C++ Build → Settings → Tool Settings → MCU GCC Linker → Miscellaneous에서 링커 플래그에 -specs=nano.specs 추가
⚠️ 주의: printf는 상당한 메모리와 처리 시간을 사용합니다. 실제 제품에서는 간단한 UART 출력 함수를 직접 구현하는 것을 권장합니다.

5. 디버깅 팁

조건부 컴파일을 사용한 디버그 매크로 구현 예제입니다.

// 디버그 매크로 정의
#ifdef DEBUG
    #define DEBUG_PRINT(fmt, ...) printf("[DEBUG] " fmt "\r\n", ##__VA_ARGS__)
#else
    #define DEBUG_PRINT(fmt, ...)
#endif

// 사용 예
DEBUG_PRINT("ADC Value: %d", adc_value);
DEBUG_PRINT("Temperature: %.1f C", temperature);

하드웨어 연결

  1. STM32F103RCT6의 PA9 (UART1_TX)를 USB-Serial 변환기의 RX에 연결
  2. STM32F103RCT6의 PA10 (UART1_RX)를 USB-Serial 변환기의 TX에 연결 (옵션)
  3. GND를 서로 연결
  4. PC에서 터미널 프로그램(PuTTY, Tera Term 등)을 실행하고 115200 baud rate로 설정
💡 성능 최적화 팁:
  • 실시간 시스템에서는 printf 대신 간단한 UART 출력 함수 사용 권장
  • 인터럽트 기반 UART 전송으로 블로킹 방지
  • DMA를 사용한 UART 전송으로 CPU 부하 감소
  • 순환 버퍼를 사용한 비동기 로깅 시스템 구현 고려

© 2024 STM32 Printf 가이드. 모든 권리 보유.

처리 중입니다...

잠시만 기다려주세요.