CubeMax : MCU의 다양한 Peripheral과 관련된 셋팅을 GUI 툴로 Setting 하고, Code gen을 하면 셋팅된 내용을 기준으로 관련된 SW Code를 자동으로 만들어주는 툴
Ex) clock설정, Uart 설정, SPI 통신 설정, GPIO 설정 , 인터럽트 설정 등등
Uart의 경우 : 각각의 Uart 채널에 대해서 BaudRate, WordLength, FIFO 사용 여부 , 해당 채널에 연결해서 사용할 Pin 셋팅, 인터럽트 사용 여부 등등을 GUI로 셋팅
GPIO의 경우: 각 핀마다 Output/Input 여부 , Output의 경우 Default 출력값, 핀 변화속도 등등을 셋팅
GUI로 셋팅된 내용과 관련하여 Peripheral 마다 Init 함수가 생성,
Code Generation을 하면 관련된 Init 코드들이 자동으로 생성되서 main 함수에서 호출되는 형태로 구성
main 함수에 보면 User code begin , user code end 라는 주석문이 있는데 유저가 어떤 코드를 짤 때는 저 주석문 내부에 내용을 넣어야 한다.
해당 주석 바깥에 코드를 짤 경우 code gen을 할 때 해당 영역은 gui 셋팅만을 보고 새롭게 쓰기 때문에 유저가 핸드코딩 한 코드는 지워지기 때문이다.
Generation 시 Includes, Core -> lnc & Src & Driver/HAL_Driver 폴더로 구성.
HAL Driver 코드와 헤더파일 자체는 STM에서 만들어서 제공하는 표준 라이브러리
main.c
직접적인 패리펄럴 셋팅 -> Mx_패리펄럴_init(void)
시스템클락 셋팅, -> SystemClock_Config(void)
main 함수에서 호출하는 코드
MCU 또는 보드 선택: STM32F103C8T6 등 원하는 MCU 선택
Pin Configuration:
GPIO 출력, 입력, Alternate Function 설정
Clock Configuration: 내부/외부 클럭 및 PLL 설정
Peripherals Configuration: 필요한 주변장치 설정 (GPIO, USART 등)
Project Settings: 프로젝트 이름, IDE 종류, 코드 구조(HAL/LL 등) 선택
Code Generation:
Src와 Inc 폴더로 구성된 main.c, stm32f1xx_hal_conf.h 등 코드 생성
사용자 코드 구역 (/ USER CODE BEGIN /) 보존 가능
GPIO는 General Purpose Input/Output의 약자로, 다용도 입출력 포트 또는 핀을 의미한다. 프로세서에서 출력 장치와 입력 장치를 연결하여 제어할 때 사용하는 포트
GPIO는 MCU가 외부 세계와 통신하는 방식이고, 모든 보드는 다양한 수의 I/O를 사용하여 외부 주변 장치를 구동하거나 여러 유형의 통신 주변 장치(UART, USB, SPI 등)를 통해 데이터를 교환
입력 : 외부의 핀 상태가 HIGH/LOW 인지를 인식 (스위치, 센서 등)
출력 : HIGH/LOW 상태를 핀을 통해 외부로 출력 (LED, 부저, 모터 등)
PORT : 다수의 개별 핀을 그룹으로 관리, GPIOA~GPIOG 가 있음
PIN : 포트별로 핀의 수는 최대 16개 존재, 개별적으로 On/Off 제어 가능
메인 소스코드의 MX_GPIO_Init(); (gpio 초기화함수) 에 F3을 눌러 GPIO 설정 확인 가능
MX_GPIO_Init
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_5, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);
/*Configure GPIO pin : PE3 */
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/*Configure GPIO pin : PC15 */
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pins : PB0 PB5 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pins : PD10 PD4 */
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*Configure GPIO pins : PD12 PD13 PD14 */
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*Configure GPIO pin : PC6 */
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
초기화 코드 (예: LED on PA5)
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
출력 제어 코드
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // High 출력
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // Low 출력
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 토글
GPIO 구조체 :
GPIO_InitTypeDef GPIO_InitStruct;
GPIO 클럭 :
Enable __HAL_RCC_GPIOG_CLK_ENABLE();
사용 핀 :
GPIO_InitStruct.Pin
사용 모드 :
GPIO_InitStruct.Mode
풀업 관련 설정 :
GPIO_InitStruct.Pull
스피드 :
GPIO_InitStruct.Speed
=해당 GPIO 초기화 :
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct)
단축키
F3 : 위치 찾기
F11 : 디버그
Ctrl+b : 빌드
Ctrl+space : 자동완성
GPIO 함수
초기화 HAL : _GPIO_Init()
리셋 : HAL_GPIO_DeInit()
상태 반전
HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
출력핀
HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
set PC13
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); / HIGH 출력 /
reset PC13
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); / LOW 출력 /
GPIO_PIN_RESET을 하는 경우 해당핀은 '0'이 되고 GPIO_PIN_SET을 하는 경우 '1'이 됨
GPIO_PinState HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)값을 통해서 해당 핀을 Read 할 수 있다.
1)
HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef * GPIO_Init)
함수설명
: GPIOx를 GPIO_Init 구조체 변수의 설정값에 맞추어 초기화
파라미터
: GPIOx : GPIO의 이름(x는 A~K까지의 값을 가질 수 있다)
: GPIO_Init : GPIO의 설정값을 가지고 있는 GPIO_InitTypeDef 구조체형의 변수
2)
HAL_GPIO_DeInit(GPIO_TypeDef * GPIOx, uint32_t GPIO_Pin)
함수 설명
: GPIOx를 리셋 시의 디폴트 값으로 설정(초기화 하제)
파라미터
: GPIOx : GPIO의 이름(x는 A~K까지의 값을 가질 수 있음)
: GPIO_Pin : GPIO Pin을 지정. GPIO_PIN_0 ~ GPIO_PIN_15 사이의 값을 가질 수 있음
3)
HAL_GPIO_ReadPin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
함수 설명
: GPIOx의 지정된 핀(GPIO_Pin)에 입력된 값을 읽어옴
파라미터
: GPIOx : GPIO의 이름(x는 A~K까지의 값을 가질 수 있음)
: GPIO_Pin : GPIO Pin을 지정. GPIO_PIN_0 ~ GPIO_PIN_15 사이의 값을 가질 수 있음
리턴값
: 지정된 핀의 입력값
4)
HAL_GPIO_WritePin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
함수 설명
: GPIOx의 지정된 핀(GPIO_Pin)을 0, 또는 1로 설정
파라미터
: GPIOx : GPIO의 이름(x는 A~K까지의 값을 가질 수 있음)
: GPIO_Pin : GPIO Pin을 지정. GPIO_PIN_0 ~ GPIO_PIN_15 사이의 값을 가질 수 있음
: PinState : 핀의 상태를 설정. 이 파라미터가 가질 수 있는 값음 다음과 같음
GPIO_PIN_RESET : 핀을 리셋(0) 한다
GPIO_PIN_SET : 핀을 셋(1) 한다
5)
HAL_GPIO_TogglePin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
함수 설명
: GPIOx의 지정된 핀(GPIO_Pin)의 값을 토글(toggle)시킴
파라미터
: GPIOx : GPIO의 이름(x는 A~K까지의 값을 가질 수 있음)
: GPIO_Pin : GPIO Pin을 지정. GPIO_PIN_0 ~ GPIO_PIN_15사이의 값을 가질 수 있음
6)
HAL_GPIO_LockPin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
함수 설명
: GPIOx의 지정된 핀(GPIO_Pin)의 값을 록(Lock)시킴
파라미터
: GPIOx : GPIO의 이름(x는 A~K까지의 값을 가질 수 있음)
: GPIO_Pin : GPIO_Pin을 지정. GPIO_PIN_0 ~ GPIO_PIN_15 사이의 값을 가질 수 있음
참고
: 핀이 록(Lock)되면 리셋되기 전까지는 그 핀의 값을 변경할 수 없음
7)
HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
함수 설명
: GPIO에서 발생하는 EXTI 인터럽트 처리를 위한 콜백함수
: 예제에서 이 함수는 stm32f10x_it.c 파일 내의 인터럽트 핸들러 함수(EXTIx_IRQHandler())에서 호출되어 사용
파라미터
: GPIO_Pin : GPIO Pin을 지정. GPIO_PIN_0 ~ GPIO_PIN_15 사이의 값을 가질 수 있음
8)
HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
함수 설명
: EXTI 인터럽트를 처리하기 위한 콜백 함수
: 에제에서 이 함수는 main.c 파닐 내에서 구현되어 사용
파라미터
: GPIO_Pin : GPIO Pin을 지정. GPIO_PIN_0 ~ GPIO_PIN_15 사이의 값을 가질 수 있음
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
// 6,0,5 출력핀 LOW
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_RESET);
//SWON으로 6번 LOW 신호 OFF로 HIGH 신호
while (1)
{
// sw on
if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3) == GPIO_PIN_SET)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_RESET);
}
else //sw off
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_SET);
}
}
// 12,13,14 1초동안 ON/OFF 반복
/* HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);*/
초기화 코드
// GPIO 초기화 설정
/*Configure GPIO pins : LED_GREEN_Pin LED_ORANGE_Pin LED_RED_Pin LED_BLUE_Pin
Audio_RST_Pin */
GPIO_InitStruct.Pin = LED_GREEN_Pin | LED_ORANGE_Pin | LED_RED_Pin | LED_BLUE_Pin
| Audio_RST_Pin; // 초기화할 핀들을 설정 (녹색, 주황색, 빨간색, 파란색 LED와 Audio Reset 핀)
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 핀 모드를 푸시 풀 출력 모드로 설정
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 저항 비활성화 (기본 상태 유지)
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 출력 속도를 낮게 설정 (저전력 소비)
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); // GPIOD 포트에 대해 설정한 초기화 구조체를 적용
LED 출력
int main(void)
{
...
while (1) // 무한 루프 (메인 실행 루프)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(led_onoff) { // led_onoff 플래그가 참인 경우에만 LED 제어
uint16_t led = GPIO_PIN_12; // 처음 LED는 12번 핀에 연결된 LED로 설정
do{
LED_OnOff(led, 200); // LED를 켜고 200ms 후 끄기
led = led << 1; // 왼쪽으로 1비트 시프트하여 다음 LED로 이동
led = led & 0xfffe; // 시프트 후 오른쪽 자리는 0으로 채움 (최하위 비트 클리어)
}while(led != GPIO_PIN_15); // 마지막 LED(15번 핀)까지 반복
do{
LED_OnOff(led, 200); // LED를 켜고 200ms 후 끄기
led = led >> 1; // 오른쪽으로 1비트 시프트하여 이전 LED로 이동
led = led & 0x7fff; // 시프트 후 최상위 비트를 0으로 채움 (최상위 비트 클리어)
}while(led != GPIO_PIN_12); // 첫 번째 LED(12번 핀)로 돌아올 때까지 반복
}
}
...
}
void LED_OnOff(uint16_t led, uint32_t interval) {
HAL_GPIO_WritePin(GPIOD, led, GPIO_PIN_SET); // 지정된 핀의 LED를 켜기
HAL_Delay(interval); // 지정된 시간(ms) 동안 대기
HAL_GPIO_WritePin(GPIOD, led, GPIO_PIN_RESET); // 지정된 핀의 LED를 끄기
}

/* USER CODE BEGIN 1 */
int16_t i = 0; // 16비트 정수형 변수 'i'를 선언하고 0으로 초기화
/* USER CODE END 1 */
/* USER CODE BEGIN WHILE */
while (1) // 무한 루프 시작
{
i++; // 변수 'i'를 1 증가시킴
if(i % 200 == 0) { // 'i'가 200의 배수일 때
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0); // GPIOC 포트의 0번 핀 상태를 토글 (ON->OFF, OFF->ON)
}
if(i % 300 == 0) { // 'i'가 300의 배수일 때
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_1); // GPIOC 포트의 1번 핀 상태를 토글 (ON->OFF, OFF->ON)
}
i %= 60000; // 'i'를 60000으로 나눈 나머지로 업데이트하여 'i'가 60000을 넘지 않도록 함
HAL_Delay(1); // 1ms 동안 대기
/* USER CODE END WHILE */
두 LED가 서로 반대로 점멸하도록 프로그램을 변경하라. 주기는 1초로 하며, 비트 연산을 이용하여 HAL_GPIO_TogglePin() 함수를 한번만 호출하도록 프로그램하라.
/* USER CODE BEGIN 1 */
int16_t i = 0; // 16비트 정수형 변수 'i'를 선언하고 0으로 초기화
/* USER CODE END 1 */
/* USER CODE BEGIN WHILE */
while (1) // 무한 루프 시작
{
i++;
if(i % 1000 == 0) { // 1초 주기로 LED 상태를 변경
// 두 LED의 상태를 반대로 토글
// GPIOC의 0번 핀과 1번 핀을 동시에 토글하기 위해 XOR 연산 사용
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0 | GPIO_PIN_1);
}
i %= 60000; // 'i'를 60000으로 나눈 나머지로 업데이트하여 'i'가 60000을 넘지 않도록 함
HAL_Delay(1); // 1ms 동안 대기
}
/* USER CODE END WHILE */
PC0의 LED가 1번 점멸한 후에 PC1의 LED가 2번 점멸, 다시 PC0의 LED가 3번 점멸, PC1의 LED가 4번 점멸하는 식으로 점멸 횟수를 늘려가는 프로그램을 작성해보라.
int main(void)
{
// STM32 초기화 관련 코드
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
int count = 1; // LED 점멸 횟수를 제어하는 변수 초기화
while (1) // 무한 루프
{
// PC0의 LED를 'count' 횟수만큼 점멸
for (int i = 0; i < count; i++) {
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0); // PC0 LED ON/OFF 토글
HAL_Delay(500); // 500ms 대기 (LED 점멸 주기)
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0); // PC0 LED ON/OFF 토글
HAL_Delay(500); // 500ms 대기
}
count++; // 점멸 횟수 증가
// PC1의 LED를 'count' 횟수만큼 점멸
for (int i = 0; i < count; i++) {
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_1); // PC1 LED ON/OFF 토글
HAL_Delay(500); // 500ms 대기 (LED 점멸 주기)
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_1); // PC1 LED ON/OFF 토글
HAL_Delay(500); // 500ms 대기
}
count++; // 점멸 횟수 증가
}
}
레지스터
MODER 0x0000 GPIO 모드 설정
OTYPER 0x0004 GPIO 출력 형태 설정 - Push-Pull 또는 Open Drain
OSPEEDR 0x0008 GPIO 출력 속도 설정 - Low, Medium, High, Very
High
PUPDR 0x000C GPIO 풀업/풀다운 저항 설정 - Pull-up, Pull-down, No pull-up and no pull-down
IDR 0x0010 GPIO 입력 데이터
ODR 0x0014 GPIO 출력 데이터
BSRR 0x0018 GPIO 비트 셋/리셋
LCKR 0x001C GPIO 설정 잠금
AFRL 0x0020 GPIO 대체기능 설정(Low word)
AFRH 0x0024 GPIO 대체기능 설정(High word)
설정 관련 레지스터들은 MX_GPIO_Init() 함수에서 STM32CubeMx를 통해 설정한 값으로 코드가 생성될 때 사용한다.
MX_GPIO_Init() 함수에서 GPIO_InitStruct라는 이름의 GPIO_InitTypeDef 구조체를 선언하고 구조체의 엘리먼트들을 설정한다. 설정된 값은 HAL_GPIO_Init() 함수를 이용하여 각 레지스터들에 저장된다.
HAL_GPIO_WritePin()와 HAL_GPIO_TogglePin() 함수는 ODR 레지스터와 BSRR 레지스터에 데이터를 써넣음으로써 출력을 제어한다.
ODR 레지스터의 구성은 다음과 같다.
주소 오프셋 : 0x14
초기값 : 0x0000 0000

비트 31:16 예약. 초기값으로 유지해야 한다.
비트 15:0 ODRy : 포트 출력 데이터(y = 0 - 15) 이 비트들은 소프트웨어적으로 읽거나 쓸 수 있다.
만일 0번 핀에 HIGH를 출력하고 싶다면 ODR0에 1을 저장하면 되고, LOW를 출력하고 싶다면 ODR0에 0을 저장하면 된다. ODR0에 1을 저장하는 코딩은 다음과 같다.
GPIOC->ODR = 0x01;
여기서 GPIOC는 GPIO C 포트에 대한 레지스터 구조체의 포인터 매크로이다.
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
마이크로컨트롤러의 포트를 하나의 핀씩 제어를 하고 싶을 때 다음 세 가지 경우가 있다.
다른 핀들의 상태는 변화시키지 않고 원하는 핀만 셋(set) 하고 싶은 경우
다른 핀들의 상태는 변화시키지 않고 원하는 핀만 리셋(reset) 하고 싶은 경우
다른 핀들의 상태는 변화시키지 않고 원하는 핀만 토글(toggle) 하고 싶은 경우
이를 위한 연산자를 비트와이즈 연산(bitwise operation)이라고 한다.

현재 GPIOC_ODR의 값이 0x0003이라고 가정하자.
2진수로 변환하면 0b0000 0000 0000 0011이 되고
GPIOC의 Pin0과 Pin1이 HIGH가 되어 LED가 켜진 상태라고 할 수 있다.
GPIOC->ODR = GPIOC->ODR | 0x0005;
위에서 GPIOC_ODR의 값은 2진수로 0b0000 0000 0000 0011이라고 하였으므로 아래와 같이 비트 연산 결과를 얻을 수 있다.

C언어에서는 위 구문을 다음과 같이 간소화 할 수 있다.
GPIOC->ODR |= 0x0005;
GPIOC->ODR |= GPIO_PIN_2;
#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */
#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */
#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */
#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */
#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */
#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */
#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */
#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */
#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */
#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */
#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */
#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */
#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */
#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */
#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */
#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */
#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */
만일 여러 개의 핀을 동시에 셋하고 싶다면 다음과 같이 작성하면 된다.
GPIOC->ODR |= GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_6;
마스크 사용법 설명
어떤 특정한 비트만 변경하고 나머지 비트들은 원래의 값을 변경하지 않는 비트와이즈 연산을 살펴보았다. 이러한 연산을 특히 비트 마스크(bit mask)라고 부른다.
set ( REGISTER |= 피연산자; )
레지스터의 비트 중 피연산자의 값이 1인 비트는 1로 셋하고 나머지는 값을 그대로 유지
clear ( REGISTER &= ~피연산자; )
레지스터의 비트 중 피연산자의 값이 1인 비트는 0으로 리셋(클리어)하고 나머지는 값을 그대로 유지
toggle (REGISTER ^= 피연산자;)
레지스터의 비트 중 피연산자의 값이 1인 비트가 1인 경우 0으로, 0인 경우 1로 변경하고 나머지는 값을 그대로 유지
Reference:
https://wikidocs.net/159412
https://hubbleconstant.tistory.com/49
https://newbie-developer.tistory.com/162
https://vuzwa.tistory.com/entry/STM32-4-STM32CubeIDE-%EC%82%AC%EC%9A%A9%EB%B0%A9%EB%B2%95
https://www.youtube.com/watch?v=myo3aTcLxzM
https://velog.io/@cjw9105/4%EC%9E%A5-GPIO
https://m.blog.naver.com/eziya76/220932765524