10년 차 펌웨어 아키텍트입니다. 하드웨어 팀에서 "미안한데, 아트웍하다가 핀이 꼬여서 UART1을 UART3으로 바꿔야 할 것 같아"라고 했을 때, 여러분의 반응은 어떤가요?
A: "아... 코드 수십 군데 고쳐야 하는데 며칠 걸려요." 😰
B: "네, `config.h`만 바꾸면 되니까 5분 뒤에 릴리즈할게요." 😎
만약 A라면 오늘 글을 꼭 정독해 주세요. 여러분의 퇴근 시간을 지켜줄 '하드웨어 추상화(HAL)' 꿀팁을 대방출합니다! 😊
1. 당신의 코드가 '스파게티'인 이유 🤔
펌웨어 개발에서 스파게티 코드의 주범은 goto문이 아닙니다. 바로 '비즈니스 로직과 하드웨어 제어 코드의 혼재'입니다.
혹시
main.c 파일 안에서 while(1) 루프 안에 HAL_GPIO_WritePin이나 HAL_UART_Transmit 같은 함수가 그대로 들어있지 않나요? 이건 "나 하드웨어랑 결혼했어!"라고 선언하는 것과 같습니다. 이혼(수정)이 아주 힘들어지죠.
우리는 ST가 제공하는 HAL 드라이버를 믿지만, 의존하지는 말아야 합니다. 벤더의 HAL은 하드웨어를 제어하는 도구일 뿐, 우리 애플리케이션의 로직이 되어서는 안 됩니다.
2. 해결책: 나만의 '방화벽' 만들기 📊
해결책은 간단합니다. 벤더 HAL 함수 앞에 나만의 함수(Wrapper)를 하나 더 두는 것입니다. 이것을 저는 '방화벽'이라고 부릅니다.
`HAL_GPIO_WritePin`은 '어떻게(How)' 제어하는지 말하지만, `Pump_Start`는 '무엇(What)'을 하는지 말합니다. 코드는 '무엇'을 하는지로 작성되어야 합니다.
[방화벽 코딩의 3단계 규칙]
- 1단계: 하드웨어 제어 코드는 반드시 별도의
.c / .h파일(드라이버 파일)로 분리한다. - 2단계: 드라이버 파일의 헤더(
.h)에는HAL_...관련 타입이나 매크로를 노출하지 않는다. - 3단계:
main.c에서는 오직 내가 만든 함수(Led_On(),Motor_Run())만 호출한다.
3. 실전 팁: 이렇게 바꾸세요! 🧮
말로만 하면 어렵죠? 나쁜 코드와 좋은 코드의 예시를 비교해 드립니다.
👎 나쁜 예: 하드웨어 종속적
// main.c
if (temp > 50) {
// 핀 이름이 바뀌면 여기를 수정해야 함
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
}
👍 좋은 예: 의도 중심적
// main.c
if (temp > 50) {
// 핀이 바뀌어도 여기는 수정 안 함
Fan_TurnOn();
}
// fan_driver.c (이 파일만 수정하면 됨)
void Fan_TurnOn() {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
}
🔢 내 프로젝트 건강 상태 체크
다음 중 해당되는 항목을 선택해보세요.
4. 마무리: 핵심 내용 요약 📝
기능 구현보다 중요한 것은 '수정하기 쉬운 구조'를 만드는 것입니다.
방화벽 코딩 수칙
자주 묻는 질문 ❓
여러분의 코드가 하드웨어로부터 자유로워지는 그날까지! 다음 강의에서 또 만나요. 😊

