HAL 라이브러리 프로젝트 수동 구축 방법

一、프로젝트 디렉토리 구조 생성

1. 프로젝트 폴더 생성

프로젝트 파일을 저장할 위치로 사용할 폴더를 생성한다. (예: HAL_Project)

2. 서브 디렉토리 생성

프로젝트 폴더 내에 Doc, User, Libraries, CMSIS, Project 하위 폴더를 생성한다:

  • Doc: 문서 저장
  • User: 사용자 코드 저장
  • main.c
  • Libraries: HAL 라이브러리
  • Include
  • Source
  • CMSIS: 코어 관련 파일
  • Include
  • Source
  • Project: 빌드 출력
  • Output
  • Listing

3. 디렉토리 구조 개요

二、HAL 라이브러리 파일 복사

1. HAL 라이브러리 복사 (Libraries)

STM32Cube_FW_F1_V1.8.0\Drivers\STM32F1xx_HAL_Driver 경로에서 Inc 폴더와 Src 폴더를 복사하여 프로젝트의 Libraries 폴더相应 위치에 붙여넣는다.

2. 시작 파일 복사 (CMSIS\Include)

1)内核 파일 위치로 이동: \STM32Cube_FW_F1_V1.8.0\Drivers\CMSIS 2)Include 폴더의 모든 파일을 프로젝트의 CMSIS/Include 폴더에 복사 3)\CMSIS\Device\ST\STM32F1xx\Include 폴더의 모든 파일을 프로젝트의 CMSIS/Include 폴더에 복사

3. 소스 파일 복사 (CMSIS\Source)

1)소스 위치로 이동: \STM32Cube_FW_F1_V1.8.0\Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates 2)system_stm32f1xx.c 파일을 프로젝트의 CMSIS/Source 폴더에 복사 3)/arm 폴더 내의 모든 파일을 프로젝트의 CMSIS/Source 폴더에 복사

4. 인터럽트 파일 추가

User 폴더에 stm32f1xx_it.c 및 stm32f1xx_it.h 파일을 생성한다.

stm32f1xx_it.c

/*--------------------------------------------------------------*/
/*                                                              */
/*          인터럽트 서비스 루틴 소스 파일                       */
/*                                                              */
/*--------------------------------------------------------------*/

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h"  

/*--------------------------------------------------------------*/
/*함수명: Non-Maskable Interrupt 처리 함수                      */
/*매개변수: 없음                                                */
/*반환값: 없음                                                  */
/*--------------------------------------------------------------*/
void NMI_Handler(void)
{

}

/*--------------------------------------------------------------*/
/*함수명: 하드폴트 예외 처리 함수                               */
/*매개변수: 없음                                                */
/*반환값: 없음                                                  */
/*--------------------------------------------------------------*/
void HardFault_Handler(void)
{

}

/*--------------------------------------------------------------*/
/*함수명: Supervisor Call 인터럽트 처리 함수                    */
/*매개변수: 없음                                                */
/*반환값: 없음                                                  */
/*--------------------------------------------------------------*/
void SVC_Handler(void)
{
    
}

/*--------------------------------------------------------------*/
/*함수명: Pendable Service Request 처리 함수                    */
/*매개변수: 없음                                                */
/*반환값: 없음                                                  */
/*--------------------------------------------------------------*/
void PendSV_Handler(void)
{
    
}

/*--------------------------------------------------------------*/
/*함수명: SysTick 타이머 인터럽트 처리 함수                      */
/*매개변수: 없음                                                */
/*반환값: 없음                                                  */
/*--------------------------------------------------------------*/
void SysTick_Handler(void)
{  
    HAL_IncTick();        
}

stm32f1xx_it.h

/**
  ******************************************************************************
  * @file    stm32f1xx_it.h
  * @brief   This file contains the headers of the interrupt handlers.
  ******************************************************************************
  */

/* Define to prevent recursive inclusion */
#ifndef __STM32F1xx_IT_H
#define __STM32F1xx_IT_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */

void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);

#ifdef __cplusplus
}
#endif

#endif /* __STM32F1xx_IT_H */

5. HAL 설정 파일 수정

Libraries/Include 폴더의 stm32f1xx_hal_conf_template.h 파일을 stm32f1xx_hal_conf.h로 rename한다. 이 작업을 하지 않으면 컴파일 시 헤더 파일을 찾을 수 없다는 오류가 발생한다.

三、Keil MDK에서 프로젝트 생성

1. 프로젝트 생성

Project 메뉴에서 새 프로젝트를 생성하고, 프로젝트 폴더를 지정한다.

2. 그룹 폴더 추가

필요한 그룹 폴더를 추가한다 (User, Libraries, CMSIS 등).

3. 파일 추가

STM32F1xx_HAL_Driver 그룹:

  • stm32f1xx_hal.c
  • stm32f1xx_hal_cortex.c
  • stm32f1xx_hal_gpio.c
  • stm32f1xx_hal_gpio_ex.c
  • stm32f1xx_hal_rcc.c
  • stm32f1xx_hal_rcc_ex.c

STARTUP 그룹:

  • system_stm32f1xx.c
  • startup_stm32f103xe.s

User 그룹:

  • main.c
  • stm32f1xx_it.c

四、프로젝트 설정

1. Target 설정

Target 옵션에서 "Use MicroLib"을 선택한다. 이는 시리얼 드라이버 작성 시 printf 함수를 사용하기 위함이다.

2. Output 설정

Output 옵션卡에서 출력 폴더를 프로젝트 디렉토리 내의 "Output" 폴더로 지정한다. 컴파일 시 HEX 파일을 생성하려면 "Create HEX File" 옵션을 체크한다.

3. Listing 설정

Listing 옵션卡에서 출력 폴더를 프로젝트 디렉토리 내의 "Listing" 폴더로 지정한다.

4. C/C++ 설정

C/C++ 옵션卡에서 전처리기 매크로와 헤더 파일 검색 경로를 추가한다.

헤더 파일 경로가 올바르지 않으면 컴파일 시 헤더 파일을 찾을 수 없다는 오류가 발생한다. C99 Mode를 선택한다.

전처리기 매크로를 추가하면 소스 파일을 수정하지 않고도 프로젝트 설정을 변경할 수 있다.

  • STM32F103xE 매크로: STM32 HAL 라이브러리에 사용할 칩의 종류(대용량)를 알림. 선택한 칩型号에 따라 HAL 라이브러리가 자동으로 구성된다.
  • USE_HAL_DRIVER 매크로: stm32f1xx.h가 stm32f1xx_hal_conf.h 헤더를 포함하도록 한다.

五、컴파일 및 테스트

1. 테스트 소스 코드

#include "stm32f1xx_hal.h"

#define USER_LED_PIN  GPIO_PIN_5
#define USER_LED_PORT GPIOA

void SystemClock_Config(void);
void Error_Handler(void);

int main(void)
{
    /* 1. HAL 라이브러리 초기화 (포팅의 핵심 첫 번째 단계) */
    HAL_Init();
    
    /* 2. 시스템 클록 설정 (하드웨어와 일치해야 함!) */
    SystemClock_Config();
    
    /* 3. 간단한 GPIO 초기화 (LED 핀만 설정) */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    GPIO_InitTypeDef led_config = {0};
    led_config.Pin = USER_LED_PIN;
    led_config.Mode = GPIO_MODE_OUTPUT_PP;
    led_config.Pull = GPIO_NOPULL;
    led_config.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(USER_LED_PORT, &led_config);
    
    /* 4. 메인 루프: LED 깜빡임 (포팅 성공 확인) */
    while (1)
    {
        HAL_GPIO_TogglePin(USER_LED_PORT, USER_LED_PIN);
        HAL_Delay(500);
    }
}

/**
 * @brief 시스템 클록 설정 (칩에 맞게 수정 필요)
 * 예: STM32F103 72MHz / STM32F407 168MHz / 크리스탈 없으면 HSI 사용
 */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef osc_config = {0};
    RCC_ClkInitTypeDef clk_config = {0};
    
    /* HSI 사용 (내부 고속 클록, 8MHz - 외부 크리스탈 불필요) */
    osc_config.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    osc_config.HSIState = RCC_HSI_ON;
    osc_config.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    
    if (HAL_RCC_OscConfig(&osc_config) != HAL_OK)
    {
        while(1);
    }
    
    /* 시스템 클록 = HSI (8MHz) */
    clk_config.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
                           RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    clk_config.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    clk_config.AHBCLKDivider = RCC_SYSCLK_DIV1;
    clk_config.APB1CLKDivider = RCC_HCLK_DIV1;
    clk_config.APB2CLKDivider = RCC_HCLK_DIV1;
    
    if (HAL_RCC_ClockConfig(&clk_config, FLASH_LATENCY_0) != HAL_OK)
    {
        while(1);
    }
}

/**
 * @brief 오류 처리 함수 (포팅 실패 시 호출)
 */
void Error_Handler(void)
{
    while (1)
    {
        /* 포팅 실패 시 LED 빠르게 깜빡임 (100ms 간격) */
        HAL_GPIO_TogglePin(USER_LED_PORT, USER_LED_PIN);
        HAL_Delay(100);
    }
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif

2. 다운로드 및 테스트

태그: STM32 HAL STM32F1 Keil Embedded

6월 16일 23:14에 게시됨