Tìm hiểu về Giao tiếp ADC của PIC16F877

1. Chuẩn bị phần cứng:
Trong bài này chúng ta sử dụng biến trở kết nối với 1 chân ADC của PIC16F887.
Khi vặn biến trở thì mức điện áp vào chân ADC sẽ thay đổi từ 0-5V.


Sơ đồ nguyên lý (schematic):

 

- Các bạn có thể gắn trên breadboard, hàn trên mạch lỗ, hoặc làm mạch in.
- Biến trở có giá trị 10k (103), nên mua loại volume cho dễ vặn (tất nhiên là các loai nào khác cũng được)


- Chân ở giữa của biến trở là “chân chạy” thì các bạn hàn với trở 1k rồi nối vào 1 header để gắn vào chân ADC của PIC.

Kết nối:
+ Header source in: cấp nguồn 5VDC.
+ Header 1: Kết nối với 1 chân ADC bất kì của PIC (ANx).
- Khi vặn biến trở xuống vị trí (3) thì áp đọc vào là 0V.
- Khi vặn biến trở lên vị trí (1) –> Đọc về 5V, nếu không có điện trở R5 1kOhm hạn dòng thì chân I/O của PIC có khả năng sẽ chết.


2. Slide bài giảngADC.pdf

3. Clip bài giảng:

Phần 1:

(mời bạn xem tại link này)

Phần 2:

(mời bạn xem tại link này)

4. Sample code:
Chương trình sau đây có nhiệm vụ:
- Chọn kênh ADC là AN3.
- Cấu hình cho module ADC (xem phần chú thích trong code)
- Đọc kết quả chuyển đổi ADC và kiểm tra nếu áp ngõ vào analog > 2.5V thì bật các LEDs gắn ở PORTB lên.


Các phần cấu hình, khởi tạo, đọc kết quả ADC, … đều được viết thành các chương trình con.
Các chú thích cần thiết được viết đầy đủ để có thể dễ dàng chỉnh sửa cấu hình khi cần.

/****************************************************************
*
* www.payitforward.edu.vn
*
****************************************************************/
/****************************************************************
*
* PIC Training Course
*
****************************************************************/
/****************************************************************
*
* Module : adc_main.c
* Description : Read ADC from AN3 channel
* If ADC_result > 2.5V then Turn On LEDs
* Tool : HI-TECH PIC
* Chip : 16F887
* History : 05/03/2011
*
* Author : Nguyen Tien Manh, CLB NCKH
* Notes :
*
*
****************************************************************/

/****************************************************************
* IMPORT
****************************************************************/

#include
__CONFIG(XT & WDTDIS & PWRTEN & MCLREN & UNPROTECT & SWBOREN &
IESODIS & FCMDIS & LVPDIS & DEBUGDIS); //1st config. Word

__CONFIG(BORV21); //2st config. Word
#define _XTAL_FREQ 4000000
/****************************************************************
* EXTERN
****************************************************************/
/*none...*/

/*****************************************************************
GLOBAL VARIABLE
******************************************************************/
/*none...*/

/*****************************************************************
* ROUTINES
******************************************************************/
void port_init()
{
ANSEL = 0x08; // Chon kenh ADC AN3
ANSELH = 0;
TRISA3 = 1; //RA3 phai la Input de doc ADC
TRISB = 0; //PortB de xuat LED nen la OutPut
PORTB = 0xFF // Tat het LED o portB
}

//----------------------------------------------------------------
void adc_init()
{
// ADC conversion clock: = Fosc/8
// ADCS <1:0> = 00 Fosc/2
// ADCS <1:0> = 01 Fosc/8
// ADCS <1:0> = 10 Fosc/32
// ADCS <1:0> = 11 F_RC
ADCS1 = 0;
ADCS0 = 1;

// Voltage reference: Internal Vref
// VCFG <1:0> = 00 Internal Vref
// VCFG <1:0> = 11 External Vref
VCFG1 = 0;
VCFG0 = 0;

// Select Input chanel: AN3
// CHS <3:0> = 0000 Select AN0
// CHS <3:0> = 0001 Select AN1
// CHS <3:0> = 0010 Select AN2
// ...
// CHS <3:0> = 1101 Select AN13
CHS3 = 0;
CHS2 = 0;
CHS1 = 1;
CHS0 = 1;

// Result format: Right
// ADFM = 1 Right justified
// ADFM = 0 Left justified
ADFM = 1;

// Turn on ADC Module
ADON = 1;

//delay to wait for adc module init.
__delay_ms (1);
}

//----------------------------------------------------------------
//interrupt initialization
void int_init()
{
GIE = 1; //Global Interrupt Enable
PEIE = 1; //Peripheral Interrupt Enable
ADIE = 1; //ADC Interrupt Enable
ADIF = 0; //Clear ADC Interrupt Flag
}

//----------------------------------------------------------------
//Interrupt service rountine
void interrupt isr()
{
int ADC_result;
if (PEIE && ADIE && ADIF)
{
ADIF = 0; //Clear ADC Interrupt Flag

//Read ADC result
ADC_result = (ADRESH<<8)|ADRESL;
//V_in > 2.5V <=> ADC_result > 512
if (ADC_result> 512)
{
PORTB = 0; //Turn LEDs ON
}
else
{
PORTB = 0xFF;
}
}
}

/****************************************************************
* MAIN
****************************************************************/

/* -- void main (void) -----------------------------------------
*
* Description : Configure port, adc module and enable interrupt
* then wait for ADC interrupt
* Parameters : none
* Return : don't care
* Notes :
*/

void main(void)
{
port_init();
adc_init();
int_init();
while(1)
{
__delay_us(50); //delay between 2 AD conversions
GODONE = 1; //Set GODONE bit to start conversion
};
}

/****************************************************************
* END OF adc_main.c
****************************************************************/

5. Bài tập:

Đọc giá trị điện áp (0-5V) từ 1 chân ADC của PIC và hiển thị kết quả lên LCD, với – Đọc giá trị ADC từ chân AN3 (giá trị này nằm trong phạm vi 0-1023)
- Tính toán ra giá trị điện áp (Volt) thực tế?
- Giá trị điện áp này yêu cầu lấy tới 3 chữ số thập phân: 0.000
- Hiển thị kết quả lên LCD.
Ví dụ: “V_in = 1.352 V”


  • Làm thế nào để căn chuẩn và tính toán bộ ADC



Làm thế nào để căn chuẩn (calibrate) bộ ADC 



 

Bộ chuyển đổi tín hiệu tương tự sang số được sử dụng một cách rộng rãi trong rất nhiều ứng dụng ví dụ như thu âm, các thiết bị sinh học, kiểm tra và giám sát các thiết bị, v.v. Có rất nhiều bộ ADC trên thị trường nơi mà một kĩ sư thiết kế điện tử có khả năng chọn mô hình phù hợp nhất dựa vào hai nhân tố sau:

o Độ phân giải (resolution), cái mà phụ thuộc vào số bit sử dụng để lưu trữ giá trị chuyển đổi. Ví dụ một bộ ADC có độ phân giải 12-bit có bit có giá trị nhỏ nhất tương đương với 1/(2^12). Nếu điện áp tham chiếu tương đương với 5V thì nó sẽ có khả năng thực hiện sự chuyển đổi với độ phân giải 0.01953125V.
o Tốc độ, được biểu diễn bởi thời gian yêu cầu để hoàn thành quá trình chuyển đổi (conversion time). Một vài loại ADC được gọi là “flash converter”, cách gọi này hoàn toàn đúng bởi chúng có thời gian chuyển đổi là rất nhỏ so với những bộ ADC khác. Trong một vài trường hợp thì độ phân giải lại được ưa chuộng hơn thời gian chuyển đổi. Ví dụ một bộ chuyển đổi ADC có độ phân giải 24-bit với thời gian chuyển đổi là 100ms thì lại có thời gian chuyển đổi không thực sự cao.
Một bộ ADC lí tưởng là bộ mà có kết quả chuyển đổi hoàn toàn chính xác và tỉ lệ tuyến tính với tín hiệu lối vào.
Thực thế là một bộ ADC bị ảnh hưởng bởi 3 ba loại lỗi chủ yếu. Bây giờ ta sẽ xem xét các lỗi đó và chúng xảy ra như thế nòa, thuật toán để cho vi xử lí hoặc vi điều khiển, thủ tục căn chuẩn.

Hình 1 chỉ ra đặc tính điện áp của một bộ ADC lí tưởng: trục x là điện áp vào (Vin), trục y là giá trị số (N) thu được tương ứng với giá trị chuyển đổi. Vref là điện áp tham chiếu của bộ ADC. Với Vin=Vref, thì ta có N=(2^Nres)-1, với Nres là độ phân giải, được biểu diễn như là số của các bits. Ví dụ một bộ ADC có độ phân giải 8bit với điện áp tham chiếu 5V, sẽ cung cấp N=(2^8)-1=255 giá trị chuyển đổi khi Vin=5V. Tuy nhiên thực tế thì khác với li tưởng. Lỗi đầu tiền là lỗi offset error, chỉ ra ở hình 2. Offser error được đo bởi số bit có giá trị nhỏ nhất (LSB) (1 LSB tương đương với 1/2^Nres) đưa ra bởi bộ ADC khi mà Vin =0. Một bộ ADC lí tưởng sẽ luôn co N=0 khi Vin=0.
Bây giờ chúng ta sẽ xem xét đến đặc tính điện của một bộ ADC thương mại, chính xác hơn là ADC0800 của National Semiconductor.Nó là bộ ADC 8 –bit.

 



 

Nhìn vào datasheet, ta thấy rằng lỗi offset đối với bộ chuyển đổi này là (còn được gọi là zero error) là +/-2 LSB .
Loại lỗi thứ hai là gain error, như trong hình 3. Gain error được gây ra bởi sự không hoàn hảo bộ khuếch đại của bộ ADC, đường dốc thể hiện đặc tính của nó thì khác so với li thuyết. Loại lỗi này là lỗi hệ thống (có nghĩa là luôn có thể xuất hiện lại) và theo một qui luật tuyến tính. Bởi vì thực tế này, ta có thể biểu diễn toàn bộ gain error như một sự dịch, khi Vin=Vref của giá trị chuyển đổi so với một giá trị lí tưởng. Do đó gain error có thể được biểu diễn bằng một số lần LSB (a*LSB). Trong trường hợp ADC0800, gain error tương đương với +/-2LSB.
Loại lỗi thứ ba là lỗi không tuyến tính non linearity error, tức là đặc tính của ADC không phải là một đường thẳng. Nó thường được đó bằng độ khoảng cách lớn nhất giữa đường thực với đường li tưởng. Đối với ADC0800 lỗi này là +/-1LSB.
Bây giờ ta sẽ xem thủ tục để điều chỉnh lỗi offset và gain. Thủ tục gồm hai bước:
1. Thiết lập Vin=0. Giá trị chuyển đổi được Nzero, đọc từ ADC sau đó lưu vào persistent memory ( ví dụ: eeprom memory).
2. Thiết lập Vin=Vfull (Vreff) tương ứng ta có giá trị chuyển đổi Nfs, sau đó đọc từ ADC và lưu vào một persisten memory (eeprom hoặc NVRAM).
Phương trình lí tưởng:
N = ( (2 ^ Nres) – 1) / Vref) x Vin
Phương trình thưc tế:
N’ = ((Nfs – Nzero) / Vref) x Vin + Nzero
Theo cách này ta sẽ thu được một phương trinh biểu diễn đặc tính thực của bộ ADC. Nzero và Nfs có thể được lưu trong eeprom hoặc NVRAM và được thay đổi khi bộ ADC được đặt lần đầu tiên trong mạch hoặc được thay thế bởi bộ ADC khác khi nó hoạt động không chính xác nữa.

Post a Comment

Mới hơn Cũ hơn