Gihak111 Navbar

ATmega 128에서 사용하는 A/D변환기 입니다.

아날로그 신호를 디지털 데이터로 변환하는 부호기 입니다. 10비트 분해능을 가진 8개의 입력 채널을 내장하고 있습니다.
8채널 아날로그 입력을 PORTF(ADC0~ADC7)로 입력 박아 멀티플렉서에 의해 A/D변환기로 입력됩니다.

ATmega128은 5V로 동작하는데요, 따라서 5V 이상의 신호가 너무 강하게 들어오면 회로에 손상이 가기 마련입니다. 따라서 입력을 받을 때 LC필터로 안정화 시켜 공급하는 것이 좋습니다.
5V에 레퍼런스 된 AREF가 들어온 5V를 최대값으로 해 줍니다. AREF를 3,3V로 하면 최대값이 3.3V가 됩니다. 또한, AVCC와 내부의 2.5 레퍼런스가 있습니자. 이렇게 3개중 하나를 선택해서 사용하면 됩니다.

받는 신호값이 최대를 넘어가면 그건 잘못된 설계입니다. 5V가 최대로 했는데 7V가 들어오면 그건 5V인 값으로 출력이 되겠지요. 하지만 레퍼런스는 입력 전압보다 높을 수 없습니다. 최대가 5V인 것이죠. 그 이상의 신호를 받고 싶으면 크기를 낮추는 회로를 구성해야 합니다. 반대로, 입력의 최대가 2.7V 라면 AREF를 5V보다는 3V로 설정하는 것이 더 좋습니다. 분해력을 더 높게 사용할 수 있기 때문이죠.

예를 들어 8V가 들어왔다고 합시다. 이를 5V 밑으로 떨구기 위해 다음 과 같은 회로를 구성합니다.

0~ 8v=>----10k저항-------pf
                   |
                10k저항
                   |
                 그라운드

이런 회로를 구성하는 것으로 8V를 4V로 내려서 공급하여 회로를 보호할 수 있습니다.

만일, AREF = 5V 일때 입력으로 2.5V가 들어오면 이는 512가 됩니다.
10 비트로 작동하기 때문에 0 ~ 1023까지 셀 수 있죠.

만일, 10비트 보다 더 쪼개고 싶으면 A/DC 12bit 칩을 추가로 달아 활용하거나, ATmega328같은걸 사용하면 됩니다.
요즘은 STMcro를 많이 사용한다고 하더군요.

입력으로 들어오는 신호는 흔들리기 마련입니다. 이를 해결하기 위해 하드웨어적으로, 소프트 웨어 적으로 해결책이 있습니다.

  1. 아날로그 입력선을 짧게 하고 주위에 그라운드 패턴을 많이 배치한다.
  2. AVCC에는 Vcc를 입력할 때 LC필터를 통해 공급한다.
  3. Vcc에 톤덴서를 달아서 ADC 입력핀 부근의 전원 잡음을 제거 한다.
  4. AD 변환 중에 출력상태를 스위칭 하지 않는다.

A/D변환기의 ADCL 레지스터.

A/D변환기의 레지스터를 총 2개가 있습니다. ADCL과 ADCH 입니다.
ADCL레지스터부터 보겠습니다.

ADCL 레지스터 Bit 7 6 5 4 3 2 1  
ADMUX REFS1 REFS0 ADLAR MUX4 MUX3 MUX2 MUX1 MUX0
  1. 비트 7, 6 REDS1, REDS0
    기준 전압을 정하는 비트 입니다. 다음의 표를 보고 설정합니다.
REFS1 REFS0 기준 전압 선택
0 0 AREF전압, 내부 Vref는 꺼진다.
0 1 AVCC전압, AREF핀에는 커페시터를 연결하여 0.1마이크로로 접지한다.
1 0 -
1 1 내부의 2.56V 기준전압을 활용한다. AREF핀에는 커페시터를 연결하여 0.1마이크로로 접지한다.
  1. 비트 5 ADLAR
    ADCH, ADCL에 쓰이는 형식을 지정합니다.
    ADLAR1 : 하위비트부터 10비트를 채웁니다. 상위 6비트는 사용하지 않습니다.
    ADLAR0 : 상위비트부터 10비트를 채웁니다. 하위 6비트는 사용하지 않습니다.
    총 16비트 안에서 10비트만 사용하는 겁니다.

  2. 비트 4 ~ 0 MUX4 ~ MUX0
    ADC 아날로그 입력채널을 선택하는 비트 입니다. 8개의 단극성 입력과 22개의 차동입력으로 구분됩니다.
    보통 차동은 잘 사용하지 않고 단일 입력만 사용한다고 합니다.

MUX4..0 단일 입력 차동입력(+)단자 차동입력(-)단자 이득
00000 ADC0      
00001 ADC1      
00010 ADC2      
00011 ADC3      
00100 ADC4      
00101 ADC5      
00110 ADC6      
00111 ADC7      

A/D변환기의 ADCH 레지스터.

다음은 ADCH 레지스터 입니다.

ADCH 레지스터 Bit 7 6 5 4 3 2 1  
ADCSRA ADEN ADSC ADFR ADIF ADIE ADPS2 ADPS1 ADPS0
  1. 비트 7 ADEN
    adc 허용 비트 입니다. aden = 1이면 동작이 허용되고, 0이면 동작이 정지 됩니다.

  2. 비트 6 ADSC
    ADSC 입니다. 1이면 ADC가 시작됩니다. 프리러인 모드에서 ADSC가 1이 되면 최조 ADC에서 25클럭이 필요하고 이후에는 매 13클럭으로 동작합니다. ADSC 도중에 ADSC 비트를 읽으면 1이고, 변환이 완료되면 0이 됩니다.

  3. 비트 5 ADFR 이 비트를 1로 설정하면 ADC가 프리러닝모드로 동작합니다. ADC를 연속적으로 실행하죠. 변환이 완료되어도 0으로 세트되지 않고 자동적으로 다음 변환이 시작되는 모드 입니다. 보통 이 모드를 사용합니다.

  4. 비트 4 ADIF AD 변환이 완료되고 결과값이 갱신되면 1이 됩니다. ADIE = 1, SREG1 = 1이면 ADC 완료 인터럽트 처리 루틴을 실행하고 0으로 지워집니다. 이 플래그를 강제적으로 0으로 지우려면 1을 사용하면 됩니다.
    SREG 레지스터는 무슨 인터럽트든 사용한다면 7번 비트만 1로 설정해주면 되는 레지스터 입니다.

  5. 비트 3 ADIE
    ADC 완료 인터럽트를 허용하는 비트입니다. 이 비트와 SREG의 비트를 1로 설정한다면 AD 완료 인터럽트가 발생될 때 ADC 완료 인터럽트 처리 루틴을 실행합니다.

  6. 비트 2 ~ 0 ADPS2 ~ 0
    ADC 입력 클럭의 분주비를 선택하는 비트입니다.
    보통 101 비트를 사용합니다.

ADPS2 ADPS1 ADPS0 분주비
0 0 0 2
0 0 1 2
0 1 0 4
0 1 1 8
1 0 0 16
1 0 1 32
1 1 0 64
1 1 1 128

코드

다음은 위의 레지스터를 활용해 코딩하여 ADC를 직접 컨트롤 하는 코드 입니다.

void InitADC(void)
{
    ADMUX = 0x00;   //00 0 00000
    
    ADCSR = 0xE5;   //ADC enable, ADC start conversion, Free_run mode, Prescaler 32
}
//ADMUX:
//00 => 기준전압으로 AREF핀을 사용합니다.
//0 => ADCH, ADCL의 하위비트부터 10비트를 채웁니다. ADCH는 비트 1 ~ 0을, ADCL은 비트 7 ~ 0을 사용합니다.
//00000 => 단일 입력채널 ADC0 ~ ADC7을 사용합니다.

// ADCSR:
//ADEN = 1 => ADC 동작을 허용합니다. ADSC = 1 => AD변환을 시작합니다.
//ADFR = 1 => ADC가 프리러닝 모드로 동작합니다.
//ADIE = 0 => ADC 인터럽트는 사용하지 않습니다.
//ADPS2 ~ 0 = 101 => ADC 입력 클럭의 분주비를 32분주로 설정합니다.


unsigned int ReadADC(unsigned char channel)
{
    //변수 설정 입니다.
    unsigned int AdcDet = 0;
    unsigned int AdcSum = 0;
    unsigned char i, AdcDetL, AdcDetH = 0;


    //읽어낼 단일 입력 채널을 설정합니다. 트 4 ~ 0은 00000 ~ 00111의 값을 가집니다.
    ADMUX = channel;    //Select Channel

    for(i = 0; i < 20; I++>)    //A/D값을 20회 읽어서 평균값을 낸다.
    {
        //ADCSR 레지스터의 ADIF 비트가 1이 될 때 까지 기다린다. 즉, AD변환이 완료될 때까지 기다린다.
        while(!(ADCSR&0x10));
        Delay(70);  //결과값을 읽기 전에 약간의 딜레이를 건다. 20회 읽는 시간을 벌고 값을 갱신하는 시간을 보장하기 위함이다.
        ADCSR |=0x10;   //ADIF 비트에 1을 써서 강제로 지운다.

        결과값을 넣어 20 축적한다.
        AdcDetL = ADCL;
        AdcDetH = ADCH;
        AdcDet = (((AdcDetH&0xff)<<8) \ (AdcDetL&0xff))
        AdcDetSum += AdcDet;
    }
    AdcDetSum /= 20;    //평균값을 계산한다.
    return AdcDetSum;   //검출한 변환값을 반환한다.

}

위의 코드로 간단하게 설정할 수 있습니다.