임베디드

14. GPIO 제어

sdafdq 2026. 2. 3. 12:46

그 다음 해줘야 할 게,

먼저 디버거용 핀 지정

 

 

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가 이렇게 연결돼 있어요:

 
Vcc ──[LED]──[저항]── GPIO 핀

즉, 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