ADC 실습 (not updated)
Download
Report
Transcript ADC 실습 (not updated)
마이크로프로세서응용설계 - 9
ADC
시스템및센서네트워크연구실
1
ATmega128
시스템및센서네트워크연구실
2
LED sink / switch pullup 회로
470
5V
PC0
+5V
PC1
…..
10K
PC7
PD2
104 (0.1uF)
시스템및센서네트워크연구실
3
LCD 회로
#1
+5V
VDD
#2
LCD 밝기 조절
V0
VSS
#3
시스템및센서네트워크연구실
+5
V
LEDA
LEDK
RS
R/W
E
PC0
PC1
PC2
DB4
DB5
DB6
DB7
PC4
PC5
PC6
PC7
4
Speaker 회로 / RC servo motor / DC motor
DC motor
RC servo motor
-
motor-
PWM Vcc GND
+
black
red
black
red
yellow
OC1A(PB5)
motor+
+5V
시스템및센서네트워크연구실
5
시스템및센서네트워크연구실
6
LCD 함수
// LCD 초기화 함수
#include <delay.h>
void LCD_init(void)
#define CLEAR
#define LINE2
#define HOME
#define RSHIFT
#define LSHIFT
#define DISPON
#define DISPOFF
0x01
0xC0
0x02
0x1C
0x18
0x0c
0x08
// Clear Display
// 2nd Line Move
// Cursor Home
// Display Right Shift
// Display Left Shift
// Display On
// Display Off
{
DDRC = 0xFF;
// 포트 C 출력 설정
PORTC &= 0xFB;
//E = 0;
// 충분한 지연시간을 통한 안정화 과정
delay_ms(15);
Command(0x20);
// D5=1
delay_ms(5);
void LCD_init(void);
void LCD_String(char flash str[]);
void Busy(void);
void Command(unsigned char);
void Data(unsigned char);
Command(0x20);
// D5=1
delay_us(100);
Command(0x20);
// D5=1
// 초기화 과정
Command(0x28);
// function set
Command(0x06);
// entry mode set
Command(0x01);
// all clear
Command(0x0c);
// display on
}
시스템및센서네트워크연구실
7
//데이터 쓰기 함수
void Data(unsigned char byte)
{
Busy();
// 인스트럭션 쓰기 함수
void Command(unsigned char byte)
{
Busy();
// 인스트럭션 상위 바이트
PORTC = (byte & 0xF0);
PORTC &= 0xFE;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// 인스트럭션 하위 바이트
PORTC = ((byte<<4) & 0xF0);
PORTC &= 0xFE;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// 데이터 상위 바이트
PORTC = (byte & 0xF0);
PORTC |= 0x01;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// 데이터
// RS = 0;
// RW = 0;
// E = 1;
// E = 0;
// 데이터 하위 바이트
PORTC = ((byte<<4) & 0xF0);
PORTC |= 0x01;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// 데이터
// RS = 0;
// RW = 0;
// E = 1;
// E = 0;
// 데이터
//RS = 1;
//RW = 0;
//E = 1;
//E = 0;
// 데이터
//RS = 1;
//RW = 0;
//E = 1;
//E = 0;
}
}
// 문자열 출력 함수
void LCD_String(char flash str[])
{
char flash *pStr=0;
// Busy Flag Check -> 일반적인 BF를 체크하는 것이 아니라
// 일정한 시간 지연을 이용한다.
void Busy(void)
{
delay_ms(2);
}
pStr = str;
while(*pStr) Data(*pStr++);
}
시스템및센서네트워크연구실
8
ADC (Analog to Digital Converter)
ADC
아날로그 신호를 디지털 형태의 데이터로 변환하는 장치
AD 변환기 동작 예
• 아날로그 입력 : 0 – 3V
• 2진 출력 : 4비트
0
0000
0.2
0001
0.4
0010
0.6
0011
0.8
0100
1.0
0101
1.2
0110
1.4
0111
1.6
1000
1.8
1001
2.0
1010
2.2
1011
2.4
1100
2.6
1101
2.8
1110
3.0
1111
AD 변환기 회로는 전압비교기, AND게이트, BCD 카운터, D/A 변환기 등을 이용하
여 구현
시스템및센서네트워크연구실
9
ADC의 분해능, 변환레이트
AD변환의 분해능
연속된 아날로그 입력을 불연속의 디지털 출력으로 변환
어느 범위 내의 아날로그 입력을 몇 비트의 디지털값으로 변환하는 가로
서, 이를 AD의 분해능(resolution)이라 함
AD 컨버터의 분해능 : 디지털 출력의 1비트에 대응하는 아날로그 입력의
변화량
변환시간, 변환 레이트(conversion rate)
변환시간 : 아날로그 입력으로부터 디지털값을 얻어내는 데 걸리는 시간
변환 레이트 : 단위 시간당 AD 변환 횟수
시스템및센서네트워크연구실
10
AD 컨버터의 일반적 구성
아날로그 멀티플렉서
복수 개의 아날로그 입력 중에서 하나를 선택하여 출력하는 선택 회로
샘플홀드회로
아날로그 전압의 어느 순간값을 샘플링(sampling)하여 일정시간 홀드
(hold)하기 위한 회로
AD컨버터
일정한 전압으로 유지한 아날로그 입력을 AD컨버터에 넣어 디지털값으
로 변환
시스템및센서네트워크연구실
11
샘플홀드회로
샘플홀드회로
샘플홀드회로의 출력 파형
시스템및센서네트워크연구실
12
ATmega128 ADC의 특징
ATmega128 ADC의 특징
10비트 분해능
13 – 260usec 변환시간
15KSPS(sampling per second)의 변환율
8채널의 멀티플렉스된 단극성 입력
7채널의 차동 입력
10배 또는 200배 증폭률을 가진 2채널의 차동 입력
0 – Vcc ADC 입력 전압 범위
선택 가능한 2.56V ADC 레퍼런스 전압
시스템및센서네트워크연구실
13
주요 기능
AVCC
• 아날로그 공급 전압 핀으로 Vcc와 0.3V 이내 차이 유지하여야 함
AREF
• AD 변환되는 전압의 범위
• AVCC, 내부 2.56V, 외부 AREF 단자에 공급되는 전압 중에서 선택됨
8채널의 단극성 입력 (ADC0 – ADC7)
• 10비트 분해능
• 0 – VREF의 입력전압이 공급되어 0x000 – 0x3FF(0 – 1023)의 디지털 값으로
변환
2채널의 차동 입력 (ADC1 & ADC0, ADC3 & ADC2)
• 1배, 10배, 200배의 이득으로 증폭 가능
• -VREF – +VREF의 입력전압이 공급되어 2의 보수 0x200 – 0x1FF(-512 – 512)
로 변환
7채널의 차동 입력
• ADC1은 공통 음극성 입력으로, 나머지 채널은 양극성 입력으로 사용
시스템및센서네트워크연구실
14
ADC 관련 레지스터
ADMUX (ADC Multiplexer Selection Register)
bit 4-0 – MUX4-0 (analog channel and gain selection bits)
• AD 변환기에 연결되는 아날로그 입력채널과 차동입력채널에 대한
이득 선택
• 입력 채널 선택 (p233, 표 9-2)
00000 - 00111 - 단극성 입력 (ADC0 – ADC7)
01001 - 차동 입력 (ADC1(+) – ADC0(-), 이득 x10)
01011 - 차동 입력 (ADC1(+) – ADC0(-), 이득 x200)
10000 - 차동 입력 (ADC0(+) – ADC1(-), 이득 x1)
시스템및센서네트워크연구실
15
ADCSRA (ADC control and status register A)
bit 7 – ADEN (ADC enable)
• 1 – ADC 모듈 인에이블
bit 6 – ADSC (ADC start conversion)
• 0 – single conversion mode
• 1 – free running mode
bit 5 – ADFR (ADC free running select)
• 1 – free running mode
• 0 – single conversion mode
시스템및센서네트워크연구실
16
bit 4 – ADIF (ADC interrupt flag)
• ADC 인터럽트 발생시 1로 셋
bit 3 – ADIE (ADC interrupt enable)
• 1 – ADC interrupt enable
bit 2-0 – ADPS2-0 (ADC prescaler select bit)
• 분주비
000 – 2
001 – 2
010 – 4
011 – 8
100 – 16
101 – 32
110 – 64
111 – 128
시스템및센서네트워크연구실
17
ADCH, ADCL (ADC data register)
ADC 모듈의 변환 결과를 저장하는 10비트 레지스터
ADCL, ADCH 값 순서로 읽음 (ADLAR = 0일때)
시스템및센서네트워크연구실
18
A/D 변환 타이밍
Single conversion mode
ADCSRA의 ADSC=1, ADEN=1 일 때 변환 시작
첫번째 변환에는 25 클럭이 요구
A/D 변환이 완료되면, ADIF가 셋됨
ADSC가 자동적으로 클리어되어 다시 소프트웨어적으로 셋해야 함
Free running mode
ADCSRA의 ADSC=1, ADEN=1 일 때 변환 시작
변환이 완료되면 자동으로 새로운 A/D 변환이 시작
ADSC 비트는 high 상태를 유지
타이머에 의한 A/D의 경우에는 문제가 되지 않지만, 무한 루프(while문)
에 넣는 경우 delay를 시켜줄 필요가 있음
시스템및센서네트워크연구실
19
A/D 변환 결과
A/D 변환 결과
단극성 변환
VIN 1024
VREF
ADC
• Vin : 선택된 입력핀의 아날로그 전압
• Vref : 선택된 기준전압
• 0x00은 접지와 같은 전압, 1023(0x3FF)은 기준전압보다 1LSB만큼 낮은 전
압값
차동 채널
ADC
(VPOS VNEG ) gain 512
VREF
• Vpos : 양의 입력핀에 입력되는 전압
• Vneg : 음의 입력핀에 입력되는 전압
• gain : 이득값
• 변환값 : 0x200(-512) – 0x1FF(511)
시스템및센서네트워크연구실
20
실습 1
// ADC0 (가변저항 연결)에 입력되는 전압을 LCD에 출력 (단극성 입력) – single conversion mode
// 이 단자를 통해 입력되는 전압을 소수 1자리까지 전압값으로 표시하는 프로그램 작성
void adc_display (void);
int adc_value=0;
float Vref = 5.0;
void main(void)
{
ADMUX = 0b00000000;
ADCSRA = 0b10000111;
// MUX(4-0):00000(ADC0 단극성 입력)
// ADEN(7)-1,ADSC(6)-0,ADATE(5)-0(single conversion mode),ADIF(4)-0,ADIE(3)-0
// ADPS(2-0)-111(128분주:16MHz/128->125kHz) : 13cycle당 1회 샘플링 - 약 9.6kHz
SREG = 0x80;
LCD_init();
adc_display();
while(1) {
ADCSRA = 0b11000111;
// ADEN=1, ADSC = 1 변환 시작
while((ADCSRA & 0x10) == 0);
// ADIF=1이 될 때까지 대기
adc_value = (int)ADCL + ((int)ADCH << 8); // A/D 변환값 읽기
adc_display();
}
}
시스템및센서네트워크연구실
21
void adc_display(void)
{
float f_val=0;
int temp0=0, temp1=0, temp=0;
Command(HOME);
LCD_String(“Value:”);
f_val = (float)adc_value * Vref / 1024;
// 전압값으로 변환
temp = (int)(f_val * 10 + 0.5);
temp1 = temp / 10;
temp0 = temp % 10;
Data(0x30 + temp1);
LCD_String(“.”);
Data(0x30 + temp0);
LCD_String(“V”);
}
시스템및센서네트워크연구실
22
실습 2
// 실습 1과 동일한 조건, 단, free running mode로 프로그래밍
void adc_display (void);
int adc_value=0;
float Vref = 5.0;
void main(void)
{
ADMUX = 0b00000000; // MUX(4-0):00000(ADC0 단극성 입력)
ADCSRA = 0b11100111; // ADEN(7)-1,ADSC(6)-1,ADATE(5)-1(free funning mode),ADIF(4)-0,ADIE(3)-0
// ADPS(2-0)-111(128분주:16MHz/128->125kHz) : 13cycle당 1회 샘플링 - 약 9.6kHz
SREG = 0x80;
LCD_init();
adc_display();
while(1) {
adc_value = (int)ADCL + ((int)ADCH << 8); // A/D 변환값 읽기
adc_display();
delay_ms(100);
}
}
시스템및센서네트워크연구실
23
실습 3
// 차동입력 (ADC0(+) - ADC1(-), gain x1) A/D 변환 전압 표시
// ADC0 및 ADC1에 가변저항 연결
// -2.5 - +2.5V로 표시
void adc_display (void);
int adc_value=0;
float Vref = 5.0;
void main(void)
{
ADMUX = 0b00010000; // MUX(4-0):10000(ADC0-ADC1 차동 입력)
ADCSRA = 0b10000111; // ADEN(7)-1,ADSC(6)-0,ADATE(5)-0(single conversion mode),ADIF(4)-0,ADIE(3)-0
// ADPS(2-0)-111(128분주:16MHz/128->125kHz) : 13cycle당 1회 샘플링 - 약 9.6kHz
SREG = 0x80;
LCD_init();
adc_display();
while(1) {
ADCSRA = 0b11000111;
// ADEN=1, ADSC=1 변환 시작
while((ADCSRA & 0x10) == 0);
// ADIF=1이 될 떄까지
adc_value = (int)ADCL + ((int)ADCH << 8); // A/D 변환값 읽기
adc_display();
}
}
시스템및센서네트워크연구실
24
void adc_display(void)
{
float f_val=0;
int temp0=0, temp1=0, temp=0;
Command(HOME);
LCD_String(“Value:”);
if(adc_value > 512) {
f_val = (float)(1024 - adc_value) * Vref / 512;
LCD_String(“-”);
}
else {
f_val = (float)adc_value * Vref / 512;
LCD_String(“+”);
}
// 전압값으로 변환
// 부호 -
// 전압값으로 변환
// 부호 +
temp = (int)(f_val * 10 + 0.5);
temp1 = temp / 10;
temp0 = temp % 10;
Data(0x30 + temp1);
LCD_String(“.”);
Data(0x30 + temp0);
LCD_String(“V”);
}
시스템및센서네트워크연구실
25
실습 4
// ADC0와 ADC1에 연결되어 있는 각각의 가변저항 값을 읽어서 차이를 계산한 후 ADC0-ADC1의 값을 LCD에 출력
// ADC0 및 ADC1에 가변저항 연결
// -5 - +5V로 표시
void adc_display (void);
int adc_value0=0, adc_value1=0, sign = 0;
float Vref = 5.0;
void main(void)
{
ADMUX = 0b00000000; // MUX(4-0): 00000(ADC0 단극성 입력)
ADCSRA = 0b10000111; // ADEN(7)-1,ADSC(6)-0,ADATE(5)-0(single conversion mode),ADIF(4)-0,ADIE(3)-0
// ADPS(2-0)-111(128분주:16MHz/128->125kHz) : 13cycle당 1회 샘플링 - 약 9.6kHz
SREG = 0x80;
LCD_init();
adc_display();
시스템및센서네트워크연구실
26
while(1) {
ADMUX = 0b00000000;
ADCSRA = 0b11000111;
while((ADCSRA & 0x10) == 0);
// MUX(4-0):00000(ADC0 단극성 입력)
// ADEN=1, ADSC = 1 변환
// ADIF=1이 될 때까지 대기
adc_value0 = (int)ADCL + ((int)ADCH << 8); // A/D 변환값 읽기
ADMUX = 0b00000001;
ADCSRA = 0b11000111;
while((ADCSRA & 0x10) == 0);
// MUX(4-0):00001(ADC1 단극성 입력)
// ADEN=1, ADSC = 1 변환
// ADIF=1이 될 때까지 대기
adc_value1 = (int)ADCL + ((int)ADCH << 8); // A/D 변환값 읽기
adc_display();
}
}
시스템및센서네트워크연구실
27
void adc_display(void)
{
float f_val0=0, f_val1=0, f_val=0;
int temp0=0, temp1=0, temp=0;
Command(HOME);
LCD_String(“Value:”);
f_val0 = (float)adc_value0 * Vref / 1024;
f_val1 = (float)adc_value1 * Vref / 1024;
if(f_val0 > f_val1) {
f_val = f_val0 - f_val1;
LCD_String(“+”); // 부호 +
}
else {
f_val = f_val1 - f_val0;
LCD_String(“-”);
// 부호 }
temp = (int)(f_val * 10 + 0.5);
temp1 = temp / 10;
temp0 = temp % 10;
Data(0x30 + temp1);
LCD_String(“.”);
Data(0x30 + temp0);
LCD_String(“V”);
}
시스템및센서네트워크연구실
28
실습 5
// 화재 감지기
// ADC0 입력을 받은 후,
// 특정 전압(4.0V) 이상일 때 화재로 판단하여 LED(PA7) 점등, 스피커 알람, LCD에 fire 점등 (평상시에는 전압값만 출력)
void adc_display (void);
int adc_value=0;
float Vref = 5.0, Vwarn = 4.0, Vdetect = 0;
int cnt = 0, cnt_bell = 0, cnt_fire = 0;
void main(void)
{
ADMUX = 0b00000000; // MUX(4-0):00000(ADC0 입력)
ADCSRA = 0b10000111; // ADEN(7)-1,ADSC(6)-0,ADATE(5)-0(single conversion mode),ADIF(4)-0,ADIE(3)-0
// ADPS(2-0)-111(128분주:16MHz/128->125kHz) : 13cycle당 1회 샘플링 - 약 9.6kHz
// timer3 normal 모드 설정 : 1/16us * 256분주 * 31250= 500ms
ETIMSK = 0b00000100; // TOIE3 = 1;
TCCR3A = 0b00000000; // 일반모드 (WGM11, WGM10)
TCCR3B = 0b00000100; // 일반모드 (WGM13, WGM12), 프리스케일 = 256
TCNT3H = 0x85;
TCNT3L = 0xED;
// 65535-31250 = 34285 (0x85ED)
// OC1A 출력 설정
DDRB = 0x30;
// PB5 = 1
시스템및센서네트워크연구실
29
// PA7 출력 설정
DDRA = 0x80;
PORTA = 0xFF;
SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 셋
LCD_init();
adc_display();
while(1) {
ADCSRA = 0b11000111;
// ADEN=1, ADSC=1 변환 시작
while((ADCSRA & 0x10) == 0);
// ADIF=1이 될 떄까지
adc_value = (int)ADCL + ((int)ADCH << 8); // A/D 변환값 읽기
Vdetect = (float)adc_value * Vref / 1024;
}
}
시스템및센서네트워크연구실
30
// 타이머/카운터3 오버플로우 서비스 루틴
interrupt [TIM3_OVF] void timer_int0(void)
{
TCNT3H = 0x85;
TCNT3L = 0xED;
// 65535-31250 = 34285 (0x85ED)
if(Vdetect >= Vwarn) {
TCCR1A = 0b01000000;
TCCR1B = 0b00001010;
// COM1A1,A0(7,6)-01, mode 4 - CTC모드 / OCR1A (WGM11,10 - 00)
// mode 4(WGM13,12 - 01), 프리스케일 = 8
if(cnt_bell == 0) {
PORTA = 0x00;
OCR1A = 2082;
// 1M / (1+2082) = 480
Command(CLEAR);
LCD_String(“Fire!!!”);
cnt_bell = 1;
}
else {
PORTA = 0xFF;
OCR1A = 2777;
// 1M / (1+2777) = 360
Command(CLEAR);
cnt_bell = 0;
}
}
else {
TCCR1A = 0b00000000;
TCCR1B = 0b00001010;
PORTA = 0xFF;
adc_display();
}
void adc_display(void)
{
int temp0=0, temp1=0, temp=0;
Command(CLEAR);
LCD_String(“Value:”);
temp = (int)(Vdetect * 10 + 0.5);
temp1 = temp / 10;
temp0 = temp % 10;
Data(0x30 + temp1);
LCD_String(“.”);
Data(0x30 + temp0);
LCD_String(“V”);
// COM1A1,A0(7,6)-01, mode 4 - CTC모드 / OCR1A (WGM11,10 - 00)
// mode 4(WGM13,12 - 01), 프리스케일 = 8
}
}
시스템및센서네트워크연구실
31