I.Sơ đồ khối ADC
Bộ chuyển đổi tương tự sang số – ADC (Analog to Digital Converter) nhận mức điện thế vào dạng tương tự. Sau đó, sau một khoảng thời gian, nó sẽ tạo ra mã đầu ra dạng số để biểu diễn mức điện thế vào ban đầu. Quá trình chuyển đổi từ tương tự sang số thường phức tạp hơn quá trình chuyển đổi từ số sang tương tự. Vì vậy, có nhiều phương pháp khác nhau để thực hiện chuyển đổi từ tương tự sang số. Sơ đồ khối dưới đây là một ví dụ về một ADC đơn giản.
Hoạt động cơ bản của loại ADC này như sau:
- Xung lệnh START khởi động quá trình chuyển đổi.
- Xung Clock điều khiển việc điều chỉnh số nhị phân được lưu trong thanh ghi liên tục.
- Số nhị phân trong thanh ghi được chuyển đổi sang mức điện thế tương tự VAX bởi DAC.
- Bộ so sánh so sánh VAX với đầu vào tương tự VA. Nếu VAX = VA, chênh lệch ít nhất bằng một ngưỡng VT (điện thế ngưỡng), đầu ra của bộ so sánh sẽ được đặt ở mức thấp và quá trình chuyển đổi số nhị phân trong thanh ghi sẽ dừng lại. Lúc này, VAX xấp xỉ VA. Giá trị nhị phân trong thanh ghi là đại lượng tương đương với VAX và cũng là đại lượng tương đương với VA, trong giới hạn độ phân giải và độ chính xác của hệ thống.
- Logic điều khiển kích hoạt tín hiệu ECO sau khi chu kỳ chuyển đổi kết thúc.
- Tiến trình này có thể thay đổi tùy thuộc vào từng loại ADC khác nhau, chủ yếu là sự khác nhau trong cách bộ điều khiển điều chỉnh số nhị phân trong thanh ghi.
- IC ADC0808 là một vi mạch tích hợp có chức năng chuyển đổi tín hiệu tương tự sang kỹ thuật số (Analog to Digital Converter), với độ phân giải 8 bit. Điều đó có nghĩa là nó sẽ chuyển đổi tín hiệu điện tương tự thành 256 mức điện áp so với Vref đưa vào bộ chuyển đổi. Bạn có thể xem datasheet của nó trong tệp đính kèm.
1.Sơ đồ chân
Dưới đây là chức năng của từng chân ADC0808:
- IN0-7 – ngõ vào tín hiệu Analog
- START – chân điều khiển tín hiệu bắt đầu quá trình chuyển đổi ADC.
- EOC – Chân phát tín hiệu báo kết thúc quá trình chuyển đổi ADC.
- 2-1 – 2-8 – Ngõ ra tín hiệu số – Data 8 bit.
- OUT EN – Chân cho phép xuất.
- CLK – chân nhận nguồn xung Clock.
- Vcc/ GND – Chân nhận điện nguồn dương.
- Vref+/ Vref- – Chân nhận/input điện áp tham chiếu.
- ALE – Address Latch Enable.
- ADD A, B, C – Address Input A, B, C (xác định ngõ vào).
ADC0808 có tổng cộng 8 đầu vào Analog, được xác định bởi A, B, C (từ 000 đến 111)! Chúng ta cần lưu ý rằng tầm điện áp đầu vào Analog là từ 0 đến 5V, tương ứng với mức 0 và mức 255 ở đầu ra. Tuy nhiên, chúng ta cũng có thể chọn giá trị đầu vào nhỏ hơn vẫn có thể chia cho 255 thông qua việc điều chỉnh điện áp trên chân điện áp tham chiếu Vref, ví dụ như 2,55V.
II.Cảm biến nhiệt độ LM35
LM35 là một cảm biến nhiệt độ, có tín hiệu điện áp đầu ra biến đổi theo nhiệt độ. Mỗi 10mV tương ứng với 1 độ C và IC này có khoảng đo từ -55 độ C đến 150 độ C, với điện áp cấp từ 4-20VDC. Để đo được nhiệt độ âm (-), ta cần cung cấp thêm nguồn -Vs cho IC:
III.Lập trình giao tiếp ADC0808
Chương trình sau sẽ tự động cập nhật giá trị nhiệt độ từ LM35 thông qua ADC0808, sau đó hiển thị lên màn hình LCD 16×2. Nó cũng tạo xung đồng hồ cho IC ADC0808 sử dụng ngắt timer.
Đầu tiên, chúng ta sẽ xây dựng hai hàm giao tiếp LCD và ADC0808:
- Hàm LCD16x2:
- LCD_Init(): Hàm khởi tạo LCD
- LCD_Clear(): Hàm xóa màn hình
- LCD_Gotoxy(X,Y): Hàm di chuyển đến vị trí trên màn hình.
- LCD_PutChar(c): Hàm gửi một ký tự ASCII lên LCD.
- LCD_Puts(“String”): Hàm gửi một chuỗi ký tự lên LCD.
- ADC0808:
- ADC0808_Read(channel): Hàm đọc giá trị ADC theo kênh từ 0-7.
Đồng thời, chúng ta cũng cần một số hàm khác như hàm delay, tính nhiệt độ và chuyển đổi hiển thị. Chi tiết hơn về mã nguồn có thể được tìm thấy trong đoạn code dưới đây! Tiếp theo, chúng ta sẽ thiết kế mạch kết nối giữa vi điều khiển 8051 và ADC0808.
Trong vi điều khiển 8051, chúng ta sẽ sử dụng PORT2 làm port nhập dữ liệu của ADC808. Chúng ta cần ba chân để điều khiển chân đầu vào tín hiệu của ADC, đó là P3.2, P3.3 và P3.4.
Ngoài ra, để có thể điều khiển được quá trình truy xuất/giao tiếp với ADC, chúng ta cũng cần một số chân để kết nối với ADC0808, bao gồm:
- Chân EOC của ADC0808 sẽ kết nối với chân P1.4 của 8051
- Chân OE của ADC0808 sẽ kết nối với chân P1.5 của 8051
- Chân LE của ADC0808 sẽ kết nối với chân P1.7 của 8051
- Chân START của ADC0808 sẽ kết nối chung với chân LE
- Nguồn xung clock cung cấp cho ADC0808 sẽ được tạo ra bởi chính chân P1.6
Một số chân khác của vi điều khiển cũng được sử dụng để điều khiển LCD:
- Chân E của LCD sẽ được điều khiển bởi chân P3.5 của 8051
- Chân RS của LCD sẽ được điều khiển bởi chân P3.6 của 8051
- Chân RW của LCD sẽ được điều khiển bởi chân P3.7 của 8051
1.Code
/*Do nhiet do dung LM35 va ADC0808 hoac ADC0809*/
#include <REGX52.H>
#define VREF 5
//Khai báo các chân giao tiếp ADC0808
#define ADC0808_DATA P3
#define ADC0808_A P2_0
#define ADC0808_B P2_1
#define ADC0808_C P2_2
#define ADC0808_ALE P2_3
#define ADC0808_START P2_4
#define ADC0808_EOC P2_5
#define ADC0808_OE P2_6
#define ADC0808_CLK P2_7
//Khai báo các chân giao tiếp LCD16x2 4bit
#define LCD_RS P0_0
#define LCD_RW P0_1
#define LCD_EN P0_2
#define LCD_D4 P0_4 // Truyền dữ liệu qua 4 chân
#define LCD_D5 P0_5
#define LCD_D6 P0_6
#define LCD_D7 P0_7
/*Hàm đọc và điều khiển ADC0808*/
unsigned char ADC0808_Read(unsigned char channel) {
unsigned char result;
ADC0808_A = channel & 0x01;
ADC0808_B = channel & 0x02;
ADC0808_C = channel & 0x04;
ADC0808_ALE = 1;
ADC0808_START = 1;
ADC0808_ALE = 0;
ADC0808_START = 0;
while (ADC0808_EOC);
while (!ADC0808_EOC);
ADC0808_OE = 1;
result = ADC0808_DATA;
ADC0808_OE = 0;
return result;
}
/*Hàm delay*/
void delay_us(unsigned int t) {
unsigned int i;
for (i = 0; i < t; i++);
}
void delay_ms(unsigned int t) {
unsigned int i, j;
for (i = 0; i < t; i++)
for (j = 0; j < 123; j++);
}
/*Chương trình giao tiếp LCD 16x2 4bit*/
void LCD_Enable(void) {
LCD_EN = 1;
delay_us(3);
LCD_EN = 0;
delay_us(50);
}
void LCD_Send4Bit(unsigned char Data) {
LCD_D4 = Data & 0x01;
LCD_D5 = (Data >> 1) & 1;
LCD_D6 = (Data >> 2) & 1;
LCD_D7 = (Data >> 3) & 1;
}
void LCD_SendCommand(unsigned char command) {
LCD_Send4Bit(command >> 4);
LCD_Enable();
LCD_Send4Bit(command);
LCD_Enable();
}
void LCD_Clear() {
LCD_SendCommand(0x01);
delay_us(10);
}
void LCD_Init() {
LCD_Send4Bit(0x00);
delay_ms(20);
LCD_RS = 0;
LCD_RW = 0;
LCD_Send4Bit(0x03);
LCD_Enable();
delay_ms(5);
LCD_Enable();
delay_us(100);
LCD_Enable();
LCD_Send4Bit(0x02);
LCD_Enable();
LCD_SendCommand(0x28);
LCD_SendCommand(0x0c);
LCD_SendCommand(0x06);
LCD_SendCommand(0x01);
}
void LCD_Gotoxy(unsigned char x, unsigned char y) {
unsigned char address;
if (!y)
address = (0x80 + x);
else
address = (0xc0 + x);
delay_us(1000);
LCD_SendCommand(address);
delay_us(50);
}
void LCD_PutChar(unsigned char Data) {
LCD_RS = 1;
LCD_SendCommand(Data);
LCD_RS = 0;
}
void LCD_Puts(char *s) {
while (*s) {
LCD_PutChar(*s);
s++;
}
}
/*Hiển thị nhiệt độ trên LCD*/
void TempShow(unsigned char temp) {
LCD_Puts("Nhiệt độ: ");
LCD_PutChar((temp / 100) + 48);
LCD_PutChar((temp % 100 / 10) + 48);
LCD_PutChar((temp % 10) + 48);
LCD_Puts(" °C");
}
/*Chương trình ngắt timer 0*/
void INT_Timer0() interrupt 1 {
ADC0808_CLK = ~ADC0808_CLK; // Đảo bit xung clock
}
/*Chương trình chính*/
unsigned char temperature;
void main() {
//Tạo xung clock cho ADC0808 - sẽ học sau
TMOD = 0x02;
TH0 = TL0 = 236;
TR0 = 1;
ET0 = 1; //Ngắt timer0
EA = 1; //Cho phép ngắt toàn cục
LCD_Init(); //Khởi tạo LCD
delay_ms(200);
LCD_Puts("Đang đo nhiệt độ...");
delay_ms(1000);
LCD_Clear();
LCD_Gotoxy(0, 1);
LCD_Puts("KT.VIXULY- PTIT");
while (1) {
LCD_Gotoxy(0, 0);
temperature = ADC0808_Read(0);
TempShow(temperature);
delay_ms(500);
}
}
2. Mô phỏng trên Proteus
Dưới đây là danh sách một số thiết bị trong mô phỏng:
Tại sao `temp = ADC0808_Read(0) = ADC0808_DATA`?
Giải thích như sau:
Với LM35, khi nhiệt độ tăng 1 độ C, điện áp đầu ra tăng 0.01V. Trong bài này, chúng ta không đo được nhiệt độ âm. Chúng ta chỉ đo nhiệt độ từ 0-150, thay vì -55 đến 150 độ C, điện áp đầu ra của LM35 từ 0-1.5V, cũng chính là Vin của ADC.
Công thức tính điện áp chuyển đổi sang dạng số của ADC là:
- ADC0808_DATA = (Vin/Vref) * 255
- Từ đó suy ra Vin = (ADC0808_DATA * Vref)/255
- Từ đó suy ra nhiệt độ temp = Vin/100
- Khi chúng ta đặt Vref = 2.55V, thì kết quả temp = ADC0808_DATA.