Nucleo 보드의 B1 버튼을 누르면 외부 인터럽트가 발생하며 LED(LD2)가 깜빡이도록 하는 것

B1 버튼은 PC13에 연결되어 있는 것을 확인할 수 있다.
또한, 회로도를 보면 스위치가 Open 상태일때 PC13이 HIGH(1)이고, Short 상태일때 PC13이 LOW(0) 상태라는 것을 알 수 있다.

또한 디바운싱을 위한 커패시터도 연결되어있는 것을 확인할 수 있다.
디바운싱 부분은 신경쓰지 않아도 될 것 같다.

PA5가 LD2 LED에 연결되어 있음을 확인할 수 있다.
(SB42와 SB21은 연결되어있다.)

프로젝트명을 EXTI로 해서 STM32 프로젝트를 하나 생성한다.

HSE와 LSE를 Disable한다.

HCLK가 64Mhz인 것을 확인한다.

현재 PC13의 GPIO mode가 External Interrupt Mode with Rising edge trigger detction 으로 설정 되어있다.
External Interrupt Mode 란 뭘까?
외부 신호(스위치, 센서, 다른 MCU의 신호 등)가 특정 핀에 들어올 때, CPU가 즉시 반응하도록 인터럽트 발생시키는 모드이다.
일반 GPIO 입력 모드로 스위치 값을 읽는 경우
인터럽트로 스위치 값을 읽는 경우
Rising Edge을 감지하는 것을 의미한다
다들 알고있겠지만, Rising Edge 는 신호가 0 → 1 (Low → High)로 바뀌는 순간을 의미한다.

앞서 설명했듯이, 회로도를 보면 스위치가 Open 상태일때 PC13이 HIGH(1)이고, Short 상태일때 PC13이 LOW(0) 상태임을 알 수 있다.
따라서 현재의 설정(External Interrupt Mode with Rising edge trigger detction) 이면 버튼을 눌렀다가 땔 때 인터럽트가 발생하고 CPU가 ISR을 호출한다.

나는 스위치를 누르자마자 LED가 켜지게 하고 싶으므로 위와같이GPIO mode를
External Interrupt Mode with Falling edge trigger detction 로 수정해줬다.
(1) 인터럽트가 발생하면 해당 인터럽트
pending 상태로 저장
(2) 만약여러 개가 pending→우선순위(priority) 비교
(3)우선순위가 가장 높은 인터럽트부터 실행
(우선순위 동일하면 → 벡터 번호가 낮은 쪽 먼저 실행)
(4) CPU가 하나 처리 끝내면다음 pending 인터럽트를 실행

NVIC-NVIC 에서 인터럽트를 활성화 및 비활성화 시킬 수 있고, 인터럽트 우선순위도 변경할 수 있다.

NVIC-Code generation에서 인터럽트 코드에 대한 초기화 순서, 인터럽트 서비스 루틴 (IRQ) 생성 여부도 설정할 수 있다.

Code를 Generate 해주고 위와 같이 Project Explorer에 EXTI가 뜨는지 확인한다.
CubeMX에서 앞서 수행한 설정 관련 코드는 이미 생성해주었다.
이제 인터럽트 발생시 실행되어야 하는 것들을 코드로 작성해주면된다.
인터럽트가 발생하면
EXT_15_10_IRQHandler()->HAL_GPIO_EXTI_IRQHandler()->HAL_GPIO_EXTI_Callback()순서로 함수가 호출된다.
사용자는 HAL_GPIO_EXTI_Callback()에 인터럽트 발생시 실행될 코드를 구현해주면 된다.

stm32f1xx_it.c 파일에 들어가면 CubeMX가 자동으로 생성한 ISR인 EXT_15_10_IRQHandler()가 HAL_GPIO_EXTI_IRQHandler()를 호출하는 것을 확인할 수 있다.

드래그-우클릭-Open Declaration 에 들어가서 HAL_GPIO_EXTI_IRQHandler()의 선언을 확인해보자.

위와같이 HAL_GPIO_EXTI_IRQHandler() 가 HAL_GPIO_EXTI_Callback()을 호출하는 것을 확인할 수 있다.

HAL_GPIO_EXTI_Callback()의 경우user file(main.c)에서 구현(implement) 하라고 나와있는 것을 확인할 수 있다.
void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin) {
switch (GPIO_Pin) // switch 문으로 "어떤 핀에서 인터럽트가 발생했는지" 구분하는 것.
{
case B1_Pin: //스위치가 연결된 PC13의 User Label이 B1 이다.
HAL_GPIO_TogglePin (LD2_GPIO_Port, LD2_Pin); // LD2_GPIO_Port의 LD2_Pin을 Toggle(반전)
break; // case문 종료
default: // 아무것도 해당 사항 없을 시. switch문의 마지막이라 break문 없어도 됨.
;
}
}
HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin) 함수의 사용법을 알아보자.
앞서 설명했듯이, 인터럽트 발생시 HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin) 함수가 자동으로 호출되고 매개변수 GPIO_Pin에는 인터럽트가 발생한 Pin 번호가 들어온다.
switch문을 통해 어떤 핀의 인터럽트 발생인지에 따라 분기해서 처리하면 된다.
빌드해준다.

성공적으로 빌드되었다.
Run-Run으로 업로드 해준다.

GOOD