본문으로 바로가기

C언어_펌웨어_int0 count dn , int4 count up

category 개발자/C 언어 2015. 4. 17. 11:46

-내 코드- 

#define DDRD    (*((volatile unsigned char*)0x2A))  //입력쪽  (INT0)
#define PIND    (*((volatile unsigned char*)0x29))  //입력핀

#define DDRE    (*((volatile unsigned char*)0x2D))  //입력쪽 (INT4)
#define PINE    (*((volatile unsigned char*)0x2C))

#define DDRC    (*((volatile unsigned char*)0x27))  //7세그먼트 표현
#define PORTC   (*((volatile unsigned char*)0x28))  //출력핀

#define SREG    (*((volatile unsigned char*)0x5F))  //상태 레지스터, 0000 0000 부분중 제일 끝 자리가 글로벌

#define EIMSK   (*((volatile unsigned char*)0x3D))  //인터럽트 사용할 핀을 설정.(현재 int0 번 사용 중)

#define EICRA   (*((volatile unsigned char*)0x69))  //edge setting(rising , falling)
#define EICRB  (*((volatile unsigned char*)0x6A))  //edge setting

#define EIFR    (*((volatile unsigned char*)0x3C))  //반환(인터럽트 사용했던 핀의 값을 반환)

volatile unsigned int uiCnt;
#define DELAY(X)    for(uiCnt = 0; uiCnt < (X) ; ++uiCnt)

void ito7seg_cal(unsigned int tmp);
unsigned char bitcal(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4, unsigned char c5, unsigned char c6, unsigned char c7);

void __vector_1(void)__attribute__((signal,used,externally_visible));//int0의 벡터 번호 1

void __vector_1(void)// 처리할 루트를 넣어준다. 끼어드는 조건이 만족하면 실행된다.
{  
  while(!(PIND & 0x01));
  
  EIFR = 0x01;  //반환 값. 그쪽 인터럽트를 사용했다라는 뜻의 반환.
}

void __vector_5(void)__attribute__((signal,used,externally_visible));//int4의 벡터 번호 5

void __vector_5(void)// 처리할 루트를 넣어준다. 끼어드는 조건이 만족하면 실행된다.
{  
  while((PINE & 0x10== 0);
  
  EIFR = 0x10;  //반환 값. 그쪽 인터럽트를 사용했다라는 뜻의 반환.
}

int main(void)
{
  volatile unsigned int uiCnt;  //DELAY 정의 한 변수
  volatile unsigned int i;    //for문 제어
  unsigned char cFlag = 0;

  DDRD = 0xEE;  //인터럽트 핀. 펌웨어 쪽에서는 사용하지 않는 핀들을 전부 출력으로 설정해 준다.

  SREG &= 0x7F;  /*0111 1111, &= 이 의미는 형태 sreg 0x7F 가 앤드 형태로 들어가 있으니 다른 어떤 값이 들어오면 &시켜버린다. 즉 지금의 형태는 모든 인터럽트를 사용 안하겠다가 된다.*/

  DDRC = 0xFF;  //7세그먼트 쪽 입/출력 핀을 전부 출력으로

  EIMSK = 0x11;  //인터럽트 핀(0),(4) 두 개 사용

  EICRA = 0x02;  //falling edge 사용
  EICRB = 0x02;  //falling edge 사용
  
  SREG |= 0x80;  //현재 인터럽트를 쓰지 않고 main 함수 while문에서 다 끝내려 한다

  while(1)
  {
    if(PIND == 1 & cFlag == 0)//입력값이 들어왔을때 INT0 작동, 그 전까진 FOR문으로 숫자 증가 작업 중 
    {
      for(i = 0; i<10; ++i)
      {
        ito7seg_cal(i);    //이렇게 되면 0~9 까지 집어넣어서 세그먼트에 숫자를 표현되게 된다.
        DELAY(5000);
      }

      cFlag = 1;
    }
    else if(PINE == 1 & cFlag == 1)
    {
      for(i = 9; i > -1; --i)
      {
        ito7seg_cal(i);    //이렇게 되면 0~9 까지 집어넣어서 세그먼트에 숫자를 표현되게 된다.
        DELAY(5000);
      }

      cFlag = 0;
    }
  }
  return 0;
}

void ito7seg_cal(unsigned int tmp)//7세그먼트의 카운트 형태 함수 정의
{
  switch(tmp)
  {
    case 0 : 
      PORTC = bitcal(0,0,0,0,0,0,1);
      break;
    case 1 :
      PORTC = bitcal(1,0,0,1,1,1,1);
      break;
    case 2 :
      PORTC = bitcal(0,0,1,0,0,1,0);
      break;
    case 3 :
      PORTC = bitcal(0,0,0,0,1,1,0);
      break;
    case 4 :
      PORTC = bitcal(1,0,0,1,1,0,0);
      break;
    case 5 :
      PORTC = bitcal(0,1,0,0,1,0,0);
      break;
    case 6 :
      PORTC = bitcal(0,1,0,0,0,0,0);
      break;
    case 7 :
      PORTC = bitcal(0,0,0,1,1,0,1);
      break;
    case 8 :
      PORTC = bitcal(0,0,0,0,0,0,0);
      break;
    case 9 :
      PORTC = bitcal(0,0,0,0,1,0,0);
      break;
  }
}

unsigned char bitcal(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4, unsigned char c5, unsigned char c6, unsigned char c7)
{

  //return ( ( !c1 << 0 ) |( !c2 << 1 ) |( !c3 << 2 ) |( !c4 << 3 ) |( !c5 << 4 ) |( !c6 << 5 ) |( !c7 << 6 )  );
  
  return ( ( c1 << 0 ) |( c2 << 1 ) |( c3 << 2 ) |( c4 << 3 ) |( c5 << 4 ) |( c6 << 5 ) |( c7 << 6 )  );  //common - anode type(세그먼트가 직접 vcc를 받는 형태) 이기에 0 값을 보내줘야 전압차로 인해서 불이 켜진다.
}


진짜 화가난다 화가나



-제혁씨 코드-


//#include <avr/interrupt.h>

#include <stdlib.h>

#define PORTE   (*((volatile unsigned char *)0x2E))
#define DDRE    (*((volatile unsigned char *)0x2D))
#define PINE    (*((volatile unsigned char *)0x2C))

#define PORTD  (*((volatile unsigned char *)0x2B))
#define DDRD    (*((volatile unsigned char *)0x2A))
#define PIND    (*((volatile unsigned char *)0x29))

#define PORTA   (*((volatile unsigned char *)0x22))
#define DDRA    (*((volatile unsigned char *)0x21))
#define PINA    (*((volatile unsigned char *)0x20))

#define EICRA    (*((volatile unsigned char *)0x69))
#define EICRB    (*((volatile unsigned char *)0x6A))

#define SREG    (*((volatile unsigned char *)0x5F))

#define EIMSK   (*((volatile unsigned char *)0x3D))

#define EIFR    (*((volatile unsigned char *)0x3C))


char led = 0;
unsigned int num = 0;


void ito7seg_cal(unsigned int tmp);
unsigned char bitcal(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4, unsigned char c5, unsigned char c6, unsigned char c7);


void __vector_1(void)__attribute__((signal, used, externally_visible));

void __vector_1(void)
{
  volatile unsigned int dt;
  while((PIND & 0x01== 0)
  {
    if(num < 9)
    {
      num++;
      ito7seg_cal(num);
      for(dt = 0; dt < 20000; dt++);
    }
  }
  
  EIFR = 0x01;  //INT0 Interrupt END
}

void __vector_5(void)__attribute__((signal, used, externally_visible));

void __vector_5(void)
{
  volatile unsigned int dt;
  while((PINE & 0x10== 0)  
  {
    if(num > 0)
    {
      num--;
      ito7seg_cal(num);
      for(dt = 0; dt < 20000; dt++);
    }
  }
  
  EIFR = 0x10;  //INT4 Interrupt END
}



int main(void)
{
  volatile unsigned int dt = 0;

  unsigned int direction = 1;
  
  SREG = SREG & 0x7F; //Global Interrupt Disable MASK
  
  DDRE = 0x00;  // all input
  DDRD = 0x00;  // all input
  DDRA = 0xFF; // led output

  EIMSK = (1 << 0| (1 << 4) ; //INT0 MASK

  EICRA = 0x02;  // INT0 falling level
  EICRB = 0x02;  // INT4 falling level

  led = 0x01;
  
  SREG |= 0x80//Global Interrupt Disable MASK



  while(1)
  {
    
    /*PORTA = (~led);

    if(led == 0x80) direction = 0;
    if(led == 0x01) direction = 1;

    if(direction == 0) led = ( led >> 1 );
    if(direction == 1) led = ( led << 1 );

    for(dt = 0; dt < 5000; dt++);*/

    
  }
  

  return 0;
}






void ito7seg_cal(unsigned int tmp)
{
  switch(tmp)
  {
    case 0 : 
      PORTA = bitcal(0,0,0,0,0,0,1);
      break;
    case 1 :
      PORTA = bitcal(1,0,0,1,1,1,1);
      break;
    case 2 :
      PORTA = bitcal(0,0,1,0,0,1,0);
      break;
    case 3 :
      PORTA = bitcal(0,0,0,0,1,1,0);
      break;
    case 4 :
      PORTA = bitcal(1,0,0,1,1,0,0);
      break;
    case 5 :
      PORTA = bitcal(0,1,0,0,1,0,0);
      break;
    case 6 :
      PORTA = bitcal(0,1,0,0,0,0,0);
      break;
    case 7 :
      PORTA = bitcal(0,0,0,1,1,0,1);
      break;
    case 8 :
      PORTA = bitcal(0,0,0,0,0,0,0);
      break;
    case 9 :
      PORTA = bitcal(0,0,0,0,1,0,0);
      break;
  }
}

unsigned char bitcal(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4, unsigned char c5, unsigned char c6, unsigned char c7)
{

  //return ( ( !c1 << 0 ) |( !c2 << 1 ) |( !c3 << 2 ) |( !c4 << 3 ) |( !c5 << 4 ) |( !c6 << 5 ) |( !c7 << 6 )  );
  
  return ( ( c1 << 0 ) |( c2 << 1 ) |( c3 << 2 ) |( c4 << 3 ) |( c5 << 4 ) |( c6 << 5 ) |( c7 << 6 )  );
}


-느낀점-

인터럽트 쪽에 가보면 알 수 있다. 굉장히 심플하고도 간단한 생각이지만 그걸 구현을 못했다라는게 하루종일 기분이 안 좋았다.

내가 몰랐던 점은 숫자가 증가하거나 감소할때나 가만히 있을때 그 값에서부터 인터럽트가 걸리면 그 숫자가 진행되던 중에 그 숫자값에서 감소,증가 를 어떻게 코드로 표현하느냐에 있었다.

제혁씨의 경우 while의 조건에 (PIND & 0x10) == 0 이런식으로 !(PIND & 0x10) 이것과 동일한데 조금 풀어 쓴 코드를 썼다. 

나는 while문을 정확히 이해를 하고 있던것이 아니였다. c언어의 조건들의 포인트는 그 조건에 만족할 때 1값을 만들어 내겠다 에 있다.

즉, while 문의 PIND 쪽이 LOW LEVEL 이기에 &를 만족 시키지 못하고 == 0 과 같으므로 1값을 만들어내어 while 문을 돌리는 것 이다.

-동작 순서-

우선 일의 세분화를 시켜야 한다.

1. main 에서 뭘 하느냐 ?(인터럽트 작동을 안하는 조건은 몇가지가 있을까? 스위치를 둘다 안켰을 때, 스위치를 둘다 켰을 때 인터럽트 조건을 만족 하지 않기에 main으로 돌아와 하던 것을 반복한다. 이 때 while로 반복만 죽어라 시킨다. 숫자를 가만히 있게끔)

2. 현재 인터럽트 edge 셋팅을 falling으로 하라 했으니 켜졌다가 꺼지면 비로소 동작한다 라는 것을 명확히 하여 세분화 시킨다. 그리하여 인터럽트는 무엇을 하느냐?(INT0 부분은 +로 나타낸다, INT4 부분은 -로 나타낸다. 딜레이 정의가 필요할 것이고 또한 그 세그먼트 숫자를 정의한 함수에다가 인자로써 보내는 역활이 필요할 것이며 그 인자 변수를 전역에 선언하여 다 같이 그 숫자를 기본으로 증가,멈춤,감소 를 표현 할 수 있도록 해야 하겠다.)

저것을 정확히 동작하게끔 하려면 우선 인터럽트 스위치를 둘 다 킨 상태에서 시작하여 그 스위치를 껐을시 falling edge 가 만족하여 (low level == 0x00 또한 같은 역활) 그 쪽 인터럽트가 작동하게 된다.

그리고 if 문 안에 

  while((PIND & 0x01== 0)
  {
    if(num < 9)
    {
      num++;
      ito7seg_cal(num);
      for(dt = 0; dt < 20000; dt++);
    }
  }

이 부분을 보자면 우선은 증가가 됬건 감소가 됬건 가만히 있었던건 간에 그 전 숫자를 이미 표현 해 냈었기 때문에 우린 그냥 그 다음 숫자만 표현하면 되는 것이다. 나는 그렇게 생각 하지 않고 그 숫자를 표현해야 하고 ++ 을 시켜야 한다고 생각했다..     (ito7seg-cal(num); 다음에 num++; 이 와야 한다고 생각했다..)

즉, c언어의 컴파일 순서를 명확히 모른다 라는 결론이 도출된다 봐도 무방할 것 같다.

크게 반성해야 하며 다시 한 번 더 열심히 해야 함을 느낀다.