아두이노] 인터럽트 비활성화 했는데도 불구하고 활성화 후 동작하는 문제 해결

문제 발생 :

아두이노의 인터럽트를 비활성화 detachInterrupt(인터업트 번호) 를 한 뒤에 다른 일을 하고 와서 다시 인터럽트 활성화를 attachInterrupt(인터럽트 번호) 하도록 했다.

문제는, 인터럽트를 끄고 있었던 기간동안 스위치 조작 (나는 이 것을 무시하고 싶었다) 이 인터럽트를 다시 키는 순간 그제서야 바로 발생하는 것이다.

가령, 어떤 스위치를 누르면 싸이렌이 울리도록 하는 프로그램을 만들었다고 하자. 그 스위치는 인터럽트 핀에 연결되어 있다.

싸이렌은 밤에 울리면 안되기 때문에 아두이노에 빛 감지 센서를 두고, 어두운 상황에서는 인터럽트를 해제하고, 빛이 들어오는 상황에서는 다시 인터럽트를 활성화  시켰다.

그런데 문제는, 어두울 때 그 스위치를 누르면 아무런 일이 일어나지 않는데, 밝아지자 마자 사이렌이 울리기 시작하는 것이다.

마치 인터럽트가 쌓여 있다가 이제서야 울리는 느낌이었다.

 

구글에 찾아본 결과 비슷한 증상을 호소하는 사람들이 있었고, 아래의 데이터시트까지 찾아보게 되었다.

아래의 데이터시트는 아두이노 우노와 나노 등에서 쓰이는 Atmega328P 의 데이터 시트중, 외부 인터럽트에 관련된 부분을 발췌한 것이다.

EIFR : 외부 인터럽트 플래그 레지스터다. 이 레지스터의 0번과 1번 비트는 각각 0번 인터럽트 (2번핀)  과 1번 인터럽트(3번핀) 에 대응된다.

Bit 1 : 인터럽트 외부 인터럽트 플래그 1

인터럽트 1번핀의 엣지(LOW -> HIGH 나 HIGH -> LOW)발생 또는 핀상태 변화(LOW <-> HIGH) 가 인터럽트 요청을 발생시킬 때, INTF1 비트는 1로 활성화 됩니다. 만약 SREG 레지스터의 I-bit (역주: 글로벌 인터럽트 활성화 비트: 7번 비트) 와 EIMSK 레지스터의 INT1비트 가 1로 셋팅 되어 있다면, MCU는 바로 그에 해당하는 인터럽트 벡터(인터럽트 함수)로 점프합니다. 이 플래그는 인터럽트 루틴이 실행된 뒤 초기화됩니다. 또는 이 플래그는 1을 셋팅함으로써 수동으로 초기화 될 수 있습니다.  이 플래그는 INT1 이 “레벨인터럽트”로 설정이 될 때 언제나 초기화됩니다.

Bit 0 : 인터럽트 외부 인터럽트 플래그 0

인터럽트 0번핀의 엣지(LOW -> HIGH 나 HIGH -> LOW)발생 또는 핀상태 변화(LOW <-> HIGH) 가 인터럽트 요청을 발생시킬 때, INTF0 비트는 1로 활성화 됩니다. 만약 SREG 레지스터의 I-bit (역주: 글로벌 인터럽트 활성화 비트: 7번 비트) 와 EIMSK 레지스터의 INT0비트 가 1로 셋팅 되어 있다면, MCU는 바로 그에 해당하는 인터럽트 벡터(인터럽트 함수)로 점프합니다. 이 플래그는 인터럽트 루틴이 실행된 뒤 초기화됩니다. 또는 이 플래그는 1을 셋팅함으로써 수동으로 초기화 될 수 있습니다.  이 플래그는 INT0 이 “레벨인터럽트”로 설정이 될 때 언제나 초기화됩니다.

즉, 인터럽트를 셋팅할 때마다 이 플래그는 언제나 0이 되어버린다는 것이다. 그리고 인터럽트를 붙이던 안붙이던 상관없이 이 레지스터는 변화에 반응하는 것이다. 이상하게도 핀에 반응하면 1로 세팅된다고 하는데, 여기에 1을 써버리면 초기화 된다는 것이다. 왜? 0을 써야 초기화 될 것 같은데 왜 1을 써야 하는것일까?

 

어쨌든, 결론은

인터럽트를 잠시 꺼두었다가 다시 키려고 하면 이걸 초기화 해 주는게 좋다.

interrupt0 을 잠시 꺼두었다가 다시 키려고 하면

EIFR |= ( 1 << INTF0 );

interrupt1 을 잠시 꺼두었다가 다시 키려고 하면

EIFR |= ( 1 << INTF1 );

하면,  인터럽트 비활성화 시 눌렸던 스위치에 대해서 반응하지 않게 된다.

 

13.2.3 EIFR – External Interrupt Flag Register
• Bit 7:2 – Reserved
These bits are unused bits in the ATmega48A/PA/88A/PA/168A/PA/328/P, and will always read as zero.
• Bit 1 – INTF1: External Interrupt Flag 1
When an edge or logic change on the INT1 pin triggers an interrupt request, INTF1 becomes set (one). If the Ibit
in SREG and the INT1 bit in EIMSK are set (one), the MCU will jump to the corresponding Interrupt Vector.
The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a
logical one to it. This flag is always cleared when INT1 is configured as a level interrupt.
• Bit 0 – INTF0: External Interrupt Flag 0
When an edge or logic change on the INT0 pin triggers an interrupt request, INTF0 becomes set (one). If the Ibit
in SREG and the INT0 bit in EIMSK are set (one), the MCU will jump to the corresponding Interrupt Vector.
The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a
logical one to it. This flag is always cleared when INT0 is configured as a level interrup

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *