2015-02-15

1/00 스톱워치 만들기 질문 및 답변

해당강좌가 개설된 까페에서 스톱워치 만들기 강좌에 관한 질문 및 답변 정리 글입니다.

출처 : cafe.naver.com/laydigital/

안녕하세요 해당강좌를 공부한후에 과제를 수행후 기본강좌에서 궁금한점이 있어 질문올려봅니다.
아래 코드는 해당강좌에 기재하신 부분을 그대로 발췌하였습니다.

아래 코드에서

ISR(INT5_vect)
{           
           state = IDLE;                          
             cur_time = 0;                                   
             stop_time = 0;                              
}
이 루틴을 수행하고 나오면 cur_time 과 stop_time은 0으로 초기화되는데 궁금증에 IDLE 상태에서 받는변수를 stop_time이 아닌 cur_time 변수를 넣어주었더니 00.00 표시값이 아닌 00.01표시값이 나오고 한번더 스위치2번을 눌러서 ISR루틴을
실행해야지 00.00이 표시되는데 왜 그런지 잘 이해가 않되서 질문드려봅니다. 0으로 초기화되서 나왔는데 왜 1값이 증가된 상태로 main 의 state==IDLE 상태에서 표시값이 받는 변수값이 증가되어 입력된건지 궁금합니다.

 혹시 질문드린부분의 의미전달이 않될수도 있어서 아래 코드에서 수정한 부분을 빨간색으로 표시해 두었습니다.

/----------------------------------------------------------------------------------------------------------------------------------------/
#include <avr/io.h>                        
#include <avr/interrupt.h>  
#define F_CPU 16000000UL
#include <util/delay.h>
#define                IDLE       0            
#define                STOP     1            
#define                GO         2           
volatile int cur_time = 0;                    
volatile int stop_time = 0;                  
volatile int state = IDLE;            
                                            
unsigned char digit[]= {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07, 0x7f, 0x67};
unsigned char fnd_sel[4] = {0x01, 0x02, 0x04, 0x08};   

ISR(INT4_vect)
{            if (state == IDLE || state == STOP)   
                      state = GO;                  
             else                                               
             {
                      state = STOP;              
                           stop_time = cur_time;        
             }
}

ISR(INT5_vect)
{           
           state = IDLE;                          
             cur_time = 0;                                   
             stop_time = 0;                              
}

void init_stopwatch(void);                               
void display_fnd(int);                                   

int main()
{
             init_stopwatch( );
             while(1)
             {
                      if (state == IDLE)                                 
                                  display_fnd(cur_time);   //원래는 stop_time , 두변수는 sw2 ISR루틴에서 모두 0으로 초기화됨.
                                                                   
                      else if (state == STOP)              
                      {
                                  display_fnd(stop_time); 
                                  cur_time++;                  
                      }
                      else                                       
                      {
                                  display_fnd(cur_time);  
                                  cur_time++;                  
                      }
                           if (cur_time == 10000)                       
                                        cur_time = 0;
             }
}

void init_stopwatch(void)
{
             DDRC = 0xff;                      
             DDRG = 0x0f;                    
             DDRE = 0xcf;                     
           sei();                        
                                            
             EICRB = 0x0a;                  
             EIMSK = 0x30;                    
}

void display_fnd(int count)              
                                                                   
{           
             int i, fnd[4];                                    
                                                                  
             fnd[3] = (count/1000)%10;  
             fnd[2] = (count/100)%10;   
             fnd[1] = (count/10)%10;                
             fnd[0] = count%10;                        
           for (i=0; i<4; i++)                      
           {
                      if (i==2)
                                 PORTC = digit[fnd[i]] | 0x80;                
                      else
                                  PORTC = digit[fnd[i]];
                      PORTG = fnd_sel[i];
                      if (i%2)  _delay_ms(2);   
                      else      _delay_ms(3);   
           }
}


확인은 안해봤지만.

위의 코드에 잠재적인 atomic접근 문제가 있습니다.
2바이트짜리 state 및 counter 를
비인터럽트 루틴에서 사용하고
인터럽트에서 수정합니다.

critical section을 적용해 보시거나,
state를 char 타입으로 해 보세요.

critical section과 관련하여 이해도가 많이 부족합니다, 관련 용어를 이해하고 적용해보는 좋은 예가 있다면
알려주시면 감사하겠습니다.

atomic : 다른 인터럽트나 이벤트로부터 보호되며 최상의 우선순위를 가지고 실행 이라고 검색되는데, 설명해주신 용어를 이해하기엔 좀 버겁네여 아직 C언어 사용에만 급급해서 따라가고있습니다 ^^;
일단 알려주신 방법을 활용하여 연습했을땐 정상적으로 작동하네요.

http://cafe.naver.com/lazydigital/3450
참조하세요.
cur_time, stop_time 도 같은 이슈에 포함됩니다.

제가 이번주말에 어디를 가야 해서,

올려주신 소스에 대한 comment는 나중에 하겠습니다.

No comments:

Post a Comment

Total Pageviews