재잼재잼의 티스토리

9. ADC 및 Cds 사용하기 본문

MCU

9. ADC 및 Cds 사용하기

재잼재잼 2019. 1. 28. 14:33

ADC에 대해서 알아보자.


이름그대로 Analog Digital Converter로, 아날로그 입력값을 디지털 값으로 바꿔주는 역할을 한다.


MCU로 입력되는 대부분의 값은 아날로그의 전압값으로, MCU에서 처리하기 위해서는 디지털 값으로 변환해주어야하는데 이를 ADC가 수행한다.



ATmega128에는 총 8개의 ADC채널이 있고, 이들은 하나의 멀티플렉서에 연결되어 있기 때문에 한번에 하나의 ADC채널을 사용할 수 있다.ㅣ


또한 10bit의 ADC를 가지고 있기 때문에 입력되는 아날로그 값을 0~1023의 값으로 표현할 수 있다.


값을 변환하기 위해서는 변환의 기준이 되는 값이 있어야하는데, 이는 AVCC, AREF, 내부 2.56V 3가지 중에서 선택할 수 있다.


AVCC는 5V, AREF는 외부에서 입력되는 전압을 기준으로 한다.


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


ADC를 사용하기 위해서 관련된 레지스터를 알아보자.


이름에서도 알 수 있듯이, 8개의 채널중 사용할 채널을 선택하는 레지스터다. 추가로 REFS1, REFS0비트를 설정하여 기준전압(AVCC, AREF, 2.56V)을 선택한다.


위와 같이 결정할 수 있다.


0 0 -> 외부의 AREF핀을 기준전압으로,

0 1 -> 외부 AVCC핀을 기준 전압으로,

1 1 - > 내부 2.56V를 기준전압으로 사용한다.



ADC제어 및 상태 레지스터다.


7번 비트(ADEN) : ADC Enable 비트로, 0으로 Clear하면 ADC기능이 꺼진다.


6번 비트 (ADSC) : ADC Start Conversion. 단일변환모드(Single Conversion)에서는 ADC변환을 시작할때 1로 set하고, 프리러닝(Free Running)모드에서는 첫번째 ADC변환을 할 때 1로 set한다.

ADSC비트는 변환이 완료되면 자동으로 0으로 clear되므로, 0를 set하는 것은 아무 영향을 미치지 않는다.


* ATmega128의 ADC에는 변환모드로 단일변환모드와 프리러닝모드를 지원한다.

- 단일변환모드(Single Conversion) - 변환시작신호(ADSC)가 1로 set되면 변환을 한번 수행하고 끝낸다.

- 프리러닝모드(Free Running) - 변환시작신호(ADSC)가 1로 set되면, 연속적으로 변환을 수행한다. 즉, 이전 변환을 완료하면 자동으로 다음 변환을 수행한다.


5번 비트 (ADFR) : ADC Free Running Select. 1로 set하면 ADC는 프리러닝모드로 동작한다. 


4번 비트 (ADIF) : ADC Interrupt Flag. ADC가 변환을 마치고, 데이터레지스터를 갱신하면 1로 set되는 플래그 비트다. ADIE비트와 전역인터럽트가 허용되어있을때(SREG의 I비트) 인터럽트가 발생한다.


3번 비트 (ADIE) : ADC Interrupt Enable. ADC변환 완료 인터럽트를 사용하기 위한 인터럽트 허용 비트.


2~0번 비트 : ADC에 공급할 클럭을 결정하는 변수로, 16Mhz를 사용할 경우, 50~200Khz 사이의 분주비를 사용하는 것을 권장하고있다.


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


실제로 ADC를 사용해보자.


가장먼저 ADC초기화를 해준다.


void ADC_init(void){

    ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //16Mhz/128 = 125Khz

    ADMUX |= (1<<REFS0);       //AVCC(5V)

    ADCSRA |= (1<<ADEN);      //ADC 인에이블

}


공급되는 클럭을 결정하고(128Khz), 기준전압을 결정하고(AVCC), ADC Enable 비트를 1로 set해준다.


int read_ADC(unsigned char channel){

   ADMUX &= 0xF0;

   ADMUX |= channel;

 

   ADCSRA |= (1<<ADSC); //변환 시작

   while(ADCSRA&(1<<ADSC)); //변환 완료되기를 기다림.


   return ADC; //ADC값 반환

}


ADC변환값을 반환하는 함수로, ADMUX에서 사용할 채널을 선택하여 변환을 한다.


단일변환모드에서는 변환이 완료되면 자동으로 ADSC비트가 clear되므로, while문을 통해서 완료될때까지 대기한다.


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


Cds센서는 빛의 양에 따라서 저항값이 변화하는 소자로, 받아들이는 빛의 양에 따라 변화하는 전압을 MCU의 핀으로 입력할 수 있다.


즉, 연속적으로 변화하는 아날로그 전압을 입력할 수 있기 때문에, ADC를 사용하여 디지털 데이터로 변환할 수 있다.


기본적인 예제인 주변이 어두워지면 LED가 켜지도록 해보자.


1. 현재 상태를 CLCD에 표시하기


2. ADC로 Cds센서 값 변환하기


3. 변환된 값으로 주변 광량에 따라 LED를 조절하기.



주변환경이 어두워지면 입력값이 증가하는데, 나의 경우 720이상일 경우 LED가 켜지도록 작성했다.




주변환경이 밝아지면 입력되는 값이 감소하고, 400이하로 떨어지면 LED가 꺼지도록 작성하였다.


LCD에 표시도 잘되고, UART로 확인해도 값이 정상적으로 잘 전송되는 것을 확인할 수 있다.


/*

 * ADC_practice.c

 *

 * Created: 2019-01-24 목 오후 1:42:13

 */ 

#include "text_LCD.h"

#include "UART1.h"

#include <avr/io.h>

#include <avr/sfr_defs.h>

#include <util/delay.h>

#include <stdio.h>

void PORT_init(void){

DDR_CTRL |= (1 << RS_PIN | 1 << RW_PIN | 1 << E_PIN);

DDR_DATA |= 0xF0;

DDRA = 0xFF;

PORTA = 0x00;

}


void ADC_init(void){

    ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //16Mhz/128 = 125Khz

    ADMUX |= (1<<REFS0);       //AVCC(5V)

    ADCSRA |= (1<<ADEN);      //ADC 인에이블

}


int read_ADC(unsigned char channel){

   ADMUX &= 0xF0;

   ADMUX |= channel;

   

   ADCSRA |= (1<<ADSC); //변환 시작

   while(ADCSRA&(1<<ADSC)); //변환 완료되기를 기다림.

   

   return ADC; //ADC값 반환

}


void print_ADC_val(char *value){

LCD_goto_XY(0, 10);

LCD_write_string("     ");

LCD_goto_XY(0, 10);

LCD_write_string(value);

}


void print_LED_stat(int stat){

LCD_goto_XY(1, 11);

LCD_write_string("   ");

LCD_goto_XY(1, 11);

if(stat == 1)

LCD_write_string("ON");

else if(stat == 0)

LCD_write_string("OFF");

}


int main(void)

{

int read;

char adc_str[5] = "0";

int led_stat = 0;

PORT_init();

LCD_init();

UART1_init();

LCD_write_string("ADC val : ");

LCD_goto_XY(1, 0);

LCD_write_string("LED stat : ");

LCD_write_string("OFF");

ADC_init();


    while (1) 

    {

read = read_ADC(0); //불켰을때, 300이상  불껐을때, 720이상

if(led_stat == 0 && read > 720){

led_stat = 1;

PORTA |= 0x01;

}

else if(led_stat == 1 && read < 400){

led_stat = 0;

PORTA &= ~(0x01);

}

sprintf(adc_str, "%d", read);

UART1_print_1_byte_number(read);

print_LED_stat(led_stat);

print_ADC_val(adc_str);

_delay_ms(1000);

    }

}


'MCU' 카테고리의 다른 글

10. 외부 인터럽트  (0) 2019.04.01
8. CLCD 사용하기(2)  (0) 2019.01.23
7. CLCD 사용하기  (0) 2019.01.22
6. UART 문자열 송/수신  (0) 2019.01.16
5.UART 문자 송/수신  (0) 2019.01.15