Lập trình ADC – Đo nhiệt độ dùng LM35 hiển thị LCD với AVR

Giới thiệu bộ ADC trên AVR

ADC (Analog to Digital Converter) là bộ chuyển đổi tín hiệu tương tự sang kỹ thuật số trên AVR. Bộ ADC trên AVR bao gồm 8 kênh với độ phân giải 10 bit, có nghĩa là điện áp sẽ được chuyển đổi thành 1024 mức level dạng bậc thang. Bộ ADC có nhiều ứng dụng như đo nhiệt độ, đọc giá trị điện áp, tính dòng điện, đọc phím nhấn theo thang điện trở và biến đổi tín hiệu âm thanh sang kỹ thuật số để lưu trữ.

Thiết kế nguồn cho bộ ADC

Chân AVCC là chân cấp nguồn cho bộ ADC của AVR, riêng không chung với VCC của chip. Chân AREF là chân chọn điện áp tham chiếu ngoài của bộ ADC (AREF Max=5V). Trong thiết kế nguồn, chỉ cần có một con tụ lọc 104 là đủ để giảm độ nhiễu và có mạch nguồn ổn định.

Công thức tính giá trị điện áp chuyển đổi

  • ADC 10 bit: Vin = (Vref*ADC)/1024
  • ADC 8 bit: Vin = (Vref*ADC)/256
    Trong đó:
  • Vref là điện áp tham chiếu (Đơn vị: V)
  • ADC là giá trị sau chuyển đổi

Các thanh ghi tham gia điều khiển ADC

  • ADMUX (ADC Multiplexer Selection Register): Là thanh ghi chọn điện áp tham chiếu và kênh ADC

  • ADMUX gồm các bit: REFS1, REFS0, ADLAR, MUX3, MUX2, MUX1, MUX0

  • REFS1 và REFS0 là 2 bit chọn điện áp tham chiếu để so sánh

  • ADLAR là bit sắp xếp 2 thanh ghi ADCH và ADCL

  • MUX3:0 là 4 bit chọn kênh ADC từ 0-7

  • ADCSRA (ADC Control and Status Register): Là thanh ghi điều khiển bộ ADC

  • ADCSRA gồm các bit: ADEN, ADSC, ADFR, ADIF, ADIE, ADPS2, ADPS1, ADPS0

  • ADEN là bit cho phép bộ ADC hoạt động

  • ADSC là bit cho phép bộ ADC chuyển đổi

  • ADFR là bit cho chế độ liên tục chuyển đổi

  • ADIF là bit cờ ngắt

  • ADIE là bit cho phép ngắt bộ ADC

  • ADPS2:0 là 3 bit chọn xung nhịp cho bộ ADC

Lập trình đọc ADC theo kênh

#define ADC_VREF 0x00 //Lấy điện áp AREF để so sánh

unsigned int read_adc(unsigned char adc_input){
 ADMUX=adc_input | ADC_VREF; //Chọn kênh ADC và điện áp so sánh
 ADCSRA|=0x40; //Start ADC
 while (!(ADCSRA & 0x10)); //Kiểm tra cờ ADC
 ADCSRA|=0x10;
 return ADCW; //Giá trị ADC 10bit
}

unsigned char read_adc(unsigned char adc_input){
 ADMUX=adc_input | ADC_VREF; //Chọn kênh ADC và điện áp so sánh
 ADCSRA|=0x40; //Start ADC
 while (!(ADCSRA & 0x10)); //Kiểm tra cờ ADC
 ADCSRA|=0x10;
 return ADCH; //Giá trị ADC 8bit
}

adc = read_adc(0); //abc chứa giá trị ADC kênh 0

Lập trình đọc ADC sử dụng ngắt

Khi ứng dụng yêu cầu tốc độ cao và không muốn bị giới hạn ở vòng lặp kiểm tra cờ ADC, ta có thể sử dụng ngắt để tiếp tục thực hiện các công việc khác trong khi chuyển đổi ADC đang diễn ra. Sử dụng ngắt giúp tận dụng tối đa tốc độ xử lý cao của AVR.

#define ADC_VREF 0xC0 //Lấy điện áp 2.56V onchip để so sánh

interrupt [ADC_INT] void adc_isr(void){
 adc_data=ADCW; //Lấy giá trị ADC 10bit
 ADCSRA|=0x40; //Tiếp tục chuyển đổi
}

Lập trình đọc nhiệt độ từ cảm biến nhiệt độ LM35 hiển thị lên LCD16x2

Cảm biến nhiệt độ LM35 có đầu ra là tín hiệu analog, cứ 10mV tương ứng với 1 độ C. Ta có thể sử dụng áp nội của AVR để so sánh và chính xác hơn là dùng ổn áp ngoài cấp vào AREF. Với áp nội, chúng ta không cần tính toán nhiều và ở chế độ ADC 8 bit có 256 thang điện áp tương ứng với 0-2.55V, từ đó suy ra cứ một giá trị ADC là tương ứng với 10mV. Ví dụ: ADC = 25 tương ứng với 25oC của LM35.

#include 
#include 
#include 

#define ADC_VREF 0xe0 //Lấy áp 2.56V, ADLAR=1

unsigned char read_adc(unsigned char adc_input){
 ADMUX=adc_input | ADC_VREF; //Chọn kênh ADC và áp so sánh
 ADCSRA|=0x40; //Start ADC
 while (!(ADCSRA & 0x10)); //Kiểm tra cờ ADC
 ADCSRA|=0x10;
 return ADCH; //ADC 8bit
}

void temp(unsigned char z){ //Chuyển đổi và hiển thị
 lcd_puts("Nhiệt độ: ");
 lcd_putchar((z/100)+48);
 lcd_putchar((z%100/10)+48);
 lcd_putchar((z%10)+48);
 lcd_puts("oC");
}

void main(void){
 ADMUX=ADC_VREF;
 ADCSRA=0x86; //Fosc/64
 lcd_init(16);
 lcd_puts("Đo nhiệt độ...");
 delay_ms(2000);
 lcd_clear();
 lcd_puts("SangTaoClub.Net");
 while (1){
 lcd_gotoxy(0,1);
 temp(read_adc(0)); //Hiển thị nhiệt độ
 }
}

Chúc các bạn học tốt!

FEATURED TOPIC

hihi