2015-02-15

스위치로 LED 불켜기 강좌 과제 및 질문 내용

3-1 스위치로 LED 불켜기 에 나온 과제와 관련된 질문과 답변 내용을 정리한 글입니다.

출처 : http://cafe.naver.com/lazydigital/delay

3-1 스위치로 LED 불켜기 [강좌]

[과제] ------------------------------------------------------------------
SW1을 누르는 시간에 관계없이 한 번 누르면 LED 왼쪽 4개가 켜지고, SW2를 누르는 시간에 관계없이 한 번 누르면LED 오른쪽 4개가 켜지는 프로그램을 작성해 보세요.
힌트 : Falling Edge, Rising Edge 조건을 이용하면 쉽게 할 수 있습니다. ^^;;
------------------------------------------------------------------------


#include <avr/io.h>
#include <avr/interrupt.h>


int main(void)
{

 DDRE = 0x30;   //입력 설정 (4번,5번 비트.)
 PORTE = 0xff;  //입력 (avr 내부적으로 풀업저항 사용가능), 연결된 sw1,2는 하드웨어적으로 이미 풀업상태가 유지되어                                //있음
 DDRA = 0xff;   //출력 설정 (PORTA)

 sei(); //SREG |= 0x80;  //status register의 7번비트만을 1로 셋.

 EIMSK |= (1<<INT4) | (1<<INT5);  //External interrupt 외부와 연결된 INT4, INT5 을 인터럽트용으로 사용 set "1"

 EICRB |= (1<<ISC40) | (1<<ISC41) | (0<<ISC50) | (1<<ISC51) ; // External interrupt int4,int3에 trigger 
                                                        // 해당되는 트리거 조건 선택 레지스트리 EICRB에
                                                        // INT4는 Rising edge,  INT5는 Falling edge. 
  
    while(1)
    {
         PINE &= 0x30;  // 입력받는 PORTE의 입력 레지스트리 값을 항상 off 상태로 유지.
    }
}

ISR(INT4_vect)
{
    PORTA = 0xf0;
}
   
SIGNAL(INT5_vect)
{
 PORTA = 0x0f;
}



안녕하세요 3-1번강좌를 진행후 내주신 과제를 위와 같이 작성하여 연습해본후 궁금증이 생겼습니다.

궁금증1)) 내주신 과제의 의도를 제가 제대로 이해하고 한건지 의아해서 질문 드려봅니다.
과제에서 힌트를 주신 Falling edge 와 Rising edge는 EICRB 레지값을 바꿔가며 연습해보았습니다.
Falling은 off:1 --> on:0 즉 스위치를 누르자마자 ISR을 바로 실행하고 Rising의 경우 sw 를 누른후 띄었을때  ISR
을 실행하는 차이점을 확인해보았습니다.  과제에 PORTA에 초기값에 대한 언급이 없으셔서 그냥 단순하게 while(1)
안의 PORTA =0x00; 값을 없애고 힌트에 맞춰서 작성하였는데 원래 의도한신 과제가 제가 한것과 다른지 궁금합니다

궁금증2)) 작성하여 올린 과제 코드에서 PINE &= 0x30;  // 입력받는 PORTE의 입력 레지스트리 값을 항상 off 상태로 유지. << 이부분은 제가 PINE값을 단순하게 입력값으로 설정하고 PORTA에 전달하여 보니 값도 없는데 LED가 막점등되고 꺼지고 이상한값들이 수시로 들어오고 나가서 초기값을 일단 위코드 처럼해서 값을 항상 off 상태를 유지할려고 하였는데 의미가 있는건지
모르겠습니다 ^^;;

궁금증3)) 코드 표현인데요, 인터럽트를 처음 접하게 되서 강좌 내용과 관련된 레지스트리에 대해 좀더 내용을 살펴
보던중에 레지스트리 설정에 대해서 표현방법을 제가 표현한 위와 같은 방법을 사용하는것을 보고 따라 사용하였는데
저런식으로 계속 표현하여 사용해도 괜찮은지 여쭈어봅니다. 대개 EIMSK = (1<<INT4) | (1<<INT5); 이런식으로 표
현하였는데 제가 혹시몰라 기존값에 영향을 주기 싫어서 EIMSK |= (1<<INT4) | (1<<INT5); 이렇게 하였는데 "|" 넣
으나 않넣으나 지금은 차이가 없었는데 괜찮은 표현인지 궁금합니다, 처음 접해본 레지스트리라 사용하는데 있어
위 강좌에서 우선 언급된 External interrupt register 관련하여 코드표현시 사용상 주의할점을 알고 싶습니다.

궁금증4)) 강좌에서 인터럽트를 LOW LEVEL TRIGGER 사용하여 wihle(1){  PORTA = 0x00;} 으로 sw1,sw2를 인터럽트로 PORA = 0x80;, 0x01; 값을 ISR로 실행하는 내용에서 while 문안에 PORTA에 값을 0xff; 놓고 인터럽트를 걸면 제가 생각하기에 sw1이 눌리경우 0x80; 만 켜지고 sw1을 놓으면 0xff 가 나오고 sw2를 누르면 0x01;만 출력되고 놓으면 0xff; 출력될것이라고 생각하고 해보았는데 예상치 않게 스위치에 따라 각 비트값은 반응하지만 반응한 비트의 led외에 다른 led는 꺼지지 않고 상대적으로 희미하게 켜진 상태를 유지하고 있습니다. while 안의 코드값만 0x00; 에서 0xff; 값으로 변경하였는데 어떤 점때문에 이러한 현상이 나타나는지 궁금합니다.

궁금증5)) 위 3번과 연관된 내용인데요, while(1){ } 안에 PORTA에 관한 어떤 값이 들어 있을경우에 인터럽트 트리거의 값이 LOW LEVEL 트리거 외에는 다른 TRIGGER 조건들은 하나도 실행이 되지 않는것같이 느껴집니다.
Falling edge 나 Rising edge 는 반응이 하나도 없는데 어떤 상태 때문인지 역시 궁금합니다. ^^;;;

간단한 코드였지만 의미를 이해할려고 하다보니 이해한 부분과 현상이 맞지 않게 일어나는 부분이 많아 아직 이해도가 부족한 부분들을 정리하여 질문으로 여쭈어보았습니다 다소 장황해 보이지만 아직 머리속에서 정리않된 부분이라
이해해주셨으면 좋겠습니다 ^^;;


질문 및 답변 출처 : http://cafe.naver.com/lazydigital/delay 


궁금증2)) 작성하여 올린 과제 코드에서 PINE &= 0x30; 
=> 이 코드는 문제가 있는듯 합니다. 입력 레지스터는 외부 핀 상태의 반영이므로 의미가 없습니다.
교수님의 설명이 필요할듯 합니다.

EIMSK = (1<<INT4) | (1<<INT5);
이렇게 사용하는 경우는 main 함수에서 처음으로 EIMSK를 설정하는 경우
(즉 이전에 어떤 값인지 알고 싶지도 않고, 명시적으로 어떤 비트만 설정하겠다!!의 의지일때)
EIMSK |= (1<<INT4) | (1<<INT5);

이건 이걸 설정하는 위치 이전에 어떤 외부 인터럽트에 대해 설정했는지 알수 없으며,
현재 설정하는 싯점에는 두개의 인터럽트만 enable(이전 상태는 유지 하겠다).


보통 인터럽트는 설정하는 곳이 정해져 있긴 하지만
좀더 복잡한 mcu에서는

init_rtc()
{
// RTC 관련 mask 설정하고

gimask |= 1 << RTC_BIT;
}
init_uart()
{
// UART관쳔 초기화및 관련 mask 설정하고
gimask |= 1 << UART_BIT;
}

init_timer()
{
gimask |= 1 << TIMER;
}
main()
{
init_rtc();
init_uart();
init_timer();
...

}

위처럼 globlal interrupt mask 레지스터가 각 함수의 호출순서 등에 독립적이며, 자신의 인터럽트
enable 만 관심있을떄 ' |= ' 형태로 대부분 사용됨.

궁금증 4, 5는 제가 잘 이해가 안됩니다.
관련 코드(위 올린 소스하고는 서로 내용이 다름)을 올리주시면 좋겠습니다.

궁금증5)) 위 3번과 연관된 내용인데요, while(1){ } 안에 PORTA에 관한 어떤 값이 들어 있을경우에 인터럽트 트리거의 값이 LOW LEVEL 트리거 외에는 다른 TRIGGER 조건들은 하나도 실행이 되지 않는것같이 느껴집니다.
Falling edge 나 Rising edge 는 반응이 하나도 없는데 어떤 상태 때문인지 역시 궁금합니다. ^^;;;
=>

while(1)
{
PORTA = xx;
}
이렇게 하고
edge 인터럽트를 하면
edge 인터럽트 걸리는 순간 잠깐 PORTA를 바꾼후에 돌아오면
다시 PORTA = xx;
가 됩니다.
즉 눈에 인터럽트가 걸려서 LED에 반영하는 시간이 너무 짧아서 그렇게 보입니다.

레벨로 하면 버턴을 누른 상태인 동안에는 인터럽트 루틴에서 벗어나지 않습니다.
(실제로는 main ->인터럽트 루틴->벗어나자 마자 다시 인터럽트루틴->벗어나자마자 다시인터럽트루틴

그래서 마치 인터럽트 루틴에서 머무는 것처럼 보입니다.

궁금증 4,5 번은 아래 와 같이 PORTA = 0xff; 했을경우를 제가 여쭈어본 것입니다.

바로 위 답변에서 질문에 대한 답변을 해주셔서 왜그런지 이해가 됐네요 감사합니다.

일종의 착시 현상 같은 일이 벌어진거네요 ^^;


int main(void)
{

DDRE = 0x30;
PORTE = 0xff;
DDRA = 0xff;

sei(); //SREG |= 0x80;

EIMSK |= (1<<INT4) | (1<<INT5); //External interrupt 외부와 연결된 INT4, INT5 을 인터럽트용으로 사용 set "1"

EICRB |= (1<<ISC40) | (1<<ISC41) | (0<<ISC50) | (1<<ISC51) ; // External interrupt int4,int3에 trigger
// 해당되는 트리거 조건 선택 레지스트리 EICRB에
// INT4는 Rising edge, INT5는 Falling edge.

while(1)
{
PORTA = 0xff;
}
}

ISR(INT4_vect)
{
PORTA = 0xf0;
}

SIGNAL(INT5_vect)
{
PORTA = 0x0f;
}

4,5번은 trigger가 Low level 일경우 스위치는 계속 눌러져 있기때문에 계속 ISR 루틴 > main > ISR 루틴이
계속 반복된거고 rising edge나 falling edge 일경우 스위치를 누르거나 땠을때 한번만 루틴으로 갔다가 바로 다시 main으로 빠져나와서 ISR루틴으로 가지고 않고 메인함수의 PORTA = xx; 값을 무한 반복한거였군요.

예..

실제로 ISR을 실행하지 않은것이 아니라 아주 짧은시간안에 눈으로 인식하지 못하는 시간안에 한번 실행하고 메인으로 돌아간거 였군요 그래서 육안으로 봤을때 작동하지 않은것으로 착각한거군요
감사합니다 궁금증은 많았는데 실제로는 같은 맥락의 얘기 였습니다..

그렇죠..


No comments:

Post a Comment

Total Pageviews