01. 임베디드 C와 Keil μVision 시작하기
PC에서 도는 C와 MCU에서 도는 C는 같은 언어지만 사고방식이 다릅니다. OS도 화면도 없는 칩 위에서 코드가 직접 하드웨어를 다뤄야 하죠. 임베디드 C가 무엇인지, 24편 내내 쓸 도구인 Keil μVision(C51/MDK-ARM)이 코드를 어떻게 빌드·디버그·시뮬레이션하는지, 그리고 임베디드 프로그램의 표준 골격(main + while(1))을 익힙니다. 보드가 없어도 PC의 gcc로 따라올 수 있습니다.
이 강의에서 배우는 것
- 1임베디드 C와 일반 PC 프로그래밍의 차이를 설명한다
- 2Keil μVision의 두 갈래(C51 / MDK-ARM)와 대상 칩을 구분한다
- 3임베디드 프로그램의 표준 골격(main + while(1) 무한 루프)을 이해한다
- 4μVision의 빌드(F7) → 디버그/시뮬(Ctrl+F5) 흐름을 따라간다
- 5순수 로직 예제를 gcc로 빌드·실행해 확인한다
소개
임베디드 시스템은 전자레인지·세탁기·드론·자동차 ECU 안의 작은 칩(MCU)처럼 특정 기능을 수행하도록 기계 안에 내장된 컴퓨터입니다. 임베디드 C는 표준 C와 같은 문법을 쓰지만 **메모리 주소를 직접 다루고**, **하드웨어 레지스터를 비트 단위로 조작**하며, **자원이 매우 제한적**(수 KB RAM)이라는 점이 다릅니다.
이번 편은 아직 실제 보드(8051·STM32)를 다루지 않습니다. 어디서나 통하는 순수 C 로직을 작성하며 μVision의 작업 흐름과 시뮬레이터 개념을 잡는 데 집중합니다. 모든 예제는 PC의 gcc 로도 확인할 수 있습니다.
핵심 개념
1) PC 프로그램 vs 임베디드 프로그램
| 구분 | PC | 임베디드 |
|---|---|---|
| 운영체제 | 있음 | 없는 경우 많음(베어메탈) |
| 종료 | main return 시 끝 | while(1)로 계속 동작 |
| 입출력 | 화면·키보드·파일 | GPIO 핀·센서·레지스터 |
| 자원 | 수 GB RAM | 수 KB~수백 KB RAM |
| 디버깅 | 콘솔 출력 | LED 토글·UART·디버거 |
2) Keil μVision — C51 vs MDK-ARM
μVision은 편집·컴파일·디버깅·시뮬레이션을 한 화면에서 하는 IDE입니다. 어떤 칩을 쓰느냐에 따라 내부 컴파일러가 갈립니다.
| 도구 | 대상 칩 | 이 트랙의 편 |
|---|---|---|
| Keil C51 | 8051 계열(AT89C52 등) | 6~12편 |
| Keil MDK-ARM | Arm Cortex-M(STM32F103 등) | 13~20·24편 |
3) 임베디드 프로그램의 표준 골격
int main(void)
{
/* 1. 초기화: 클럭·핀·주변장치 설정 (단 한 번) */
while (1) {
/* 2. 본문: 센서 읽고·판단하고·출력하고 ... 무한 반복 */
}
/* 여기에는 절대 도달하지 않는다 */
}main 앞에는 스택을 세팅하고 전역 변수를 초기화한 뒤 main 으로 점프하는 **시작 코드(startup)** 가 있습니다. Keil 디바이스 팩이 이 파일을 포함하므로 우리는 main 부터 작성합니다.
4) 빌드 → 디버그 → 시뮬레이션
- **F7 (Build)** — 소스를 컴파일·링크해 실행 이미지 생성
- **Ctrl+F5 (Debug)** — 디버거 시작. 시뮬레이터 모드면 보드 없이 칩 동작 흉내
- 디버그 중 **F11**(한 줄), **F5**(연속)로 레지스터·변수를 눈으로 확인
핵심 예제
실제 보드라면 led 변수 대신 GPIO 핀이 LED를 켜고 끕니다. 여기서는 변수로 흉내 내고 printf 로 "무한 루프 안에서 상태가 바뀐다"는 감각을 잡습니다(PC 관찰용으로 5회 제한).
#include <stdio.h>
#include <stdint.h>
int main(void)
{
uint8_t led = 0; /* 0=꺼짐, 1=켜짐 */
uint8_t tick;
printf("Hello, Embedded C!\n");
for (tick = 0; tick < 5; tick++) {
led = (uint8_t)!led; /* LED 토글 */
printf("tick %u: LED = %s\n",
(unsigned)tick, led ? "ON" : "OFF");
}
return 0;
}PC에서 검증:
gcc main.c -o main && ./main
# Hello, Embedded C!
# tick 0: LED = ON
# tick 1: LED = OFF
# ... (ON/OFF 반복)"순수 로직은 PC(gcc)로, 하드웨어 제어는 시뮬레이터로"가 이 트랙의 방식입니다. 토글 같은 결정을 toggle() 함수로 떼어내면 하드웨어 없이도 단위 검증할 수 있습니다.
자주 하는 실수
Q. 임베디드 main 은 왜 return 하지 않나요?
A. 베어메탈 MCU에는 돌아갈 OS가 없습니다. main 이 return 하면 갈 곳이 없어 정의되지 않은 동작에 빠지죠. 그래서 실제 임베디드 main 은 while(1)로 끝나며 절대 반환하지 않습니다. 이번 예제는 PC 관찰용이라 일부러 종료시킨 것입니다.
Q. int 면 되는데 왜 uint8_t 같은 걸 쓰나요?
A. MCU마다 int 크기가 다르고(8051은 16비트) 레지스터는 폭이 정확히 정해져 있습니다. uint8_t/uint16_t/uint32_t 는 폭이 이름에 박혀 이식성과 의도가 분명합니다(2편에서 자세히).
Q. gcc 로 되는데 정말 임베디드 학습이 맞나요?
A. 토글·무한 루프·자료형은 하드웨어와 무관한 C의 토대입니다. 토대를 PC에서 빠르게 다진 뒤 6편부터 실제 칩의 레지스터로 같은 개념을 적용합니다.
정리
- 임베디드 C는 OS·풍부한 자원에 기대지 않고 하드웨어를 직접 다루는 C다
- Keil μVision은 C51(8051)·MDK-ARM(STM32)으로 갈리며 같은 IDE를 공유한다
- 임베디드 골격은 초기화 + while(1) 무한 루프이며 main 은 반환하지 않는다
- μVision 흐름: F7(빌드) → Ctrl+F5(디버그/시뮬) → 창으로 결과 관찰
- 순수 로직은 gcc로 빠르게 검증한다
과제
- main.c 의 토글 메시지를 본인 이름이 들어간 문장으로 바꿔 gcc 로 다시 실행
- 토글 로직을 toggle(state) 함수로 분리해 pc_test.c 로 단위 검증
- Keil MDK-Arm(또는 C51) 평가판을 내려받아 빈 프로젝트를 만들고 F7 빌드가 도는지 확인