본문 바로가기
Embedded system/Microcontroller

ATmega2560의 ADC (2)

by 은빛초코 2021. 10. 26.

이번에는 Atmega2560의 ADC를 이용하여 가변 저항의 값을 읽어보도록 하겠습니다.

가변저항은 ATmega2560보드에 부착되어 있는 것으로 사용했습니다.


우선 두 가지의 모드가 존재합니다.

  1. 프리 러닝 모드 코드
  2. 단일 변환 모드 코드

프리 러닝 모드는 자동 트리거 모드에 속하는 모드입니다. 자동 트리거 모드는 이전 변환이 끝나면 특정 신호에 의해 다시 AD 변환이 시작되는 모드인데, 이에 속하는 프리 러닝 모드는 이전 변환이 끝나면 자동으로 다음 변환이 시작됩니다.

단일 변환 모드는 변환 시작 신호가 주어지면 한 번 AD 변환을 수행하고 끝내는 모드입니다.

 

딱 한번만 변환하려면 단일 변환 모드

여러번 반복할건데, 특정 신호에 의해 시작하고 싶다면 자동 트리거모드

여러번 반복할건데, 자동으로 시작하고 싶다면 프리 러닝 모드

 

 


가변저항의 값을 읽기 위한 코드를 짜기 전에, 꼭 써야하는 register을 먼저 확인하도록 하겠습니다.

 

 

ADC = ADCH + ADCL 레지스터 (ADC Register) [15:0]

  • [9:0] ADCn
  • ADCH, ADCL : AD 변환된 디지털 데이터가 저장되는 레지스터
  • 레지스터는 모두 8비트로, 두 개의 레지스터에 변환된 값이 나누어 저장
  • ADCH, ADCL 레지스터의 16비트 중 6비트는 사용되지 않음
  • 데이터를 정렬하는 방식에 따라 ADCH의 상위 6비트 or ADCL의 하위 6비트 사용하지 않음
  • 정렬 방식 : ADMUX 레지스터의 ADLAR (ADC Left Adjust Result) 비트
  • Default value : 오른쪽 정렬 (ADLAR = 0)

 

 

ADMUX 레지스터 (ADMUX Register) [7:0]

  • AD 변환을 위한 기준 전압과 입력 채널을 선택하는 데 사용
  • [7:6] REFS1~0 : AD변환의 기준 전압을 선택할 때 사용
    • REFS1 = 0, REFS0 = 0이면, 외부 AREF 핀 입력을 기준 전압으로 선택
    • REFS1 = 0, REFS0 = 1이면, 외부 AVCC 핀 입력을 기준 전압으로 선택
    • REFS1 = 1, REFS0 = 0이면, 내부 1.1V를 기준 전압으로 선택
    • REFS1 = 1, REFS0 = 1이면, 내부 2.56V를 기준 전압으로 선택
  • [5] ADLAR : 변환된 디지털 데이터의 저장 방법을 설정할 때 사용
    • ADLAR = 1이면, 왼쪽 정렬
    • ADLAR = 0이면, 오른쪽 정렬
  • [4:0] MUXn : ADCSRB 레지스터의 3번 비트 MUX5와 함께 ADC에 가해질 입력을 선택하는데 사용. 단일 / 차동 입력 가능

 

 

ADCSRA 레지스터 (ADC Control and Status Register A) [7:0]

  • AD 변환의 상태를 나타내거나 AD변환 과정을 제어하는데 사용
  • [7] ADEN (ADC Enable) : ADC 활성화 비트, Default value = 0
  • [6] ADSC (ADC Start Conversion) : 1로 설정해야 AD변환을 시작. 이 비트를 설정하면 단일 변환 모드는 변환을 시작하고, 프리 러닝 모드는 첫 번째 변환을 시작
  • [5] ADATE (ADC Auto Trigger Enable) : 자동 트리거 모드 설정 사용. 선택한 트리거 소스의 상승 엣지에서 변환 시작
  • [4] ADIF (ADC Interrupt Flag) : AD 변환이 종료되고 데이터 레지스터가 업데이트 되면 1로 세트
  • [3] ADIE (ADC Interrupt Enable) : AD변환이 끝났을 때, 인터럽트 발생을 허용. 실제 인터럽트가 발생하려면 SREG 레지스터의 1비트가 세트되어 있어야 함.
  • [2:0] ADPSn (ADC Prescaler Select Bit) : AD변환에 사용되는 클록을 생성하기 위한 분주율 설정

 

 

ADCSRB 레지스터 (ADC Control and Status Register B) [7:0]

  • AD 변환의 상태를 나타내거나 AD변환 과정을 제어하는데 사용
  • [6] ACME (Analog Comparator Multiplexer Enable) : 아날로그 비교기에서 음의 입력을 선택할 때 사용
  • [3] MUX5 : ADCSRA의 MUXn비트와 함께 ADC 압력 선택 시 사용
  • [2:0] ADTSn (ADC Auto Trigger Source) : AD변환을 시작할 트리거 소스를 선택하는 데 사용
    • ADTS2 = 0, ADTS1 = 0, ADTS0 = 0이면, 프리 러닝 모드
    • ADTS2 = 0, ADTS1 = 0, ADTS0 = 1이면, 아날로그 비교기

 

 


가변저항 값 읽기 단일 변환 모드와 프리 러닝 모드의 차이점 

 

 

단일 변환 모드의 코드에서 read_ADC함수의 ADCSRA |= (1 << ADSC)
프리 러닝 모드의 코드에서
ADC_init함수의 ADCSRA |= (1 << ADATE)
ADCSRB &= ~(1 << ADTS2) & ~(1 <<ADTS1) & ~(1 << ADTS0)
ADCSRA |= (1 << ADSC)

 

 

 

 


가변저항으로 LED 개수 제어 코드

 

 

그러면 가변저항으로 LED 개수를 제어하는 코드를 짜보도록 하겠습니다.

가변저항의 값이 높아질수록 LED를 많이 켜고, Putty에 현재 가변저항의 값과 켜진 LED의 개수를 출력해야 합니다.

 

ADC.cpp

#include "ADC.h"

int MODE = FREE_RUNNING;

void ADC_init(unsigned char channel, int mode/* = FREE_RUNNING*/) {
	mode = FREE_RUNNING;
	MODE = mode;
	
	ADMUX |= (1 << REFS0);
	ADMUX = ((ADMUX & 0xE0) | (channel & 0x07));
	if(channel > 8) ADCSRB |= (1 << MUX5);
	
	ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
	
	ADCSRA |= (1 << ADEN);
	
	if(MODE == FREE_RUNNING) {
		ADCSRA |= (1 << ADATE);
		
		ADCSRB &= ~(1 << ADTS2) & ~(1 << ADTS1) & ~(1 << ADTS0);
		
		ADCSRA |= (1 << ADSC);
		
	}
}

int read_ADC(void) {
	if(MODE == SINGLE_CONVERSION) {
		ADCSRA |= (1 << ADSC);
	}
	
	while(!(ADCSRA & (1 << ADIF)));
	
	return ADC;
}

 

ADC.h

#ifndef _ADC_
#define _ADC_
#include <avr/io.h>
#include <avr/interrupt.h>
#define FREE_RUNNING	1
#define SINGLE_CONVERSION	2

void ADC_init(unsigned char channel, int mode = FREE_RUNNING);
int read_ADC(void);

#endif /* ADC_H_ */

 

main.cpp

#define F_CPU 16000000L
#include <util/delay.h>
#include <avr/io.h>
#include "UART0.h"
#include "ADC.h"

#define set_bit(value, bit) (_SFR_BYTE(value) |= _BV(bit))
#define clear_bit(value, bit) (_SFR_BYTE(value) &= ~_BV(bit))

void PORT_init() {
	set_bit(DDRE, 4);							//아두이노 2번
	set_bit(DDRE, 5);							//아두이노 3번
	set_bit(DDRG, 5);							//아두이노 4번
	set_bit(DDRE, 3);							//아두이노 5번
}


int main(void)
{
    UART0_init();								//UART 통신 초기화
	ADC_init(0);								//AD 변환기 초기화
	PORT_init();								//LED 연결 핀을 출력으로 설정
	
    while (1) 
    {
		int read = read_ADC();					//가변저항 읽기
		int count = (read >> 8) + 1;
		
		switch(count) {							//LED 개수에 따라 LED 점멸
		case 1:
			set_bit(PORTE, 4);
			clear_bit(PORTE, 5);
			clear_bit(PORTG, 5);
			clear_bit(PORTE, 3);
			break;
		case 2:
			set_bit(PORTE, 4);
			set_bit(PORTE, 5);
			clear_bit(PORTG, 5);
			clear_bit(PORTE, 3);
			break;
		case 3:
			set_bit(PORTE, 4);
			set_bit(PORTE, 5);
			set_bit(PORTG, 5);
			clear_bit(PORTE, 3);
			break;
		case 4:
			set_bit(PORTE, 4);
			set_bit(PORTE, 5);
			set_bit(PORTG, 5);
			set_bit(PORTE, 3);
			break;
		}
		
		UART0_print("Read : ");
		UART0_print(read);
		UART0_print(",\t");
		UART0_print(count);
		UART0_print(" LEDs are ON!");
		UART0_print("\r");
		UART0_print("\n");
		
		
		_delay_ms(1000);						//1초에 한 번 읽음
			
    }
	
	return 0;
}

 

 

 

 

 

출력결과

putty 출력 화면
Atmega2560 화면

 

 

 

 

 

 

 


 

참고 : 따라 하면서 배우는 마이크로컨트롤러 - 한빛아카데미

 

댓글