29
Lập trình C cho vi điều khiển bằng Keil C [email protected] LẬP TRÌNH C CHO VI ĐIỀU KHIỂN VỚI KEIL C Lập trình C cho VĐK - Cơ bản I.Giới thiệu C là một ngôn ngữ khá mạnh và rất nhiều ngưòi dùng .Nếu nói số lệnh cơ bản của C thì không nhiều và khi lập trình cho VDK, chúng ta chi cần biết số lượng lệnh không nhiều. Trong tài liệu này sử dụng phần mềm biên dịch Keil C 8.05. Đầu tiên bạn phải làm quen với - Các kiểu toán tử ở C - Các kiểu dữ liệu - Cấu trúc cơ bản của một chương trình - Các cấu trúc điều khiển (chính các tập lệnh) - Cấu trúc điều kiện : if và else - Các cấu trúc lặp - Vòng lặp while - Vòng lặp do while - Vòng lặp for - Lệnh break. - Cấu trúc lựa chọn: switch. Case - Hàm và chương trình con . II.Lập trình C cơ bản 1. Các chỉ thị trước xử lý của Keil C a) Chú thích: // Chú thích Hoặc /********** Chú thích ****************** **************************************** ****************************************/ Đây là dòng chú thích. Tất cả các dòng bắt đầu bằng hai dấu sổ (//) được coi là chú thích mà chúng không có bất kì một ảnh hưởng nào đến hoạt động của chương trình. Các lập trình viên dùng chúng để chú thích cho chương trình. Trong trường hợp này, dòng chú Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 1

Lap trinh C cho VDK

  • Upload
    kypvqn

  • View
    663

  • Download
    1

Embed Size (px)

DESCRIPTION

Lap trinhC (C for PIC)

Citation preview

Page 1: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

LẬP TRÌNH C CHO VI ĐIỀU KHIỂN VỚI KEIL C

Lập trình C cho VĐK - Cơ bảnI.Giới thiệuC là một ngôn ngữ khá mạnh và rất nhiều ngưòi dùng .Nếu nói số lệnh cơ bản của C thì không nhiều và khi lập trình cho VDK, chúng ta chi cần biết số lượng lệnh không nhiều. Trong tài liệu này sử dụng phần mềm biên dịch Keil C 8.05.Đầu tiên bạn phải làm quen với

- Các kiểu toán tử ở C- Các kiểu dữ liệu- Cấu trúc cơ bản của một chương trình- Các cấu trúc điều khiển (chính các tập lệnh)- Cấu trúc điều kiện : if và else- Các cấu trúc lặp- Vòng lặp while- Vòng lặp do while- Vòng lặp for- Lệnh break.- Cấu trúc lựa chọn: switch. Case- Hàm và chương trình con .

II.Lập trình C cơ bản1. Các chỉ thị trước xử lý của Keil Ca) Chú thích:

// Chú thích

Hoặc

/********** Chú thích **************************************************************************************************/

Đây là dòng chú thích. Tất cả các dòng bắt đầu bằng hai dấu sổ (//) được coi là chú thích mà chúng không có bất kì một ảnh hưởng nào đến hoạt động của chương trình. Các lập trình viên dùng chúng để chú thích cho chương trình. Trong trường hợp này, dòng chú thích là một giải thích ngắn gọn những gì mà chương trình chúng ta làm. Còn trong dấu (/* */) bạn có thể chú thích bao nhiêu dòng tuỳ thích.b) Chỉ thị #include và #defineĐầu file .c ta phải khai báo

#include <AT89X52.H>

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 1

Page 2: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

hoặc

#include "AT89X52.H"

Để báo cho trình biên dịch biết ta đang sử dụng loại chip nào, ở đây là AT89C/S52

Chỉ thị #define cho phép ta đặt tên các hằng số, các vùng nhớ RAM, các bit đặc biệt.

#define True 1 // Định nghĩa giá trị True = 1// Khi sử dụng ta có thể sử dụng True thay vì 1// Ví dụ: a = True cũng tương đương với a = 1.

#define Output P0_6 // Định nghĩa bit P0.6 có tên là Output_1

Lưu ý: Keil C quy định cách sử dụng các bit tương ứng với các chân của chip như sau:P1.0 ---- P1_0P1.1 ---- P1_1Tức khi sử dụng P1.1 trong chương trình ta phải dùng P1_1

Một ưu điểm nổi bật của C là các bạn có thể tạo ra các bộ thư viện .Ví dụ sau là tạo thư viện thuvien.h (đuôi .h bạn có thể tạo bằng cách save as .. *.h ở Keil C ).

#ifndef _thuvien_H#define _thuvien_H....//mã chương trình#endif

2. Các toán tử:- Toán tử gán (=).Ví dụ:

b = 5;a = 2 + b;a = 2 + (b = 5);a = b = c = 5;

- Các toán tử số học ( +, -, *, /, % )

+ cộng- trừ* nhân/ chia% lấy phần dư (trong phép chia)

VD: i = 5%2; // i = 1

- Các toán tử gán phức hợp (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=)

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 2

Page 3: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

a += 5; a = a + 5;a -= 5; a = a – 5;a /= b; a = a / b;a *= b; a = a * b;

a *= (b + c); a = a * (b+c);

Tăng và giảm ++ - -a++; a = a + 1;a+=1; a = a + 1;

Tính chất tiền tố hoặc hậu tố (++a) khác với (a++)

Ví dụ:

B=3;A=++B; // Lúc này A = 4, B = 4

// Trình dịch xử lý tăng B thêm 1 xong mới gán A = B.

Khác với:

B=3;A=B++; // Lúc này A = 3, B = 4

// Trình dịch xử lý gán A = B xong mới tăng B thêm 1.

- Các toán tử quan hệ ( ==, !=, >, <, >=, <= )

== Bằng!= Khác> Lớn hơn< Nhỏ hơn>= Lớn hơn hoặc bằng<= Nhỏ hơn hoặc bằng

Ví dụ:

(7 == 5) sẽ cho giá trị false(6 >= 6) sẽ cho giá trị true

Ta cũng có thể sử dụng bất cứ biểu thức nào.

Cho a=2, b=3 và c=6(a*b >= c) sẽ cho giá trị true.(b+4 < a*c) sẽ cho giá trị false

Chú ý : = (một dấu bằng) khác hoàn toàn khác với == (hai dấu bằng). (==) nhằm so sánh còn (=) gán giá trị của biểu thức bên phải cho biến ở bên trái.

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 3

Page 4: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

- Các toán tử logic ( !, &&, || ).

! NOT&& AND|| OR

Ví dụ:

!(5 == 5) trả về false vì biểu thức bên phải (5 == 5) có giá trị true.!(6 <= 4) trả về true vì (6 <= 4)có giá trị false.!true trả về false.!false trả về true.((5 == 5) && (3 > 6)) trả về false (true && false).((5 == 5)

- Các toán tử thao tác bit ( &, |, ^, ~, <<, >> ).

& AND| OR^ XOR~ NOT<< SHL: dịch sang trái>> SHR: dịch sang phải

- Thứ tự ưu tiên của các toán tử

Thứ tự Toán tử Mô tả Associativity1 :: Scope Trái2 () [] . -> sizeof Trái3 ++ -- tăng/giảm Phải

~!& *(type)+ -

4 * / % Toán tử số học Trái5 + - Toán tử số học Trái6 << >> Dịch bit Trái7 < <= > >= Toán tử quan hệ Trái8 == != Toán tử quan hệ Trái9 & ^ | Toán tử thao tác

bitTrái

10 && || Toán tử logic Trái11 ?: Toán tử điều kiện Phải12 = += -= *= /= %=

>>= <<= &= ^= |=Toán tử gán Phải

13 , Dấu phẩy Trái

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 4

Page 5: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

3. Các kiểu dữ liệuCác kiểu biến chuẩn:

Kiểu Bits Bytes Rangechar 8 1 -128 to 127unsigned char 8 1 0 to 255enum 16 2 -32,768 to 32,767short 16 2 -32,768 to 32,767unsigned short 16 2 0 to 65535int 16 2 -32,768 to 32,767unsigned int 16 2 0 to 65,535long 32 4 -2,147,483,648 to 2,147,483,647unsigned long 32 4 0 to 4,294,697,295

Một số kiểu dữ liệu đặc trưng trong Keil C:Để phù hợp với vi điều khiển, trong Keil C còn định nghĩa thêm các kiểu dữ liệu như trong bảng sau:

Kiểu Bits Bytes Rangebit 1 0 0 to 1sbit 1 0 0 to 1sfr 8 1 0 to 255sf16 16 2 0 to 65,535

- Kiểu bit: người dùng có thể truy nhập trực tiếp đến 1 bit trong vùng RAM có thể đánh địa chỉ bit.

- Kiểu sbit: dùng truy nhập vùng nhớ chứa các thanh ghi đặc biệt (SFR), ví dụ bit 7(LSB) của thanh ghi 0x90 được truy nhập với tên P1_7, tức chân P1.7 của chip.

- Kiểu sfr để định nghĩa các thanh ghi trong vùng nhớ đặc biệt, vùng SFR. Các định nghĩa các biến có kiểu sfr sẽ được tìm thấy trong file header khai báo chip đang được sử dụng trong chương trình, file AT89X51.H

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 5

Page 6: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

4. Cấu trúc cơ bản của một chương trình C

//Các chỉ thị tiền định#include <AT89X51.H> // Gọi thư viện có sẵn cách viết khác "*.h"#define led1 P1_0 // Dùng định nghĩa các biến

char bien1,bien2; // Các biến cần dùngint c,d; // biến c, d kiểu integer

/***********************************************************/// Các chương trình con/***********************************************************/

void ChuongTrinhCon(unsigned int b; char a) // Chương trình con{

// Mã lệnh xử lý trong chương trình con...

}

/***********************************************************/// Các hàm/***********************************************************/int QuetPhim(void) // chuong trinh con dang ham{

...return(MaPhim);

}

/***********************************************************/// Chương trình chính/***********************************************************/

void main(void) // Chương trình chính{

int a; // Khai báo các biến cục bộChuongTrinhCon(4,6); // Gọi các chương trình cona = Ham(); // Gọi các hàm

}

Chương trình con là nơi các bạn viết các chương trình nhỏ, rất tiện cho các đoạn lệnh gặp lại nhiều lần. Chương trình con có thể được gọi ở bất kì đâu kể cả chương trình chính, các chương trình con khác và các chương trình phục vụ ngắt (ISR). Hàm là chương trình con trả về cho mình một giá trị. Cuối hàm bắt buộc phải có lệnh return(x);

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 6

Page 7: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

5. Các lệnh cơ bản của CCấu trúc điều kiện: if và else- Cú pháp:

if (condition) statement;

Ví dụ:if (x==100) x++;

- Cú pháp:

if (condition) { statement1; statement2; ... // Nếu xử lý có nhiều hơn 1 lệnh}

Ví dụ:if (x==100) { i++; j++;}

- Cú pháp:

if (condition) statement1; else statement2;

Ví dụ:if (x == 100) x++;else x--; // Nếu x=100 thì tăng x thêm 1 nếu không thì giảm x đi 1.

- Cú pháp:

if (condition) { statement1; statement2; ... // Nếu xử lý có nhiều hơn 1 lệnh}else { statement3; statement4; ... // Nếu xử lý có nhiều hơn 1 lệnh{

Ví dụ:if (x==100) { x++; x-=2;}else{ x--; x-=2;

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 7

Page 8: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

}

Các cấu trúc lặp- Vòng lặp while .Cú pháp:

while (expression) statement;

Ví dụ:while(1) {

};

Tạo vòng lặp mãi mãi, rất hay sử dụng trong lập trình VĐK. Chương trình chính sẽ được viết trong dấu ngoặc.

- Vòng lặp do-whileCú pháp:

do statement while (condition);

hoặc

do { statement1; statement2; ...} while (condition);

Ví dụ:do x++ while (x<10);

hoặcdo { x++; i++; j++;} while (x<10);

Tăng giá trị của x cho đến khi x >= 10Chứ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 statement được thực hiện, vì vậy statement sẽ được thực hiện ít nhất một lần ngay cả khi condition không bao giờ được thoả mãn .Như vd trên kể cả x >10 thì nó vẫn tăng giá trị 1 lần trước khi thoát. Nếu x=10 thì tăng x thêm 1 còn không thì giảm x.

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 8

Page 9: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

Vòng lặp for .Cú pháp:

for (initialization; condition; increase) statement;

Chức năng chính vòng lặp for là lặp lại statement chừng nào condition còn mang giá trị đúng, như trong vòng lặp while. Nhưng thêm vào đó, vòng lặp for cung cấp chỗ dành cho lệnh khởi tạo và lệnh tăng. Vì vậy vòng lặp này được thiết kế đặc biệt lặp lại một hành động với một số lần xác định.

Cách thức hoạt động của nó như sau:1. initialization được thực hiện. Nói chung nó đặt một giá trị ban đầu cho biến điều khiển. Lệnh này được thực hiện chỉ một lần.2. condition được kiểm tra, nếu nó là đúng vòng lặp tiếp tục còn nếu không vòng lặp kết thúc và statement được bỏ qua.3. statement được thực hiện. Nó có thể là một lệnh đơn hoặc là một khối lệnh được bao trong một cặp ngoặc nhọn. { }4. Cuối cùng, increase được thực hiện để tăng biến điều khiển và vòng lặp quay trở lại bước 2.Phần khởi tạo và lệnh tăng không bắt buộc phải có. Chúng có thể được bỏ qua nhưng vẫn phải có dấu chấm phẩy ngăn cách giữa các phần. Vì vậy, chúng ta có thể viết

Đầy đủ: for (n=0;n<10;n++) { }

hoặcfor (;n<10;) { }

hoặc

for (;n<10;n++){ }

Bằng cách sử dụng dấu phẩy, chúng ta có thể dùng nhiều lệnh trong bất kì trường nào trong vòng for, như là trong phần khởi tạo. Ví dụ chúng ta có thể khởi tạo một lúc nhiều biến trong vòng lặp:

for (i=2, n=0; n!=100 ; n++){ // đặt các lệnh ở đây.}

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 9

Page 10: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

Các lệnh rẽ nhánh và lệnh nhảyLệ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. Ví dụ, chúng ta sẽ dừng việc đếm ngược trước khi nó kết thúc:

Ví dụ:

unsigned char i, j;...j= 0;for (i=1; i<10; i++) {

if (i==6) break;j++;

}

Sau đoạn mã trên i=6; j=5;

Kết thúc vòng lặp i sẽ có giá trị là 6 vì khi i=6 thì điều kiện if xảy ra và vòng lặp for sẽ bị dừng tại điểm đó.

Lệnh continueLệ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.

Ví dụ:

unsigned char i, j;...j= 0;for (i=1; i<10; i++) {

if (i==6) continue;j++;

}

Sau đoạn mã trên i=9; j=8 do bỏ qua lần i=6 (không tăng j khi i=6);

Lệnh gotoLệ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ói chung bạn nên tránh dùng nó trong chương trình C vì đây là một lệnh có thể phá vỡ cấu trúc của chương trình gây ra những hiện tượng khó hiểu nếu địa chỉ nhảy đến nằm ngoài chương trình con chứa lệnh goto này.

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 10

Page 11: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

Ví dụ:

unsigned char i, j;{...j= 0;for (i=1; i<10; i++) {if (i==6) goto There;j++;

}...

There:...// Ít nhất phải có 1 lệnh sau nhãn trước khi kết thúc chương trình

}

Sau đoạn mã trên i=6; j=5;

Trong các lệnh trên, lệnh break hay được dùng để thoát khỏi vòng lặp. Các lệnh khác thường rất ít được sử dụng.

Ví dụ:

while(1){ LCD_GotoXY(1,1); StrToLCD("Quay thuan"); QuayThuan(); if(!Stop) { LCD_Clear(); StrToLCD("Dung"); Stop(); break; } }

Cấu trúc lựa chọn: switch.Cú pháp của lệnh switch hơi đặc biệt một chút. Mục đích của nó là kiểm tra một vài giá trị hằng cho một biểu thức, tương tự với những gì chúng ta làm ở đầu bài này khi liên kết một vài lệnh if và else if với nhau.

Cú pháp:

switch (expression) {case constant1:{ block of instructions 1 // Khối lệnh 1break;}case constant2:

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 11

Page 12: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

block of instructions 2 // Khối lệnh 2break; . . .default: default block of instructions }

Nó hoạt động theo cách sau: switch tính biểu thức và kiểm tra xem nó có bằng constant1 hay không, nếu đúng thì nó thực hiện “block of instructions 1” cho đến khi tìm thấy từ khoá break, sau đó nhảy đến phần cuối của cấu trúc lựa chọn switch.Còn nếu không, switch sẽ kiểm tra xem biểu thức có bằng constant2 hay không. Nếu đúng nó sẽ thực hiện block of instructions 2 cho đến khi tìm thấy từ khoá break.Cuối cùng, nếu giá trị biểu thức không bằng bất kì hằng nào được chỉ định ở trên (bạn có thể chỉ định bao nhiêu câu lệnh case tuỳ thích), chương trình sẽ thực hiện các lệnh trong phần default: nếu nó tồn tại vì phần này không bắt buộc phải có.

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 12

Page 13: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

III. MảngMảng là một chuỗi các dữ liệu nằm nối tiếp nhau trong bộ nhớ mà ta có thể truy cập đến từng phần tử riêng rẽ của nó theo số thứ tự của nó trong mảng.

Ví dụ: Một mảng gồm 5 số nguyên có tên là A có thể biểu diễn như sau:

Mỗi ô chứa 1 phần tử của mảng và được đánh số thứ tự bắt đầu từ 0.

Cách khai báo một mảng như sau:

KieuDuLieu Ten [So_Phan_Tu_Cua_Mang];

KieuDuLieu là kiểu dữ liệu của các phần tử trong mảng ví dụ như int, float, char ...Ten là tên mảngSo_Phan_Tu_Cua_Mang: số phần tử trong mảng

Ví dụ:int A[5]; // Khai báo mảng A gồm 5 phần tử kiêu số nguyên

Lưu ý: So_Phan_Tu_Cua_Mang phải là một hằng số vì đây không phải là một mảng động nên số phần tử cần phải được xác định.

Khởi tạo mảng.

Khi khai báo một mảng, nếu ta không khới tạo các giá trị ban đầu cho nó thì các phần tử trong mảng sẽ tự động mặc định giá trị là 0. Ta có thể khởi tạo các giá trị ban đầu của mảng bằng cách như sau:

int A[5] = { 16, 2, 77, 40, 12071 };

Khai báo này sẽ tạo ra một mảng trong bộ nhớ RAM như sau:

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 13

A

A

Page 14: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

Truy cập mảng.

Tại bất cứ đâu trong chương trình ta có thể truy cập (đọc- ghi) các phần tử của mảng bằng dạng sau.

Ten[index]

Ví dụ mảng billy có 5 phần tử

Ví dụ muốn lưu giá trị 75 vào phần tử thứ 3 của mảng billy, ta làm như sau:

billy[2] = 75;

và, ví dụ muốn gán giá trị thứ 3 của mảng cho một biến a khác ta làm như sau:

a= billy[2];

Lưu ý ở đây, phần tử thứ 3 của mảng billy có số thứ tự là 2 vì các phần tử trong mảng được đánh số từ 0.

Một chú ý nữa là ta nên lưu ý khi truy cập các phần tử của mảng, không được truy cập các phần tử có chỉ số lớn hơn hoặc bằng tổng số phần tử trong mảng. Ví dụ mảng A chỉ có 5 phần tử được đánh số từ 0 đến 4, ta truy cập phần tử thứ 5, tức A[5] của mảng thì sẽ gây ra nhiều lỗi rất khó hiểu vì khi khai báo thì mảng chỉ có 5 phần tử, trình biên dịch sẽ chỉ cấp phát 5 vùng nhớ cho các phần tử trong mảng, vùng nhớ kế tiếp với mảng có thể chứa 1 biến nào đó, việc đọc ghi phần tử thứ 5 trong mảng tình cờ sẽ đọc ghi giá trị biến nằm kế mảng đó, gây sai trong chương trình. Tuy nhiên với lỗi này thì trình biên dịch không báo vì nó không gây lỗi khi biên dịch. Do đó ta cần phải cẩn thận khi truy cập các phần tử của mảng.

Một số phép toán thao tác với mảng:

billy[0] = a;billy[a] = 75;b = billy [a+2];billy[billy[a]] = billy[2] + 5;

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 14

Page 15: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

// arrays example

int A [] = {16, 2, 77, 40, 12071};int n, KetQua=0;

void main () { for (n=0; n<5; n++) KetQua += A[n];} // KetQua = 12206

Mảng nhiều chiềuMảng nhiều chiều được mô tả như mảng của các mảng, ví dụ một mảng 2 chiều được khai báo như sau.

jimmy là một mảng 2 chiều với 3 mảng 1 chiều, mỗi mảng chứa 5 phần tử.

Cách khai báo mảng 2 chiều như sau

int jimmy [3][5];

Truy cập mảng 2 chiều

jimmy[1][3]=10;

a = jimmy[1][3];

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 15

Page 16: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

III. C cho 80511. Các kiểu biến, các loại vùng nhớ và các chế độ đánh địa chỉ:data địa chỉ trực tiếp MOV A, 07Fhidata địa chỉ gián tiếp MOV R0, #080h

MOV A, @R0xdata bộ nhớ ngoài MOVX @DPTR, #10code bộ nhớ chương trình MOVC A, @A+DPTR

Ví dụ 1:unsigned char data X = 0; // Khai báo biến X kiểu số nguyên (integer) nằm trong RAM từ 00 đến 7FH.

unsigned int idata Y = 0; // Khai báo biến Y kiểu số nguyên (integer) nằm trong RAM từ 80H đến FFH, vùng nhớ này chỉ có trong các chip có 256 byte RAM nội trở lên như AT89C52, AT89S52, AT89S8252, AT89C55WD ...Chỗ khác nhau khi khai báo 1 biến nằm trong vùng data hay idata là ở kiểu đánh địa chỉ.Một biến nằm trong vùng nhớ data là biến được truy cập trực tiếp còn biến nằm trong vùng idata là biến được truy cập gián tiếp. Khi lập trình bằng C chúng ta không cần quan tâm đến điều này, tuy nhiên khi cần thiết mới khai báo 1 biến nằm trong vùng idata vì nó sẽ làm chậm chương trình. Ta xem ví dụ sau:

unsigned int data i = 0; C:0x000F E4 CLR AC:0x0010 F508 MOV 0x08,AC:0x0012 F509 MOV 0x09,A

unsigned int idata j = 0; C:0x0014 780A MOV R0,#0x0AC:0x0016 F6 MOV @R0,AC:0x0017 08 INC R0C:0x0018 F6 MOV @R0,A

Khi thao tác xử lý các biến nằm trong vùng idata sẽ phải tốn nhiều lệnh hơn, do đó chương trình sẽ bị chậm hơn. Một lời khuyên là chỉ đặt các biến cần tốc độ xử lý không cao nằm trong vùng nhớ này.

Ví dụ 2:unsigned char code KetQua = 100; // Đây là một cách khai báo hằng số, vì từ khoá code xác định KetQua nằm trong vùng nhớ chương trình (ROM). KetQua sẽ là một hằng số nên ta chỉ có thể thao tác đọc nó chứ không thay đổi được nó (không cho phép ghi).

Ví dụ 3:unsigned char xdata KetQua = 0;

Chú ý rằng, bạn có thể không cần khai báo cụ thể vị trí của một biến nằm trong vùng nhớ nào, chỉ cần khai báo như sau, trình biên dịch của Keil C mặc định biến này sẽ nằm trong vùng nhớ data.unsigned int Y = 0;

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 16

Page 17: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

Trong trường hợp này trình biên dịch tự động phân bổ vùng nhớ RAM cho biến Y cho đến lúc nào số biến mà bạn sử dụng nhiều vượt quá dung lượng vùng nhớ data, khi đó trình biên dịch sẽ báo cho ta biết không đủ bộ nhớ, ta phải chuyển bớt các biến ra vùng nhớ idata bằng cách khai báo như ví dụ 1.

2. Bảng vector ngắt và cách khai báo một chương trình con phục vụ ngắt - ISR

Interrupt Vectoraddress

Interruptnumber

Ngắt ngoài 0 0003h 0Ngắt timer 0 000Bh 1Ngắt ngoài 1 0013h 2Ngắt timer 1 001Bh 3

Ngắt do cổng nối tiếp 0023h 4

Trong 8051 có 5 nguyên nhân sinh ra ngắt: ngắt ngoài 0, timer0, ngắt ngoài 1, timer1, ngắt nối tiếp.

Các bạn lại mở file regx51.h ra ở phần cuối của file như sau:

/*------------------------------------------------Interrupt Vectors:Interrupt Address = (Number * 8) + 3------------------------------------------------*/#define IE0_VECTOR 0 /* 0x03 External Interrupt 0 */#define TF0_VECTOR 1 /* 0x0B Timer 0 */#define IE1_VECTOR 2 /* 0x13 External Interrupt 1 */#define TF1_VECTOR 3 /* 0x1B Timer 1 */#define SIO_VECTOR 4 /* 0x23 Serial port */

Địa chỉ của ngắt trong bảng vector ngắt = 8 * số thứ tự ngắt + 3, số thứ tự ngắt = 0,1,2,3,4 như kí hiệu trong file đó. Như vậy địa chỉ trong RAM từ 0x03 đến 0x30 là dành cho bảng vector ngắt.

Chương trình con phục vụ ngắt là một hàm không có tham số, không có kiểu trả về. Vì thực chất các biến mà hàm này thao tác chính là các biến toàn cục (các thanh ghi, các port). Các chương trình con phục vụ ngắt này sẽ tự động được CPU gọi khi điều kiện ngắt xảy ra, thực chất khi điều kiện ngắt xảy ra thì CPU sẽ tạm dừng chương trình đang thực hiện, nhảy đến chương trình con phục vụ ngắt tương ứng, thực hiện hết chương trình ngắt đó và trở về lại tại điểm mà lúc nãy nó bị dừng bởi ngắt.

Cấu trúc một chương trình ngắt như sau:Code:

void TenChuongTrinhPhucVuNgat(void) interrupt a using b{// code

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 17

Page 18: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

}

Trong đó: những chữ in nghiêng là bắt buộc phải có và using b có thể có hoặc không có.

TenChuongTrinhPhucVuNgat: tùy ýa : là thứ tự của ngắt trong bảng vector ngắta = 0 : ngắt ngoài 0a = 1 : ngắt timer 0a = 2 : ngắt ngoài 1a = 3 : ngắt timer 1a = 4 : ngắt nối tiếp

b: là bank được chọn dùng để thực hiện hàm ngắt. Do 8051 có 4 bank là bank 0, 1, 2, 3. Do đó : b có thể là một trong các giá trị 0,1,2,3.

Lưu ý: nếu không viết thêm using b thì mặc định là hàm ngắt thực hiện tại bank0.

Ví dụ về hàm ngắt nối tiếp sẽ có dạng như sau:

void Serial_ISR(void) interrupt 4 using 2{// mã thực hiện hàm}

Ví dụ: Tạo một xung ở chân P1.0 và khi nhận được dữ liệu nối tiếp thì chuyển sang port P2. Tần số thạch anh là 11.0592 MHz. Dùng AT89C51

Code:

# include "regx51.h"

// Hàm tạo trễvoid delay(int time){ while(time--){ unsigned char j = 122; while(j--); }}

// Hàm thiết lập ban đầuvoid init(){ EA = 1; // Cho phép ngắt toàn cục ES = 1; // Cho phép ngắt nối tiếp // Thiet lap tan so bus TMOD = 0x02; // dung timer1, che do 8 bit tu nap lai TH1 = 253; // chon tan so bus = 9600 TR1 = 1 ; // khoi dong timer1}

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 18

Page 19: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

// Chương trình con phục vụ ngắt nối tiếpvoid inter4(void) interrupt 4 using 2{ if (RI){ // Kiểm tra cờ nhận RI. P2 = SBUF; // Lấy dữ liệu từ SBUF RI = 0; // Xóa cờ ngắt }}

// Chương trình chínhvoid main(){ // tao xung tren chan P1.0 init(); while(1){ P1_0 = 1; delay(500); P1_0 = 0; delay(500); }}

Lưu ý: là để VĐK nhảy đến bảng vector ngắt thì ta phải cho phép ngắt đó.

Ví dụ: Muốn tạo ngắt nối tiếp:Code:

EA = 1;// cho phép ngắt toàn cụcES = 1;// chp phép ngắt do cổng nối tiếp (ngắt truyền thông)

Các bit trong thanh ghi IE đã được Keil C định nghĩa trong thư viện regx51.h, các bit này có tên giống hệt tên các bit được ghi trong datasheet.

3. Cấu trúc cơ bản của một chương trình C

//Các chỉ thị tiền định#include <AT89X51.H> // Gọi thư viện có sẵn cách viết khác "*.h"#define led1 P1_0 // Dùng định nghĩa các biến

char bien1,bien2; // Các biến cần dùngint c,d; // biến c, d kiểu integer

/***********************************************************/// Các chương trình con/***********************************************************/

void ChuongTrinhCon(unsigned int b; char a) // Chương trình con{

// Mã lệnh xử lý trong chương trình con...

}

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 19

Page 20: Lap trinh C cho VDK

Lập trình C cho vi điều khiển bằng Keil C [email protected]

/***********************************************************/// Các hàm/***********************************************************/int QuetPhim(void) // chuong trinh con dang ham{

...return(MaPhim);

}

/***********************************************************/// Chương trình con phục vụ ngắt/***********************************************************/void ISR() interrupt 1 // chuong trinh con dang ham{

...}

/***********************************************************/// Chương trình chính/***********************************************************/

void main(void) // Chương trình chính{

int a; // Khai báo các biến cục bộChuongTrinhCon(4,6); // Gọi các chương trình cona = Ham(); // Gọi các hàm

}

Biên soạn: Cao Nguyễn Khoa Nam – Khoa Điện – Trường Cao đẳng công nghệ 20