2015-02-15

광센서를 이용한 가로등 만들기 강좌

광선세를 이용해 가로등을 만들어보는 연습 코드와 관련한 질문을 정리한 글입니다.

출처 : cafe.naver.com/laydigital/

6-2. 해지면 켜지고 해뜨면 꺼지는 가로등
과제] ------------------------------------------------------------------

1.     100 Lux 정도에서는 2개의 가로등(LED)만 켜지고, 10 Lux 가 되면 4개, 1 Lux 가 되면 8개의 가로등(LED)이 켜지도록 함
2.     주위환경에 의하여 경계점에서 불이 꺼졌다 켜졌다하는 것을 방지하기 위하여 각 가로등은 일단 한 번 켜지면 어느 정도 수준까지 밝아지지 않으면 꺼지지 않고, 반대로 한 번 꺼지면 어느 정도 수준까지 어두어지지 않으면 켜지지 않도록 함(즉, 완충 공간을 설정)
 ------------------------------------------------------------------------

6-2 강좌에 있던 수행과제 입니다. 코드작성하면서 궁금증이 생겨서 질문 드립니다.
아래는 제가 과제조건에 맞추어 작성한 코드입니다.

질문1 은 아래 작성한 코드중에  while((ADCSRA & adc_start) != adc_start); // question?
이부분이 있는데요, 강좌에서는 (1<<ADIF)로 비트를 확인해서 시작과 끝을 확인해서 ADCH,ADCL data 를 read
하는데요, single mode 에서 바로 (1<<ADSC)를 사용자 set 해주고 시작시키면 conversion 완료시ADSC bit 자동으로 hardware clear된다고 해서 사용했는데 큰 무리가 없는지 일단 궁금합니다. 사용자가 conversion 중에 set 해도 영향을 주지않는다고 해서 괜찮다고 봤거든요.

질문2 는 C언어 문법에 대해  while((ADCSRA & adc_start) != adc_start);  이 mian 안에서 실행될때 실제로
int main()       ---- 1
{
  while(!)        ---- 2
  {
     single_conversion_mode()   ----- 3
  }  
}
위와 같은 구성에서 함수 3 안의 while((ADCSRA & adc_start) != adc_start); 는 함수3안에 있는 while문 아래 있는 code들은  실제로 while() { loop } 형태로 구성하면 원하는 구현동작을 실행시키지 않았습니다. 다른 if(){}형태도 마찮가지 이고 이 loop를 구성하면 뭔가 오작동이 일어나는데 뭔가 타이밍이 않맞는건지 왜그런지 몰라서 이유가 궁금해서 일단 질문으로 정리해봤습니다.

질문3  state_check() 함수를 만들어서 예전 올려주신 자료  [C+AVR 보충자료] high water / low water mark 를 참조해서 코드로 구현했는데  마음에 썩 들지가 않아서 좀더 괜찮은 표현형태나 방법이 있다면 알려주시면 대단히 감사하겠습니다.
물론 작동은 되는데 조건에 충실히 작동되는지 파악해보기 좋은 방법이 떠오르지 않아서 도움을 구합니다.

-------------------------------------------------------------------------------------------------------------------

#include <avr/io.h>

void init_adc_conversion(void);
//void alternative_func_set(void);
uint16_t single_conversion_mode(void);
uint8_t state_check(uint16_t val);

#define _1000lux 1000
#define _100lux 901
#define _10lux 871
#define _1lux 92
#define OFF 0
#define DAY 1
#define NIGHT 2
#define MidNight 3

#define  lights PORTA

struct lux_led
{
  uint16_t ref_val;
  uint8_t  led_num;
             
}light_senosr[]=
{
 {_1000lux,0x00},
 {_100lux,0x03},
 {_10lux,0x0f}, 
 {_1lux,0xff} 
};          //       cds: 10 lux - 35k,  100lux: 8k,  1lux: 2000k 

int main(void)
{
 uint16_t return_val;//,state=DAY;
 init_adc_conversion(); //adc initiate                        
 DDRA = 0xff; //led initiate

 struct lux_led *ptr= light_senosr;

 while(1)     //loop
 {
  return_val = single_conversion_mode();
  
  switch(state_check(return_val))
  {
   case OFF:      lights= ptr[OFF].led_num;      break;
   case DAY:      lights= ptr[DAY].led_num;      break;
   case NIGHT:    lights= ptr[NIGHT].led_num;    break;
   case MidNight: lights= ptr[MidNight].led_num; break;
  }
  
 }

}

void init_adc_conversion()
{
  ADMUX |= (0<<MUX4)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);  //AD0 enable.
  ADMUX &= ~(1<<ADLAR); //right present.
  ADMUX |= (0<<REFS1)|(0<<REFS0); //ADREF, internal  Vref turned off
  ADCSRA |= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);  //adc: enable, ad prescale select 111: 128 
  ADCSRA &= ~(1<<ADFR); // ad free running mode 0: single, 1: enable. 
}


uint16_t single_conversion_mode()
{
   uint16_t adc_val,adc_regH;
   uint8_t adc_start, adc_regL;//,adc_flag;
  
   //adc_flag = (1<<ADIF);
   adc_start = (1<<ADSC);
   ADCSRA |= adc_start;           //in single, software give set signal ADSC bit for each single start.
  
   while((ADCSRA & adc_start) != adc_start); //question?
    //PORTA = 0x01;
     adc_regL = ADCL;   // low bit must read before high bit
     adc_regH = ADCH;   // if read ADCH bit conversion data first will update immediately
     adc_val = (adc_regH<<8)|(adc_regL);
     
   return adc_val;
   
}


uint8_t state_check(uint16_t val)
{
  uint16_t state = NIGHT;

  if (state == NIGHT)
  {
   if(900 <=val) state = DAY;
   
   else if((871>val) && (901>val) && (val>=871)) state = NIGHT;
   
   else if ((92<val)&&(871>val)) state = MidNight;
   
  }
  
  if(state == DAY) 
  {
   if((901<val) && (901>=val) && (val>871)) state = DAY;
         
   else if(871>=val) state = NIGHT;
   
  }
  
  if(901<val) state = OFF;

  return state;
}


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

1. ADC 를 동작시키는 ADCSRA의 
비트 6 (ADSC)는 adc 변환을 시작 시키는 비트이고
종료를 체크하는건 비트 4(ADIF) 입니다.
single conversion 모드시에는
ADCSRA |= (1 < ADSC);
while(ADCSRA & (1 << ADIF));
ADCSRA |= (1<< ADIF);
이게 정상적인 과정입니다.
ADIF 는 해당 비트를 1로 쓰기 하거나, 또는 ADC 인터럽트 루틴이 enable 되어서 인터럽트 루틴으로
진입할때 clear 됩니다.

ADSC비트를 체크하도록 코딩하신것 같은데요?

2. ADIF flag를 체크하도록 코딩하시면 되겟죠.

uint8_t state_check(uint16_t val)
{
uint16_t state = NIGHT;

state 변수를 위처럼 선언하면 매번 함수 호출시마다 NIGHT가 됩니다.
해당변수를 state_check에서만 사용하고 계속 그 값이 유지 되게 하실려면

static uint8_t state = NIGHT;
// 8비트로도 충분하므로


if (state == NIGHT)
{
if(NIGHT_TO_DAY <= val) state = DAY;

// 이 줄은 필요없음.. else if((871>val) && (901>val) && (val>=871)) state = NIGHT;

else if ((92<val)&&(871>val)) state = MidNight;

}

if(state == DAY) 
{
if((901<val) && (901>=val) && (val>871)) state = DAY;

else if(871>=val) state = NIGHT;

}

uint8_t state_check(uint16_t val)
그리고 이 함수가 3개의 상태에 대한 코드로 작성되어 있지 않네요(midNight에서 전환하는 
코드가 없음)

No comments:

Post a Comment

Total Pageviews