하드웨어 설계에 관련한 공개 강좌를 게재하는 공간입니다.
운영진에 의해 강좌글은 편집되며, 공익을 위한 게시글은 '하드웨어 강좌'란으로 이동될 수 있습니다.
판매자 | 아크마 | 판매 납포인트 | 무료 | 평점 | 1.0점 / 총 1명 참여 |
---|
/***************************************************** Project : Version : Date : 2006-02-25 Author : akma Company : arcs Comments: Chip type : ATmega128 Program type : Application Clock frequency : 16.000000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 1024 *****************************************************/ /* interrupt 방식으로 하이패스를 통해 들어온 값을 adc를 이용하여 디지털로 변환하여 lcd에 출력하는 프로그램 */ #include <mega128.h> // Alphanumeric LCD Module functions #asm .equ __lcd_port=0x18 ;PORTB #endasm #include <lcd.h> #include <delay.h> #include <stdio.h> #define TIMER0_32PRESCALE_VALUE 2 // (1/16MHz)*32*1000000 #define SENSOR_ON_TIME 50 // 40us 후에 센서를 끔. #define SENSOR_OFF_TIME 250 // 트리거 신호의 주기 = 240us #define front_sen_on() PORTG=0x18 #define front_sen_off() PORTG=0x00 #define SENSOR_MODE_ON 1 #define SENSOR_MODE_OFF 2 typedef unsigned char byte; typedef unsigned int word; typedef unsigned long dword; word sensor_input[8]; dword sensor_temp[8]; byte sensor_mode; byte sensor_cnt=0; word adc_cnt = 0; word adc_max = 5; byte adc_idx; word i,j; #define ADC_VREF_TYPE 0x00 // ADC interrupt service routine interrupt [ADC_INT] void adc_isr(void) { word adc_data; adc_data=ADCW; sensor_temp[sensor_cnt] += adc_data; sensor_cnt++; ADMUX = sensor_cnt; // adc cheannel select if(sensor_cnt>=8) { sensor_cnt=0; adc_cnt++; } if(adc_cnt >= adc_max) { for(adc_idx=0;adc_idx<8;adc_idx++) { sensor_input[adc_idx]= sensor_temp[adc_idx]/adc_max; sensor_temp[adc_idx] = 0; } } /* 250us 이내에 8개 센서값 adc로 받기 - 8us주기로 되있어서 값이 잘 안나옴 너무 느림 if(sensor_mode == SENSOR_MODE_OFF) { ADCSRA|=0x40; } */ } // Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { TCCR0 = 0x00; if(sensor_mode == SENSOR_MODE_OFF) { front_sen_on(); sensor_mode = SENSOR_MODE_ON; TCNT0 = (byte)(0xff - (SENSOR_ON_TIME/TIMER0_32PRESCALE_VALUE)); TCCR0 = 0x03; //start timer }else if(sensor_mode == SENSOR_MODE_ON) { front_sen_off(); sensor_mode = SENSOR_MODE_OFF; ADCSRA|=0x40; // ADC Start Conversion TCNT0 = (byte)(0xff - (SENSOR_OFF_TIME/TIMER0_32PRESCALE_VALUE)); TCCR0 = 0x03; //start timer } } // 10비트 분해능으로 정상적인 동작 위해 50kHz~200kHz범위의 클럭이 사용되어야함 // 보통 그래서 128 프리스케일로 125kHz를 쓰고 변환 타이밍은 104us // 그러나 나는 2 프리스케일로 1us를 만들어 보려 한다....안정적인 전압의 문제로 실패할 가능성이 있다.. void adc_init(void) { ADCSRA = 0x00; //disable adc ADMUX = ADC_VREF_TYPE; // VRef ACSR = 0x80; //ADCSRA = 0xCF; ADCSRA = 0x89; // ADC Prescaler : 2, // Conversion time: 1uS // interrupt mode // ADEN=1로 설정하고 최초 변환에은 25변환 클럭과 13.5샘플/홀드 클럭이 소요된다. // 그 다음부터는 13변환 클럭와 1.5클럭 주기의 샘플/홀드 시간이 포함되되어 있다. // 25클럭만큼 시간을 벌어준다. //ADCSRA|=0x40; // ADC Start Conversion //delay_ms(100); } void main(void) { char lcd_buf[16]; DDRG = 0x18; DDRF = 0x00; // LCD module initialization lcd_init(8); lcd_gotoxy(0,0); lcd_putsf("adc test"); adc_init(); TCNT0 = 0xff; TCCR0 = 0x03; //start timer, prescale 32 TIMSK = 0x01; //timer 0 interupt sensor_mode == SENSOR_MODE_OFF; #asm("sei"); while (1) { for(i=0;i<8;i++) { sprintf(lcd_buf, "%d : %4d", i, sensor_input[i]); lcd_gotoxy(0,1); lcd_puts(lcd_buf); delay_ms(1000); //1초 지연 } }; }