출처 : 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