본문 바로가기
MCU/AVR

[AVR128DB48] ADC 및 DAC 사용 방법 및 예제 코드

by linuxgo 2025. 8. 20.
반응형

1. AVR128DB48 ADC 및 DAC 모듈 개요

Microchip의 AVR128DB48은 8비트 AVR DB 시리즈 마이크로컨트롤러로, 12비트 차동 아날로그-디지털 변환기(ADC)와 10비트 디지털-아날로그 변환기(DAC)를 포함하여 센서 데이터 처리, 아날로그 신호 생성 등 다양한 아날로그 애플리케이션에 적합합니다. 이 문서는 ADC와 DAC의 설정 방법, Bitfield 구조를 활용한 레지스터 설정, 그리고 실용적인 예제 코드를 제공하여 초보자와 숙련된 개발자 모두 쉽게 활용할 수 있도록 돕습니다.

ADC 주요 사양

  • 해상도: 12비트 (차동 및 단일 종료 모드)
  • 채널: 최대 22개의 단일 종료 입력 (PORTA, PORTB, PORTF의 특정 핀)
  • 샘플링 속도: 최대 375ksps (24MHz 시스템 클럭 기준)
  • 레퍼런스: 내부 1.024V, 2.048V, 2.5V, 4.096V, VDD, 외부 레퍼런스
  • 모드: 단일 변환, 프리 러닝, 윈도우 비교, 샘플 누적 (최대 128 샘플)
  • 주요 레지스터:
    •   ADC0.CTRLA: ADC 활성화 및 모드 설정
    •   ADC0.MUXPOS: 입력 채널 선택
    •   ADC0.RES: 변환 결과
    •   ADC0.WINCMP: 윈도우 비교 레지스터
  • 인터럽트: 결과 준비 완료, 윈도우 비교 인터럽트 지원

DAC 주요 사양

  • 해상도: 10비트
  • 출력 채널: DAC0 (PA6 핀)
  • 레퍼런스: 내부 1.024V, 2.048V, 2.5V, 4.096V, VDD
  • 주요 레지스터:
    •   DAC0.CTRLA: DAC 활성화 및 출력 설정
    •   DAC0.DATA: 출력 데이터
  • 특징: 저전력 모드 지원, 외부 핀 출력 가능

전원 및 클럭

  • 전압 레벨: 1.8V~5.5V
  • 클럭 소스: 시스템 클럭 (최대 24MHz, OSCHF 내부 오실레이터)
  • 전력 관리: ADC 및 DAC의 저전력 모드 지원

2. ADC 및 DAC Bitfield 설정 상세

AVR128DB48의 ADC 및 DAC 레지스터는 Bitfield 구조로 정의되며, <avr/io.h> 헤더 파일을 통해 접근합니다.

2.1 ADC 주요 레지스터

  • ADC0.CTRLA:
    •   ENABLE: ADC 활성화 (1: 활성화)
    •   FREERUN: 프리 러닝 모드 (1: 활성화)
    •   RESSEL: 해상도 선택 (0: 12비트, 1: 10비트)
  • ADC0.MUXPOS: 입력 채널 선택 (예: ADC_MUXPOS_AIN0_gc for PA0)
  • ADC0.COMMAND: 변환 시작 (STCONV_bm)
  • ADC0.RES: 변환 결과 (12비트 또는 10비트)
  • ADC0.WINCMP: 윈도우 비교 값 설정

2.2 DAC 주요 레지스터

  •   DAC0.CTRLA:
    •   ENABLE: DAC 활성화 (1: 활성화)
    •   OUTEN: 출력 핀(PA6) 활성화 (1: 활성화)
  •   DAC0.DATA: 10비트 출력 데이터 (0~1023)

3. ADC 및 DAC 설정 절차

ADC 설정

  1. 시스템 초기화:
    •   시스템 클럭 설정 (24MHz, XOSC32K 오토튜닝)
    •   인터럽트 비활성화 (cli())
  2. ADC 클럭 활성화:
    •   별도의 클럭 활성화 불필요 (시스템 클럭 사용)
  3. 레퍼런스 설정:
    •   VREF.CTRLA로 ADC 레퍼런스 전압 설정 (예: 2.5V)
  4. 입력 채널 선택:
    •   ADC0.MUXPOS로 아날로그 입력 핀 선택 (예: PA0)
  5. ADC 활성화:
    •   ADC0.CTRLA로 ADC 활성화 및 모드 설정
  6. 변환 시작:
    •   ADC0.COMMAND로 변환 시작 또는 프리 러닝 모드 설정
  7. 결과 읽기:
    •   ADC0.RES에서 변환 결과 읽기

DAC 설정

  1. 시스템 초기화:
    •   시스템 클럭 설정 (24MHz, XOSC32K 오토튜닝)
  2. 레퍼런스 설정:
    •   VREF.CTRLA로 DAC 레퍼런스 전압 설정 (예: 2.5V)
  3. DAC 활성화:
    •   DAC0.CTRLA로 DAC 활성화 및 출력 핀(PA6) 설정
  4. 출력 데이터 설정:
    •   DAC0.DATA에 10비트 데이터 작성
  5. 출력 확인:
    •   PA6 핀에서 아날로그 출력 확인

4. ADC 및 DAC 설정 고려사항

  • 클럭 안정성: 시스템 클럭과 XOSC32K 안정화 확인
  • 레퍼런스 전압: ADC와 DAC의 레퍼런스 전압 일치 주의
  • 노이즈: 아날로그 입력 핀에 외부 노이즈 필터 추가 권장
  • 인터럽트: ADC 결과 준비 완료 인터럽트로 효율적 데이터 처리
  • 저전력: ADC 프리 러닝 모드 비활성화 시 전력 소모 감소
  • 핀 충돌: PA6(DAC 출력)과 다른 주변 장치 멀티플렉싱 충돌 주의
  • ADC 샘플 누적: 최대 128 샘플 누적 가능, 고해상도 애플리케이션에 유용

5. 실용적인 ADC 및 DAC 예제 코드 (Bitfield 구조)

아래는 AVR128DB48의 ADC 및 DAC를 Bitfield 구조로 설정한 3개의 예제 코드입니다. 각 예제는 Atmel Studio 또는 MPLAB X IDE와 AVR-GCC 환경에서 실행 가능합니다. ADC는 12비트 해상도를 사용하도록 수정되었습니다.

5.1 예제 1: 기본 ADC 입력 (전압 읽기)

// File: adc_basic.c
// Description: AVR128DB48 ADC 기본 입력 예제 (PA0 전압 읽기, 12비트)
// Compiler: AVR-GCC
// Target: AVR128DB48

#include <avr/io.h>        // AVR 입출력 관련 헤더 파일
#include <util/delay.h>    // 지연 함수 관련 헤더 파일

#define F_CPU 24000000UL  // 시스템 클록 주파수를 24 MHz로 정의

void set_system_clock(void) {
    _PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
    while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
    _PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
}

void adc_init(void) {
    VREF.CTRLA = VREF_ADC0REFSEL_2V5_gc; // ADC 레퍼런스 2.5V 설정
    PORTA.DIRCLR = PIN0_bm;              // PA0 입력 설정
    ADC0.MUXPOS = ADC_MUXPOS_AIN0_gc;    // PA0를 ADC 입력으로 선택
    ADC0.CTRLA = ADC_ENABLE_bm;          // ADC 활성화, 12비트 모드
}

uint16_t adc_read(void) {
    ADC0.COMMAND = ADC_STCONV_bm;        // 변환 시작
    while (!(ADC0.INTFLAGS & ADC_RESRDY_bm)); // 결과 준비 대기
    uint16_t result = ADC0.RES;          // 12비트 결과 읽기
    ADC0.INTFLAGS = ADC_RESRDY_bm;       // 인터럽트 플래그 클리어
    return result;
}

int main(void) {
    set_system_clock(); // 시스템 클록 설정
    adc_init();         // ADC 초기화

    while (1) {
        uint16_t adc_value = adc_read(); // PA0에서 12비트 ADC 값 읽기
        _delay_ms(100);                  // 100ms 간격으로 변환
        // adc_value를 UART 또는 디버거로 출력 가능
    }

    return 0;
}

설명:

  • 기능: PA0 핀에서 아날로그 전압을 읽어 12비트 ADC 값으로 변환
  • 설정: PA0 입력, 2.5V 레퍼런스, 단일 변환 모드, 12비트 해상도
  • 출력: ADC0.RES에서 0~4095 값 읽기

5.2 예제 2: DAC 출력 (아날로그 전압 생성)

// File: dac_basic.c
// Description: AVR128DB48 DAC 기본 출력 예제 (PA6에서 전압 출력)
// Compiler: AVR-GCC
// Target: AVR128DB48

#include <avr/io.h>        // AVR 입출력 관련 헤더 파일
#include <util/delay.h>    // 지연 함수 관련 헤더 파일

#define F_CPU 24000000UL  // 시스템 클록 주파수를 24 MHz로 정의

void set_system_clock(void) {
    _PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
    while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
    _PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
}

void dac_init(void) {
    VREF.CTRLA = VREF_DAC0REFSEL_2V5_gc; // DAC 레퍼런스 2.5V 설정
    DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // DAC 활성화, PA6 출력
}

void dac_write(uint16_t value) {
    DAC0.DATA = value & 0x03FF; // 10비트 데이터 작성 (0~1023)
}

int main(void) {
    set_system_clock(); // 시스템 클록 설정
    dac_init();         // DAC 초기화

    while (1) {
        dac_write(0);     // PA6에서 0V 출력
        _delay_ms(1000);  // 1초 대기
        dac_write(512);   // PA6에서 약 1.25V 출력 (2.5V * 512/1024)
        _delay_ms(1000);  // 1초 대기
        dac_write(1023);  // PA6에서 약 2.5V 출력
        _delay_ms(1000);  // 1초 대기
    }

    return 0;
}

설명:

  • 기능: PA6 핀에서 0V, 1.25V, 2.5V 아날로그 전압을 순차적으로 출력
  • 설정: PA6 출력, 2.5V 레퍼런스, 10비트 DAC
  • 출력: PA6에서 아날로그 전압 변화

5.3 예제 3: ADC와 DAC 연동 (입력 전압 복사)

// File: adc_dac_loop.c
// Description: AVR128DB48 ADC-DAC 연동 예제 (PA0 입력을 PA6 출력으로 복사)
// Compiler: AVR-GCC
// Target: AVR128DB48

#include <avr/io.h>        // AVR 입출력 관련 헤더 파일
#include <util/delay.h>    // 지연 함수 관련 헤더 파일

#define F_CPU 24000000UL  // 시스템 클록 주파수를 24 MHz로 정의

void set_system_clock(void) {
    _PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
    while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
    _PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
}

void adc_init(void) {
    VREF.CTRLA |= VREF_ADC0REFSEL_2V5_gc; // ADC 레퍼런스 2.5V 설정
    PORTA.DIRCLR = PIN0_bm;               // PA0 입력 설정
    ADC0.MUXPOS = ADC_MUXPOS_AIN0_gc;     // PA0를 ADC 입력으로 선택
    ADC0.CTRLA = ADC_ENABLE_bm;           // ADC 활성화, 12비트 모드
}

void dac_init(void) {
    VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; // DAC 레퍼런스 2.5V 설정
    DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // DAC 활성화, PA6 출력
}

uint16_t adc_read(void) {
    ADC0.COMMAND = ADC_STCONV_bm;        // 변환 시작
    while (!(ADC0.INTFLAGS & ADC_RESRDY_bm)); // 결과 준비 대기
    uint16_t result = ADC0.RES;          // 12비트 결과 읽기
    ADC0.INTFLAGS = ADC_RESRDY_bm;       // 인터럽트 플래그 클리어
    return result;
}

void dac_write(uint16_t value) {
    DAC0.DATA = (value >> 2) & 0x03FF; // 12비트 ADC 값을 10비트 DAC 값으로 변환
}

int main(void) {
    set_system_clock(); // 시스템 클록 설정
    adc_init();         // ADC 초기화
    dac_init();         // DAC 초기화

    while (1) {
        uint16_t adc_value = adc_read(); // PA0에서 12비트 ADC 값 읽기
        dac_write(adc_value);            // PA6에 변환된 전압 출력
        _delay_ms(10);                   // 10ms 간격으로 업데이트
    }

    return 0;
}

설명:

  • 기능: PA0에서 입력된 아날로그 전압을 읽어 PA6에서 근사적으로 동일한 전압 출력
  • 설정: PA0(ADC 입력, 12비트), PA6(DAC 출력, 10비트), 2.5V 레퍼런스
  • 출력: 12비트 ADC 값을 10비트 DAC 값으로 변환(2비트 우측 시프트)하여 PA6에서 출력
  • 주의: ADC(12비트, 04095)와 DAC(10비트, 01023)의 해상도 차이로 인해 정밀도가 약간 손실됨

6. 사용 방법

6.1 환경 설정

  • AVR-GCC 설치: Atmel Studio 또는 MPLAB X IDE에 AVR-GCC 툴체인 설치
  • 헤더 파일: <avr/io.h>, <util/delay.h> 포함
  • 프로젝트 설정: AVR128DB48 타겟으로 프로젝트 생성
  • 클럭 정의: #define F_CPU 24000000UL로 시스템 클럭 설정

6.2 코드 실행

  • 각 예제를 별도의 .c 파일로 저장하거나, main.c에 복사
  • 다른 예제 코드 주석 처리
  • Atmel Studio/MPLAB X IDE에서 빌드 및 플래싱

6.3 하드웨어 준비

  • ADC 입력: PA0에 아날로그 신호(예: 가변 저항, 센서) 연결
  • DAC 출력: PA6에 멀티미터 또는 오실로스코프로 출력 확인
  • 전원: 1.8V~5.5V 전원 공급
  • 노이즈 방지: 아날로그 입력에 커패시터(예: 0.1µF) 추가 권장

6.4 디버깅

  • Atmel Studio/MPLAB X IDE의 디버거 사용
  • ADC0.RES, DAC0.DATA 레지스터 확인
  • 오실로스코프 또는 멀티미터로 PA0, PA6 신호 점검

7. 추가 팁

  • 클럭 설정: set_system_clock()로 XOSC32K 안정화 및 24MHz 설정 확인
  • 노이즈 감소: ADC 입력에 외부 저항-커패시터 필터 추가
  • 샘플 누적: ADC 샘플 누적(최대 128 샘플)을 활용하여 노이즈 감소 및 정밀도 향상
  • Microchip 리소스: AVR128DB48 데이터시트, Application Notes, AVR-GCC 예제
  • 문제 해결:
    •  ADC 출력 부정확: 레퍼런스 전압 및 입력 핀 연결 확인
    •  DAC 출력 없음: DAC0.CTRLA.OUTEN 및 PA6 핀 설정 확인
    •  노이즈 문제: 아날로그 입력/출력 핀에 쉴드 추가
  • 커뮤니티: Microchip Community, AVR Freaks 포럼 참고

8. 결론

이 문서는 AVR128DB48의 12비트 ADC 및 10비트 DAC 모듈 설정 방법과 Bitfield 구조를 활용한 예제 코드를 제공하여 아날로그 신호 처리 애플리케이션에 쉽게 적용할 수 있도록 구성했습니다. 초보자는 기본 ADC/DAC 예제부터 시작하고, 숙련자는 ADC-DAC 연동 및 샘플 누적 기능을 활용하여 고해상도 시스템을 구현할 수 있습니다.

키워드: AVR128DB48, ADC, DAC, 12비트 아날로그-디지털 변환, 10비트 디지털-아날로그 변환, Atmel Studio, MPLAB X IDE, 레퍼런스 전압, 아날로그 입력, 아날로그 출력, 샘플 누적

반응형