05. ADC 변환

안양진·2022년 8월 23일
0

ATmega128

목록 보기
7/7
post-custom-banner

주변 환경에서 얻을수 있는 데이터들은 모두 아날로그 데이터이다.
하지만 우리가 사용하는 전자기기들의 데이터들은 0과 1로만 이루어진
디지털 신호로만 이루어져있다.
떄문에 이러한 자연의 아날로그 신호를 전자기기가 처리할 수 있게끔 변환 시켜주는 방법이 바로 아날로그-디지털 변환기(Analog-Digital Converter, ADC)라고 한다,

ATmega128은 아날로그 데이터를 디지털 데이터로 변환하기 위한 비트가 10개가 있다.
즉 전압을 0~1023(=2^10-1)사이의 디지털 값으로 변환 할수 있는 것이다
ADC 채널은 8개로 8개의 아날로그 출력장치를 ATmega128에 연결한수 있다. 하지만 8개의 채널은 하나의 AD 변환기에 멀티플렉스(Multiplexer, MUX)로 연결되어 있으므로 한번에 하나의 아날로그 입력만 변환 할 수있다.
8개의 채널은 포트 F의 PF0~PF7까지 있다.

ADC를 함에 있어 고려할점 중 하나가 바로 몇 볼트를 1023으로 변환할 것인가 이다. 기준 전압은 AD 변환에 있어서 최대갓으로 변환되는 전압을 의미한다. ATmega128에서는 기준 전압으로 AVCC(Analog VCC), AREF(Analog Reference), 내부 2.56V중 하나를 선택하여 사용할 수 있다.
AVCC는 보통 VCC와 동일하게 5V가 가해진다. 5V이외의 기준을 잡고자 한다면, AREF 핀에 5V 이하의 전압을 연결해주면 된다. 그외 내부 2.56V를 기준으로 사용할 수 있다.

예를 들어 5V가 기준이라고 했을때
이를 나누면 5/1023= 4.89mV 씩의 차이마다 변화를 인식한다.

하지만 주의할 점이 있다.

  • 낮은 해상동
  • 잡음
  • 아날로그 신호의 좁은 전압 범위

낮은 해상도의 경우 보다 높은 ADC 칩을 사용하면 해결할 수 있다.

잡음의 경우에는 차동 입력(differential input)을 통해 보완할 수 있다. 신호의 크기를 접지(GND)와 비교하는 방식인 단일(Single-Ended) 입력과 달리 차동 입력은 2개의 핀 입력((+)입력과 (-)입력)으로 신호를 받아 이들의 차이를 ADC의 입력으로 받아 들이는 방식이다.
단일입력의 경우 잡음또한 그래도 반영되는것과 달리, 차동 입력은 2개의 핀에 잡음이 공통으로 들어올경우 잡음이 상쇄되는 효과를 얻을수 있다.
물론 공통 잡음이 입력되는 공통 모드 잡음(common mode noise)이 아닌 경우에는 잡음제거효과를 기대할 수 없다.

위 둘의 또 다른 차이점으론 디지털로 변환 할수 있는 범위의 차이이다.
단일의 경우 GND를 기준으로 하므로 변환할 수 있는 최소값이 항상 0V 이다. 따라서 단일입력에서 2.5V기준 전압을 사용할 경우 변환 가능 범위가 0V~2.5V라는 위미이다. 하지만 차동의 경우 2V~4.5V 범위의 전압을 변환 할수 있으며, 이때는 2V의 값이 0에 해당된다. 하지만 차동의 경우 각 입력에 가해지는 전압은 GND와 AVCC범위 내에 있어야 한다.

ADC 레지스터

1. ADC=ADCH+ADCL

AD 변환한 디지털 데이터를 저장하는 레지스터이다.
ATmega128에서의 레지스터는 모드 8비트를 지원한다. 때문에 변환된 데이터의 값은 2개의 레지스터에 나눠져서 저장된다.
ADCH와 ADCL 16개의 비트중 6개의 비트는 사용하지 않으며, 데이터 정렬 방식에 따라서 상위 또는 하위 6개의 비트 비사용 여부가 정해진다.
기본값은 우측 정렬이다.

우측 정렬
비트15141312121098
ADCH------ADC9ADC8
ADCLADC7ADC6ADC5ADC4ADC3ADC2ADC1ADC0
비트76543210
좌측 정렬
비트15141312121098
ADCHADC9ADC8ADC7ADC6ADC5ADC4ADC3ADC2
ADCLADC1ADC0------
비트76543210

2. ADMUX

비트76543210
이름REFS1REFS0ADLARMUN4MUX3MUX2MUX1MUX0
초기값00000000

이름비트설명
REFS17AD변환을 위한 기준 전압과 입력 채널 선택을 위한 레지스터
REFS06-
ADLAR
(ADC Left Adjust Result)
51 : 좌측 정렬
0 : 우측 정렬
MUN44ADC에 입력으로 가해지는 전압을 선택하는 레지스터
ATmega128은 단일, 차동을 지원한다.
또한 차동 입력 시에 이득을 정할 수 있다.
MUX33
MUX22
MUX11
MUX00

REFSn 표

REFS1REFS0설명
00외부 AREF 핀 입력을 기준 전압으로 사용
01외부 AVCC 핀 입력을 기준 전압으로 사용
10
11내부 2.56V를 기준 전압으로 사용

ADLART설명
0우측 정렬(기본값)
1좌측 정렬

MUXn 비트 설정 표
MUX단일 입력차동 +차동 -이득
00000ADC0
00001ADC1
00010ADC2
00011ADC3
00100ADC4
00101ADC5
00110ADC6
00111ADC7
01000ADC0ADC010x
01001ADC1ADC010x
01010ADC0ADC0200x
01011ADC1ADC0200x
01100ADC2ADC210x
01101ADC3ADC210x
01110ADC2ADC2200x
01111ADC3ADC2200x
10000ADC0ADC11x
10001ADC1ADC11x
10010ADC2ADC11x
10011ADC3ADC11x
10100ADC4ADC11x
10101ADC5ADC11x
10110ADC6ADC11x
10111ADC7ADC11x
11000ADC0ADC21x
11001ADC1ADC21x
11010ADC2ADC21x
11011ADC3ADC21x
11100ADC4ADC21x
11101ADC5ADC21x
111101.23V(V bg)---
111110V(GND)---

3. ADCSRA

비트76543210
이름ADENADSCADFRADIFADIEADPS2ADPS1ADPS0
초기값00000000

이름비트설명
ADEN7ADC 활성화 비트
ADSC6AD변환을 시작하도록 하는 비트
단일모드에서는 각 변환을, 프리러닝 모드에서는 첫 번째 변환을 시작하기 위해 사용한다.단일모드에서는 변환이끝나면 알아서 0으로 초기화 된다.
ADFR
(ADC Left Adjust Result)
50 : 단일 변환 모드
1 : 프리러닝 모드
ADIF4AD 변환이 종료되고 데이터 레지스터가 업데이트 되면 1로 세트된다.
ADIE3AD 변환이 끝났을때 인터럽트 발생 허용 비트이다
이떄 실제로는 SREG 레지스터의 I 가 세트되어 있어야 한다.
즉 AD 변환이 끝나고 ADIF 세트 되었을때
ADIE와 SREG의 I가 세트 되었을때 AD 변환 완료 인터럽트가 발생한다.
ADPS22-
ADPS11-
ADPS00사용되는 클럭의 분주율을 설정한다.

ADPSn 표

ADPS2ADPS1ADPS0분주율
0002
0012
0104
0118
10016
10132
11064
111128
//************************************************************************
//  Ex9-1.c 
//************************************************************************

// ADC0 단극성 입력, 단일 변환, 128분주, VREF=AREF

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include "lcd_2_line.h"

int main(void)
{
	int ADval;
	double Vin, Vref=5.0;
	char msg[16];

	LCD_init();  				// LCD 초기화
	
	DDRF = 0x00;				// 포트 F 입력  
	ADMUX = 0x40;			// VREF=AREF, ADC0 단극성 입력
	ADCSRA = 0x87; 		// 단일변환, 128분주
	_delay_ms(5); 

	while(1) 
	{
		
				

		ADCSRA = ADCSRA | 0x40; 		// ADSC=1 변환시작
		while((ADCSRA & 0x10) == 0);	// ADIF=1 ?, 변환완료 체크
		ADval = (int)ADCL + ((int)ADCH << 8);
		Vin = (double)ADval*Vref/1023.0;		// val=(Vin*1024)/Vref
		LCD_goto_XY(0, 1); 		// LCD 1행 1열에 표시
		sprintf(msg, "ADC0 = %.2lf[V]", Vin);
		LCD_write_string(msg); 					// LCD에 A/D 변환 결과 표시
		_delay_ms(1000);
	}
}
post-custom-banner

0개의 댓글