Tải bản đầy đủ (.doc) (11 trang)

CHNG5 lập TRÌNH c CHO VI điều KHIỂN PIC 16f877a

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (154.29 KB, 11 trang )

Chng 5:LP TRèNH C CHO VI IU KHIN PIC
16F877A
5.1. Gii thiu chung
C l mt ngụn ng khỏ mnh v rt nhiu ngi dựng. Nu núi s
lnh c bn ca C thỡ khỏ nhiu. Nhng i vi lp trỡnh cho vi x lý,
chỳng ta ch cn bit s lng lnh khụng nhiu. u tiờn chỳng ta phi
lm quen vi:
- Cỏc kiu toỏn t C
- Cỏc kiu d liu
- Cu trỳc c bn ca mt chng trỡnh
- Cỏc cu trỳc iu khin (cỏc tp lnh chớnh)
- Cu trỳc iu kin: if else.
- Cỏc cu trỳc lp
- Vũng lp while
- Vũng lp do while
- Vũng lp for
- Lnh break
- Cu trỳc la chn: switch case
- Bit s dng cỏc hm v chng trỡnh con.
Sau õy chỳng ta s nghiờn cu v lp trỡnh C cho vi iu khin PIC, s
dng phn mmCCS.
C bn v lp trỡnh C cho vi iu khin PIC
5.2 Cỏc ch th tin x lý
Chỳng ta s núi v cỏc ch th tin x lý thng dựng:
a/ _#INCLUDE :
- Cỳ phỏp : #include <filename> hoc #include filename
+ Filename : tờn file cho thit b *.h , *.c . Nu ch nh file ng dn
khỏc thỡ thờm ng dn vo. Ch th ny luụn phi cú khai bỏo
chng trỡnh vit cho vi iu khin no, v luụn t dũng u tiờn.
- VD :
#include <16F877.H> // Chng trỡnh s dng cho vi iu khin 16F877


#include < C:\INCLUDES\COMLIB\MYRS232.C >
b / _ # DEVICE :
- Cỳ phỏp: # DEVICE_Chip_Option
+ Chip : tờn vi iu khin s dng , khụng dựng tham s ny nu ó khai
bỏo tờn chip # include .
+ Option : toỏn t tiờu chun theo tng chip:
* = 5 duứng pointer 5 bit ( taỏt caỷ PIC )
* = 8 duứng pointer 8 bit ( PIC14 vaứ PIC18 )
* = 16 duứng pointer 16 bit ( PIC14 ,PIC 18)
ADC = x: s dng ADC x bit ( 8 , 10 , . . . bit tựy chip ) , khi dựng hm
read_adc( ) , s tr v giỏ tr x bit . ICD = TRUE: to mó tng thớch


debug phần cứng Microchip HIGH_INTS = TRUE: cho phép dùng ngắt
ưu tiên cao
Lưu ý: Khai báo pointer 8 bit, sử dụng được tối đa 256 byte RAM cho
tất cả biến chương trình. Khai báo pointer 16 bit , sử dụng được toàn bộ
dung lượng RAM có của vi điều khiển.Vì vậy, chỉ nên dùng duy nhất 1
khai báo #device cho cả pointer và ADC.
- VD : #device * = 16 ADC = 10
c/ _ # USE :
c1/ _# USE delay ( clock = speed )
+ Speed : giá trị OSC mà chúng ta dùng .
- VD: dùng thạch anh dao động 40Mhz thì :
#use delay( clock = 40000000)
Chỉ khi có chỉ thị này thì trong chương trình chúng ta mới được dùng hàm
delay_us ( ) và delay_ms( ) .
c2/ _#USE fast_io ( port)
+ Port : là tên port: từ A-G ( tuỳ chip)
Dùng chỉ thị này thì trong chương trình khi dùng các lệnh io như

output_low() , . . . nó sẽ set chỉ với 1 lệnh , nhanh hơn so với khi
không dùng chỉ thị này.Trong hàm main( ) chúng ta phải dùng hàm
set_tris_x( ) để chỉ rõ chân vào ra thì chỉ thị trên mới có hiệu lực, không
thì chương trình sẽ chạy sai .
* Lưu ý: Không nên dùng chỉ thị này nếu không có yêu cầu gì đặc biệt .
- VD : # use fast_io( A ) // Dùng port A là port xuất-nhập
c3/ _#USE I2C ( options )
- Thiết lập giao tiếp I2C.
- Options bao gồm các thông số sau, cách nhau bởi dấu phẩy :
Master : chip ở chế độ master
Slave : chip ở chế độ slave
SCL = pin : chỉ định chân SCL
SDA = pin : chỉ định chân SDA
ADDRESS =x : chỉ định địa chỉ chế độ slave
FAST : chỉ định FAST I2C
SLOW : chỉ định SLOW I2C
RESTART_WDT : restart WDT trong khi chờ I2C_READ( )
FORCE_HW : sử dụng chức năng phần cứng I2C (nếu chip hỗ trợ)
NOFLOAT_HIGH : không cho phép tín hiệu ở float high, tín hiệu được lái
từ thấp lên cao.
SMBUS : bus dùng không phải bus I2C , nhưng là loại bus khác tương
tự .
- VD :
#use I2C ( master , sda=pin_B0 , scl = pin_B1 )
#use I2C (slave , sda= pin_C4 , scl= pin_C3 , address = 0xa00 , FORCE_HW )


c4/ _#USE RS232 ( options )
- Thiết lập giao tiếp RS232 cho chip ( có hiệu lực sau khi nạp
chương trình cho chip , không phải giao tiếp RS232 đang sử dụng để

nạp chip ) .
- Option bao gồm :
BAUD = x : thiết lập tốc độ baud rate : 19200 , 38400 , 9600 , . . .
PARITY = x : x= N, E hay O, với N : không dùng bit chẵn lẻ
XMIT = pin : set chân transmit ( chuyển data)
RCV = pin : set chân receive ( nhận data )
- VD :
#use rs232(baud=19200,parity=n,xmit=pin_C6,rcv=pin_C7)
d/ _ #ASM và #ENDASM :
- Cho phép đặt 1 đoạn mã ASM giữa 2 chỉ thị này. CCS định nghĩa
sẵn 1 biến 8 bit _RETURN_ để chúng ta gán giá trị trả về cho hàm
từ đoạn mã Assembly.
- C đủ mạnh để thay thế Assmemly. Vì vậy nên hạn chế lồng mã
Assembly vào vì thường gây ra xáo trộn dẫn đến sau khi biên dịch mã
chạy sai.
- Khi sử dụng các biến không ở bank hiện tại , CCS sinh thêm mã
chuyển bank tự động cho các biến đó . Nếu sử dụng #ASM thì CCS
không sinh thêm mã chuyển bank tự động, ta phải tự thêm vào trong mã
ASM .
* Lưu ý : Mã Assembly phải theo đúng mã tập lệnh vi điều khiển,
không phải mã kiểu MPLAB .
- VD : int find_parity (int data)
{
int count;
#asm
movlw 0x8
movwf count
movlw 0
loop:
xorwf data,w

rrf data,f
decfsz count,f
goto loop
movwf _return_
#endasm
}
e/ _#BIT id = x . y
+ id : tên biến
+ x : biến C ( 8,16,32,…bit) hay hằng số địa chỉ thanh ghi


+ y : vị trí bit trong x
Chỉ thị này có tác dụng tạo biến 1 bit đặt ở byte x vị trí bit y, tiện
dùng kiểm tra hay gán trị cho bit thanh ghi . Điểm khác biệt so với
dùng biến 1 bit từ khai báo int1 là : int1 tốn 1 bit bộ nhớ , đặt ở thanh
ghi đa mục đích do CCS tự chọn, còn #BIT thì không tốn thêm bộ nhớ
do id chỉ là danh định đại diện cho bit chỉ định ở biến x. Vì thế khi
thay đổi giá trị id ( 0 / 1 ) sẽ thay đổi giá trị bit tương ứng y, dẫn
đến thay đổi giá trị biến x.
- VD:
#bit TMR1Flag = 0xb.2 //bit cờ ngắt timer1 ở địa chỉ 0xb.2
// Khi đó TMR1Flag = 0 xoá cờ ngắt timer1
int16 a=35; //a=00000000 00100011
#bit b= a.11 //b=0, nếu b=a.0 thì b chỉ vị trí LSB
// Sau đó : b=1; //a=00001000 00100011 = 2083
* Lưu ý: Không dùng được: if ( 0xb.2 ) mà phải khai báo như trên
rồi dùng :
if(TMR1Flag).
f/ _#BYTE id = x
+ x: địa chỉ

+ id: tên biến C
Chỉ thị này có tác dụng gán tên biến id cho địa chỉ (thanh ghi ) x, sau
đó muốn gán hay kiểm tra địa chỉ x chỉ cần dùng id, không tốn thêm bộ
nhớ, tên id thường dùng tên gợi nhớ chức năng thanh ghi ở địa chỉ
đó.
* Lưu ý: Giá trị thanh ghi có thể thay đổi bất kỳ lúc nào do hoạt động
chương trình nên giá trị id cũng tự thay đổi theo giá trị thanh ghi đó.
Vì vậy khôngnên dùng id cho thanh ghi đa mục đích như cách
dùng biến int8 vì CCS có thể dùng các thanh ghi này bất kỳ lúc nào cho
chương trình.
- VD:
#byte port_b = 0xc6; // 16F877 :0xc6 là địa chỉ portb port_b=120; // Giá trị
thanh ghi 0xc6=120 #byte status = 0xc3;
g/ _# LOCATE id = x
- Làm việc như #byte nhưng có thêm chức năng bảo vệ không cho
CCS sử dụng địa chỉ đó vào mục đích khác .
- VD: # LOCATE temp = 0xc20 // 0xc20 :thanh ghi đa mục đích
- Sử dụng #LOCATE để gán biến cho 1 dãy địa chỉ kề nhau (cặp
thanh ghi) sẽ tiện lợi hơn thay vì phải dùng 2 biến với #byte .
- VD : CCP1 có giá trị là cặp thanh ghi 0x15 (byte thấp ) và 0x16 (byte cao)
.
Để gán trị cho CCP1 :
Int16 CCP1;


locate CCP1= 0x15 // byte thấp của CCP1 ở 0x15 , byte cao của CCP1 ở
0x16 CCP1 = 1133 ; // 1133(D) = 00000100 01101101 0x15 = 00000100; 0x16 =
01101101
h/ _# DEFINE id text
+ Text : chuỗi hay số .

- Dùng định nghĩa giá trị .
- VD : #define a 12345
i/ _ # ORG :
- Cú pháp: # org start , end
hoặc # org segment
hoặc #org start , end { }
+ Start, end: bắt đầu và kết thúc vùng ROM dành riêng cho hàm theo sau,
hoặc để riêng không dùng.
- VD :
org 0x30 , 0x1F
Void xu_ly( )
{
} // hàm này bắt đầu ở địa chỉ 0x30
org 0x1E00
anotherfunc( )
{
} //hàm này bắt đầu tuỳ ý ở 0x1E00 đến 0x1F00
Org 0x30 , 0x1F { } // không có gì cả đặt trong vùng ROM này
- Thường thì không dùng ORG .
k/ _Một số chỉ thị tiền xử lý khác
k1/ #CASE : cho phép phân biệt chữ hoa/ chữ thường trong tên biến,
dành cho gười quen lập trình C .
k2/ #OPT n (n=0 – 9): chỉ định cấp độ tối ưu mã, không dùng thì mặc định
là 9.
k3/ #PRIORITY ints: ints là danh sách các ngắt theo thứ tự ưu tiên thực
hiện khi có nhiều ngắt xảy ra đồng thời, ngắt đứng đầu sẽ là ngắt ưu
tiên nhất.
- Lệnh này chỉ dùng nếu sử dụng hơn 1 ngắt.
- VD : #priority int_CCP1 , int_timer1 // ngaét CCP1 ưu tiê nhất
5.3. Khai báo biến, hằng,mảng

- Khai báo biến:
int1 số 1 bit, giá trị TRUE (1) hoặc FALSE (0)
int8 số nguyên 1 byte (8 bit)
int16 số nguyên 16 bit
int32 số nguyên 32 bit
char ký tự 8 bit
float số thực 32 bit


short mặc định như kiểu int1
byte mặc định như kiểu int8
int mặc định như kiểu int8
long mặc định như kiểu int16
+Thêm signed hoặc unsigned phía trước để chỉ đó là số có dấu hay
không dấu.Nếu không dùng signed hoặc unsigned thì mặc định là
không dấu.
VD :
Signed int8 a ; // số a là số 8 bit có dấu
Signed int16 b; // số b là số 16 bit có dấu
Signed int32 c; // số c là số 32 bit có dấu
+ Phạm vi biến :
int8 : 0  255
int16 : 0  2^16-1 (32767)
int32 : 0  2^32-1
signed int8 : -128 _127
signed int16 : -2^15_ 2^15-1
signed int32 : -2^31 _ 2^31-1
- Khai báo hằng số:
VD:
int8 const a=231; // a là hằng số 8 bit, có giá trị bằng 231

- Khai báo một mảng hằng số:
VD:
int8 const a[5]= { 3,5,6,8,6 } ; // mảng 5 phần tử, chỉ số mảng bắt
// đầu từ 0: a[0]= 3;
a[1]= 5…
int32 số nguyên 32 bit
char ký tự 8 bit
float số thực 32 bit
short mặc định như kiểu int1
byte mặc định như kiểu int8
int mặc định như kiểu int8
long mặc định như kiểu int16
+Thêm signed hoặc unsigned phía trước để chỉ đó là số có dấu hay
không dấu. Nếu không dùng signed hoặc unsigned thì mặc định là
không dấu.
VD :
Signed int8 a ; // số a là số 8 bit có dấu
Signed int16 b; // số b là số 16 bit có dấu
Signed int32 c; // số c là số 32 bit có dấu
+ Phạm vi biến :
int8 : 0 -255


int16 : 0 _2^16-1 (32767)
int32 : 0 _2^32-1
signed int8 : -128 _127
signed int16 : -2^15 _ 2^15-1
signed int32 : -2^31 _ 2^31-1
- Khai báo hằng số:
VD:

int8 const a=231; // a là hằng số 8 bit, có giá trị bằng 231
- Khai báo một mảng hằng số:
VD:
int8 const a[5]= { 3,5,6,8,6 } ; // mảng 5 phần tử, chỉ số mảng bắt // đầu
từ 0: a[0]= 3; a[1]= 5…
5.4 cấu trúc lệnh cơ bản
* Cấu trúc điều kiện: if….else
- Cú pháp:
If (điều kiện)
s;
else
se;
- Hoạt động:
-Phần lệnh else có thể thêm vào trong câu lệnh if để chỉ thị các lệnh
thực hiện khi điều kiện bằng 0 (FALSE).

* Cấu trúc lặp
a/ Vòng lặp while
Cú pháp:


while(TRUE) {};
- Hoạt động của vòng lặp này được mô tả như sau:
- Tạo vòng lặp mãi mãi. Chương trình chính sẽ được viết trong dấu
ngoặc {}.Lệnh này rất hay dùng trong các chương trình của vi xử lý.

b/ Vòng lặp do-while
- Cú pháp:
do
s;

while(điều kiện);
+ s: là 1 câu lệnh. Nếu là một khối lệnh thìphải đặt trong dấu ngoặc {}.
- Hoạt động:
- Chức năng của nó là hoàn toàn giống vòng lặp while chỉ trừ có một
điều là điều kiện điều khiển vòng lặp được tính toán sau khi câu lệnh
(khối lệnh) được thực hiện, vì vậy lệnh sẽ được thực hiện ít nhất một
lần ngay cả khi điều kiện không bao giờ được thoả mãn.
C/ Vòng lặp for
- Cú pháp:
for ( khởi động; điều kiện lặp; điều khiển)
s;
- Hoạt động của vòng lặp for được mô tả qua hình sau:


*

Các lệnh rẽ nhánh và lệnh nhảy
a/ Lệnh break
Sử dụng break chúng ta có thể thoát khỏi vòng lặp ngay cả khi
điều kiện để nó kết thúc chưa được thoả mãn. Lệnh này có thể được
dùng để kết thúc một vòng lặp không xác định hay buộc nó phải
kết thúc giữa chừng thay vì kết thúc một cách bình thường.
b/ Lệnh continue
Lệnh continue làm cho chương trình bỏ qua phần còn lại của vòng
lặp và nhảy sang lần lặp tiếp theo.
c/ Lệnh goto
Lệnh này cho phép nhảy vô điều kiện tới bất kì điểm nào trong chương
trình. Nên tránh dùng lệnh này trong chương trình.
d/ Hàm exit
Mục đích của exit là kết thúc chương trình và trả về một mã xác định.

3.2.4. Các hàm xử lý số
- Bao gồm các hàm:
sin () hàm sin
cos () hàm cosin
tan () hàm tang
asin () hàm arcsin
acos () hàm arccos
atan () hàm arctang
Abs () lấy trị tuyệt đối
ceil () làm tròn theo hướng tăng
floor() làm tròn theo hướng giảm
exp() tính e^x
log() hàm logarit
log10() hàm logarit cơ số 10
pow() tính luỹ thừa
sqrt() căn thức
5.5. Các hàm xử lý bit
A/ Shift_right ( address , byte , value )
Shift_left ( address , byte , value )


- Dịch phải (trái) 1 bit vào 1 mảng hay 1 cấu trúc. Địa chỉ có thể là
địa chỉ mảng hay địa chỉ trỏ tới cấu trúc. Bit 0 byte thấp nhất là
LSB.
B/ Bit_clear (var , bit)
- Bit_clear () dùng xóa (set = 0) bit được chỉ định bởi vị trí bit
trong biến var.
- VD:
int8 x;
x=12; // x=1100

bit_clear(x, 2); // x=1000b= 8
C/ Bit_set(var, bit)
- Bit_set() dùng set bit được chỉ định bởi vị trí bit trong biến var .
+ var: biến 8 , 16 , 32 bit bất kỳ .
D/ Bit_test ( var , bit )
- Dùng kiểm tra vị trí bit trong biến var .
- Hàm trả về 0 hay 1 là giá trị bit đó trong var .
E / Swap(var )
+ var : biến 1 byte
- Hàm này tráo vị trí 4 bit trên với 4 bit dưới của var.
- Hàm không trả về trị .
- VD :
x= 5 ; //x=00000101b
swap ( x) ; //x = 01010000b = 80
F/ make8 (var, offset)
- Hàm này trích 1 byte từ biến var .
+ var: biến 8,16,32 bit.
+ offset: vị trí của byte cần trích ( 0,1,2,3).
- Hàm trả về giá trị byte cần trích .
- VD :
int16 x = 1453 ; // x=0x5AD
y = make(x, 1) ; // y= 5 = 0x05
G/ make16 (varhigh, varlow)
- Trả về giá trị 16 bit kết hợp từ 2 biến 8 bit varhigh và varlow. Byte
cao là varhigh, byte thấp là varlow.
H/ make32 (var1, var2, var3, var4)
- Trả về giá trị 32 bit kết hợp từ các giá trị 8 bit hay 16 bit từ var1
tới var4 .
Trong đó var2 đến var4 có thể có hoặc không. Giá trị var1 sẽ là
MSB, kế tiếp là var2. Nếu tổng số bit kết hợp ít hơn 32 bit thì 0 được

thêm vào MSB cho đủ 32 bit.
- VD:
int a=0x01 , b=0x02 , c=0x03 , d=0x04 ;


int32 e ;
e = make32 (a, b, c, d); // e=0x01020304
e = make32 (a, b, c, 5) ; // e=0x01020305
e = make32 (a, b, 8); // e=0x00010208
e = make32 ( a, 0x1237) ; // e=0x00011237
5.6. Các hàm delay
- Để sử dụng các hàm delay , cần có khai báo tiền xử lý ở đầu file.
VD: sử dụng OSC 20 Mhz, ta cần khai báo : #use delay(clock =
20000000).
- Hàm delay không sử dụng bất kỳ timer nào. Chúng thực ra là 1 nhóm
lệnh ASM để khi thực thi từ đầu tới cuối thì xong khoảng thời gian
mà bạn quy định
. Tuỳ thời gian delay yêu cầu dài ngắn mà CCS sinh mã phù hợp. Có khi
là vài
lệnh NOP cho thời gian rất nhỏ, hay 1 vòng lặp NOP, hoặc gọi tới 1
hàm phức tạp trong trường hợp delay dài. Các lệnh này không dùng vào
việc gì mà chỉ kéo dài sao cho đủ thời



×