I /XỬ LÝ ADC :
+ PIC có nhiều chân ship hàng giải quyết và xử lý ADC với nhiều phương pháp khác nhau. Để dùng ADC, bạn phải có khai báo # DEVICE cho biết dùng ADC mấy bit ( tuỳ chip tương hỗ, thường là 8 hay 10 bit hoặc hơn ). Bạn cần chú ý quan tâm là : 1 VDK tương hỗ ADC 10 bit thì giá trị vào luôn là 10 bit, nhưng chia cho 4 thì còn 8 bit. Do đó 1 biến trở chiết áp cấp cho ngõ vào ADC mà bạn chọn chính sách 10 bit thì sẽ rất nhạy so với chính sách 8 bit ( vì 2 bit cuối có biến hóa cũng không ảnh hưởng tác động giá trị 8 bit cao và do đó hiệu quả 8 bit ADC ít biến hóa ), nếu chương trình có chính sách kiểm tra ADC để update đo lường và thống kê, hay dùng ngắt ADC, thì nó sẽ chạy hoài thôi. Dùng ADC 8 bit sẽ hạn chế điều này. Do đó mà CCS phân phối lựa chọn ADC 8 hay 10 bit tùy mục tiêu sử dụng .
Cấu hình bộ ADC :
+ Thông dụng nhất khi dùng ADC là sử dụng 1 biến trở, điều chỉnh bởi 1 nút vặn, qua đó thu được 1 điện áp nhỏ hơn điện áp tham chiếu ( Vref – áp max ), đưa vào chân biến đổi ADC, kết quả cho 1 giá trị số ADC 8 bit ( 0-255 ) hay ADC 10 bit (0-1023 ). Thường thì áp Vref lấy bằng Vdd ( 5V ).
+ Trên các PIC có ngõ AVdd và AVss ( PIC 18 ), thường thì bạn luôn nối AVdd tới Vdd, AVss tới Vss để đảm bảo họat động cho lập trình qua ICD 2 .
Các hàm sau phục vụ ADC :
1 / Setup_ADC ( mode ) :
+ Không trả về trị. Dùng xác định cách thức hoạt động bộ biến đổi ADC. Tham số mode tuỳ thuộc file thiết bị *.h có tên tương ứng tên chip bạn đang dùng, nằm trong thư mục DEVICES của CCS . Muốn biết có bao nhiêu tham số có thể dùng cho chip đó, bạn mở file tương ứng đọc, tìm tới chỗ các định nghĩa cho chức năng ADC dùng cho chip đó tương ứng với hàm này. Sau đây là các giá trị mode của 16F877, ( 1 số khác có thể không có hoặc có thêm như 16F877A có thêm 1 số thứ là ADC_CLOCK_DIV_2/4/8/16/32/64. . .) :
ADC_OFF : tắt hoạt động ADC ( tiết kiệm điện, dành chân cho hoạt động khác ) .
ADC_CLOCK_INTERNAL : thời gian lấy mẫu bằng xung clock IC ( mất 2-6 us ) thường là chung cho các chip .
ADC_CLOCK_DIV_2 : thời gian lấy mẫu bằng xung clock / 2 ( mất 0.4 us trên thạch anh 20MHz )
ADC_CLOCK_DIV_8 : thời gian lấy mẫu bằng xung clock / 8 ( 1.6 us )
ADC_CLOCK_DIV_32 : thời gian lấy mẫu bằng xung clock / 32 ( 6.4 us )
2 / Setup_ADC_ports ( value )
+ Xác định chân lấy tín hiệu analog và điện thế chuẩn sử dụng. Tùy thuộc bố trí chân trên chip, số chân và chân nào dùng cho ADC và số chức năng ADC mỗi chip mà value có thể có những giá trị khác nhau. Xem file tương ứng trong thư mục DEVICES để biết số chức năng tương ứng chip đó . Để tương thích chương trình viết cho phiên bản cũ, 1 số tham số có 2 tên khác nhau ( nhưng cùng chức năng do định nghĩa cùng địa chỉ ), ở đây dùng phiên bản 3.227 .Lưu ý : Vref : áp chuẩn, Vdd : áp nguồn .
Sau đây là các giá trị cho value ( chỉ dùng 1 trong các giá trị ) của 16F877 :
ALL_ANALOGS ………: dùng tất cả chân sau làm analog : A0 A1 A2 A3 A5 E0 E1 E2 (Vref=Vdd)
NO_ANALOG ……………………………………………………..: không dùng analog, các chân đó sẽ là chân I /O .
AN0_AN1_AN2_AN4_AN5_AN6_AN7_VSS_VREF .: A0 A1 A2 A5 E0 E1 E2 VRefh=A3
AN0_AN1_AN2_AN3_AN4 ……………………………….: A0 A1 A2 A3 A5
( tên thì giống nhau cho tất cả thiết bị nhưng 16F877 chỉ có portA có 5 chân nên A0, A1, A2, A5 được dùng, A6, A7 không có )
AN0_AN1_AN3 ……………………………………………….: A0 A1 A3 , Vref = Vdd
AN0_AN1_VSS_VREF ……………………………………….: A0 A1 VRefh = A3
AN0_AN1_AN4_AN5_AN6_AN7_VREF_VREF ……: A0 A1 A5 E0 E1 E2 VRefh=A3 , VRefl=A2 .
AN0_AN1_AN2_AN3_AN4_AN5 ……………………….: A0 A1 A2 A3 A5 E0
AN0_AN1_AN2_AN4_AN5_VSS_VREF ……………… : A0 A1 A2 A5 E0 VRefh=A3
AN0_AN1_AN4_AN5_VREF_VREF …………………….: A0 A1 A5 E0 VRefh=A3 VRefl=A2
AN0_AN1_AN4_VREF_VREF ……………………………. : A0 A1 A5 VRefh=A3 VRefl=A2
AN0_AN1_VREF_VREF …………………………………….: A0 A1 VRefh=A3 VRefl=A2
AN0 ……………………………………………………………………: A0
AN0_VREF_VREF …………………………………………….. : A0 VRefh=A3 VRefl=A2
VD : setup_adc_ports (AN0_AN1_AN3 ) ; // A0, A1, A3 nhận analog, áp nguồn +5V cấp cho IC sẽ là điện áp chuẩn .
3 / Set_ADC_channel ( channel ) :
+ Chọn chân để đọc vào giá trị analog bằng lệnh Read_ADC ( ) . Giá trị channel tuỳ số chân chức năng ADC mỗi chip .Với 16F877 , channel có giá trị từ 0 -7 :
0-chân A0, 1-chân A1, 2-chân A2, 3-chân A3, 4-chân A5, 5-chân E0, 6-chân E1, 7-chân E2
+Hàm không trả về trị. Nên delay 10 us sau hàm này rồi mới dùng hàm read_ADC ( ) để bảo đảm kết quả đúng. Hàm chỉ hoạt động với A /D phần cứng trên chip.
4 / Read_ADC ( mode ) :
+ Dùng đọc giá trị ADC từ thanh ghi (/ cặp thanh ghi ) chứa kết quả biến đổi ADC. Lưu ý hàm này sẽ hỏi vòng cờ cho tới khi cờ này báo đã hoàn thành biến đổi ADC ( sẽ mất vài us ) thì xong hàm .
+ Nếu giá trị ADC là 8 bit như khai báo trong chỉ thị #DEVICE , giá trị trả về của hàm là 8 bit , ngược lại là 16 bit nếu khai báo #DEVICE sử dụng ADC 10 bit trở lên .
+ Khi dùng hàm này, nó sẽ lấy ADC từ chân bạn chọn trong hàm Set_ADC_channel( ) trước đó . Nghĩa là mỗi lần chỉ đọc 1 kênh Muốn đổi sang đọc chân nào, dùng hàm set_ADC_channel( ) lấy chân đó. Nếu không có đổi chân, dùng read_ADC( ) bao nhiêu lần cũng được .
+ mode có thể có hoặc không, gồm có :
ADC_START_AND_READ : giá trị mặc định
ADC_START_ONLY : bắt đầu chuyển đổi và trả về
ADC_READ_ONLY : đọc kết quả chuyển đổi lần cuối
# DEVCE 8 bit 10 bit 11 bit 16 bit
ADC = 8 0-255 0-255 00-255 00-255
ADC = 10 x 0-1023 x x
ADC = 11 x x 0-2047 x
ADC = 16 0-6528 0 0-6547 2 0-6550 4 0-6553 5
+ 16F877 chỉ tương hỗ ADC 8 và 10 bit .
VD :
setup_adc ( ADC_CLOCK_INTERNAL ) ;
setup_adc_ports ( ALL_ANALOG ) ;
set_adc_channel ( 1 ) ;
while ( input ( PIN_B0 ) )
{
delay_ms ( 5000 ) ;
value = read_adc ( ) ;
printf ( “ A / D value = % 2 x \ n \ r ”, value ) ;
}
read_adc ( ADC_START_ONLY ) ;
sleep ( ) ;
value = read_adc ( ADC_READ_ONLY ) ;
+ Lưu ý : trên PIC 18, cấu trúc ADC tương đối phức tạp, đa năng hơn như thể được cho phép lấy 2 mẫu cùng lúc ,. .. cũng sử dụng với những hàm trên, có nhiều thông số kỹ thuật trong file *. h, sẽ đề cập sau .
5 / _ Ví dụ :
+ Chương trình sau lấy ADC 8 bit, đọc và xuất ra dãy led ở port B, và xuất ra màn hình hiển thị máy tính .
+ Kết nối chân trên 16F877 : RA0 là chân lấy Analog vào, áp chuẩn là nguồn + 5V, mass = 0 V
# include < 16F877. h >
# use delay ( clock = 20000000 )
# device * = 16 ADC = 8 / / sử dụng ADC 8 bit, giá trị ADC vào từ 0-255
# use rs232 ( baud = 19200, parity = n, xmit = pin_C6, rcv = pin_C7 )
Int8 adc ;
Main ( )
{
Setup_ADC ( ADC_internal ) ;
Setup_ADC_ports (AN0);
Set_ADC_channel ( 0 ) ;
Delay_us ( 10 ) ; / / delay 10 us
While ( true )
{ adc = read_adc ( ) ;
Output_B ( adc ) ; / / xuat ra port B gia tri bien adc
Printf ( “ gia tri adc la : % u “, adc ) ; / / in ra man hinh
}
}
/ / giá trị biến adc từ 0-255, dùng chương trình Serial port Monitor trong mục Tools của CCS để
giám sát giá trị. Nhớ thiết lập vận tốc là 19200 như khai báo trên .
II / CÁC HÀM VÀO RA TRONG C :
+ Bao gồm những hàm sau :
Output_low ( ) Output_high ( )
Output_float ( ) Output_bit ( )
Input ( ) Ouput_X ( )
Input_X ( ) port_b_pullups ( )
Set_tris_X ( )
1 / Output_low ( pin ), Output_high (pin ) :
+ Dùng thiết lập mức 0 ( low, 0V ) hay mứ c 1 ( high, 5V ) cho chân IC, pin chỉ vị trí chân .
+ Hàm này sẽ đặt pin làm ngõ ra, xem mã asm để biết đơn cử .
+ Hàm này dài 2-4 chu kỳ luân hồi máy. Cũng hoàn toàn có thể xuất xung dùng set_tris_X ( ) và # use fast_io .
VD : chương trình sau xuất xung vuông chu kỳ 500ms, duty =50% ra chân B0 ,nối B0 với 1 led sẽ làm nhấp nháy led .
# include < 16F877. h >
# use delay ( clock = 20000000 )
Main ( )
{ while ( 1 )
{ output_high ( pin_B0 ) ;
Delay_ms ( 250 ) ; / / delay 250 ms
Output_low ( pin_B0 ) ;
Delay_ms ( 250 ) ;
}
}
2 / Output_bit ( pin, value ) :
+ pin : tên chân value : giá trị 0 hay 1
+ Hàm này cũng xuất giá trị 0 / 1 trên pin, tương tự 2 hàm trên. Thường dùng nó khi giá trị ra tuỳ thuộc giá trị biến 1 bit nào đó, hay muốn xuất đảo của giá trị ngõ ra trước đó .
VD : Chương trình xuất xung vuông chu kỳ 500ms ,duty =50%
int1 x; // Khai báo x, mặc định = 0
Main() //Trong hàm main :
{ while (1 )
{ output_bit( pin_B0, !x ) ;
Delay_ms(250 );
}
}
3 / Output_float ( pin ) :
+ Hàm này set pin như ngõ vào, cho phép pin ở mức cao như 1 cực thu hở.
4 / Input ( pin ) :
+ Hàm này trả về giá trị 0 hay 1 là trạng thái của chân IC. Giá trị là 1 bit
5 / Output_X ( value ) :
+ X là tên port có trên chip. Value là giá trị 1 byte .
+ Hàm này xuất giá trị 1 byte ra port. Tất cả chân của port đó đếu là ngõ ra .
VD :
Output_B ( 212 ) ; // xuất giá trị 11010100 ra port B
6 / Input_X ( ) :
+ X : là tên port ( a, b ,c ,d e ) .
+ Hàm này trả về giá trị 8 bit là giá trị đang hiện hữu của port đó .VD : m=input_E();
7 / Port_B_pullups ( value ) :
+ Hàm này thiết lập ngõ vào port B pullup ( điện trở kéo lên). Value =1 sẽ kích hoạt tính năng này và value =0 sẽ ngừng .
+ Chỉ các chip có port B có tính năng này mới dùng hàm này .
8 / Set_tris_X ( value ) :
+ Hàm này định nghĩa chân IO cho 1 port là ngõ vào hay ngõ ra. Chỉ được dùng với #use fast_IO . Sử dụng #byte để tạo biến chỉ đến port và thao tác trên biến này chính là thao tác trên port .
+ Value là giá trị 8 bit. Mỗi bit đại diện 1 chân và bit=0 sẽ set chân đó là ngõ vào, bit= 1 set chân đó là ngõ ra .
VD : chương trình sau cho phép thao tác trên portB 1 cách dễ dàng:
#include < 16F877.h >
#use delay(clock=20000000)
#use Fast_IO( B )
#byte portB = 0x6 // 16F877 có port b ở địa chỉ 6h
#bit B0 = portB. 0 // biến B0 chỉ đến chân B0
#bit B1=portB.1 // biến B1 chỉ đến chân B1
#bit B2=portB.2 // biến B2 chỉ đến chân B2
#bit B3=portB.3 // biến B3 chỉ đến chân B3
#bit B4=portB.4 // biến B4 chỉ đến chân B4
#bit B5=portB.5 // biến B5 chỉ đến chân B5
#bit B6=portB.6 // biến B6 chỉ đến chân B6
#bit B7=portB.7 // biến B7 chỉ đến chân B7
Main()
{ set_tris_B ( 126 ) ; //portB=01111110 b
// B0 là ngõ vào, thường làm ngắt ngoài
//B1. .. B6 là ngõ ra, Vd làm 6 ngõ ra điều chế PWM
//B7 là ngõ vào, Vd là nhận tín hiệu cho phép chẳng hạn
if ( B7 ) //nếu ngõ vào chân B7 là 1 thì xuất 3 cặp xung đối nghịch
{ B1 = 1 ;
B2 = 0 ;
B3 = 1 ;
B4 = 0 ;
B5 = 1 ;
B6 = 0 ;
}
Else B1=B2=B3=B4=B5=B6= 0;
}
+ Lưu ý :
+ Set_tris_B (0 ) : port B =00000000 : tất cả chân portB là ngõ ra
+ set_tris_B ( 1 ) : portB = 00000001 : chỉ B0 là ngõ vào, còn lại là ngõ ra
+ set_tris_B ( 255 ) : portB=11111111: tất cả chân portB là ngõ vào. Bạn nên dùng giá trị ở dạng nhị phân cho dễ . VD : set_tris_B ( 00110001b ) ;
+ Đến đây là bạn có thể viết nhiều chương trình thú vị rồi đó. Vd như là dùng ADC để điều chỉnh tốc độ nhấp nháy của dãy đèn led, truyền giá trị 8 bit từ chip này sang chip khác ,. . .
+ VD: Chương trình sau dùng ADC qua chân A0 để điều chỉnh tốc độ nhấp nháy dãy đèn led nối vào portB, có thể dùng fast_io hay hàm output_B () để xuất giá trị đều được. chương trình dùng hàm. Nếu ngõ vào chân C0 =0 thì tiếp tục nhận ADC và xuất ra portB, C0=1 thì không xuất
#include <16F877.h>
#device *=16 ADC= 8
#use delay( clock =20000000)
Int8 ADC_delay ;
Void hieu_chinh ( )
{ ADC_delay = read_adc ( 0 ) ;
Output_B ( 0) ; //portB=00000000
Delay_ms ( ADC_delay );
Output_B ( 255 ) ; // portB= 11111111
Delay_ms ( ADC_delay );
}
Main()
{
setup_adc_ports(AN0_AN1_AN3); // A0, A1 và A3 là chân analog, ta chỉ cần dùng A0 lấy
tín hiệu
setup_adc(adc_clock_internal);
set_adc_channel ( 0 ); // chọn đọc ADC từ chân A0
while(1)
{ hieu_chinh ( ) ;
If ( input ( pin_C0 )
{ output_B (0 );
Break ; // thoát khỏi vòng lặp while nhỏ
}
}
}