뽕구의 개발일지
[STM32] GPIO - 입출력 제어 본문

앞전에 STM32가 아니고 CH32 라는 중국제 MCU 보드를 구매해 CubeIDE에서 인식이 안되어 빌드를 못했던 적이 있었습니다. 아래 걸어놓은 링크가 그 글입니다.
2023.07.31 - [개발일기/STM32] - 7. STM32 개발환경 구축하기 - 빌드하기 (삽질)
위 내용 때문에 임시로 Nucleo-F103, F446 보드로 진행하다가 최근 STM32 Smart V2라는 보드를 구매하였습니다. STM32103C8T6 정품 MCU가 실장된 보드이고 아래 보드 제조사의 링크입니다. 자세한 정보를 알 수 있습니다. https://stm32-base.org/boards/STM32F103C8T6-STM32-Smart-V2.0.html
STM32F103C8T6 - SMT32 Smart V2.0
The STM32-base project is meant for students and hobbyists. The goal of the STM32-base project is to provide a simple and easy to use base project for working with STM32 microcontrollers.
stm32-base.org
보통 보드에 ST-Link V2만 연결하면 보드가 동작하는데, 이 보드의 경우 간혹 안들어오는 경우가 있다고 합니다.
또 가짜 제품을 산건지 걱정했는데,
이 문제는 ST-Link V2에서 보내주는 전류가 부족해서 일어난 현상이었고, 보드에 있는 USB 단자를 함께 사용해 바로 보드에 전원을 넣어주어 동작시켰습니다.
주의 : USB 단자에 레귤레이터에 연결되어 있어 3.3V로 출력 레벨을 맞춰서 문제가 없는데, 와이어로 5V 인가해주면 레귤레이터가 없어서 보드가 탈 수 있다고 합니다!!!
해당 보드 사용하시는 분들은 참고하세요~
![]() |
![]() |
| ST-Link만 연결 시 전원 안들어옴 | 보드에 USB 추가 연결 시 전원 들어옴 |
GPIO 제어
1. 보드 소개
STM32F103C8T6 MCU가 실장된 STM32 Smart V2 개발보드와 CubeIDE 이용해
GPIO INPUT, OUTPUT처리를 해보도록 하겠습니다. 보드에는 아래와 같이 물리적 스위치 2개와 내장 LED 1개 존재합니다.
왼쪽은 MCU Reset 스위치이고, 오른쪽은 User 스위치로 다목적으로 사용할 수 있습니다.

이 보드를 사용해 User 스위치를 누를 때 LED가 점등되도록 하는 간단한 코드를 작성해 보겠습니다.
먼저 User 스위치와 내장 LED의 회도로를 확인 해보겠습니다.

- S2 스위치는 왼쪽에는 PA0 포트, 오른쪽에는 GND 연결되어 있으며, 보드에 S2라고 프린트되어 있습니다.
- SPST 스위치네요. Single Pole Single Throw 방식으로 기본적인 스위치 (ON/OFF) 동작입니다.
- *참고로 Pole은 극 수를 나타내고, Throw는 ON/OFF 되는 라인 수를 의미한다고 합니다.
- 간단히 Throw가 많으면 뻗쳐 나갈 수 있는 경로가 많다는 뜻이고 전류를 흐름을 선택할 수 있겠습니다.
- SPDT, DPDT 방식 외 여러가지가 있습니다. (DPDT : Double Pole Double Throw)
- D2 LED는 [PC13]-----[저항]------[LED]-------[3.3V] 로 연결되어 있네요. 3.3V는 계속 출력 상태일거고 PC13 포트의 상태가 LOW가 되면 전류 차에 의해 PC13 핀으로 전류가 흐르면서 LED가 켜질 것으로 예상이 됩니다.
안켜지면 설정 바꿔보면서 하죠 뭐
2. GPIO 제어하기 INPUT&OUTPUT
- 이제 ST-Link V2와 STM32 Smart V2 보드를 연결하고, CubeIDE를 실행합니다.

- 프로젝트 생성 모르시면 아래 링크로 따라와주시고, MCU는 STM32F103C8T6을 선택합니다.
2023.07.31 - [개발일기/STM32] - 6. STM32 개발환경 구축하기 - 프로젝트 생성
2.1. CubeMX - INPUT 설정
- CubeMX에서 보드의 S2 스위치가 연결된 PA0 핀을 마우스로 클릭하여 GPIO_INPUT으로 설정합니다.

- GPIO를 INPUT으로 설정하고 Pinout & Configuration 탭의 System Core - GPIO를 클릭해보면 아래 사진과 같이 PA0 핀이 GPIO mode가 Input Mode로 설정되어 있는것을 볼 수 있습니다.
- User Label은 개발자가 해당 핀의 별칭을 붙이는 것 인데, #define 처리되어 핀과 포를 직접 찾을 필요 없이 별칭으로 호출이 가능합니다.
PA0의 별칭을 "GPIO_SW_PIN" 으로 지었습니다.

2.2. CubeMX - OUTPUT 설정
- 내장된 LED를 켜지도록 하려면 우선 LED가 연결된 PC13 핀을 OUTPUT으로 설정합니다. 위에서 PA0을 INPUT으로 설정한 것 처럼 PC13을 OUTPUT으로 설정해줍니다.

- Output level은 GPIO 핀의 초기 출력 상태를 지정합니다. (Low = 0 V, High = 3.3V, Five vold toerant 핀 경우 5V)
- GPIO mode는 Push Pull과 Open Drain 방식이 있는데 Push Pull은 Low, High가 그대로 나가고 Open Drain 방식은 Low일때는 Low, High일때는 Floating 상태입니다. Open Drain의 경우 MCU내에서 VDD를 공급하지 않기 때문에 외부 전원을 사용 및 외부 IC를 사용하는 것으로 추측됩니다.
- Maximum Output Speed는 디지털 신호가 High가 되는 Rising Edge 구간의 속도를 선택하는 것으로 Low, Medium, Fast가 존재하며 Low ~ Fast 구간을 간략히 설명하면 속도와 노이즈 비례 관계라고 합니다.
속도가 올라가면 노이즈가 탈 수 있고, 느리면 안정적입니다.
해당 부분은 추후에 설정을 바꿔보면서 오실로스코프로 찍어보도록 하겠습니다.
2.3. 프로그래밍
- 설정이 완료되면 CubeIDE의 Code Generation 기능을 통해 설정값을 Code화 해줍시다.
- Generation된 Main.c 코드의 main 함수입니다. HAL_Init(), SystemClock_Config(), MX_GPIO_Init(), While(1) 이 생겼네요.
(코드를 추가할 때 /*USER CODE BEGIN */ 과 /*USER CODE END*/ 사이에 해야한다는거 잊지마세요. Generation시 다 사라집니다.) - 먼저 HAL_Init()은 HAL(Hardware Abstraction Layer) 드라이버를 초기 설정합니다. HAL 드라이버 및 함수를 설명하면 글이 길어지니 추후에 다뤄보고, 간단히 아두이노로 예를 들어 DigitalWrite(), DigitalRead()처럼 함수화된 제어 코드들이 있어 HW 제어 및 개발을 편하게 해줍니다.
- SystemClock_Config()는 CPU, MCU, MPU 동작의 기준이 되는 Clock을 초기 설정합니다. 모든 동작은 Clock에 의해 처리됩니다. 외부 Clock, 내부 Clock 등 Clock 개념은 추후에 더 다루겠습니다.
- MX_GPIO_Init()은 CubeMX에서 설정한 GPIO를 초기 설정합니다.
- 모든 MCU 프로그래밍은 While(1)에서 무한반복하며 핀을 제어하고 상태를 읽어 처리합니다. 아두이노로 예를 들면 Loop() 문에 해당합니다.
이제 While(1) 반복문 안에 스위치를 상태를 읽고, LED를 켜는 코드를 추가해보겠습니다.
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
- 먼저 스위치의 상태를 읽어야 합니다. HAL의 GPIO 관련 코드를 사용할건데, HAL_GPIO 라고치고 컨트롤 + 스페이스를 누르면 입력한 코드와 비슷한 함수들을 쭉 찾아줍니다. 여기서 HAL_GPIO_ReadPin() 함수를 호출하겠습니다.
- HAL_GPIO_ReadPin() 함수는 사용할 GPIO의 포트와 GPIO 핀을 매개변수로 입력받습니다.

- 스위치가 연결된 핀은 PA0였습니다. 따라서 HAL_GPIO_Readpin() 함수에 GPIOA 그룹, GPIO A 그룹의 0번 핀을 매개변수로 입력하였습니다. if 조건문 통해 핀 상태에 따라 수행문을 추가할 수 있습니다.

- 위쪽에서 CubeMX를 활용해 핀에 대한 별칭을 부여했었습니다.
별칭 입력 시 아래와 같이 define 코드에 추가되어 코딩이 편리하게 사용할 수 있습니다.

- GPIO_SW_PIN으로 입력한 별칭으로 핀을 호출하겠습니다.

- 이제 스위치가 눌린 상태인 if()조건문에 GPIO를 Write하는 함수를 추가하겠습니다.
- HAL_GPIO_WritePin() 함수는 사용할 GPIO의 포트명과 GPIO 핀넘버, 출력할 GPIO 핀 상태를 매개변수로 입력받습니다.

- LED 핀에 대한 포트와 핀을 별칭으로 입력하고, 출력 상태를 GPIO_PIN_SET 하겠습니다.

- GPIO_PinState enum은 Reset = 0, Set = 1 로 지정되어 있습니다. 이는 해당 핀의 Bit 값을 키고 끄는것 입니다.
따라서 LED를 키려면 Set으로, 끄려면 Reset으로 입력해주어야 합니다.

- 코드를 완성해보겠습니다.
- 스위치를 누르면 LED가 켜지고 스위치를 떼면 LED가 꺼지는 코드입니다.
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (HAL_GPIO_ReadPin(GPIO_SW_PIN_GPIO_Port, GPIO_SW_PIN_Pin))
{
HAL_GPIO_WritePin(GPIO_LED_PIN_GPIO_Port, GPIO_LED_PIN_Pin, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(GPIO_LED_PIN_GPIO_Port, GPIO_LED_PIN_Pin, GPIO_PIN_RESET);
}
HAL_Delay(100);
}
/* USER CODE END 3 */
}
결과

기본적인 동작이었는데 이것저것 설명하면서 쓰느라 글이 길어졌네요. 결국엔 다 응용이니 GPIO 제어는 이렇게 제어하시면 될 것 같습니다. 추후에는 레지스터 접근해서 제어하는 방법도 다뤄봐서 HAL 드라이버 사용 시와 속도면에서 차이가 얼마나 나는지 오실로스코프로 찍어보도록 하겠습니다.
읽어주셔서 감사합니다.
'개발 일지 > STM32' 카테고리의 다른 글
| [STM32] Interrupt - 개요 (1) | 2023.12.24 |
|---|---|
| [STM32] GPIO - Toggle 출력 예제 (1) | 2023.09.03 |
| [STM32] GPIO - OUTPUT 구조 (2) | 2023.08.03 |
| [STM32] GPIO - INPUT 구조 (0) | 2023.08.03 |
| [STM32] 개발환경 구축하기 5 - 빌드하기 (Nucleo) (0) | 2023.08.02 |

