Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 36Bài 2 : NGÔN NGỮ C CƠ BẢN
I. Giải thuật lập trình.
Giải thuật lập trình có tác dụng định hướng cho lập trình viên trước khi
bắt tay vào viết mã lệnh, nó giúp lập trình viên có cái nhìn khái quát và phân rõ
nhiệm vụ, chức năng cho từng khối lệnh.
Giải thuật lập trình được cô đọng lại thành lưu đồ giải thuật với các khối
chức năng được mô tả theo quy ước chung theo bảng 1.
Hình dạng Chức năng
Dữ liệu vào - ra
Xử lý
Kiểm điều kiện
Hướng xử lý
Gọi chương trình con hoặc hàm
Điểm bắt đầu hoặc kết thúc
Điểm ghép nối
Bảng 1. Mô tả biểu tượng – chức năng cơ bản của lưu đồ giải thuật.
Để xây dựng lưu đồ giải thuật, bạn cần phải trả lời các câu hỏi:
+Mục đích của chương trình, xây dựng để làm gì, cần phải có chức năng
gì?
+Cần các hàm, các chương trình con như thế nào để đạt được từng chức
năng đã đặt ra?
Tùy mỗi người mà cách giải quyết 1 vấn đề sẽ khác nhau, tuy nhiên,
nếu làm nhiều và rút kinh nghiệm ta sẽ có các hướng giải quyết hợp lý nhất.
Bởi vì tài nguyên vi điều khiển là hạn hẹp nên việc cân nhắc sử dụng tài
nguyên đó như thế nào cho hợp lý rất đáng được quan tâm.
Trì hoãn 1s
Số lần=8?
PORTA x 2
Cho PORTA=1
S
ố lần=0
C
ấu hình h
ư
ớng
dữ liệu PORTA
Bắt đầu
Đúng
Sai
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 38
II. Cấu trúc chương trình viết bằng ngôn ngữ C.
Một câu lệnh (statement) xác định một công việc mà chương trình phải
thực hiện để xử lý dữ liệu đã được mô tả và khai báo. Các câu lệnh được ngăn
cách với nhau bởi dấu chấm phẩy “ ; ”.
2. Chú thích.
Khi viết chương trình đôi lúc ta cần phải có vài lời ghi chú về 1 đoạn
chương trình nào đó để dễ nhớ và dễ điều chỉnh sau này. Phần nội dung ghi chú
không thuộc về chương trình (khi biên dịch phần này bị bỏ qua). Trong ngôn
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 39
ngữ C, nội dung chú thích phải được viết trong cặp dấu /* và */ (nếu chú thích
trên nhiều dòng), hoặc đặt sau cặp dấu // (nếu chú thích trên 1 dòng).
Chú ý: Trình biên dịch MikroC có chức năng khóa 1 đoạn mã lệnh bằng
cặp dấu chú thích, khi cần khóa 1 đoạn lệnh, ta bôi đen đoạn lệnh đó và bấm
vào nút {…} hoặc bấm tổ hợp phím Ctr+Shift+dấu chấm, khi muốn phục hồi
lại đoạn lệnh đó, ta bấm vào nút {…} hoặc tổ hợp phím Ctr+Shift+ dấu phẩy.
3. Chỉ thị tiền xử lý.
- Chỉ thị sự gộp vào của các tập tin nguồn khác: #include
- Chỉ thị việc định nghĩa các macros hoặc ký hiệu: #define
Chỉ thị đầu tiên được sử dụng trước hết là nhằm gộp vào nội dung của
các tập tin cần có (header file), không thể thiếu trong việc sử dụng một cách tốt
nhất các hàm của thư viện chuẩn. Cú pháp :
#include tên_thư_viện.h
Đối với MikroC, chỉ thị include các thư viện của phần mềm vào chương
trình được thực hiện tự động qua công cụ Library Manager. Nếu dùng các thư
viện tự định nghĩa, ta vẫn dùng lệnh include để gộp tập tin thư viện.
Chỉ thị thứ hai là dùng định nghĩa các biến, cú pháp :
#define tên đối_tượng_cần_gán_tên
Kiểu_dữ_liệu_trả_về tên_hàm( các tham số)
{
Các khai báo cục bộ trong hàm.
Các câu lệnh dùng để định nghĩa hàm
return kết_quả_trả_về;
}
Một chương trình C bắt đầu thực thi từ hàm main (thông thường là từ
câu lệnh đầu tiên đến câu lệnh cuối cùng).
III. Bộ chữ viết, tên và hằng trong ngôn ngữ C.
1. Bộ chữ viết trong C.
Bộ chữ viết trong ngôn ngữ C bao gồm những ký tự, ký hiệu sau: (phân
biệt chữ in hoa và in thường):
26 chữ cái latin lớn A,B,C Z
26 chữ cái latin nhỏ a,b,c z.
10 chữ số thập phân 0,1,2 9.
Các ký hiệu toán học: +, -, *, /, =, <, >, (, )
Các ký hiệu đặc biệt: :. , ; " ' _ @ # $ ! ^ [ ] { }
Dấu cách hay khoảng trống.
2. Tên (danh biểu).
Tên hay còn gọi là danh biểu (identifier) được dùng để đặt cho chương
trình, hằng, kiểu, biến, chương trình con Tên có hai loại là tên chuẩn và tên
do người lập trình đặt.
Tên chuẩn là tên do C đặt sẵn như tên kiểu: int, char, float,…; tên hàm:
sin, cos
Tên do người lập trình tự đặt để dùng trong chương trình của mình. Sử
dụng bộ chữ cái, chữ số và dấu gạch dưới (_) để đặt tên, nhưng phải tuân thủ
quy tắc:
Bắt đầu bằng một chữ cái hoặc dấu gạch dưới.
Khoảng giá trị
(unsigned) char 1 0 255
signed char 1 -128 127
(signed) short (int) 1 -128 127
unsigned short (int) 1 0 255
(signed ) int 2 -32768 32767
unsigned int 2 0 65535
(signed) long (int) 4 -2147483648 2147483648
unsigned long (int) 4 0 4294967295
c. Kiểu số thực
Tên kiểu Kích thước Khoảng giá trị
float 4 -1.5*10
45
+3.4*10
38
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 42
double 4 -1.5*10
45
+3.4*10
38
long double 4 -1.5*10
45
+3.4*10
38
Tên mảng: đây là một cái tên đặt đúng theo quy tắc đặt tên của danh
biểu. Tên này cũng mang ý nghĩa là tên biến mảng.
Số phần tử: là một hằng số nguyên, cho biết số lượng phần tử tối đa
trong mảng là bao nhiêu (hay nói khác đi kích thước của mảng là gì). Giá trị
này có thể bỏ trống gọi là khai báo không tường minh.
Để truy xuất từng phần tử của mảng, ta dùng cú pháp:
Tên_mảng [Số_thứ_tự_của phần_tử];
Trong đó số thứ tự của phần tử có giá trị từ 0 đến “số phần tử” trừ đi 1.
Khởi tạo giá trị đầu cho mảng: Giá trị của các phần tử trong mảng có thể
được khởi tạo lúc khai báo bằng cú pháp sau:
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 43
Kiểu Tên_mảng [ ]= {Các giá trị cách nhau bởi dấu phẩy};
Nếu kích thước của mảng được chỉ định thì số giá trị không được vượt
quá kích thước của mảng này. Ngược lại, nếu không chỉ định thì trình biên dịch
tự động cập nhật giá trị này cho phù hợp.
Nếu khai báo 1 mảng kiểu char (character – ký tự). Thì ta có thể viết gọn
lại dưới dạng chuỗi.
Ví dụ:
const char msg1[] ={“T”, “E”,“S”,“T”} ;
const char msg2] = “TEST ” ;
Hai hằng số trên có giá trị như nhau.
3. Cấu trúc.
Chứa 1 tập hợp các phần tử được đặt tên bởi lập trình viên, các phần tử
này có thể có 1 kiểu bất kỳ.
Khai báo và khởi tạo cấu trúc:
struct Tên_cấu_trúc {
Kiểu Phần_tử 1 ;
“.” Truy xuất trực tiếp các phần tử trong cấu trúc.
“->” Truy xuất gián tiếp các phần tử trong cấu trúc. Chỉ áp dụng
đối với con trỏ.
Ví dụ:
struct mystruct{
int i;
char str[21];
double d;
} s,*sptr=&s;
s.i=3; // gán giá trị 3 cho phần tử I trong cấu trúc
sptr ->d=1.23; // gán gián tiếp giá trị 1.23 cho phần tử d.
V. Biểu thức
Biểu thức là một sự kết hợp giữa các toán tử (operator) và các toán hạng
(operand) theo đúng một trật tự nhất định.
Mỗi toán hạng có thể là một hằng, một biến hoặc một biểu thức khác.
Trong trường hợp, biểu thức có nhiều toán tử, ta dùng cặp dấu ngoặc
đơn () để chỉ định toán tử nào được thực hiện trước.
1. Các toán tử số học
Bảng tóm tắt các toán tử số học
Toán tử Ý nghĩa Độ ưu tiên
Các toán tử 2 toán hạng
+ Phép cộng 12
- Phép trừ 12
* Phép nhân 13
/ Phép chia lấy phần nguyên 13
% Phép chia lấy phần dư (không hỗ trợ kiểu float) 13
Các toán tử 1 toán hạng
là sai (false).
Trong các biểu thức sử dụng toán tử quan hệ và logic kết quả trả về là
1(1 được xem là số khác 0 tiêu biểu) nếu biểu thức đúng và trả về 0 nếu
biểu thức sai.
Bảng tóm tắt các toán tử quan hệ và logic.
Toán tử Ý nghĩa
Độ ưu tiên
Các toán tử quan hệ
> Lớn hơn 10
>= Lớn hơn hoặc bằng 10
< Nhỏ hơn 10
<= Nhỏ hơn hoặc bằng 10
== Bằng 9
!= Khác 9
Các toán tử Logic
&& Logic AND 5
|| Logic OR 4
! Logic NOT 14
Bảng sự thật cho các toán tử logic.
p q p&&q p||q !p
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 46
0 0 0 0 1
0 1 0 1 1
1 0 0 1 0
1 1 1 1 0
0x1234 | 0x5678; // Bằng 0x567C
0x1234 ^ 0x5678; // Bằng 0x444C
~0x1234 ; // Bằng 0xEDCB
Toán tử thao tác bit phân biệt nhau dựa vào ví dụ sau:
0x2222 & 0x5555 = 0x0000;
0x2222 & 0x5555 = 1; /*AND logic giữa 2 giá trị khác 0 (đúng AND
đúng = 1) */
~0x1234 = 0xEDCB;
!0x1234=0; // Đảo giá trị khác 0 (đúng) thành giá trị sai =0 4. Toán tử điều kiện “?:”
Toán tử điều kiện “?:” là toán tử 3 đối số trong C. Cú pháp:
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 47
(Biểu_thức_1) ? (Biểu thức 2) : ( Biểu thức 3) ;
Trong đó biểu thức 1 được tính toán trước, nếu kết quả là đúng thì biểu
thức 2 được thực hiện , nếu kết quả là sai thì biểu thức 3 được thực hiện.
Ví dụ: Tìm số lớn hơn trong 2 số a và b
max=(a>b)?a:b;
Đổi ký tự in thường thành in hoa:
c=(c>=’a’&&c<=’z’)?(c-32):c; // Trong bảng mã ASCII giá trị ký tự in
thường lớn hơn ký tự in hoa 32 đơn vị.
5. Toán tử gán
a. Gán thông thường
Không giống như các ngôn ngữ khác, C xem việc gán là 1 toán tử,
không phải là 1 lệnh.
+Kích thước của biến con trỏ không phụ thuộc vào kiểu dữ liệu, con trỏ
phải có khả năng chứa được địa chỉ ô nhớ lớn nhất của bộ nhớ.
b. Khai báo
Cú pháp: Kiểu * Tên_con_trỏ
Ý nghĩa: Khai báo một biến có tên là Tên_con_trỏ dùng để chứa địa chỉ của
các biến có kiểu Kiểu.
Ví dụ 1: Khai báo 2 biến a,b có kiểu int và 2 biến pa, pb là 2 biến con trỏ kiểu
int.
Ghi chú: Nếu chưa muốn khai báo kiểu dữ liệu mà con trỏ ptr đang chỉ đến, ta
sử dụng:
void *ptr;
Sau đó, nếu ta muốn con trỏ ptr chỉ đến kiểu dữ liệu gì cũng được. Tác dụng
của khai báo này là chỉ dành ra 2 bytes trong bộ nhớ để cấp phát cho biến con trỏ ptr.
c. Thao tác
Toán tử & dùng để định vị con trỏ đến địa chỉ của một biến đang làm việc.
Cú pháp: Tên_biến_con_trỏ=&Tên_biến
Giải thích: Ta gán địa chỉ của biến Tên_biến cho con trỏ Tên_biến_con_trỏ.
Ví dụ: Gán địa chỉ của biến a cho con trỏ pa, gán địa chỉ của biến b cho con trỏ
pb.
pa=&a; pb=&b;
Khi gán địa chỉ của biến tĩnh cho con trỏ cần phải lưu ý kiểu dữ liệu của
chúng.
d. Truy xuất
Để truy cập đến nội dung của ô nhớ mà con trỏ chỉ tới, ta sử dụng cú
pháp:
*Tên_biến_con_trỏ
Với cách truy cập này thì * Tên_biến_con_trỏ có thể coi là một biến có kiểu
được mô tả trong phần khai báo biến con trỏ.
Ví dụ: Ví dụ sau đây cho phép khai báo, gán địa chỉ cũng như lấy nội
}
b. Dạng đầy đủ (if … else).
Cú pháp: if( biểu thức điều kiện){
Các lệnh khi biểu thức điều kiện đúng;
}
else{
Các lệnh khi biểu thức điều kiện sai;
}
Giải thích: Nếu biểu thức điều kiện đúng (khác 0)
thì thực hiện khối lệnh <Công việc> và thoát khỏi
if.
Nếu biểu thức điều kiện if sai (bằng 0) thì
thực hiện khối lệnh 2 và thoát khỏi if.
Ví dụ:
if(a==b) a++; //Nếu a=b thì a tăng 1
if (a!=b){
a++;
b=a;
}
Vào
Bt
đi
ều
kiện
Khối lệnh 1
Đúng
Ra
Khối lệnh 2
Giải thích: Nếu biểu thức điều kiện thứ n đúng thì thực hiện khối lệnh n,
nếu tất cả biểu thức điều kiện đều cho giá trị sai thì thoát mà không làm gì
cả.
Vào
BTĐK1
BTĐK2
BTĐK(n-1)
BTĐKn
Khối lệnh 1 Khối lệnh 2 Khối lệnh n-1 Khối lệnh n
Ra
Sai
Nếu gặp lệnh break thì thoát ngay lập tức, nếu không có lệnh break thì
tiếp tục thực hiện các nhóm lệnh ở các case tiếp theo cho đến khi gặp break
hoặc kết thúc đoạn lệnh.
Nếu giá trong giá trị tính toán không có giá trị nào giống với giá trị của
các case thì switch sẽ thực thi đoạn lệnh trong mục default. Mục default có thể
lược bỏ, khi đó nếu rơi vào trường hợp không có giá trị phù hợp thì cấu trúc
switch sẽ thoát ra.
Lưu ý: biểu thức phải có kết quả là giá trị kiểu nguyên (char, int,
long…). Các nhóm lệnh có thể gồm nhiều lệnh nhưng không cần đặt trong dấu
ngoặc nhọn{}.
So sánh lưu đồ giải thuật của 2 dạng switch - case (có default và không có
default).
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 52
case giá trị n
= giá trị 1
= giá trị 2
= giá trị n
Ra
có break ?
Vào
Biểu thức
case giá trị 1
có break ?
case giá trị 2
có break ?
case giá trị n
= giá trị 1
= giá trị 2
= giá trị n
Ra
có break ?
default
có break ?
= giá trị
của câu lệnh for như sau:
B1: Tính giá trị của biểu thức 1.
B2: Tính giá trị của biểu thức 2.
- Nếu giá trị của biểu thức 2 là sai (=0): thoát khỏi câu lệnh for.
- Nếu giá trị của biểu thức 2 là đúng (!=0): <Công việc> được
thực hiện.
B3: Tính giá trị của biểu thức 3 và quay lại B2.
b. Vòng lặp while.
Vòng lặp while giống như vòng lặp for, dùng để lặp lại một công việc
nào đó cho đến khi điều kiện sai.
Sai
Vào
Tính giá trị
Biểu thức 1
Kiểm điều kiện
ở biểu thức 2
Đúng
Ra
Thực hiện
công việc
Tính giá trị
biểu thức 3
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 54
Cú pháp:
while (Biểu thức điều kiện)
<công việc
Kiểm biểu
thức điều kiện
Vào
Ra
Thực hiện
công việc
Đúng
Sai
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 55
Lưu đồ:
Giải thích:
Khi bắt đầu vào vòng lặp thì khối lệnh công việc được thực hiện trước,
sau đó chương trình sẽ tiến hành tính toán và kiểm tra biểu thức điều kiện, nếu