시뮬레이션 환경 활성화 설정
Keil uVision 에서 물리 보드 없이 코드의 동작을 확인하기 위해서는 시뮬레이터 모드를 활성화해야 합니다. 프로젝트 옵션(魔术棒 아이콘) 으로 이동한 후 'Debug' 탭을 선택합니다. 해당 메뉴에서 'Use Simulator' 항목에 체크를 수행하면 에뮬레이션 환경으로 전환됩니다.
준비물로는 STM32 표준 펄리페리 라이브러리 기반의 프로젝트 템플릿과 Keil IDE 가 필요합니다. 본 내용은 STM32F103 시리즈를 기준으로 설명되며, 타 계열도 기본 개념은 동일하게 적용됩니다.
출력 포트 상태 모니터링 (Logic Analyzer)
GPIO 핀의 전기적 레벨 변화를 시각적으로 확인하는 것은 디버깅의 핵심입니다. 아래 예제 코드는 여러 GPIO 포트를 출력용으로 초기화하고 주기가 다른 작업 루틴에서 핀 상태를 토글하는 구조를 보여줍니다.
#include "System_GPIO.h"
void Configure_Output_Ports(void) {
// 클럭 인에이블 단계
RCC_APB2PeriphClockCmd((RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE), ENABLE);
GPIO_InitTypeDef GPIO_Setting;
GPIO_Setting.GPIO_Mode = GPIO_Mode_Out_PP; // Push-Pull 모드 설정
GPIO_Setting.GPIO_Speed = GPIO_Speed_50MHz;
// 특정 핀 매핑
GPIO_Setting.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOB, &GPIO_Setting); // PB5
GPIO_Setting.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOD, &GPIO_Setting); // PD5
GPIO_Setting.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOE, &GPIO_Setting); // PE5
}
// 작업 스케줄러 내 실행 함수
void Toggle_LED_Status(void) {
// 각 채널의 논리치 반전
Set_Port_State(GPIOB, GPIO_Pin_5, !Get_Port_State(GPIOB, GPIO_Pin_5));
Set_Port_State(GPIOD, GPIO_Pin_5, !Get_Port_State(GPIOD, GPIO_Pin_5));
Set_Port_State(GPIOE, GPIO_Pin_5, !Get_Port_State(GPIOE, GPIO_Pin_5));
Delay_Milliseconds(100); // 시간 지연
}
프로젝트 컴파일 후 오류가 없는 상태에서 시뮬레이션 시작 버튼(F7) 을 누르면 디버깅 창이 열립니다. 여기서 좌측 도구 모음의 'Logic Analyzer' 아이콘을 클릭하여 파형 관찰 창을 엽니다.
'Set Up' 버튼을 통해 모니터링할 대상 핀을 추가합니다. 텍스트 필드에 'PORTB.5'와 같이 [포트명].[핀번호] 형식으로 입력하고 엔터를 칩니다. 목록에 추가된 항목의 'Display Type'을 'Bit'로 설정하고 색상 팔레트를 지정하면 됩니다. 이 색상이 파형 그래프상의 선 색상에 반영됩니다.
실행 중에는 실시간으로 핀의电平이 상하변동하며 표시되지만, 일시정지 상태에서는 정적인 파형을 관찰할 수 있습니다. 파형 상단을 마우스로 드래그하거나 휠을 회전하여 시간 축을 확대/축소할 수 있으므로, 정확한 주기 계산이나 딜레이 시간을 분석하는 데 유용합니다.
입력 신호 가상 조작 (Virtual Button)
실제 버튼 연결 없이 소프트웨어적으로 입력 신호를 생성하여 처리 로직을 검증하는 과정입니다. 아래 코드는 풀업 및 풀다운 모드를 활용한 입력 포트 스캐닝 함수입니다.
#include "Input_Control.h"
void Initialize_Switch_Ports(void) {
// GPIOA 와 GPIOE 클럭 켜기
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE, ENABLE);
GPIO_InitTypeDef Switch_Config;
// PE2, PE3, PE4 : 내부 풀업 저항 활성화
Switch_Config.GPIO_Mode = GPIO_Mode_IPU;
Switch_Config.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;
GPIO_Init(GPIOE, &Switch_Config);
// PA0 : 내부 풀다운 저항 활성화
Switch_Config.GPIO_Mode = GPIO_Mode_IPD;
Switch_Config.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &Switch_Config);
}
uint8_t Read_Switch_State(void) {
static uint8_t debounce_lock = 1;
// 조건부 체크 및 안정화 딜레이
if (debounce_lock && (Is_Switch_Active())) {
Delay_Milliseconds(10);
debounce_lock = 0;
return Get_Triggered_Key_Index();
} else if (!Any_Switch_Active()) {
debounce_lock = 1;
}
return 0xFF;
}
// 외부 추상화 함수들 (구현은 생략)
bool Is_Switch_Active(void);
uint8_t Get_Triggered_Key_Index(void);
bool Any_Switch_Active(void);
Keil 의 시뮬레이션 인터페이스 하단에 위치한 'IO States' 또는 유사한 입력 설정 창을 엽니다. 여기서는 각 GPIO 핀의 현재 전압 레벨을 수동으로 제어할 수 있습니다. 예를 들어 'PA.0'과 같은 주소창 옆의 체크박스를 조작하여 고전위 (1) 또는 저전위 (0) 를 강제로 할당합니다.
- 풀다운 입력인 경우: 체크박스를 선택 (High) 하면 버튼 누름 상태로 인식되고, 해제 (Low) 하면 놓은 상태로 간주됩니다.
- 풀업 입력인 경우: 체크박스를 해제 (Low) 하면 누름 상태, 선택 (High) 하면 미누름 상태가 됩니다.
입력 레벨을 변경한 후 로직 분석기와 연동하면, 버튼 이벤트 발생 시 내부 변수나 다른 출력 핀의 반응 여부를 실시간으로 추적할 수 있습니다.