광선세를 이용해 가로등을 만들어보는 연습 코드와 관련한 질문을 정리한 글입니다.
출처 : 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