2015-02-15

모터를 돌려 봅시다 강좌 질문

모터 구동과 과련된 강좌에 질문내용과 답변을 정리한 글입니다.

출처 : cafe.naver.com/laydigital/

5-2. 모터를 돌려봅시다 C + AVR + 임베디드 여행
안녕하세요 오랜만(?)에 올리는 연습과제 수행입니다.
목적은 구조체를 사용하여 구현해보자 였습니다만...알려주셨던 구조체 연습 코드를 조금 변형하는 수준에서 멈췄습니다...;

[과제] ------------------------------------------------------------------
[과제1] SW1을 누르면 모터가 정방향으로 돌고, SW2를 누르면 정지하는 프로그램을 작성해 보세요.
[과제 2] [과제 1]의 프로그램에 모터의 상태가 바뀔 때마다, FND에 “STOP”, “GO”가 디스플레이되도록 프로그램을 추가해 보세요.
------------------------------------------------------------------------
위의 과제를 추가하여 아래와 같이

FND: STAN 표시:  모터 준비.
SW1 를 한번 누르면 FND: GOOO 회전
SW1 를 다시 누르면 FND: REVE 역회전
SW2 를 누르면 각상태에 상관없이 정지 FND: STOP 로 바꾸어 구성해 보았습니다.

질문1) 아래 코드 중 빨간색 switch~case 문을 한번만 써서 수행 해보고자 했지만 표현의 한계를 느끼고
2개를 사용하여 구성하게 됐습니다;;. 좀더 효율적인(?) 표현 방법이 떠오르지않아 고민하다 C구문 표현력의 한계를
느끼고 수행코드를 올리오니 살펴보시고 개선할 부분이나 보충할 부분이 보이시면 여과없이 알려주시기 바랍니다.


질문2) 각 SW 초기 상태는 PUSH(X): HIGH(1), PUSH(O): LOW(O)
EICRB = (1<<ISC41)|(1<ISC40)|(1<<ISC51)|(1<<ISC50);// 00:low_act, 01:logic_act, 10:falling_act, 11:rising_act
위와 같이 선언하였는데 sw1은 의도하지않게 falling(1->0)으로 동작하고 sw2만 rising(0->1) 형태로 동작하는데
문제점을 찾아볼려고 애썼지만 결국 못찾아서 질문으로 올립니다.


수행 코드.
/* MCU library setting */
#include <avr/io.h>  // i/o 
#define kilo 1000UL
#define mega (kilo*kilo)
#define F_CPU 16*mega    // necessary define for delay function (must)
#include <util/delay.h>  // library function for delay
#include <avr/interrupt.h>  //using for external interrupt 

/*Motor state define*/
#define STANDBY 0
#define GO      1
#define STOP    2
#define REVERSE 3

/*FND display*/
#define DSP_DATA PORTC
#define DSP_FIGU PORTG

/*FND Font*/
#define A 0
#define B 1
#define C 2
#define D 3
#define E 4
#define G 5
#define N 6
#define O 7
#define P 8
#define R 9
#define S 10
#define T 11
#define V 12
#define Y 13


void init_switch(void);
void init_motor(void);
void init_fnd(void);
void fnd_dsp(char val);
volatile uint8_t STATE_SW1=STANDBY;  //global Variable for external interrupt sw1
//volatile uint8_t STATE_SW2=STANDBY;  
uint8_t fnd_font[]={0x77,0x7f,0x39,0x3f,0x79,0x7d,0x37,0x3f,0x73,0xf7,0x6d,0x31,0x72,0x66}; //a,b,c,d,e,g,n,o,p,r,s,v,y


struct _motor_op
{
   uint8_t sw_state;
   uint8_t stop;
   uint8_t revese;
   uint8_t go;
   uint8_t standby; 
}motor_op[]=
 {
   {STANDBY,S,R,G,S},
   {GO     ,T,E,O,T},
   {STOP   ,O,V,O,A},       
   {REVERSE,P,E,O,N}
          
 };

int main(void)
{
    init_switch();
   init_motor();
   init_fnd();
 while(1)
 {
       cli();
       switch(motor_op[STATE_SW1].sw_state)  //switch(STATE_SW1)
 {
        case GO      : PORTB = (0<<PB6)|(1<<PB7),fnd_dsp(GO) ; break;
        case REVERSE : PORTB = (1<<PB6)|(0<<PB7),fnd_dsp(REVERSE) ; break;
        case STOP    : PORTB = (1<<PB6)|(1<<PB7),fnd_dsp(STOP) ; break;
        case STANDBY : PORTB = (0<<PB6)|(0<<PB7),fnd_dsp(STANDBY) ; break;
       }
        sei(); // 채터링 방지목적..
 }   
}

void init_switch(void)
{
 DDRE = (0<<DDE4)|(0<<DDE5);   // switch current input 
 EIMSK = (1<<INT4)|(1<<INT5);  // external interrupt enable
 EICRB = (1<<ISC41)|(1<ISC40)|(1<<ISC51)|(1<<ISC50);// 00:low_act, 01:logic_act, 10:falling_act, 11:rising_act
 sei(); 
}

void init_motor(void)
{
    DDRB = (1<<DDB6)|(1<<DDB7);    // motor current output
}

void init_fnd(void)
{
    DDRC = 0xff;    //display_data
 DDRG = 0xff;    //display_figure
}

void fnd_dsp(char val)
{
 uint8_t i;

 for(i=0; i<4; i++)  //20ms
 {
  
  switch(val)
  {
  case GO      : DSP_DATA = fnd_font[motor_op[i].go]; break;
  case REVERSE : DSP_DATA = fnd_font[motor_op[i].revese]; break;
  case STOP    : DSP_DATA = fnd_font[motor_op[i].stop]; break;
  case STANDBY : DSP_DATA = fnd_font[motor_op[i].standby]; break;
  }
  DSP_FIGU = (0x08>>i);
  _delay_ms(5);  // 5ms
 }
  }


ISR(INT4_vect) //external_sw1
{
   if(STATE_SW1==STANDBY || STATE_SW1 == STOP)
 STATE_SW1 = GO;
   else if(STATE_SW1 == GO)
    STATE_SW1 = REVERSE; 
   else if(STATE_SW1 == REVERSE)
    STATE_SW1 = GO;  
}

ISR(INT5_vect) //external_sw2
{
   if(STATE_SW1 == GO)
    STATE_SW1 = STOP;
   else if( STATE_SW1 == REVERSE)
    STATE_SW1 = STOP; 
   else if(STATE_SW1 == STOP || STATE_SW1 == STANDBY)
    STATE_SW1 = STANDBY;  
}







EICRB = (1<<ISC41)|(1<ISC40)|(1<<ISC51)|(1<<ISC50);// 00:low_act, 01:logic_act, 10:falling_act, 11:rising_act

1 < ISC40 
=>
1 << ISC40



struct _motor_op
{
uint8_t sw_state;
uint8_t stop;
uint8_t revese;
uint8_t go;
uint8_t standby; 
}motor_op[]=
{
{STANDBY,S,R,G,S},
{GO ,T,E,O,T},
{STOP ,O,V,O,A}, 
{REVERSE,P,E,O,N}

};
이 구조체에서 
sw_state와
stop,revese,go,standby 간에 연관성이 있나요?

스위치 각각이 현재 상태가 따로 운용되지 않아 보입니다.
구조체는 switch(button)의 상태라기 보다

motor 의 상태로 보입니다.

struct _motor_context_t {
uint8_t status;
struct {
uint8_t map[4];
} fnd_map[4]; // 0 : stop, 1 : reverse, 2 : go, 3 : standby
} motor_state =
{
STANDBY,
/* fnd_map[0] for stop */
{S,T,O,P },
{R,E,V,E },
{G,O,O,O},
{S,T,A, N}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////


/* MCU library setting */
#include <avr/io.h>  // i/o 
#define kilo 1000UL
#define mega (kilo*kilo)
#define F_CPU 16*mega    // necessary define for delay function (must)
#include <util/delay.h>  // library function for delay
#include <avr/interrupt.h>  //using for external interrupt 

/*Motor state define*/
#define STANDBY 3
#define GO      2
#define REVERSE 1
#define STOP    0

/*FND display*/
#define DSP_DATA PORTC
#define DSP_FIGU PORTG

/*FND Font*/
#define A 0
#define B 1
#define C 2
#define D 3
#define E 4
#define G 5
#define N 6
#define O 7
#define P 8
#define R 9
#define S 10
#define T 11
#define V 12
#define Y 13


void init_switch(void);
void init_motor(void);
void init_fnd(void);
void fnd_dsp(char val);

//volatile uint8_t STATE_SW2=STANDBY;  
uint8_t fnd_font[]={0x77,0x7f,0x39,0x3f,0x79,0x7d,0x37,0x3f,0x73,0xf7,0x6d,0x31,0x72,0x66}; //a,b,c,d,e,g,n,o,p,r,s,v,y

struct _motor_context_t {
    volatile uint8_t status;
    uint8_t map[4][4];
     // 0 : stop, 1 : reverse, 2 : go, 3 : standby
} motor_state =
{
    STANDBY,
/* fnd_map[0] for stop */
    { {S,T,O,P },
      {R,E,V,E },
      {G,O,O,O },
      {S,T,A, N}
 }
};


int main(void)
{
   init_switch();
   init_motor();
   init_fnd();
   DDRA = 0xff;
   PORTA = 0xff;
   _delay_ms(1000);
   while(1)
  {

       switch(motor_state.status)  //switch(STATE_SW1)
        {
        case GO      : PORTB = (0<<PB6)|(1<<PB7),fnd_dsp(GO) ; break;
        case REVERSE : PORTB = (1<<PB6)|(0<<PB7),fnd_dsp(REVERSE) ; break;
        case STOP    : PORTB = (1<<PB6)|(1<<PB7),fnd_dsp(STOP) ; break;
        case STANDBY : PORTB = (0<<PB6)|(0<<PB7),fnd_dsp(STANDBY) ; break;
       }

 }   
}

void init_switch(void)
{
 DDRE = (0<<DDE4)|(0<<DDE5);   // switch current input 
 EIMSK = (1<<INT4)|(1<<INT5);  // external interrupt enable
 EICRB = (1<<ISC41)|(1<<ISC40)|(1<<ISC51)|(1<<ISC50);// 00:low_act, 01:logic_act, 10:falling_act, 11:rising_act
 sei(); 
}

void init_motor(void)
{
    DDRB = (1<<DDB6)|(1<<DDB7);    // motor current output
}

void init_fnd(void)
{
    DDRC = 0xff;    //display_data
    DDRG = 0xff;    //display_figure
}

void fnd_dsp(char val)
{
 uint8_t i;

  for( i = 0 ; i < 4 ; i ++)
  {
      DSP_DATA = fnd_font[motor_state.map[val][i]]; DSP_FIGU = 8 >> i; _delay_ms(5);
  }
}

ISR(INT4_vect) //external_sw1
{
/*                          cur_state STOP, REVERSE, GO,     STANDYBY */
   static uint8_t state_trans[4] =   {GO   ,GO      ,REVERSE,GO};

   motor_state.status = state_trans[motor_state.status]; 

 _delay_ms(50);
 EIFR = 1 << 4;

}

ISR(INT5_vect) //external_sw2
{
/*                          cur_state STOP,      REVERSE, GO,     STANDYBY */
   static uint8_t state_trans[4] =   {STANDBY   ,STOP    ,STOP,   GO};

   motor_state.status = state_trans[motor_state.status]; 

 _delay_ms(50);
 EIFR = 1 << 5;

}

인터럽트 루틴에서는 각자 state_trans[] 가 있고
현재 상태를 넣으면 다음 상태를 알려주는 상태 천이 테이블입니다.
sw2인 경우
state_trans[STOP] = STANDBY 입니다.

즉 STOP에서 버턴이 눌러지면 STANDBY 를 리턴하는 테이블입니다.


No comments:

Post a Comment

Total Pageviews