一、프로젝트 디렉토리 구조 생성
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