Chào mừng đến với Câu Lạc Bộ Sáng Tạo
Chia sẻ kinh nghiệm
Kết nối đam mê
Đang cập nhật thời gian...
BÀI VIẾT NỔI BẬT
Xin chào! Tôi là Ếch Sáng Tạo :-)
Chia sẻ trang




Chuyên mục
Bài mới
Xem nhiều
Thống kê
  • Bài viết: 334/334
  • Thành viên: 10.085
  • Đang online: 6
  • Khách hôm nay: 537
  • Khách hôm qua: 3.625
  • Tổng khách: 16.183.493
Bài viết
[Bài 5] Lập trình ADC - Đo nhiệt độ dùng LM35 hiển thị LCD với AVR - SangTaoClub.Net
[Bài 5] Lập trình ADC - Đo nhiệt độ dùng LM35 hiển thị LCD với AVR
Đăng bởi: Vũ Văn Thái - Thời gian: 25-06-2014, 10:17
Chuyên mục: Học lập trình AVR - Lượt xem: 57.819

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

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

        ADC (Analog to Digital Converter) Chuyển đổi tín hiệu tương tự sang kỹ thuật số. Trên AVR được tích hợp 8 kênh ADC với độ phân giải 10bit, tức điện áp sẽ được chuyển đổi thành 1024 mức level dạng bậc thang.

        ADC được ứng dụng rất nhiều 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ở (trong tivi...), biến đổi tín hiệu âm thanh sang kỹ thuật số để lưu trữ,.... ADC có độ phân giải càng cao thì càng khó chế tạo và từ đó giá thành cũng tỉ lệ thuận, nhưng với AVR bạn khỏi phải no chuyện giá thành của các chip ADC, nó đã được tích hợp bên trong tất cả các chip AVR kể cả dòng nhỏ gọn như ATtiny.

2. Thiết kế nguồn cho bộ ADC:

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

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 nha chú ý điều này.

Chân AREF là chân chọn điện áp tham chiếu ngoài của bộ ADC (AREF Max=5V) nó sẽ so sánh áp tham chiếu để cho ra các mức logic tương ứng kiểu tỷ lệ %. VD: AREF=5V, ADC input =2.5V tức bằng 50% AREF thì giá trị ADC là 1024/2=512.

Thiết kế nguồn như trên là lý tưởng cho các bộ ADC của AVR, nhưng trong thực tế nhằm giảm độ cồng kềnh và đã có các mạch nguồn ổn định thì ta chỉ cần có một con tụ lọc 104 là đủ

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

           ADC 10bit: Vin = (Vref*ADC)/1024

           ADC 8bit: Vin = (Vref*ADC)/256

           Trong đó:

                        Vref là điện áp tham chiếu (Đơn vị: V)

                        ADC là giá trị sau chuyển đổi.

4. 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à chọn kênh ADC

7 6 5 4 3 2 1 0
REFS1 REFS0 ADLAR   -   MUX3 MUX2 MUX1 MUX0

Trong đó:

    REFS1 và REFS0 Là 2bit chọn điện áp tham chiếu để so sánh, ta có bảng sau:

REFS1 REFS0 Giá trị điện áp
0 0 Bằng AREF đưa vào, mã HEX 0x00
0 1 Bằng AVCC đưa vào, mã HEX 0x40
1 0 Dự trữ - Không sử dụng
1 1 2.56V onchip, mã HEX 0xC0

     Tại sao lại có phần mã HEX trên thì ta sẽ xét trong phần lập trình.... Giá trị này là khi ADLAR=0

    ADLAR là bit sắp xếp 2 thanh ghi ADCH và ADCL, do bộ chuyển đổi ADC là 10bit nên ta phải có 2 thanh ghi 8bit để lưu giá trị chuyển đổi, việc sắp xếp này sẽ tùy vào sở thích của lập trình viên.

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

    MUX3:0 Là 4bit chọn kênh ADC có giá trị thập phân từ 0-7 tương ứng với kênh ADC0-ADC7. MUX3:0=1110: VBG=1.3V,  MUX3:0=1111: 0V GND

- ADCSRA Là thanh ghi điều khiển bộ ADC:

7 6 5 4 3 2 1 0
ADEN ADSC ADFR ADIF ADIE ADPS2 ADPS1 ADPS0

Trong đó:

   ADEN: Là bit cho phép bộ ADC hoạt động, nếu ta không set bit này lên 1 thì bộ ADC không hoạt động.

   ADSC là bit cho phép bộ ADC chuyển đổi, khi quá trình chuyển đổi hoàn tất bit này sẽ tự động được xóa về 0 và ta muốn bộ ADC chuyển đổi tiếp ta bắt buộc phải set lại bit này.

   ADFR Là bit cho chế độ liên tục chuyển đổi, Nếu set bit này thì bộ ADC sẽ liên tục chuyển đổi.

   ADIF là bit cờ ngắt, khi quá trình chuyển đổi hoàn tất thì bit này tự động được set lên 1, ta sẽ kiểm tra bit này để đảm bảo quá trình đọc ADC không bị lỗi.

   ADIE là bit cho phép ngắt bộ ADC. Khi chuyển đổi hoàn tất sẽ có một ngắt xảy ra nếu cho phép ngắt ADC

   ADPS2:0 là 3bit chọn xung nhịp cho bộ ADC, tốc độ chuyển đổi phụ thuộc vào 3 bit này. Chú ý chế độ 10bit sẽ chuyển đổi chậm hơn chế độ 8bit. Ta có bảng sau:

ADPS2 ADPS1 ADPS0 Xung nhịp
0 0 0 Fosc/2
0 0 1 Fosc/2
0 1 0 Fosc/4
0 1 1 Fosc/8
1 0 0 Fosc/16
1 0 1 Fosc/32
1 1 0 Fosc/64
1 1 1 Fosc/128

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

Khai báo thay thế đầu chương trình:

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

Khởi tạo trong hàm main:

        ADMUX=ADC_VREF; //Đặt áp tham chiếu ban đầu
        ADCSRA=0x85; //Khởi tạo ADC, xung clock Fosc/32

Chương trình con đọc ADC đơn kênh 10bit:

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
}

Chương trình con đọc ADC đơn kênh 8bit:

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
}

Sử dụng hàm: adc=read_adc(0); //abc chứa giá trị ADC kênh 0

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

Khi ứng dụng của bạn đòi hỏi tốc độ mà nó lại bị giới hạn ở vòng lặp kiểm tra cờ ADC (vì quá trình chuyển đổi ADC sẽ mất một khoảng thời gian 13-260us) thì giải pháp là sử dụng ngắt, ngắt sẽ cho VXL hoạt động như đang chạy đa nhiệm. Khi nào chuyển đổi xong ta mới đọc giá trị, nó sẽ cải thiệt rất nhiều khi phải chờ vài trăm us để đọc dc ADC, khoảng thời gian đó ta có thể làm được rất nhiều việc khác vì AVR có tốc độ rất cao với chu kỳ lệnh T=1/Fosc khoảng vài chục ns (nano giây) tùy vào thạch anh mắc vào chip từ 1-16Mhz.

Việc sử dụng ngắt rất đơn giản ta chỉ việc khởi động ADC, chọn kênh, điện áp so sánh, set bit ngắt và Run. Chương trình ngắt sẽ như sau:

Khai báo thay thế đầu chương trình:

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

Khởi tạo trong hàm main:

 ADMUX = 1 | ADC_VREF;  //Chọn kênh ADC1 và điện áp so sánh
 ADCSRA = 0xCD; //Start ADC, Fosc/32, Cho phép ngắt

  #asm("sei")  //Ngắt cục bộ

Chương trình ngắt:

unsigned int adc_data; //Biến lưu giá trị ADC

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

}

6. Chế độ Auto Scan ADC - Các bạn tìm hiểu trong phần mềm CodeVisionAVR

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

   LM35 là cảm biến nhiệt độ đầu ra là tín hiệu analog, cứ 10mV tương ứng với 1 độ C, VD: 250mV là 25 độ C

   Việc đọc giá trị từ cảm biến này rất đơn giản do nó có áp OUTPUT MAX nhỏ hơn 2.56V lên ta sử dụng luôn áp nội của AVR để so sánh sẽ chính xác hơn là dùng ổn áp ngoài cấp vào AREF.

   Với áp nội thì chúng ta không phải tính toán nhiều mà ở chế độ ADC8bit có 256 thang điện áp tương ứng 0-2.55V, từ đó suy ra cứ một giá trị ADC là ứng với 10mV. VD ADC=25 ứng với 25oC của LM35.

Ta sẽ có Code như sau:

#include >
#include <delay.h>
#include <alcd.h>
#define ADC_VREF 0xe0 //Lay ap 2.56V, ADLAR=1
unsigned char read_adc(unsigned char adc_input){
         ADMUX=adc_input | ADC_VREF; //Chon kenh ADC va ap so sanh
         ADCSRA|=0x40; //Start ADC
         while (!(ADCSRA & 0x10)); //Kiem tra co ADC
         ADCSRA|=0x10;
         return ADCH; //ADC 8bit
}
void temp(unsigned char z){ //Chuyen doi hien thi
         lcd_puts("Nhiet do: ");
         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("Do nhiet do...");
         delay_ms(2000);
         lcd_clear();
         lcd_puts("SangTaoClub.Net");
         while (1){
                  lcd_gotoxy(0,1);
                  temp(read_adc(0)); //Show Temp
         }
}

Mạch mô phỏng:

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

Tải Code và mô phỏng ở cuối bài viết, trong phần đính kèm....

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


Tải về đính kèm:
LM35_AVR_LCD.zip
Kích thước: 68.17 KB
Bài viết sửa lúc 08-08-2014, 09:32 bởi Vũ Văn Thái
  • Bạn chưa đăng nhập, không thể viết bình luận!
    Bấm vào đây để Đăng nhập hoặc Đăng ký!
  • Vũ Văn Thái lúc 23-04-2017, 23:09
    Có nhé bị ảnh hưởng một chút thôi, nếu đo nhiệt độ bằng LM35 thì đọc theo áp nội sẽ gây sai số khoảng +2 độ C
  • thanhnhanktvn95 lúc 23-04-2017, 15:38
    mình dùng điện áp tham chiếu nội nhưng mạch thực tế nối lên vcc thì có ảnh hưởng gì không
  • Vũ Văn Thái lúc 22-04-2017, 18:28
    CodeVisionAVR bạn nhé
  • thanhnhanktvn95 lúc 22-04-2017, 14:03
    AD cho hỏi là cái này lập trình trên phần mềm gì ạ?
  • allofyou lúc 16-01-2017, 19:21
    Ad cho hỏi là sao khi tăng nhiệt độ thì LCD chỉ hiện đến 50 là tối đa
    • thanhnhanktvn95 lúc 23-04-2017, 13:12
      cái đó hình như là do cái phần mềm mô phỏng thì phải
  • Vũ Văn Thái lúc 04-11-2016, 20:01
    LM35 thì dùng áp nội cho chuẩn, chú ý khi làm áp nội chân vref bỏ trống không được nối vcc hoặc nối tụ 104 xuống mass, lý do phần cứng thật nếu nối lên 5v sẽ làm sai áp vref nội làm đo sai nhiệt độ.
  • sonuet lúc 04-11-2016, 15:48
    Chào a! e muốn hỏi sao em viết chương trình đo nhiệt độ bằng LM35 hiển thị LCD16X2 với ADC kênh đơn 10bit dùng điện áp tham chiếu VREF=5V. công thức tính T=read_adc*5/(0.01*1024).khi chạy nó luôn hiển thị 99oC là sao ạ?
  • Vũ Văn Thái lúc 21-06-2016, 22:04
    Bạn tải đính kèm về rồi sửa lại, chú ý ADLAR=0 dùng cho 10bit và ADLAR=1 dùng cho 8bit.
  • trannam1994 lúc 21-06-2016, 21:28
    e chào a,hi anh cho e hỏi sao e copy thay Chương trình con đọc ADC đơn kênh 10bit: vào mà không chạy được a
  • Vũ Văn Thái lúc 01-04-2016, 23:21
    Chào bạn, mình xin giải thích câu hỏi của bạn như sau:
        Câu lệnh while (!(ADCSRA & 0x10)); được thực hiện như sau: Ban đầu đọc giá trị trong thanh ghi ADCSRA ra sau đó sử dụng toán tử logic AND các bit trong thanh ghi với 0x10 (phép tính nhân bit) rồi sau đó được đảo bởi toán tử NOT (!) để tạo ra điều kiện đúng hoặc sai khi sử dụng vòng lặp while. VD: ADCSRA=0x03, sau khi AND 0x10 sẽ cho ra kết quả 0x00, tiếp tục NOT logic sẽ bằng 1 (true) tại sao bằng true mà không phải 0xff là vì đây là toán tử dùng để đảo mức khi giá trị đó lớn hơn 0 (logic 1) hoặc bằng 0 (logic 0) do đó điều kiện while lúc này là luôn đúng vi điều khiển sẽ chạy lệnh NOP do trong while không có gì. Trong trường hợp cờ chuyển đổi ADC được set VD ADCSRA=0x12, sau khi AND với 0x10 sẽ cho ra kết quả 0x10 lớn hơn 0 (logic 1) qua đảo bit sẽ bằng 0 (false), vòng lặp while thoát.
        Câu lệnh ADCSRA|=0x10; là ta ghi lại cờ để phần cứng nó xóa cờ ngắt chuyển đổi ADC.
  • Trang 1/3: 123Sau

    Bài viết cùng chuyên mục
    ATMG16 giao tiếp với LCD ATMG16 giao tiếp với LCD
    Đăng bởi: haydayanh - Thời gian: 04-06-2021, 22:33
    Chuyên mục: Học lập trình AVR - Lượt xem: 2.680
    Hướng dẫn làm KIT AVR đơn giản Hướng dẫn làm KIT AVR đơn giản
    Đăng bởi: Vũ Văn Thái - Thời gian: 25-10-2014, 09:39
    Chuyên mục: Học lập trình AVR - Lượt xem: 11.061
    [Bài 6] Lập trình giao tiếp USART và RS232 với AVR [Bài 6] Lập trình giao tiếp USART và RS232 với AVR
    Đăng bởi: Vũ Văn Thái - Thời gian: 15-08-2014, 15:25
    Chuyên mục: Học lập trình AVR - Lượt xem: 19.125
    [Bài 4] Lập trình giao tiếp LCD16x2 cho AVR trên CodeVisionAVR [Bài 4] Lập trình giao tiếp LCD16x2 cho AVR trên CodeVisionAVR
    Đăng bởi: Vũ Văn Thái - Thời gian: 22-06-2014, 10:42
    Chuyên mục: Học lập trình AVR - Lượt xem: 24.147
    [Bài 3] Lập trình ngắt cho AVR trên CodeVisionAVR [Bài 3] Lập trình ngắt cho AVR trên CodeVisionAVR
    Đăng bởi: Vũ Văn Thái - Thời gian: 16-06-2014, 14:06
    Chuyên mục: Học lập trình AVR - Lượt xem: 23.176
    [Bài 2] Tìm hiểu bộ Timer-Counter trên AVR [Bài 2] Tìm hiểu bộ Timer-Counter trên AVR
    Đăng bởi: Vũ Văn Thái - Thời gian: 15-06-2014, 11:55
    Chuyên mục: Học lập trình AVR - Lượt xem: 20.607
    [Bài 1] Xuất nhập Port đơn giản cho AVR [Bài 1] Xuất nhập Port đơn giản cho AVR
    Đăng bởi: Vũ Văn Thái - Thời gian: 29-05-2014, 21:22
    Chuyên mục: Học lập trình AVR - Lượt xem: 9.828
    Hướng dẫn set fuse bit cho AVR Hướng dẫn set fuse bit cho AVR
    Đăng bởi: Vũ Văn Thái - Thời gian: 16-05-2014, 22:09
    Chuyên mục: Học lập trình AVR - Lượt xem: 22.631
    Mạch nạp ISP cho vi điều khiển AVR và 89S Mạch nạp ISP cho vi điều khiển AVR và 89S
    Đăng bởi: Vũ Văn Thái - Thời gian: 10-05-2014, 12:22
    Chuyên mục: Học lập trình AVR - Lượt xem: 20.752
    Lập trình C trong CodeVisionAVR Lập trình C trong CodeVisionAVR
    Đăng bởi: Vũ Văn Thái - Thời gian: 28-04-2014, 19:30
    Chuyên mục: Học lập trình AVR - Lượt xem: 17.138
    
    Chào mừng hieutrang đã tham gia câu lạc bộ sáng tạo!
    Vũ Văn Thái - vuthai
    Hôm nay là sinh nhật của thien_tai_bk, nguyenvanly10153023, congnam1994, Tubaden, phamvanle, tranhung_09, kakaricardo, kakuta827, minhtrieudtv, tranconganhtu, ngochoanvfone, vantung2004, huynhngoctan_04dhdt, superprofessorA30, ntt762001, huynhngoctan95, phamnhatcuongddt, quangthang25, nguyenhuuphuoc2096, tan00123, gauxam, hvhieu, music1234, huynhngoctan, malacuda, NguyenCuong, caotrungtruc2041996, Quachdaik, Nhattanfc, minhk45, hoangthuong052, trancaoson181945, tuphuong, sangtaoclup_96, khaiptc2, Ngoctram27, no1bestrivenpt, ← Gửi tin nhắn chúc mừng
    Múi giờ: UTC+07:00 - Asia/Ho Chi Minh ***** IP của bạn: 3.145.156.250 ***** Status: Cache Update thành công!