Đây là hướng dẫn thứ 9 của chúng tôi về Học vi điều khiển PIC sử dụng MPLAB và XC8. Cho đến bây giờ, chúng tôi đã đề cập đến nhiều hướng dẫn cơ bản như bắt đầu với MPLABX, đèn LED nhấp nháy với PIC, Bộ hẹn giờ trong PIC, màn hình LCD giao diện, giao diện 7 đoạn, v.v. Nếu bạn là người mới bắt đầu, vui lòng truy cập danh sách đầy đủ các hướng dẫn PIC tại đây và bắt đầu học.
Trong hướng dẫn này, chúng ta sẽ học Cách sử dụng ADC với bộ vi điều khiển PIC PICF877A của chúng tôi. Hầu hết các dự án Vi điều khiển sẽ liên quan đến bộ chuyển đổi ADC (Analog to Digital) trong đó, bởi vì nó là một trong những cách được sử dụng nhiều nhất để đọc dữ liệu từ thế giới thực. Hầu hết tất cả các cảm biến như cảm biến nhiệt độ, cảm biến từ thông, cảm biến áp suất, cảm biến dòng điện, cảm biến điện áp, con quay hồi chuyển, gia tốc kế, cảm biến khoảng cách và hầu hết mọi cảm biến hoặc bộ chuyển đổi đã biết đều tạo ra điện áp tương tự từ 0V đến 5V dựa trên số đọc của cảm biến. Ví dụ, một cảm biến nhiệt độ có thể cho ra 2,1V khi nhiệt độ là 25C và lên đến 4,7 khi nhiệt độ là 60C. Để biết nhiệt độ của thế giới thực, MCU chỉ cần đọc điện áp đầu ra của cảm biến nhiệt độ này và liên hệ nó với nhiệt độ trong thế giới thực. Do đó ADC là một công cụ làm việc quan trọng cho các dự án MCU và chúng ta hãy tìm hiểu cách chúng ta có thể sử dụng nó trên PIC16F877A của mình.
Ngoài ra, hãy xem các bài viết trước của chúng tôi về cách sử dụng ADC trong các bộ vi điều khiển khác:
ADC in PIC Microcontroller PIC16F877A:
Các kênh tương tự AN0 đến AN7 được đánh dấu cho bạn. Chỉ những chân này mới có thể đọc điện áp tương tự. Vì vậy, trước khi đọc điện áp đầu vào, chúng ta phải chỉ định trong mã của mình kênh nào phải được sử dụng để đọc điện áp đầu vào. Trong hướng dẫn này, chúng tôi sẽ sử dụng kênh 4 với một chiết áp để đọc điện áp tương tự tại kênh này.
Mô-đun A / D có bốn thanh ghi phải được cấu hình để đọc dữ liệu từ các chân Đầu vào. Các thanh ghi này là:
• Đăng ký A / D Kết quả Cao (ADRESH)
• Đăng ký kết quả thấp A / D (ADRESL)
• Thanh ghi điều khiển A / D 0 (ADCON0)
• Thanh ghi điều khiển A / D 1 (ADCON1)
Programming for ADC:
Trong thanh ghi này, chúng ta phải bật mô-đun ADC bằng cách đặt ADON = 1 và bật Đồng hồ chuyển đổi A / D bằng cách sử dụng các bit ADCS1 và bit ADCS0, phần còn lại sẽ không được thiết lập ngay bây giờ. Trong chương trình của chúng tôi, đồng hồ chuyển đổi A / D được chọn là Fosc / 16, bạn có thể thử các tần số của riêng mình và xem kết quả thay đổi như thế nào. Chi tiết đầy đủ có trên trang của biểu dữ liệu 127. Do đó ADCON0 sẽ được khởi tạo như sau.
ADCON0 = 0b01000001;
Trong thanh ghi này, chúng ta phải thực hiện Định dạng kết quả A / D Chọn bit cao bằng ADFM = 1 và đặt ADCS2 = 1 để chọn lại Fosc / 16. Các bit khác vẫn bằng 0 vì chúng tôi đã lên kế hoạch sử dụng điện áp tham chiếu bên trong. Chi tiết đầy đủ có trên biểu dữ liệu trang 128. Do đó ADCON1 sẽ được chúng tôi thiết lập như sau.
ADCON1 = 0x11000000;
Bây giờ sau khi khởi tạo mô-đun ADC bên trong chức năng chính của chúng ta, hãy vào vòng lặp while và bắt đầu đọc các giá trị ADC. Để đọc giá trị ADC, bạn phải thực hiện theo các bước sau.
Khởi tạo mô-đun ADC
Chọn kênh analog
Bắt đầu ADC bằng cách tăng bit Go / Done
Chờ bit Go / DONE xuống thấp
Nhận kết quả ADC từ thanh ghi ADRESH và ADRESL
1. Khởi tạo Mô-đun ADC: Chúng ta đã học cách khởi tạo một ADC nên chúng ta chỉ cần gọi hàm dưới đây để khởi tạo ADC
Hàm void ADC_Initialize () như sau.
void ADC_Initialize() { ADCON0 = 0b01000001; //ADC ON and Fosc/16 is selected ADCON1 = 0b11000000; // Internal reference voltage is selected }
2. Chọn kênh analog: Bây giờ chúng ta phải chọn kênh mà chúng ta sẽ sử dụng để đọc giá trị ADC. Hãy tạo một hàm cho điều này, để chúng ta dễ dàng chuyển đổi giữa mỗi kênh bên trong vòng lặp while.
unsigned int ADC_Read(unsigned char channel) { //****Selecting the channel**/// ADCON0 &= 0x11000101; //Clearing the Channel Selection Bits ADCON0 |= channel<<3; //Setting the required Bits //**Channel selection complete***/// }
Sau đó, kênh được chọn sẽ được nhận bên trong kênh biến đổi. Trong dòng
ADCON0 &= 0x1100101;
Lựa chọn kênh trước đó (nếu có) sẽ bị xóa. Điều này được thực hiện bằng cách sử dụng bitwise và toán tử “&”. Các bit 3, 4 và 5 buộc phải bằng 0 trong khi các bit khác được giữ nguyên ở các giá trị trước đó của chúng.
Sau đó, kênh mong muốn được chọn bằng cách chuyển sang trái ba lần số kênh và thiết lập các bit bằng cách sử dụng bitwise hoặc toán tử “|”.
ADCON0 |= channel<<3; //Setting the required Bits
3. Bắt đầu ADC bằng cách đặt bit Go / Done lên cao: Khi kênh được chọn, chúng ta phải bắt đầu chuyển đổi ADC đơn giản bằng cách đặt bit GO_nDONE lên cao:
GO_nDONE = 1; //Initializes A/D Conversion
4. Chờ bit Go / DONE xuống thấp: Bit GO / DONE sẽ ở mức cao cho đến khi quá trình chuyển đổi ADC hoàn tất, do đó chúng ta phải đợi cho đến khi bit này xuống thấp một lần nữa. Điều này có thể được thực hiện bằng cách sử dụng một vòng lặp while.
while(GO_nDONE); //Wait for A/D Conversion to complete
Lưu ý: Đặt dấu chấm phẩy bên cạnh while sẽ làm cho chương trình được giữ ở đó cho đến khi điều kiện của vòng lặp while là sai.
5. Lấy kết quả ADC từ thanh ghi ADRESH và ADRESL: Khi bit Go / DONE xuống thấp trở lại có nghĩa là quá trình chuyển đổi ADC đã hoàn tất. Kết quả của ADC sẽ là giá trị 10 bit. Vì MCU của chúng tôi là MCU 8 bit nên kết quả được chia thành 8 bit trên và 2 bit dưới. Kết quả 8 bit trên được lưu trong thanh ghi ADRESH và 2 bit dưới được lưu trong thanh ghi ADRESL. Do đó, chúng tôi phải thêm chúng vào các thanh ghi để có được giá trị ADC 10-bit của chúng tôi. Kết quả này được trả về bởi hàm như hình dưới đây:
return ((ADRESH<<8)+ADRESL); //Returns Result
Chức năng hoàn chỉnh được sử dụng để chọn kênh ADC, kích hoạt ADC và trả về kết quả được hiển thị ở đây.
unsigned int ADC_Read(unsigned char channel) { ADCON0 &= 0x11000101; //Clearing the Channel Selection Bits ADCON0 |= channel<<3; //Setting the required Bits __delay_ms(2); //Acquisition time to charge hold capacitor GO_nDONE = 1; //Initializes A/D Conversion while(GO_nDONE); //Wait for A/D Conversion to complete return ((ADRESH<<8)+ADRESL); //Returns Result }
Bây giờ chúng ta có một hàm sẽ lấy lựa chọn kênh làm đầu vào và trả về cho chúng ta giá trị ADC. Do đó, chúng ta có thể gọi trực tiếp hàm này bên trong vòng lặp while của chúng ta, vì chúng ta đang đọc điện áp tương tự từ kênh 4 trong hướng dẫn này, lệnh gọi hàm sẽ như sau.
i = (ADC_Read(4)); //store the result of adc in “i”.
Hardware Setup and Testing:
Các kết nối của mô-đun hiển thị 4 chữ số bảy đoạn với vi điều khiển PIC cũng giống như dự án trước, chúng tôi chỉ thêm một chiết áp vào chân 7 là kênh tương tự 4. Bằng cách thay đổi nồi, một điện áp thay đổi sẽ được gửi đến MCU sẽ được đọc bởi mô-đun ADC và hiển thị trên Mô-đun hiển thị 7 đoạn. Xem hướng dẫn trước để tìm hiểu thêm về màn hình 7 đoạn 4 chữ số và giao diện của nó với PIC MCU.
Ở đây chúng tôi đã sử dụng cùng một bảng Vi điều khiển PIC mà chúng tôi đã tạo trong Hướng dẫn nhấp nháy đèn LED. Sau khi đảm bảo kết nối, hãy tải chương trình lên PIC và bạn sẽ thấy một đầu ra như thế này
Ở đây chúng tôi đã đọc giá trị ADC từ nồi và chuyển đổi nó thành điện áp thực tế bằng cách ánh xạ đầu ra 0-1024 dưới dạng 0-5 volt (như được hiển thị trong chương trình). Giá trị sau đó được hiển thị trên 7 đoạn và được xác minh bằng đồng hồ vạn năng.
Vậy là xong, bây giờ chúng tôi đã sẵn sàng sử dụng tất cả các Cảm biến Analog hiện có trên thị trường, hãy tiếp tục và thử cái này và nếu bạn gặp bất kỳ vấn đề nào như bình thường, hãy sử dụng phần bình luận, chúng tôi sẽ sẵn lòng giúp bạn.
CODE :
// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
#define _XTAL_FREQ 20000000
//***Define the signal pins of all four displays***//
#define s1 RC0
#define s2 RC1
#define s3 RC2
#define s4 RC3
//***End of definition**////
void ADC_Initialize()
{
ADCON0 = 0b01000001; //ADC ON and Fosc/16 is selected
ADCON1 = 0b11000000; // Internal reference voltage is selected
}
unsigned int ADC_Read(unsigned char channel)
{
ADCON0 &= 0x11000101; //Clearing the Channel Selection Bits
ADCON0 |= channel<<3; //Setting the required Bits
__delay_ms(2); //Acquisition time to charge hold capacitor
GO_nDONE = 1; //Initializes A/D Conversion
while(GO_nDONE); //Wait for A/D Conversion to complete
return ((ADRESH<<8)+ADRESL); //Returns Result
}
void main()
{ int a,b,c,d,e,f,g,h,adc; //just variables
int i = 0; //the 4-digit value that is to be displayed
int flag =0; //for creating delay
unsigned int seg[]={0X3F, //Hex value to display the number 0
0X06, //Hex value to display the number 1
0X5B, //Hex value to display the number 2
0X4F, //Hex value to display the number 3
0X66, //Hex value to display the number 4
0X6D, //Hex value to display the number 5
0X7C, //Hex value to display the number 6
0X07, //Hex value to display the number 7
0X7F, //Hex value to display the number 8
0X6F //Hex value to display the number 9
}; //End of Array for displaying numbers from 0 to 9
//*****I/O Configuration****//
TRISC=0X00;
PORTC=0X00;
TRISD=0x00;
PORTD=0X00;
//***End of I/O configuration**///
ADC_Initialize();
#define _XTAL_FREQ 20000000
while(1)
{
if(flag>=50) //wait till flag reaches 100
{
adc = (ADC_Read(4));
i = adc*0.488281;
flag=0; //only if flag is hundred "i" will get the ADC value
}
flag++; //increment flag for each flash
//***Splitting "i" into four digits***//
a=i%10;//4th digit is saved here
b=i/10;
c=b%10;//3rd digit is saved here
d=b/10;
e=d%10; //2nd digit is saved here
f=d/10;
g=f%10; //1st digit is saved here
h=f/10;
//***End of splitting***//
PORTD=seg[g];s1=1; //Turn ON display 1 and print 4th digit
__delay_ms(5);s1=0; //Turn OFF display 1 after 5ms delay
PORTD=seg[e];RD7=1;s2=1; //Turn ON display 2 and print 3rd digit
__delay_ms(5);s2=0; //Turn OFF display 2 after 5ms delay
PORTD=seg[c];s3=1; //Turn ON display 3 and print 2nd digit
__delay_ms(5);s3=0; //Turn OFF display 3 after 5ms delay
PORTD=seg[a];s4=1; //Turn ON display 4 and print 1st digit
__delay_ms(5);s4=0; //Turn OFF display 4 after 5ms delay
}
}