그 다음 해줘야 할 게,
먼저 디버거용 핀 지정

ioc 들어가서,
SYS 들어가서,

여기서 Serial Wire 씀
보통 JTAG나 Serial Wire 쓰는데,
Serial Wire가 핀 2개밖에 안 씀.

이렇게 두개 자동으로 지정해 줌.
이름도 저거 TimeBase Source에 적혀진데로 SYS_TICK

이러면 PIN 4개
또 툴 장점은

이렇게 STM32칩이랑은 정보가 있기 때문에 각 핀마다 어떤 걸 할 수 있는지 알아서 한정시켜 줌.
원래는 데이터 시트 봐야 하는건데.
여튼 ioc 저장하면 디버깅 관련 핀 설정 알아서 다 코드에 쳐짐.
이제 GPIO 하나를 제어 해 볼건데, LED하나 제어 해 볼거임.
데이터 시트 보면, LED에 연결된 GPIO가

PC13이 저렇게 발광 다이오드랑 연결되어 있음.
저 다이오드는 D2,

여 칩에서,

여기 S1 위에.
이거는 칩 보고 찾는게 더 빠르긴 했음..
여튼 이제, PC13에서 신호를 내보내야 하니까,

Output
그럼 이렇게

GPIO가 생성 되고,
저거 눌러서 옵션 변경할 수 있는데,

우선 전력을 줄거니 output level은 High로,
GPIO mode는 뭔지 모르겠고,
GPIO Pull-up/Pull-down도 뭔지 모르겠음.
Maximum output speed도 뭔지 모르겠지만 뭔가 신호의 정밀함, 빠르기 그럴 것 같긴한데,
여튼 이런 거 다 나중에 설명.

네이밍은 GPIO_LED 해서 저걸로 코드에서 접근 가능할 듯.
여튼 이렇게 하면,

이렇게 MX_GPIO_Init() 코드가 생김.
따라가 보면,

main.c 자체에 새 함수가 생겼음.
GPIO_InitTypeDef 저거는 GPIO 관련 초기화 같고,
GPIO 포트 클럭 저거는 잘 모르겠지만 포트 CLOCK 가능하게끔 설정? 그런 거 같고,
HAL_GPIO_WritePin은,
그러니까 저 핀마다 지정포트가 있나봄. 그거에 GPIO_LED_Pin 이것도,

이것도 이렇게 자동으로 13번핀 아까 설정해놨더니 접근할 수 있도록 정의된 듯.

GPIO_PIN_SET은
저기 칩에 대해 정의해놓은 헤더파일에서 enum에서 가져오는 듯.
저기 보면 16진수(사실 상 2진수)로 다 핀 위치 가져오는 듯.
다시 돌아와서,

HAL_GPIO_WritePin()은 어떤 핀에 전력을 줄지 말지 지정해주는 그런 초기화 코드 같고,
아래는 아까 UI로 핀 뭐 Pull-up할건지 Pull-down 할건지 등 그런 설정이랑,
이름 정해주는거랑, 그런 거 설정한 거 같음.
여튼 이거는 다 초기화 관련 내용인 듯.
그럼 이제 핀 관련 초기화는 했으니까 사용을 해 보면,

핀에 입력신호를 쓰는 코드를 해볼건데,
/* USER CODE BEGIN WHILE */
while (1)
{
//HAL_GPIO_WritePin(핀포트그룹, 핀, 핀상태);
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState);
HAL_Delay(100);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
저건데,

아까 Init할 때 따라갔던 곳에 다 있음.
GPIO_LED_Pin 저것도 내가 네이밍 한 거고.
GPIO_PIN_13 저거를 직접 쓰는 것 보다, GPIO_LED_Pin 네이밍 한 걸로 쓰길.
그래야 나중에 핀 혹시라도 바꿨을 때,

저 이름만 PC13이 아니라 다른 핀을 GPIO_LED로 해주면 그대로 PC13핀에 하던 로직이 다른핀에 동작하니까.
15번 핀이면 15번 핀
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
HAL_Delay(100);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
여튼 포트, 핀, 넣고 1이 High일거임.
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 0);
HAL_Delay(100);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
이렇게 해주면 0.2초 간격으로 깜빡깜빡.
스위치 제어까지 해 봅시다.

PA0이 스위치.
저 입력을 input으로 받고 LED 제어해보자.


PA0 설정에서,
GPIO Pull-up/Pull-down은 아직 뭔지 모르겠고,
User Label은 그냥 GPIO_SW로 설정.
이번에 쓸 코드는,
//HAL_GPIO_ReadPin(포트, 핀);
HAL_GPIO_ReadPin(GPIOx, GPIO_Pin);
저거 함수 따라가 봤더니, return값이

GPIO_PIN_SET
가 1
GPIO_PIN_RESET
0임.
C언어는 if문에서 1이 참인걸로 기억함.
그리고 핀의 포트와 핀은

아까 UI에서 설정한 거 저장하면 저렇게 생성됨.
저 GPIO_SW_Pin 따라가보면,

아까거와 나란히 추가됨.
이번에도 마찬가지로, 유지보수를 위해 GPIO_PIN_0 이걸 직접 선택하는 것이 아니라, 우리가 역할에 따라 네이밍한, 앞쪽
GPIO_SW_Pin과 GPIO_SW_GPIO_Port로 사용.
//HAL_GPIO_ReadPin(포트, 핀);
HAL_GPIO_ReadPin(GPIO_SW_GPIO_Port, GPIO_SW_Pin);
우선 그 전에,
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
LED만 켜보려고 함.
근데 1주면 High로 전압 준다고 생각하고 해봤더니 안됨.
근데 GPT한테 물어보니,
그런데 LED는 보드에 따라 “반대로” 동작할 수 있음 (중요)
많은 STM32 보드(특히 Nucleo, Discovery)는 LED가 이렇게 연결돼 있어요:
즉, GPIO가 LOW일 때 전류가 흘러서 LED가 켜짐 (Active Low)
전압이 역으로 들어오는 구조임.. (????)
근데, 직렬이면 저항이 LED 앞쪽에 있든 뒤쪽에 있든 보호를 해준다고 하기는 함...
3.3V ──[저항]──[LED]── GPIO 핀 이든,
3.3V ──[LED]──[저항]── GPIO 핀 이든
똑같이 보호해준다고 함.
그리고,
VCC----[스위치 or LED 등 기타 여러 부품들]------GPIO-----GND
대부분 이런 구조라고 함.
전압을 외부에서 받아서 부품 거쳐서 GPIO로 들어오고 그걸 칩에서 GND로 흘려보내는..
그래서 내가 전압이 칩에 가까이 있으면 노이즈, 발열때문에 그런가 했는데,
뭐 NMOS PMOS 이야기 하면서 반도체 관련 이야기를 함.
STM32가 전류를 GPIO핀을 통해 밀어내는 것 보다 전류를 그냥 GND로 흘려보내주는 걸 더 잘한다고 함.
그리고,
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
이게, 전기를 흐르게 할 지 말지를 해주는 스위치 역할이라고 함.
전압을 내보낸다기 보다는, 길을 터줄지 말지 스위치 역할이라고 함.
이게 보니까, Vcc가 외부쪽에도, GPIO쪽에 있는 칩 쪽에도 Vcc레일이 같음.
만약 이 둘이 연결되어도 둘다 같은 레일이라, 둘다 + + 라서 칩 안전.
그래서,
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
이거는 Vcc쪽을 열어주는 역할이라,
3.3V ──[저항]──[LED]── GPIO ── 3.3V
이렇게 되서 전압차가 0이므로 전압이 흐르지 않음.
그래서 LED가 꺼짐.
근데
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 0);
이렇게 하면,
3.3V ──[저항]──[LED]── GPIO ── GND
이렇게 일반적으로 전압이 0인 GND쪽으로 흘러서,
3.3V의 전압차가 발생하기 때문에 전류가 흐름. 그래서 LED가 켜짐.
이것도 뭐 회로에 따라 Push-pull 뭐 그게 또 다른 거 같음. 그건 일단 나중에.
확인해보니까

일단은 이거 Pull-up으로 바꿔야 작동 하는 거 같음. 일단 저게 뭔지는 나중에.
다시 이제 ReadPin으로 돌아와서,
/* USER CODE BEGIN WHILE */
while (1)
{
if(HAL_GPIO_ReadPin(GPIO_SW_GPIO_Port, GPIO_SW_Pin)){
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 0);
}else {
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
HAL_GPIO_ReadPin(GPIO_SW_GPIO_Port, GPIO_SW_Pin)
해서 버튼이 눌려진 상태면 0으로 해서 GND로 가게해서 길을 열어서 LED를 켤 계획.
그런데 반대로 작동함.
버튼이 안눌려져 있을 때는 불이켜져 있고 버튼이 눌려지면 불이 꺼짐.
그래서 GPT한테 물어봤더니.
대부분의 STM32 보드에서 버튼은 Active-Low라서
HAL_GPIO_ReadPin(...) == 0 일 때 스위치를 누른 상태입니다.
일단은 0일때 스위치를 누른 상태라고 함.
Active-Low가 뭔지 물어봤더니
신호가 0V(LOW)일 때 “동작/참/켜짐”으로 취급하는 방식입니다.
이라고 함.
STM32보드에서 대부분 버튼은 Active-Low방식.
0일때가 버튼 눌렸다! 동작했다! 참이다! 켜졌다!
이것도 아까 LED 그것과 마찬가지로 칩에서 GPIO를 통해 전압을 내보내는 것 보다는 빨아들여서 GND로 흘려보내는 그런 역구조의 연장선상이라고 함.
산업에서 Active Low가 구조 상 유리해서 대부분이라고 함.
0으로 가면 GND열려서 흐르는 거,
1로 가면 Vcc열려서 안 흐르는 거.
0이 switch on 되서 흐르는 거..
/* USER CODE BEGIN WHILE */
while (1)
{
//HAL_GPIO_ReadPin 이거는 0이면 GND로 흐르는 거라서 스위치 누른 거, 1이면 Vcc열리는 거라서 전압차 0이라서 안 흐르는 거.
if(!HAL_GPIO_ReadPin(GPIO_SW_GPIO_Port, GPIO_SW_Pin)){
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 0);
}else {
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
여튼간에,
이렇게 하면 됨.
0의 역 1의 경우 WritePin을 0, GND 길을 열어서 전기가 흘러서 LED 빛 들어오고,
1의 역 0의 경우 1로 GND가 아니라 Vcc길을 열어서 전압차 0이라 전기가 안흘러서 LED 안 들어옴.
'임베디드' 카테고리의 다른 글
| 16. 구조체 (0) | 2026.02.04 |
|---|---|
| 15. HAL 드라이버 분석 (0) | 2026.02.03 |
| 13. 프로젝트 생성 (0) | 2026.02.03 |
| 12. 환경구축 (0) | 2026.02.03 |
| 11. 티지털 멀티미터 (0) | 2026.02.02 |