Từ câu trả lời, bạn đã có khái quát cấu trúc của chương trình, sau đó, bằng các biểu tượng ở bảng 1, ta có thể lập thành lưu đồ, cuối cùng là chi tiết hóa bằng mã lệnh.. Cú pháp: Kiểu_kế
Trang 1Bà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
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ừ câu trả lời, bạn đã có khái quát cấu trúc của chương trình, sau đó, bằng các biểu tượng ở bảng 1, ta có thể lập thành lưu đồ, cuối cùng là chi tiết hóa bằng mã lệnh Nếu là người có nhiều kinh nghiệm, có thể các bước trên đã nằm sẵn trong kỹ năng của bạn và chỉ việc viết code theo định hướng có sẵn trong tư duy, tuy nhiên nếu là người mới thì làm việc có trình tự và quy tắc giúp ta đạt được mục đích 1 cách nhanh chóng và hiệu quả nhất có thể
Ví dụ: ai đó yêu cầu bạn dùng AVR làm cho 1 dãy đèn led gồm 8 bóng phát sáng lần lượt từng bóng từ phải sang trái và mỗi trạng thái duy trì 1s và cứ như thế xoay vòng mãi
Trang 2+Đầu tiên, đề yêu cầu điều khiển ngoại vi là led, do đó dữ liệu của chân điều khiển phải là dữ liệu xuất, ta cấu hình hướng dữ liệu xuất, việc cấu hình này chỉ cần làm 1 lần
+Thứ 2, cần điều khiển 8 bóng led thì 1 PORT vi điều khiển AVR là đầy
đủ Vì vậy ta sẽ thao tác dữ liệu trên thanh ghi PORT (PORTA chẳng hạn)
+Thứ 3, nếu xem dữ liệu dữ liệu thanh ghi là 8 bit tương đương với 8 led, từng bóng lần lượt phát sáng, ta thấy tại mỗi thời điểm chỉ có 1 trong 8 bit
ở mức cao, và hình như bit cao này, sau 1 giây lại dịch trái 1 bit Từ đây ta có thể suy ra, chỉ cần cho dữ liệu lúc ban đầu bằng 1, sau đó, mỗi 1s lại nhân nó lên 2 lần (dịch trái 1 bit tương đương nhân lên 2 lần), và sẽ lặp lại 8 lần Như vậy ta có thể xây dựng lưu đồ như sau:
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
Trang 3II Cấu trúc chương trình viết bằng ngôn ngữ C
Để tìm hiểu cấu trúc 1 chương trình viết bằng ngôn ngữ C, ta sẽ xem xét
1 ví dụ đơn giản như sau:
Ví dụ 1:
/* CHUONG TRINH DICH LED
NAM TRONG DVD TAI LIEU LAP TRINH C CHO VI DIEU KHIEN AVR TAI LIEU NAY CO NGUON TU WEBSITE WWW.EEELAB.ORG
*/
#include <delay.h>
#define led_port PORTD //DINH NGHIA PORTB LA led_port
char i; // KHAI BAO BIEN i, KIEU
DU LIEU CUA I LA CHAR
//CHUONG TRINH CHINH
void main() {
DDRD=0xff;
while(1){
for(i=0;i<=7;i++){
led_port=0x01;
led_port=led_port<<i;
delay_ms(500);
}
}
}
1 Khái niệm câu lệnh
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
Trang 4ngữ 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
4 Khai báo biến(biến toàn cục)
Khai báo các biến thuộc các kiểu dữ liệu khác nhau Cú pháp:
Kiểu dữ liệu tên_biến_1, tên_biến_2 ;
var3, var4 ;
5 Khai báo các prototype
Đây là phần khai báo đầu hàm (phần này không bắt buộc)
Cú pháp:
Kiểu_kết_quả_trả_về Tên_hàm (danh sách đối số vào) Lưu ý: Nếu 1 hàm được cài đặt sau 1 hàm khác, nó không thể được gọi trong các hàm cài đặt trước nó Tuy nhiên, nếu khai báo prototype của hàm
ta có thể cài đặt hàm ở bất cứ đâu và có thể gọi hàm ở bất kỳ hàm nào cài đặt trước hoặc sau nó
6 Chương trình chính
Bắt buộc phải có
void main( )
{
Các khai báo cục bộ trong hàm main; /* Các khai báo này chỉ tồn tại trong hàm mà thôi, có thể là khai báo biến hay khai báo kiểu.*/
Trang 5Các câu lệnh dùng để định nghĩa hàm main;
}
7 Cài đặt các hàm
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
Không có khoảng trống ở giữa tên
Không được trùng với từ khóa(tên các lệnh hoặc đối tượng đã định nghĩa trong các thư viện)
Độ dài tối đa của tên là 32 ký tự, tuy nhiên cần đặt sao cho rõ ràng, dễ nhận biết và dễ nhớ
Không cấm việc đặt tên trùng với tên chuẩn nhưng khi đó ý nghĩa của tên chuẩn không còn giá trị nữa
Ví dụ: Tên do người lập trình đặt: Chieu_dai, Chieu_Rong, Chu_Vi,
Dien_Tich
Trang 6Tên không hợp lệ: Do Dai, 12A2…
3 Hằng (Constant)
Là đại lượng không đổi trong suốt quá trình thực thi của chương trình Hằng số có thể là một chuỗi ký tự, một ký tự, một con số xác định Chúng có thể được biểu diễn hay định dạng với nhiều dạng thức khác nhau
IV Các kiểu dữ liệu
1 Các kiểu dữ liệu cơ bản
a Định dạng số học
Đây là cách biểu diễn các hệ thống số đếm trong trình biên dịch C -Thập phân: Biểu diễn giống như số thập phân bình thường Ví dụ 120 -Thập lục phân: Số thập lục phân được biểu diễn bắt đầu bằng “0X” (chữ
“X” viết tắt của HEX và không phân biệt hoa thường) Ví dụ 0X0F
-Nhị phân: Số nhị phân được biểu diễn bắt đầu bằng “0B” (chữ “B” viết tắt cửa BINARY và không phân biệt hoa thường) Ví dụ 0b01101100
b Các kiểu dữ liệu số học
(byte)
Khoảng giá trị
(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*1045 +3.4*1038
Trang 7double 4 -1.5*1045 +3.4*1038
long double 4 -1.5*1045 +3.4*1038 Ngoài ra ta còn có kiểu dữ liệu void, kiểu này mang ý nghĩa là kiểu rỗng không chứa giá trị gì cả Đối với AVR có thêm 1 kiểu dữ liệu đặc biệt là kiểu bit, kiểu này chỉ có giá trị 0 hoặc 1
d Ép kiểu
Khi thực hiện các phép toán, nếu các số hạng không cùng kiểu dữ liệu, MikroC sẽ tự động chuyển các số hạng này về cùng kiểu dữ liệu trước rồi mới tính toán Việc ép kiểu cũng có thể thực hiện bởi lập trình viên Nguyên tắc ép kiểu: Số hạng có kiểu đơn giản hơn được chuyển sang kiểu của số hạng có kiểu phức tạp hơn
Ép kiểu bắt buộc:
<(type)> object
Chuyển đổi kiểu đối tượng (object) thành kiểu mới (type)
Ví dụ:
/* Cho 2 biến a và b có kiểu dữ liệu là char */
char a, b;
/* Chuyển kiểu dữ liệu của biến a thành int*/
(unsigned int) a;
/* Dòng lệnh sau sẽ chuyển biến a sang kiểu double sau đó
chuyển biến b sang dạng double sau đó lấy a+b kết quả thuộc kiểu double */
(double) a + b; // equivalent to ((double) a) + b;
2 Các kiểu dữ liệu có cấu trúc
a Mảng: là kiểu dữ liệu có cấu trúc đơn giản và được sử dụng phổ biến nhất chứa 1 tập hợp các phần tử có cùng kiểu
Cú pháp khai báo mảng:
Cú pháp: Kiểu Tên_mảng [số phần tử] ; Kiểu dữ liệu: là kiểu dữ liệu mà mỗi phần tử của mảng được định dạng 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:
Trang 8Kiể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 ; Kiểu Phần_tử 2 ;
……
Kiểu Phần_tử n ; }
Ví dụ:
struct I2CSendByte{
char control;
char dat;
} Khai báo biến thuộc kiểu cấu trúc: Có thể khai báo lúc khai báo cấu trúc hoặc khai báo sau khi khai báo cấu trúc đều được
Ví dụ: Khai báo biến lúc khai báo cấu trúc:
struct I2CSendByte{
char control;
char dat;
}d1,d2;
Khai báo biến sau khi khai báo cấu trúc:
struct I2CSendByte {
char control;
char dat;
};
Trang 9struct I2CSendByte d1,d2;
Khởi tạo giá trị biến cấu trúc: tương tự như mảng
Ví dụ: struct I2CSendByte d1={0xA1,'A'};
Truy xuất các phần tử trong cấu trúc: Sử dụng 2 toán tử sau:
“.” 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
Các toán tử 2 toán hạng
% 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
++ Tăng, cộng 1 đơn vị vào giá trị toán hạng 14
Giảm, trừ 1 đơn vị vào giá trị toán hạng 14
Tăng và giảm (++ & )
Trang 10Toán tử ++ thêm 1 vào toán hạng của nó và – trừ bớt 1 Nói cách khác:
x = x + 1 giống như ++x
x = x – 1 giống như x—
Cả 2 toán tử tăng và giảm đều có thể tiền tố (đặt trước) hay hậu tố
(đặt sau) toán hạng Ví dụ: x = x + 1 có thể viết x++ (hay ++x)
Tuy nhiên giữa tiền tố và hậu tố có sự khác biệt khi sử dụng trong
1 biểu thức Khi 1 toán tử tăng hay giảm đứng trước toán hạng của nó, C thực hiện việc tăng hay giảm trước khi lấy giá trị dùng trong biểu thức Nếu toán tử
đi sau toán hạng, C lấy giá trị toán hạng trước khi tăng hay giảm nó Tóm lại:
y = ++x //y = 11, x=11
Tuy nhiên:
y = x++ //y = 10, x=11
2 Các toán tử quan hệ và các toán tử Logic
Các toán tử quan hệ dùng trong các biểu thức điều kiện Ý nghĩa chính của toán tử quan hệ và toán tử logic là đúng hoặc sai
Trong ngôn ngữ C, các biểu thức có giá trị khác 0 là đúng(true), bằng 0
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
Các toán tử quan hệ
>= Lớn hơn hoặc bằng 10
<= Nhỏ hơn hoặc bằng 10
Các toán tử Logic
Bảng sự thật cho các toán tử logic
Trang 110 0 0 0 1
3 Các thao tác bit
& Thực hiện AND 2 bit tương ứng, trả về 1 nếu cả 2
cùng bằng 1, trả về 0 nếu 1 trong 2 bằng 0
8
| Thực hiện OR 2 bit tương ứng, trả về 0 nếu cả 2
cùng bằng 0, trả về 1 nếu 1 trong 2 bằng 1
6
^ Thực hiện XOR 2 bit tương ứng, trả về 1 nếu 2 bit
khác nhau và trả về 0 nếu 2 bit giống nhau
7
<< Dịch trái, dịch trái các bit, bỏ bit ngoài cùng bên
trái(MSB) và gán 0 cho bit ngoài cùng bên phải
(LSB)
11
>> Dịch phải, dịch trái các bit, bỏ bit ngoài cùng bên
phải(LSB) và gán 0 cho bit ngoài cùng bên trái
(MSB)
11
Các ví dụ:
0x1234 & 0x5678; // Bằng 0x1230
Vì:
0x1234 : 0001 0010 0011 0100
&
0x5678 : 0101 0110 0111 1000
0001 0010 0011 0000 Tương tự:
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: