Tải bản đầy đủ (.pdf) (65 trang)

đề cương ứng dụng lập trình c cho vi điều khiển 8051

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 (1.06 MB, 65 trang )

<span class='text_page_counter'>(1)</span><div class='page_container' data-page=1>

<b>Đề cương ứng dụng lập trình C cho vi điều khiển 8051 </b>
<b>Bài 1: Ngôn ngữ C – Trình dịch Keil C </b>


<i><b>I. Ngơn ngữ C cho vi điều khiển </b></i>
<i><b>1, Giới thiệu ngôn ngữ C </b></i>


Trong kỹ thuật lập trình vi điều khiển nói chung, ngơn ngữ lập trình được sử dụng thường chia làm 2 loại: Ngôn
ngữ bậc thấp và Ngôn ngữ bậc cao.


Ngôn ngữ bậc cao là các ngôn ngữ gần vơi ngơn ngữ con người hơn, do đó việc lập trình bằng các ngôn ngữ này
trở nên dễ dàng và đơn giản hơn. Có thể kể đến một số ngơn ngữ lập trình bậc cao như C, Basic, Pascal… trong dó C là
ngơn


ngữ thơng dụng hơn cả trong kỹ thuật vi điều khiển. Về bản chất, sử dụng các ngôn ngữ này thay cho ngôn ngữ bậc thấp
là giảm tải cho lập trình viên trong việc nghiên cứu các tập lệnh và xây dựng các cấu trúc giải thuật. Chương trình viết
bằng ngơn ngữ bậc cao cũng sẽ được một phần mềm trên máy tính gọi là trình biên dịch (Compiler) chuyển sang dạng
hợp ngữ trước khi chuyển sang mã máy.


Khi sử dụng ngôn ngữ C người lập trình khơng cần hiểu sâu sắc về cấu trúc của bộ vi điều khiển. Có nghĩa là với
một người chưa quen với một vi điểu khiển cho trước sẽ xây dựng được chương trình một cách nhanh chóng hơn, do
khơng phải mất thời gian tìm hiểu kiến trúc của vi điều khiển đó. Và việc sử dụng lại các chương trình đã xây dựng trước
<i><b>đó cũng dễ dàng hơn, có thể sử dụng tồn bộ hoặc sửa chữa một phần. </b></i>


<i><b>2. Ngơn ngữ C </b></i>
<i><b>2.1 Kiểu dữ liệu </b></i>


<i><b>2.1.1 Kiểu dữ liệu trong C </b></i>


Kiểu Số Byte Khoảng giá trị


Char 1 -128 – +127



Unsigned char 1 0 – 255


Int 2 -32768 - +32767


Unsigned int 2 0 - 65535


Long 4 -2147483648 - +2147483647


Unsigned long 4 0 – 4294697295


Float 4


<i>* Khai báo biến: </i>


<i> - Cú pháp: Kiểu_dữ_liệu Vùng_nhớ Tên_biến _at_ Đia_chỉ; </i>
Ví dụ:


Unsigned char data x;


<i> - Khi khai báo biến có thể gán luôn cho biến giá trị ban đầu. </i>
Ví dụ:


Thay vì: unsigned char x;
x = 0;


Ta chỉ cần: unsigned char x = 0;


</div>
<span class='text_page_counter'>(2)</span><div class='page_container' data-page=2>

<i> - Chỉ định vùng nhớ: từ khố “Vùng_nhớ” cho phép người dùng có thể chỉ ra vùng nhớ sử dụng để lưu trữ các biến sử </i>
dụng trong chương trình. Các vùng nhớ có thể sử dụng là: CODE, DATA, DATAB, IDATA, PDATA, XDTA. Khi khơng


khai báo vùng nhớ trình dịch Keil C sẽ mặc định đó là vùng nhớ DATA.


Vùng nhớ Ý nghĩa


CODE Bộ nhớ mã nguồn chương trình


DATA Bộ nhớ dữ liệu gồm 128 Byte thấp của RAM trong vi điều khiển
BDATA Bộ nhớ dữ liệu có thê định địa chỉ bit, nằm trong vùng nhớ DATA


IDATA Bộ nhớ dữ liệu gồm 128 Byte cao của RAM trong vi điều khiển chỉ có ở một số dịng vi
điều khiển sau này


PDATA Bố nhớ dữ liệu ngoài gồm 256 Byte, được truy cập bởi địa chỉ đặt trên P0


XDATA Bộ nhớ dữ liệu ngồi có dung lượng có thể lên đến 64 KB, được truy cập bởi địa chỉ đặt
trên P0 và P2


* Định nghĩa lại kiểu


- Cú pháp: typedef Kiễu_dữ_liệu Tên_biến;


- Ten_biến sau này sẽ được sử dụng như một kiểu dữ liệu mới và có thể dùng để khai báo các biến khác
Ví dụ: typedef int m5[5];


Dùng tên m5 khai báo hai biến tên a và b có kiểu dữ liệu là mảng 1 chiểu 5 phần tử:
<i><b> m5 a,b; </b></i>


<i><b>2.1.2 Kiểu dữ liệu trong Keil C </b></i>


Kiểu Số bit



Bit 1


Sbit 1


Sfr 8


Sfr16 16


- bit : dùng để khai báo các biến có giá trị 0 hoặc một hay các biến logic trên vùng RAM của vi điều khiển. Khi
khai báo biến kiểu bit trình dịc Keil C sẽ mặc định vùng nhớ sử dụng là BDATA.


` - sbit, sfr, sfr16: dùng để định nghĩa các cho các thanh ghi chức năng hoặc các cổng trên vi điều khiển dùng để
truy nhập các đoạn dữ liệu 1 bit, 8 bit, 16 bit


<i><b>2.1.3 Mảng </b></i>


Mảng là một tập hợp nhiều phần tử cùng một kiểu giá trị và chung một tên. Các phần tử của mảng phân biệt với
nhau bởi chỉ số hay số thứ tự của phần tử trong dãy phẩn tử. Mỗi phần tử có vai trị như một biến và lưu trữ được một giá
trị độc lập với các phần tử khác của mảng.


Mảng có thể là mảng một chiều hoặc mảng nhiều chiều
Khai báo:


<i> - Cú pháp: Tên_kiểu Vùng_nhớ Tên_mảng[số_phần_tử_mảng]; </i>


Khi bỏ trống số phần tử mảng ta sẽ có mảng có số phần tử bất kì.
Ví dụ:


Unsigned int data a[5],b[2] [3];



</div>
<span class='text_page_counter'>(3)</span><div class='page_container' data-page=3>

Chỉ số của mảng bắt đầu từ số 0. Mảng có bao nhiêu chiều phải cung cấp đầy đủ bấy nhiêu chỉ sơ
Ví du: phần tử mảng b[0] [1] là đúng


Khi viết b[0] là sai
<i><b>2.1.4. Con trỏ </b></i>


Khi ta khai báo một biến, biến đó sẽ được cấp phát một khoảng nhớ bao gồm một số byte nhất định dùng để lưu
trữ giá trị. Địa chỉ đầu tiên của khoảng nhớ đó chính là địa chỉ của biến được khai báo.


Con trỏ là một biến dùng để chứa địa chỉ mà không chứa giá trị, hay giá trị của con trỏ chính là địa chỉ khoảng
nhớ mà nó trỏ tới.


Với các vùng nhớ cụ thể con trỏ tới vùng nhớ đó chiếm dung lượng phụ thuộc vào độ lớn của vùng nhớ đó. Con
trỏ tổng qt khi khơng xác định trước vùng nhớ sẽ có dung lượng lớn nhất vì vậy tốt nhất nên sử dụng con trỏ cụ thể.
Loại con trỏ Kích thước


Con trỏ tổng quát 3 byte
Con trỏ XDATA 2 byte
Con trỏ CODE 2 byte
Con trỏ DATA 1 byte
Con trỏ IDATA 1 byte
Con trỏ PDATA 1 byte
Khai báo biến con trỏ:


- Cú pháp: Kiểu_Dữ_liệu Vùng_nhớ *Tên_biến;
- Ví dụ:


int *int_ptr;



long data *long_ptr;


- khi không chỉ rõ vùng nhớ con trỏ sẽ được coi là con trỏ tổng quát.
<i><b>2.1.5 Kiểu dữ liệu cấu trúc </b></i>


Kiểu dữ liệu cấu trúc là một tập hợp các biến, các mảng và cả các kiểu cấu trúc khác được biểu thị bởi một tên
duy nhất. kiểu dữ liệu cấu trúc dùng để lưu trữ các giá trị, thông tin có liên quan đến nhau.


Định nghĩa và khai báo biến cấu trúc:
- Định nghĩa: typedef struct {


Khai báo các biến thành phần;
} Tên_kiểu_cấu_trúc;


- Khai báo: Tên_kiểu_cấu_trúc Vùng_nhớ Tên_biến;
Ví dụ: typedef struct {


char day;
char month;
int year;
} Date_type;
Date_type date,date_arr[5];
<i><b>2.2 Phép tốn </b></i>


</div>
<span class='text_page_counter'>(4)</span><div class='page_container' data-page=4>

Trong đó Biến_2 có thể là giá trị xác định cũng có thể là biến.
<i><b>2.2.1 Phép toán số học </b></i>


Phép toán ý nghĩa Ví dụ


+ Phép cộng X=a+b



- Phép trừ X=a-b


* Phép nhân X=a*b


/ Phép chia lấy phần nguyên X=a/b


(a=9, b=2 → X=4)


% Phép chia lấy phần dư a%b


(a=9, b=2 → X=1)
<i><b>2.2.2 Phép toán Logic </b></i>


AND: &&
OR: ||
NOT: !


<i><b>2.2.3 Các phép toán so sánh: </b></i>


Phép
tốn


ý nghĩa Ví dụ


> So sánh lớn hơn a>b


4>5 các giá trị 0



>= So sánh lớn hơn hoặc bằng a>=b


6>=2 các giá trị 1


< So sánh nhỏ hơn a<b


6<7 các giá trị 1


<= So sánh nhỏ hơn hoặc bằng a<=b


</div>
<span class='text_page_counter'>(5)</span><div class='page_container' data-page=5>

<i><b>2.2.4 Phép </b></i>
<i><b>toán </b></i> <i><b>thao </b></i>
<i><b>tác Bit </b></i>


Phép tốn Ý nghĩa Ví dụ


& Phép và (AND) Bit_1 & Bit_2


| Phép hoặc (OR) Bit_1 | Bit_2


! Phép đảo (NOT) !Bit_1


^ Phép hoặc loại trừ (XOR) Bit_1 ^ Bit_2


<< Dịch trái a<<3


>> Dịch phải a>>4


~ Lấy bù theo bit ~a



<i><b>2.2.5 Phép toán kết hợp </b></i>
Phép tốn Ví dụ


+= a+=5 <=> a=a+5
-= a-=5 <=> a=a-5
*= a*=5 <=> a=a*5


/= a/=5 <=> a=a/5
%= a%=5 <=> a=a%5


<i><b>2.3 Cấu trúc chương trình C </b></i>
<i><b>2.3.1 Cấu trúc chương trình </b></i>


* Cấu trúc


1. Khai báo chỉ thị tiền xử lý
2. Khai báo các biến toàn cục
3. Khai báo nguyên mẫu các hàm


4. Xây dựng các hàm và chương trình chính
* Ví dụ:


#include<regx51.h>
#include<string.h>
#define Led1 P1_0


Unsigned char code Led_arr[3];
Unsigned char data dem;
Unsigned int xdata X;



Void delay(unsigned int n);
bit kiemtra(unsigned int a);


void delay(unsigned int n)


== So sánh bằng nhau a==b


6==6 các giá trị 1


!= So sánh khác nhau a!=b


9!=9 các giá trị 0


Khai báo chỉ thị tiền xử lý



Khai báo biến toàn cục



</div>
<span class='text_page_counter'>(6)</span><div class='page_container' data-page=6>

{


Khai báo biến cục bộ;
Mã chương trình trễ;
}


Void main()
{


Khai báo biến cụ bộ;
Mã chương trình chính;
}



Bit kiemtra(unsigned int a)
{


Khai báo biến cục bơ;


Mã chương trình kiểm tra biến a;
}


Chú ý: Hàm không khai báo nguyên mẫu phải được xây dựng trước hàm có lời gọi hàm đó. Ở ví dụ trên do hàm
“bit kiemtra(unsigned int a)” đã được khai báo nguyên mẫu hàm ở trên nên có thể xây dựng hàm ở bất kì vị trí nào trong
chương trình.


<i><b>2.3.2 Chỉ thị tiền xử lý </b></i>


Các chỉ thị tiền sử lý không phải là các lệnh của ngôn ngữ C mà là các lệnh giúp cho việc soạn thảo chương trình
nguồn C trước khi biên dịch. Khi dịch một chương trình C thì khơng phải chính bản chương trình nguồn mà ta soạn thảo
được dịch. Trước khi dịch, các lệnh tiền xử lý sẽ chỉnh lý bản gốc, sau đó bản chỉnh lý này sẽ được dịch. Có ba cách chỉnh
lý được dùng là:


+ Phép thay thế #define
+ Phép chèn tệp #include
+ Phép lựa chọn biên dịch #ifdef


Các chỉ thị tiền xử lý giúp ta viết chương trình ngắn gọn hơn và tổ chức biên dịch, gỡ rối chương trình linh hoạt,
hiệu quả hơn.


* Chỉ thị #define


Chỉ thị #define cho phép tạo các macro thay thế đơn giản
<i><b> - Cú pháp: #define Tên_thay_thế dãy_kí_tự </b></i>



Một Tên_thay_thế có thể được định nghĩa lại nhiều lần, nhưng trước khi định nghĩa lại phải giải phóng định nghĩa
bằng chỉ thị:


#undef Tên_thay_thế
- Ví dụ: #define N 100


* Chỉ thị #include


Chỉ thị #include báo cho trình biên dịch nhận nội dung của tệp khác và chèn vào tệp chương trình nguồn mà ta
soạn thảo.


<i><b> - Cú pháp: </b></i>


Cách 1: #include<tên_tệp>
Cách 2: #include“tên_tệp”


</div>
<span class='text_page_counter'>(7)</span><div class='page_container' data-page=7>

- Ví dụ:


Cách 1: #include<regx51.h>


Ở cách này tệp regx51.h sẽ được tìm trong thư mục INC để chèn vào chương trình nguồn.
Cách 2: #include“regx51.h”


Ở cách này tệp regx51.h sẽ được tìm trong thư mục chứa chương trình nguồn nếu khơng có mới tìm trong
thư mục INC


Khi muốn chèn tệp ngoài thư viện hoặc ngoài thư mục chứa chương trình nguồn thì tên_tệp sẽ bao gồm cả đường
dẫn thư mục chứa tệp.



* Chỉ thị #ifdef


Chỉ thị #ifdef này thường dùng để biên dịch các tệp thư viện.
<i><b> - Cú pháp: </b></i>


Cách 1: #ifdef ten_macro


Đoạn chương trình
#endif


Cách 2: #ifdef ten_macro


Đoạn chương trình 1
#else


Đoạn chương trình 2
#endif


Ở cách 1 nếu tên_macro đã được định nghĩa “Đoạn chương trình” sẽ được dịch ngược lại “Đoạn chương trình” sẽ
bị bỏ qua.


* Chỉ thị #ifndef


Chỉ thị #ifndef này thường dùng để biên dịch các tệp thư viện.
<i><b> - Cú pháp: </b></i>


Cách 1: #ifndef ten_macro


Đoạn chương trình
#endif



Cách 2: #ifndef ten_macro


Đoạn chương trình 1
#else


Đoạn chương trình 2
#endif


Ở cách 1 nếu tên_macro chưa được định nghĩa “Đoạn chương trình” sẽ được dịch ngược lại “Đoạn chương trình”
sẽ bị bỏ qua.


<i><b>2.3.3 Chú thích trong chương trình </b></i>


</div>
<span class='text_page_counter'>(8)</span><div class='page_container' data-page=8>

Chú thích trong chương trình sẽ khơng ảnh hưởng đến chương trình mà ta soạn thảo vì trình dịch sẽ bỏ qua tất cả
lời chú thích khi biên dịch chương trình sang mã máy.


Lời giải thích được đặt sau dấu “//” nếu chú thích chỉ viết trên một dòng hoặc trong
cặp dấu “\*” và “*\”.


<i><b>3 Các lệnh cơ bản trong C </b></i>
<i> + Câu lệnh rẽ nhánh if: </i>
<i> </i> <i>- Cấu trúc: if(dieu_kien) </i>
{


// Đoạn chương trình
}





Giải thích: nếu dieu_kien đúng thì xư lí các câu lệnh bên trong cịn sai thì nhảy qua.
- Cấu trúc: if(dieu_kien)


{


// Đoạn chương trình 1
}


else
{


// Đoạn chương trình 2
}


Giải thích: nếu dieu_kien đúng thì xử lí “Đoạn chương trình 1” bên trong cịn sai thì x ử l ý “Đoạn chương trình
1”


<i> + Câu lệnh lựa chọn: </i>
Cấu trúc: switch(bien)
{


case gia_tri_1: {//các câu lệnh break;}
case gia_tri_2: {//các câu lệnh break;}
case gia_tri_3: {//các câu lệnh break;}
………...
case gia_tri_n: {//các câu lệnh break;}
}


Giải thích: tuỳ vào biến có gia_tri_1 thì thực hiện các câu lệnh tương ứng rồi sau đó thốt khỏi cấu trúc nhờ câu lệnh
break.



Biến có gia_tri_2 thì thực hiện câu lệnh tương ứng rồi thoát.
……….


Biến có gia_tri_n thì thực hiện các câu lệnh tương ứng rồi thốt.
<i> + Vịng lặp xác định: </i>


Cấu trúc: for(n=m;n<l;n++)
{


</div>
<span class='text_page_counter'>(9)</span><div class='page_container' data-page=9>

}
Giải thích:


m,l là giá trị(m>l), còn n là biến.
thực hiện lặp các câu lệnh (l-m) lần.
<i> + Vịng lặp khơng xác định while: </i>


Cấu trúc: while(dieu_kien)
{


// các câu lệnh
}


Giả thích: thực hiện lặp các câu lệnh khi điều kiện đúng nếu điều kiện sai thì thốt khỏi vịng lặp.
<i> + Vịng lặp không xác định do while: </i>


Cấu trúc: do
{


// các câu lệnh


} while(dieu_kien);


Giả thích: thực hiện lặp các câu lệnh sau đó kiểm tra điều kiện nếu đúng, nếu sai thì thốt khỏi vịng lặp.


<i><b>II. Trình biên dịch Keil C (compiler) </b></i>
<i><b>2.1. Khởi tạo cho Project. </b></i>


</div>
<span class='text_page_counter'>(10)</span><div class='page_container' data-page=10>



<b> Hộp thoại create new project hiện ra như sau: </b>


</div>
<span class='text_page_counter'>(11)</span><div class='page_container' data-page=11>

Trong này có 1 loạt các hãng điện tử sản xuất 8051. bạn lập trình cho con nào thì chọn con đấy, kích chuột vào dấu + để
mở rộng các con IC của các hang. ở đây ta lập trình cho AT89C51 của hang ATMEN nên ta chọn như trên.


Khi chọn chip thì ngay lập tức 1 bảng hiện ra 1 số tính năng của chip các bạn có thể nhìn thấy: 8051 based fully static
24Mhz …. nhập OK, chọ câu trả lời NO khi được hỏi “copy standard 8051 startup code to project and addfile to project”
vì nếu chon YES chỉ làm cho file lập trình của bạn thêm nặng.


</div>
<span class='text_page_counter'>(12)</span><div class='page_container' data-page=12>

<b> Cửa sổ text1 hiện ra. Tiếp theo bạn chọn File → save As hoặc Ctrl+S, để lưu File mặc dù chưa có gì như sau: </b>


</div>
<span class='text_page_counter'>(13)</span><div class='page_container' data-page=13>

Các bạn nhập tên vào text box file name.chú ý tên gì cũng được nhưng không được thiếu đuôi mở rộng .C, và nhấn
SAVE.


Trong ơ bên trái màn hình, cửa sổ PROJECT WORKSPACE, các bạn mở rộng cái target 1 ra như sau:


</div>
<span class='text_page_counter'>(14)</span><div class='page_container' data-page=14></div>
<span class='text_page_counter'>(15)</span><div class='page_container' data-page=15>

Phần cuối cùng của công việc khởi tạo là các bạn viết lời giải thích cho dự án của mình. phần này rất cần thiết vì nó để
người khác hiểu mình làm gì trong project này và khi mình cần sử dụng lại code đọc lại cịn biết nó là cái gì.


<b>2.2. Soạn thảo chương trình. </b>



Các bạn viết thử 1 chương trình làm ví dụ. khi viết xong mỗi dịng lệnh nên giải thích dịng lệnh đó làm gì. Ví dụ:


<b>2.3. Biên dịch một chương trình. </b>


</div>
<span class='text_page_counter'>(16)</span><div class='page_container' data-page=16>



</div>
<span class='text_page_counter'>(17)</span><div class='page_container' data-page=17></div>
<span class='text_page_counter'>(18)</span><div class='page_container' data-page=18>

<b> Để mô phỏng các bạn chon Debug→Start/stop debug session hoặc ấn Ctrl+F5, hoặc nhấn vào Icon chữ D màu đỏ trong </b>
cái kính lúp trên thanh công cụ.


</div>
<span class='text_page_counter'>(19)</span><div class='page_container' data-page=19>

Các bạn thấy 1 cửa sổ nhỏ Parallel Port xuất hiện đó là cái để mô phỏng cho 1 cổng của AT89C51. dấu tick tương đương
chân ở mức cao (5V), không tick chân ở mức thấp 0V.trong menu peripherals cịn có các ngoại vi khác như timer,


</div>
<span class='text_page_counter'>(20)</span><div class='page_container' data-page=20>

Để chạy chương trình các bạn ấn chuột phải vào màn hình soạn thảo, rồi ấn F11.mỗi làn ấn sẽ chạy 1 lệnh.khi debug nếu
các bạn chờ hàm delay lâu quá 1000 lần lặp các bạn nhấn ctrl+F11 để bỏ qua hàm.


</div>
<span class='text_page_counter'>(21)</span><div class='page_container' data-page=21>

<b>Bài 2: Điều khiển Led đơn, Led 7 thanh và nút nhấn </b>


<b>I. Hiển thị Led đơn </b>


<i><b> Bài toán:Ghép nối LED dơn với chân P1.0 của vi điều khiển, viết chương trình điều khiển LED nhấp nháy với thời </b></i>
<i>gian trễ là 1s. </i>


+ Lưu đồ thuật toán của bài LED nháy:




+ Chương trình điều khiển:


*/==================Bo tien xu li===================*/
#include<AT89x51.h> // Dinh kem file thu vien



#define bat 1 // Dinh nghia gia tri bat den Led
#define tat 0 // Dinh nghia gia tri tat den Led


START



Khởi tạo hệ thống



Sáng Led


Trễ 1S


Tắt Led



</div>
<span class='text_page_counter'>(22)</span><div class='page_container' data-page=22>

/*==================khai bao bien==================*/
sbit Led = P1^0; // Khai bao bien Led kieu bit chan P1.0




/*================= Khai bao hàm==================*/
/*---ham tre ---*/
void delay(long time)


{


while(time--);
}


/*---ham chinh---*/
void main(void)


{



while(1)
{


Led = bat; // bat Led
delay(25000); // tre 1s
Led = tat; // tat Led
delay(25000); //tre 1s
}


}


<b>II. Phối hợp Led và nút nhấn </b>
<b>1. Phối hợp Led đơn và nút nhấn </b>


</div>
<span class='text_page_counter'>(23)</span><div class='page_container' data-page=23>

+ Lưu đồ thuật giải của bài toán:


+ Chương trình điều khiển:


*/==================Bo tien xu li===================*/
#include<AT89x51.h> // Dinh kem file thu vien


#define bat 1 // Dinh nghia gia tri bat den Led
#define tat 0 // Dinh nghia gia tri tat den Led


/*==================khai bao bien==================*/


Start



Led = tat




Start = 0



Stop = 0

Led = tat



</div>
<span class='text_page_counter'>(24)</span><div class='page_container' data-page=24>

sbit Led = P1^0; // Khai bao bien Led kieu bit chan P1.0
sbit STOP = P3^0; // cong tac STOP de tat Led


sbit START = P3^1; // cong tac START de bat Led


/*=================== ham chinh==================*/
void main(void)


{


Led = tat; //ban dau tat Led
while(1){


if((START==0)&&(STOP==1)) {
Led = bat;


}


if((START==1)&&(STOP==0)){
Led = tat;


}
}
}



<b>2. Phối hợp Led 7 thanh và nút nhấn </b>
Các số
hiển thị
P1.0
g
P1.1
f
P1.2
e
P1.3
d
P1.4
c
P1.5
b
P1.6


a dp


số nạp hex
mov P1,#


0 1 0 0 0 0 0 0 1 81


1 1 1 1 1 0 0 1 1 cf


2 0 1 0 0 1 0 0 1 92


3 0 1 1 0 0 0 0 1 86



4 0 0 1 1 0 0 1 1 cc


5 0 0 1 0 0 1 0 1 a4


6 0 0 0 0 0 1 0 1 a0


7 1 1 1 1 0 0 0 1 8f


8 0 0 0 0 0 0 0 1 80


9 0 0 1 0 0 0 0 1 84


<b>Bài toán: </b>


</div>
<span class='text_page_counter'>(25)</span><div class='page_container' data-page=25>

<b>+ Lưu đồ thuật giải: </b>


+ Chương trình điều khiển:


/*==================Bo tien xu li===================*/

START



Dem=0;



ctac==0?



dem++;



dem<=10?



dem=0;




</div>
<span class='text_page_counter'>(26)</span><div class='page_container' data-page=26>

#include<AT89x51.h> // Dinh kem file thu vien


/*=================Khai bao bien toan cuc=============*/
sfr dataP = 0x90; // du lieu la P1


// ma 7 thanh tu 0 den 9 la


// 0x81h,0xcfh,0x92h,0x86h,0xcch,0xa4,0xa0h,0x8fh,0x80h,0x84h.


sbit ctac = P3^4;
unsigned char dem=0;


/*====================Khai bao ham==================*/
/*---ham delay========================*/
void delay(long time)


{


while(time--);
}


/*---chuong trinh con kiem tra co phim nhan---*/
void phim_an(void)


{


if(ctac==0) //co phim nhan
{



delay(500); //chong rung phim
while(ctac==0); //Cho nha phim
delay(500); // chong rung phim
dem++; //tang bien dem
if(dem==10) dem=0;
}


}


/*---hien thi so lan an phim---*/
void solan_an(void)


{


switch(dem)
{


</div>
<span class='text_page_counter'>(27)</span><div class='page_container' data-page=27>

};
}


/*---chuong trinh chinh---*/
void main(void)


{


dataP = 0x81; // ban dau la so 0
while(1){


phim_an();
solan_an();


}


}


<i><b>Bài 3 Hiển thị LCD, Giao tiếp bàn phím Hex, Hiển thị ma trận Led </b></i>
<b>I. LCD </b>


<b>1. Ghép nối vi điều khiển với LCD 16x2. </b>
<b> - Bảng mô tả sơ đồ chân của LCD 16x2: </b>


Chân Ký hiệu I/O Mô tả


1 Vss - Mass


2 Vcc - Dương nguồn 5v


3 VEE - Cấp nguồn điều khiển tương phản


4 RS I RS=0 chon thanh ghi lệnh


RS=1 chon thanh ghi dữ liệu


5 R/W I R/W=1 đọc dữ liệu, R/W=1 ghi


6 E I/O Cho phép


7 DB0 I/O Bit dữ liệu


8 DB1 I/O Nt



9 DB2 I/O Nt


10 DB3 I/O Nt


11 DB4 I/O Nt


12 DB5 I/O Nt


13 DB6 I/O Nt


14 DB7 I/O Nt


Chân 15 và 16 là A và K. Nó được nối với 2 chân của 1 con Led dùng để sáng LCD trong bóng tối chúng ta
khơng sử dụng.


</div>
<span class='text_page_counter'>(28)</span><div class='page_container' data-page=28>

<b> 2. Nguyên lí hoạt động của LCD. </b>


<b> - Chân V</b>CC, Vss, và VEE: các chân VCC và VSS cáp dương nguồn 5v và mass tương ứng. Chân VEE được dùng để điều


khiển độ tương phản.


- Chân chọn thanh ghi RS(Register Select): có 2 thanh ghi trong LCD chân RS được dùng để chọn thanh ghi. nếu
RS=0 thì thanh ghi mã lệnh được chọn để cho phép người dùng gửi 1 lệnh lên chẳng hạn như xố màn hình, đưa con trỏ
về đầu dịng… Nếu RS=1 thì thanh ghi dữ liệu được chọn cho phép người dùng gửi dữ liệu cần hiển thị lên LCD.


- Chân đọc/ghi (R/W): đầu vào đọc/ghi cho phép người dùng đọc thông tin từ LCD khi R/W=1 hoặc ghi thông tin lên
LCD.


- Chân cho phép E(Enable): chân cho phép được sử dụng bởi LCD để chốt dữ liệu của nó. Khi dữ liệu được cấp đến
chân dữ liệu thì 1 xung mức cao xuống thấp phải được áp đến chân này để LCD chốt dữ liệu trên các chân dữ liệu. Xung


này có độ rộng tối thiểu 450ns.


- Chân DB0-DB7: đây là đường dữ liệu 8 bít, được dùng để gửi thơng tin lên LCD hoặc đọc nội dung các thanh ghi
trong LCD. Để hiển thị các chữ cái và các con số, chúng ta gửi mã ASCII của các chữ cái từ A đến Z , a đến z và các chữ
số từ 0 đến 9 đến các chân này khi bật RS=1.


- Bảng mã lệnh của LCD:


Mã (HEX) Lệnh đến thanh ghi của LCD


01 Xố màn hình hiển thị


02 Trở về đầu dòng


04 Giảm con trỏ(dịch con trỏ sang trái )


06 Tăng con trỏ(dịch con trỏ sang phải)


05 Dịch hiển thị sang phải


07 Dịch hiển thị sang trái


08 Tắt con trỏ, tắt hiển thị


</div>
<span class='text_page_counter'>(29)</span><div class='page_container' data-page=29>

0c Bật hiển thi, tắt con trỏ


0e Bật hiển thị, nhấp nháy con trỏ


0f Tắt con trỏ, nhấp nháy con trỏ



10 Dịch vị trí con trỏ sang trái


14 Dịch vị trí con trỏ sang phải


18 Dịch tồn bộ hiển thị sang trái


1c Dịch toàn bộ hiển thị sang phải


80 Ép con trỏ về đầu dòng thứ nhất


0c0 Ép con trỏ về đầu dòng thứ 2


38 Hai dòng và ma tận 5x7.




<b> 3. Phần luyện tập: </b>


<i>Hãy viết chương trình hiển thị trên LCD: </i>


<i>Dòng 1 chữ “VIETNAM” bằng cách hiển thị tưng kí tự </i>


<i>Dịng 2 chữ "VI DIEU KHIEN" bằng cách hiển thị cả chữ. Với sơ đồ mạch cho dướí đây. </i>


<i>Chương trình: </i>


/*=========bo tien xu li===============*/
#include<AT89x51.h>


#include<string.h>



/*===========khai bao bien toan cuc============*/
sfr LCDdata = 0xA0; // cong P2, 8 bit du lieu.


sbit BF = 0xA7; // co ban, bit DB7.
sbit RS = P3^0; // chon thanh ghi
sbit RW = P3^1; // doc/ghi


sbit EN = P3^2; //cho phep chot du lieu


</div>
<span class='text_page_counter'>(30)</span><div class='page_container' data-page=30>

{


RS=0; //chon thanh ghi lenh
RW=1; //đoc tu LCD
LCDdata=0xff; //gia tri 0xff
while(BF) //kiem tra co ban


{


EN=0; //dua xung cao xuong thap đe chot.
EN=1; //dua chan cho phep len cao


}


}


/*---thiet lap lenh cho LCD---*/
void LCDcontrol(unsigned char x)


{



RS=0;//chon thanh ghi lenh
RW=0;//ghi len LCD.
LCDdata=x ;// gia tri x


EN=1;//cho phep muc cao
EN=0;//xung cao xuong thap
wait();//đoi LCD san sang.


}


/*---Khoi tao LCD---*/
void LCDinit(void)


{


LCDcontrol(0x38);//2 dong va ma tran 5x7
LCDcontrol(0x0e);//bat man hinh, bat con tro
LCDcontrol(0x01);//xoa man hinh


}


/*---thiet lap du lieu cho LCD---*/
void LCDwrite(unsigned char c)


{


RS=1;//ghi du lieu


RW=0;//ghi du lieu len LCD


LCDdata=c;//gia tri C
EN=1;//cho phep muc cao
EN=0;//xung cao xuong thap
wait();//cho


}


void LCDwrites(unsigned char *s)


{


</div>
<span class='text_page_counter'>(31)</span><div class='page_container' data-page=31>

for(count=0;count<lens;count++){
LCDwrite(*(s+count));
}


}


/*=====================chuong trinh tre================*/
void delay(long time)


{


while(time--);
}


/*========================ham chinh==================*/
void main(void)


{



LCDinit(); // khoi tao LCD


LCDcontrol(0x82);// dua con tro den vi tri thu 4 dong 1
LCDwrite(‘V’);


LCDwrite(‘I’);
LCDwrite(‘E’);
LCDwrite(‘T’);
LCDwrite(‘ ’);
LCDwrite(‘N’);
LCDwrite(‘A’);
LCDwrite(‘M’);
LCDcontrol(0xC0);


LCDwrites("VI DIEU KHIEN");
while(1); //vong lap vo han
}


<b>II. Giao tiếp bàn phím Hex (ma trận phím 4x4) </b>
<b>1. Thuật tốn đọc bàn phím </b>


<b>2. Chương trình </b>


<i>Hãy viết chương trình đọc ma trận phím và hiển thi số thứ tự phím trên LCD. </i>


Cột

i

= 0 (i=1-4)



Begin



Hàng

i

= 0




(i =1-4)



Trả lại kết quả phím đã


nhấn



</div>
<span class='text_page_counter'>(32)</span><div class='page_container' data-page=32>

<i>Chương trình: </i>


/*=========bo tien xu li===============*/
#include<AT89x51.h>


#include<string.h>


#define H1 P1_0
#define H2 P1_1
#define H3 P1_2
#define H4 P1_3


/*===========khai bao bien toan cuc============*/
sfr LCDdata = 0xA0; // cong P2, 8 bit du lieu.


sbit BF = 0xA7; // co ban, bit DB7.
sbit RS = P3^0; // chon thanh ghi
sbit RW = P3^1; // doc/ghi


sbit EN = P3^2; //cho phep chot du lieu
#include"LCD.h"// Thu vien LCD tu xay dung


/*--- ham doc phim nhan tu ma tran phim 4x4---*/
unsigned char Phim(void)



{


unsigned char phimnhan, dem, chot;
phimnhan=0;


</div>
<span class='text_page_counter'>(33)</span><div class='page_container' data-page=33>

while(dem--){
P1=~chot;
if(!H1){


delay(500);
phimnhan=dem+1;
delay(500);
}else if(!H2){


delay(500);
phimnhan=dem+5;
delay(500);
}else if(!H3){


delay(500);
phimnhan=dem+9;
delay(500);
}else if(!H4){


delay(500);


phimnhan=dem+13;
delay(500);



}


chot>>=1;
}


return phimnhan;
}


void viewphim(unsigned char phimnhan)
{


if(phimnhan<10){


LCDwrite(phimnhan+48);
}else{


LCDwrite(phimnhan/10+48);
LCDwrite(phimnhan%10+48);
}


}


void main(void)
{


unsigned char phimnhan=0;
LCDinit();


LCDwrites("Hay Nhan Phim");
LCDcontrol(0xC0);



while(1){


</div>
<span class='text_page_counter'>(34)</span><div class='page_container' data-page=34>

LCDcontrol(0x01);


LCDwrites("Hay Nhan Phim");
LCDcontrol(0xC0);


viewphim(phimnhan);
}


}
}


<b>III. Hiển thị ma trận Led </b>
<b>1. Thuật toán </b>


<b>2. Xây dựng chương trình </b>


Bài tốn: Viết chương trình hiển thị ma trận LED bằng phương pháp quét cột hiển thị dong chữ "LAP TRINH VI
DIEU KHIEN BANG NGON NGU C", với dong chữ chạy từ trái sang phải.


+ Chương trình:


// Khai bao chi thi tien xu ly
#include<AT89x51.h>


// Dinh nghia cac cong va cac chan dieu khien
#define CLOCK P3_2



#define DATA P3_3
#define CLEAR P3_4
#define Pxanh P1
#define Pdo P2


</div>
<span class='text_page_counter'>(35)</span><div class='page_container' data-page=35>

#define Nhanh 10
#define Trungbinh 25
#define Cham 50
#define Cuccham 75
#define Sieucham 150
#define Mxanh 1
#define Mdo 2
#define Mcam 3


// Khai bao mang chu hien thi
unsigned char code Mcode[256]={


0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,255,1,1,1,1,/* L */


0,63,72,136,72,63,/* A */
0,255,144,144,144,96,/* P */
0,


0,128,128,255,128,128,/* T */
0,255,144,144,144,111,/* R */
0,129,129,255,129,129,/* I */
0,255,96,24,6,255,/* N */
0,255,16,16,16,255,/* H */
0,



0,252,2,3,2,252,/* V */
0,129,129,255,129,129,/* I */
0,


0,255,129,129,129,126,/* D */
0,129,129,255,129,129,/* I */
0,255,145,145,145,129,/* E */
0,254,1,1,1,254,/* U */
0,


0,255,24,36,66,129,/* K */
0,255,16,16,16,255,/* H */
0,129,129,255,129,129,/* I */
0,255,145,145,145,129,/* E */
0,255,96,24,6,255,/* N */
0,


0,255,145,145,145,110,/* B */
0,63,72,136,72,63,/* A */
0,255,96,24,6,255,/* N */
0,126,129,129,137,78,/* G */
0,


</div>
<span class='text_page_counter'>(36)</span><div class='page_container' data-page=36>

0,126,129,129,137,78,/* G */
0,126,129,129,129,126,/* O */
0,255,96,24,6,255,/* N */
0,


0,255,96,24,6,255,/* N */


0,126,129,129,137,78,/* G */
0,254,1,1,1,254,/* U */
0,


0,126,129,129,129,70,/* C */


0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0


};


// Khai bao bien toan cuc


unsigned char data Start,End,Tocdolap,i,j,k;
unsigned char data Mdata1[32],Mdata2[32],Mau;
unsigned char data Dk1,Dk2,Dk3,Dk4,Dk5;


// Khai bao nguyen mau cac ham
void delay(unsigned long time);


unsigned char Mu2(unsigned char somu);


void Do(unsigned char chiso);
void Xanh(unsigned char chiso);
void Cam(unsigned char chiso);
void Dobyte(unsigned char chiso);
void Xanhbyte(unsigned char chiso);
void Cambyte(unsigned char chiso);


void Chaychudo(void);
void Chaychuxanh(void);


void Chaychucam(void);
void Chaychu(void);


void Taomangnhapnhay(void);
void Nhapnhayxanh(void);
void Nhapnhaycam(void);
void Nhapnhaydo(void);


</div>
<span class='text_page_counter'>(37)</span><div class='page_container' data-page=37>

void Lcam(void);
void Len(void);


/******************Ma nguon cac ham*************************/
// Ham tao tre


void delay(unsigned long time)
{


while(time--);
}


// Khoi ham hien thi chu chay tu trai sang phai
void Xanh(unsigned char chiso)


{


CLOCK=1;
DATA=0;
CLOCK=0;


Pxanh=Mcode[chiso];


delay(12);


Pxanh=0;
}


void Do(unsigned char chiso)
{


CLOCK=1;
DATA=0;
CLOCK=0;


Pdo=Mcode[chiso];
delay(12);


Pdo=0;
}


void Cam(unsigned char chiso)
{


CLOCK=1;
DATA=0;
CLOCK=0;


Pxanh=Mcode[chiso];
Pdo=Pxanh;


</div>
<span class='text_page_counter'>(38)</span><div class='page_container' data-page=38>

void Chaychucam(void)
{



for(i=Start+1;i<Dk1;i++)
{


Tocdolap=Nhanh;
while(Tocdolap--)
{


DATA=1;
Dk2=i+32;


for(j=i;j<Dk2;j++)Cam(j);
}


}
}


void Chaychuxanh(void)
{


for(i=Start+1;i<Dk1;i++)
{


Tocdolap=Nhanh;
while(Tocdolap--)
{


DATA=1;
Dk2=i+32;



for(j=i;j<Dk2;j++)Xanh(j);
}


}
}


void Chaychudo(void)
{


for(i=Start+1;i<Dk1;i++)
{


Tocdolap=Nhanh;
while(Tocdolap--)
{


DATA=1;
Dk2=i+32;


for(j=i;j<Dk2;j++)Do(j);
}


}
}


</div>
<span class='text_page_counter'>(39)</span><div class='page_container' data-page=39>

{


Dk1=End-31;



if(Mau==Mxanh)Chaychuxanh();
else if(Mau==Mdo)Chaychudo();
else Chaychucam();


}


// Khoi ham hien thi chu nhap nhay tai cho
void Cambyte(unsigned char chiso)
{


CLOCK=1;
DATA=0;
CLOCK=0;


Pxanh=Mdata2[chiso];
Pdo=Pxanh;


delay(12);
Pdo=0;
Pxanh=0;
}


void Dobyte(unsigned char chiso)
{


CLOCK=1;
DATA=0;
CLOCK=0;



Pdo=Mdata2[chiso];
delay(12);


Pdo=0;
}




void Xanhbyte(unsigned char chiso)
{


CLOCK=1;
DATA=0;
CLOCK=0;


Pxanh=Mdata2[chiso];
delay(12);


</div>
<span class='text_page_counter'>(40)</span><div class='page_container' data-page=40>

void Nhapnhaydo(void)
{


while(Tocdolap--){
DATA=1;


for(k=0;k<32;k++)Dobyte(k);
}


}


void Nhapnhayxanh(void)


{


while(Tocdolap--){
DATA=1;


for(k=0;k<32;k++)Xanhbyte(k);
}


}


void Nhapnhaycam(void)
{


while(Tocdolap--){
DATA=1;


for(k=0;k<32;k++)Cambyte(k);
}


}


void Taomangnhapnhay(void)
{


for(i=0;i<32;i++)
Mdata2[i]=0;


Dk4=End-Start;
Dk5=(32-Dk4)/2;
Dk4=32-Dk5;



for(i=Dk5;i<Dk4;i++)


Mdata2[i]=Mcode[Start+i-Dk5];
}


void Nhapnhay(void)
{


unsigned char demnhay;
demnhay=10;


</div>
<span class='text_page_counter'>(41)</span><div class='page_container' data-page=41>

Tocdolap=Nhanh;


if(Mau==Mxanh)Nhapnhayxanh();
else if(Mau==Mdo)Nhapnhaydo();
else Nhapnhaycam();


CLEAR=0;
delay(1250);
CLEAR=1;
}


}


// Khoi ham hien thi chu di tu duoi len
unsigned char Mu2(unsigned char somu)
{


if(!somu) return 1;



else return 2*Mu2(somu-1);
}


void Taomanglen(void)
{


for(i=0;i<32;i++)
Mdata2[i]=0;


Dk4=End-Start;
Dk5=(32-Dk4)/2;
Dk4=32-Dk5;


for(i=Dk5;i<Dk4;i++)


Mdata1[i]=Mcode[Start+i-Dk5];
i=8;


}


void Lcam(void)
{


unsigned char data dem;
Tocdolap=Trungbinh;
while(Tocdolap--)
{


DATA=1;



for(dem=0;dem<32;dem++)


{


CLOCK=1;
DATA=0;
CLOCK=0;


</div>
<span class='text_page_counter'>(42)</span><div class='page_container' data-page=42>

Pdo=Pxanh;
delay(12);
Pxanh=0;
Pdo=0;
}


}
}


void Ldo(void)
{


unsigned char data dem;
Tocdolap=Trungbinh;
while(Tocdolap--)
{


DATA=1;


for(dem=0;dem<32;dem++)



{


CLOCK=1;
DATA=0;
CLOCK=0;


Pdo=Mdata2[dem];
delay(12);


Pdo=0;
}


}
}


void Lxanh(void)
{


unsigned char data dem;
Tocdolap=Trungbinh;
while(Tocdolap--)
{


DATA=1;


for(dem=0;dem<32;dem++)


{


CLOCK=1;


DATA=0;
CLOCK=0;


Pxanh=Mdata2[dem];
delay(12);


</div>
<span class='text_page_counter'>(43)</span><div class='page_container' data-page=43>

}
}


}


void Len(void)
{


Taomanglen();
while(i--)
{


for(j=Dk5;j<Dk4;j++)


Mdata2[j]= Mdata1[j]/Mu2(i);
if(Mau==Mxanh)Lxanh();


else if(Mau==Mdo)Ldo();
else Lcam();


}


for(i=0;i<7;i++)


{


for(j=Dk5;j<Dk4;j++)


Mdata2[j]= Mdata2[j]*2;
if(Mau==Mxanh)Lxanh();
else if(Mau==Mdo)Ldo();
else Lcam();


}
}


/*Ham chinh*/
void main(void)
{


TMOD=0x01;
Pxanh=0;
Pdo=0;
P3=16;



while(1)


{


Start=0;End=194;Mau=3;
Chaychu();


Start=0;End=17;Mau=1;


Len();


</div>
<span class='text_page_counter'>(44)</span><div class='page_container' data-page=44>

Len();


Start=50;End=61;Mau=1;
Len();


Start=63;End=87;Mau=1;
Len();


Start=89;End=118;Mau=1;
Len();


Start=120;End=143;Mau=1;
Len();


Start=145;End=168;Mau=1;
Len();


Start=170;End=187;Mau=1;
Len();


Start=189;End=194;Mau=1;
Len();


Start=0;End=17;Mau=2;
Nhapnhay();


Start=19;End=48;Mau=2;
Nhapnhay();



Start=50;End=61;Mau=2;
Nhapnhay();


Start=63;End=87;Mau=2;
Nhapnhay();


Start=89;End=118;Mau=2;
Nhapnhay();


Start=120;End=143;Mau=2;
Nhapnhay();


Start=145;End=168;Mau=2;
Nhapnhay();


Start=170;End=187;Mau=2;
Nhapnhay();


Start=189;End=194;Mau=2;
Nhapnhay();


}


</div>
<span class='text_page_counter'>(45)</span><div class='page_container' data-page=45>

<i><b>Bài 5: Giao tiếp ADC - Xử lý ngắt </b></i>
<i><b>I. Giao tiếp ADC </b></i>


+Chương trình:
#include<regx51.h>
#include<string.h>



/*===========khai bao bien toan cuc============*/
sfr LCDdata = 0xA0; // cong P2, 8 bit du lieu.


sbit BF = 0xA7; // co ban, bit DB7.
sbit RS = 0xb0; // chon thanh ghi
sbit RW = 0xb1; // doc/ghi


sbit EN = 0xb2; //cho phep chot du lieu
#include"Lcd.h"// Thu vien LCD tu xay dung
#define RD P3_3


#define WR P3_4
#define INTR P3_5


/*--- Ham tre ---*/
void delay(long time)


{


while(time--);
}


</div>
<span class='text_page_counter'>(46)</span><div class='page_container' data-page=46>

void view(unsigned char val)
{


unsigned char var;
if(val<10){


LCDwrite(val+48);


}else if(val<100){


LCDwrite(val/10+48);
LCDwrite(val%10+48);
}else{


var=val/10;


LCDwrite(var/10+48);
LCDwrite(var%10+48);
LCDwrite(val%10+48);
}


}


void main(void)
{


unsigned char ADCval=0;
RD=0;


LCDinit();


LCDcontrol(0x83);
LCDwrites("ADC0804");
while(1){


WR=1;
WR=0;
while(!INTR);


ADCval=P1;
LCDcontrol(0x01);
LCDcontrol(0x83);
LCDwrites("ADC0804");
LCDcontrol(0xC0);
view(ADCval);
delay(5000);
}


}


<i><b>II. Lập trình xử lý ngắt </b></i>
<i><b>1. Ngắt timer/counter. </b></i>


<i><b> 1.1. cơ chế tạo trễ của timer và cách tính tốn giá trị nạp vào timer. </b></i>
<i><b> a. chế độ 1: </b></i>


- ở chế độ 1 đó là bộ định thời 16 bit, do đó các giá trị trong khoảng từ 0000 đến FFFF có thể sử dụng để nạp cho
TH và TL của bộ định thời.


</div>
<span class='text_page_counter'>(47)</span><div class='page_container' data-page=47>

là FFFF. Khi đó bộ định thời sẽ quay vong từ FFFF về 0000 và bật cờ báo tràn TF0 với timer0 và TF1 với timer1(ban dầu
TFx=0) khi đó cần phải có thao tác để xố cờ để lần sau cịn biết được khi nào bộ đếm tràn.


- khi bộ đếm tràn thì TH và Tl của bộ định thời sẽ mang giá trị 0 do đó phải có thao tác nạp lại giá trị ban đầu cho
chúng và xoá cờ TF để bộ đếm được lặp lại.


- Như vậy khoảng thời gian mà bộ định thời tạo trễ chính là khoangre thời gian nó đếm tăng từ giá trị ban đầu
được nạp cho tới giá trị đỉnh FFFF.


- tính toán giá trị nạp vào thanh ghi chứa của bộ định thời từ thời gian muốn tạo trễ(t): gọi N = 65536 – t/chu ki


máy. Sau khi chuyển sang mã HEX được 1 số có 4 chữ số có dạng: x1x2y1y2. khi đó giá trị nạp cho thanh ghi chứa như
sau: TH = x1x2, TL = y1y2.


Ví dụ: muốn tạo trễ 500us thì:


Giả sử chu kì máy là 1us: có N = 65536 – 500/1 = 65036. chuyển sang mã HEX là FE0C, từ đó: TH = 0xFE, TL =
0x0C.


- các bước lập trình cho bộ định thời để tạo trễ ở chế độ 1:


+B1: chọn chế độ 1 cho bộ định thời cần dung, từ đó xác định giá trị nạp cho thanh ghi TMOD.
+ B2: tính tốn giá trị ban đầu cần nạp cho TH và TL từ thời gian trễ mong muốn.


+ B3: khởi động bộ định thời.


+ B4: kiểm tra trạng thái bật của cờ TF.
+ B5:dung bộ định thời.


+ B6: xố cờ TF cho vịng lặp kế tiếp.


+ B7: quay trở về B2 để nạp lại giá trị cho TH và TL.
<b> b. Chế độ 2: </b>


- Ở chế độ này bộ định thời là 8 bit, do vậy chỉ cho phép các giá trị từ 00 đến FF được nạp vào thanh ghi TH của
bộ định thời. sau khi nạp giá trị 8 bit thì vi điều khiển sẽ sao nội dung của TH sang TL và bộ định thời được khởi động
bằng lệnh TRx=1.


- Sau khi được khởi động thì bộ định thời bắt đầu đếm tăng trong thanh ghi TL từ giá trị ban đầu đến giá trị đỉnh
FF. và khi quay vòng từ FF về 00 thì cờ TFx được bật lên 1, khi này thanh ghi TL mang giá trị 0 nhưng TL sẽ ngay lập
tức được tự động nạp lại với giá trị ban đầu được lưu trong thanh ghi TH.



- như vậy trong chế độ này mỗi khi bộ đếm tràn thì thanh ghi chứa sẽ được vi điều khiển nạp lại giá trị ban đầu,
do đó chế độ này được gọi là chế độ tự động nạp lại.


- tính giá trị nạp vào thanh ghi chứa của bộ định thời từ thời gian trễ (t):


Gọi N = 256 – t/chu kì máy. Sau khi chuyển sang mã HEX được 1 số, ta nạp số này vào thanh ghi TH và cả
TL(nạp vào TL giá trị đếm lần 1 và nạp vào TH cho những lần sau để khi bộ đếm tràn thì phần cứng của vi điều khiển sẽ
tự động sao TH sang TL).


Ví dụ: tạo trễ 50usthì là:


Giả sử chu kì máy là 1us: có N = 256 – 50/1 = 205, chuyển sang mã HEX : 0CE
Từ đó: TH = 0xCE và TL = 0xCE.


- các bước lập trình cho bộ định thời để tạo trễ ở chế độ 2.


+ B1: nạp giá trị cho thanh ghi thiết lập chế độ TMOD với timer muốn sử dụng.
+ B2: nạp vào TH giá trị đém ban đầu.


+B3: khởi động bộ định thời.
+ B4: kiểm tra cờ báo tràn TFx.
+ B5: xoá cờ tràn TFx, quay về B4.


* lưu ý: 2 chế độ khác của bộ định thời là chế độ 0(chế độ bộ định thời 13 bit, bộ định thời/bộ đếm 8 bit, định tỷ lệ
trước 5 bit ) và chế độ 3(chế độ bộ định thời chia tách) ở đay không giới thiệu.


<b> 1.2. Ngắt của bộ định thời. </b>


<b> - nguyên tắc sử dụng bộ định thời ở chế độ ngắt: </b>


+ khai báo ngắt của bộ định thời muốn sử dụng
+ nguồn gây ngắt.


+ chương trình chính và chương trình phục vụ ngắt.


- với ngắt định thời việc khai báo nguồn ngắt bao gồm việc khai báo ngắt toàn cục là EA = 1 và khai báo ngắt cho
từng bộ định thời muốn dùng ET0 = 1(timer0) và ET1 = 1(timer1)


</div>
<span class='text_page_counter'>(48)</span><div class='page_container' data-page=48>

trình phục vụ ngắt.khi thực hiện xong chương trình phục vụ ngắt vi điều khiển quay trở về chương trình tại nơi bị gián
đoạn khi trước.


- Tóm lại ngắt định thời là việc ta sử dụng bộ định thời tạo trễ một khoảng thời gian được tính tốn trước, sau khoảng
thời gian này 1 công việc ta mong muốn sẽ được thực hiện ở chương trình phục vụ ngắt. cơng việc đó có thể coi là độc lập
với cơng việc ở chương trình chính


- các cơng việc lập trình sử dung ngắt định thời :


+ tính tốn thời gian trễ mong muốn và cơng việc muốn thực hiện sau khoảng thời gian đó.
+ khai báo ngắt định thời trong chương trình chính (EA=1, ETX=1).


+ lựa chon bộ định thời và chế độ của nó trong thanh ghi TMOD
+ khởi động bộ định thời.


+ Xây dựng chương trình chính và các chương trình con cần thiết.


+ xây dựng chương trình phục vụ ngắt thực hiện 1 công việc mong muốn (xác định rõ địa chỉ ngắt theo thứ tự
ngắt trong bảng vector ngắt)


- Chú ý: trong chương trình phục vụ ngắt các bạn phải xoá cờ báo tràn TFx và nạp lại giá trị cho bộ định thời với chế
độ 1 còn chế độ 2 thì khơng cần.



<b> 1.3. bài toán: </b>


<i><b> Bài toán 1: sử dụng bộ định thời với ngắt của nó tạo một xung vuông với tần số 1kHZ đối xứng (50% mức 1 và 50% </b></i>
<i>mức 0 ) trên chân P1.0. </i>


<i>Bài giải: </i>


- ta có : f = 1kHZ → T = 1/1000s = 1000us → TON = TOFF = T/2 = 500us. Như vậy chu kì xung là đối xứng nên hai phần


này bộ đếm đếm giống nhau(tạo trễ khoảng thời gian bằng nhau). nửa chu kì đầu bộ đếm tạo trễ 500us cho mức 0, sau khi
bộ đếm đếm đến giá trị đỉnh của thanh ghi chứa là FFFF thì cờ báo TFx = 1 gây ngắt, vi điều khiển phải chuyển vào
chương trình phục vụ ngắt và sẽ lật trạng thái xung ra. Trong nửa chu kì cịn lại cũng như vậy và cứ như thế.


- Do thời gian trễ là 500us do đó ta chọn chế độ 16 bit, sử dụng kết quả từ ví dụ trên để nạp giá trị ban đầu cho TH và
TL.


- Chương trình điều khiển:


/*================khai bao thu vien===============*/
#include<AT89x51.h>


/*=============khai bao bien=====================*/
sbit xung = P1^0;


/*==============khai bao ham ==================*/


/*---chuong trinh phuc vu ngat timer0 tao xung---*/
void timer0_int(void) interrupt 1



{


TF0=0; // xoa co bao tran timer0
xung = !xung; // tao muc 1 ra chan P1.0


TH0 = 0xfe; // (65536-500)↔hex =0fe0c (thach anh 12MHz)
TL0 = 0x0c;


}


/*=============chuong trinh chinh=============*/
void main(void)


{


EA = 1; // cho phep ngat toan cuc
ET0 = 1; // cho phep ngat T0
TMOD = 0x01; // timer0 che do 1


xung = 0; //gia tri ban dau cua xung muon tao


TH0 = 0xfe; // (65536-500)↔hex =0fe0c (thach anh 12MHz)
TL0 = 0x0c;


TR0 = 1; // khoi dong timer


while(1) PCON|=1; //khong lam gi ca de doi ngat.
}


</div>
<span class='text_page_counter'>(49)</span><div class='page_container' data-page=49>

<b>+ Chương trình: </b>



/*================khai bao thu vien===============*/


#include<regx51.h>
#include<string.h>


#define LCDdata P2
sbit RS=P3^0;
sbit RW=P3^1;
sbit EN=P3^2;
sbit BF=LCDdata^7;
#include"lcd.h"


/*=============khai bao bien=====================*/
unsigned char data Time[8];


unsigned char data i;


/*==============khai bao ham ==================*/
void T10ms(void) interrupt 1 using 0


{


TR0=0;
TH0=0xD8;
TL0=0xEF;
TR0=1;


if(Time[0]==9){
Time[0]=0;


if(Time[1]==9){


Time[1]=0;
if(Time[2]==9){


Time[2]=0;
if(Time[3]==5){


Time[3]=0;
if(Time[4]==9){


Time[4]=0;
if(Time[5]==5){


</div>
<span class='text_page_counter'>(50)</span><div class='page_container' data-page=50>

if(Time[6]==9&&Time[7]<2){
Time[6]=0;
Time[7]++;
}else if(Time[6]==3&&Time[7]==2){
Time[6]=0;
Time[7]=0;
}else Time[6]++;
}else Time[5]++;
}else Time[4]++;
}else Time[3]++;
}else Time[2]++;
}else Time[1]++;
}else Time[0]++;
LCDwrite(Time[7]+48);LCDwrite(Time[6]+48);LCDwrite(':');
LCDwrite(Time[5]+48);LCDwrite(Time[4]+48);LCDwrite(':');
LCDwrite(Time[3]+48);LCDwrite(Time[2]+48);LCDwrite(':');


LCDwrite(Time[1]+48);LCDwrite(Time[0]+48);
LCDcontrol(0xC0);
}


/*==============Chuong trinh chinh ==================*/
void main()
{
TMOD|=1;
EA=1;
ET0=1;
TH0=0xD8;
TL0=0xEF;
for(i=0;i<8;i++)Time[i]=0;
LCDinit();


LCDwrites("Dong ho so");
LCDcontrol(0xC0);
TR0=1;


while(1)PCON|=1;
}


<b> 2. Lập trình với các ngắt ngoài của vi điều khiển. </b>
<b> 2.1. Khái niệm: </b>


- bộ vi điều khiển 8051có hai ngắt ngồi là INT0 và INT1 với 2 chân tác động đầu vào tương ứng là P3.2 và P3.3.
- Ngắt ngoài là ngắt của vi điều khiển mà tác động ngắt ở đây chính là các tác động bên ngoài của vi điều khiển tác
động vào vi điều khiển thong qua các chân ngắt đưới dạng một tín hiệu điện áp dạng xung.


- tác động ngắt ngồi có hai dạng là tác động theo dạng mức và dạng sườn.



+ kích hoạt theo mức: ở chế độ này các chân INT0 và INT1 bình thường ở mức cao giống như các chân khác của
vi điều khiển, khi có tín hiệu mức thấp cấp tới thì tín hiệu này kích hoạt ngắt. lưu ý là trước khi thực hiện lệnh cuối cùng
của chương trình phục vụ ngắt thì mức thấp tại các chân ngắt phải được chuyển lên mức cao, nếu không sẽ lại gây ra một
ngắt ngay lập tức.


+ Kích hoạt theo sườn: bình thường các chân ngắt của vi điều khiển ở mức cao, khi có tín hiệu tác động vào
chúng có dạng sườn xuống thì sẽ tác động ngắt.


- Để sử dụng chế độ ngắt này thì phải tác động vào thanh ghi TCON cụ thể là TCON.1=1 hoặc IT0=1 thì cho phép
ngắt ngồi 0 kích hoạt sườn, cịn TCON.2=1 hoặc IT1=1 thì cho phép ngắt ngồi 1 kích hoạt sườn.


<b> 2.2. cách lập trình: </b>


- Để lập trình cho ngắt của vi điều khiển ta phải thực sự hiệu bản chất của ngắt và quá trình thực hiện ngắt của vi điều
khiển diễn ra.


- mẫu viết hàm ngắt như sau:


</div>
<span class='text_page_counter'>(51)</span><div class='page_container' data-page=51>

{


//chương trình phục vụ ngắt
}


- Trong chương trình chính ta phải có thao tác thiết lập việc cho phép các ngắt được sử dụng.
<b> 2.3. bài tốn: </b>


<i>sử dụng ngắt ngồi của vi điều khiển với nhiệm vụ là: bình thường vi điều khiển bật một Led đơn tại chân P1.0 và </i>
<i>khi có ngắt ngồi thì tắt Led ở P1.0 và bật Led ở chân P1.1 sau 1s thì bật lại Led P1.0 và tắt Led P1.1. </i>



<i>Bài giải: </i>


/*==================Bo tien xu li===================*/
#include<AT89x51.h> // Dinh kem file thu vien


#define bat 1 // Dinh nghia gia tri bat den Led
#define tat 0 // Dinh nghia gia tri tat den Led


/*==================khai bao bien==================*/
sbit Led1 = P1^0; // Khai bao bi?n Led ki?u bit chan P1.0


sbit Led2 = P1^1; // Khai bao bi?n Led ki?u bit chan P1.0


/*================= Khai bao hàm==================*/
/*---ham tre ---*/
void delay(long time)


{


while(time--);
}


void INT_0(void) interrupt 0 // chuong trinh phuc vu ngat
{


</div>
<span class='text_page_counter'>(52)</span><div class='page_container' data-page=52>

}


/*---ham chinh---*/
void main(void)



{


EA=1; // cho phep ngat toan cuc
EX0=1; // cho phep ngat ngoai 0
IT0=1; //ngat kich phat suon
Led1=bat;


</div>
<span class='text_page_counter'>(53)</span><div class='page_container' data-page=53>

<i><b>Bài 6: Điều khiển động cơ DC, động cơ Servo, động cơ bước </b></i>
<i><b>1. Đông cơ DC </b></i>


<i><b>2. Động cơ Servo </b></i>


<i><b>3. Động cơ bước (Step motor) </b></i>


Điều khiển động cơ bước với tốc độ tăng dần từ 5 đến 100 v/p, mỗi lần chuyển tốc độ tăng 5v/p thời gian chuyển
1s, hiển thị tốc độ trên LCD.


+ Chương trình:
#include<regx51.h>
#include<string.h>


#define LCDdata P2
sbit RS=P3^0;
sbit RW=P3^1;
sbit EN=P3^2;
sbit BF=LCDdata^7;
#include"lcd.h"


unsigned char data Bytecao1,Bytethap1;


unsigned char data Buoc,Nbuoc;


unsigned char data Mbuoc[4]={144,192,96,48};


void viewspeed(unsigned char speed);
void Xuly(unsigned char Nspeed);


</div>
<span class='text_page_counter'>(54)</span><div class='page_container' data-page=54>

{


TR0=0;


TH0=Bytecao1;
TL0=Bytethap1;
TR0=1;


P1=Mbuoc[Buoc];
Buoc++;


if(Buoc==4)Buoc=0;
}




void Xuly(unsigned char speed)
{


unsigned int data Chuki1,Chuki2;
unsigned int data tam1,tam2;



TR0=0;


viewspeed(speed);
Nbuoc=200;


tam2=10000/Nbuoc;
tam1=6000/speed;
Chuki1=tam1*tam2;
Chuki2=65535-Chuki1;
Bytecao1=Chuki2/256;
Bytethap1=Chuki2%256;
TR0=1;


}


void delay(unsigned long time)
{


while(time--);
}


void viewspeed(unsigned char speed)
{


</div>
<span class='text_page_counter'>(55)</span><div class='page_container' data-page=55>

LCDwrites("(vong/phut)");
}



void main()



{


unsigned char data i;
TMOD=17;


EA=1;
LCDinit();
ET0=1;


LCDcontrol(0x80);


LCDwrites("CT DK DC buoc" );
LCDcontrol(0xc0);


LCDwrites("V:5-100(v/p)");
delay(100000);


while(1){
Buoc=2;


for(i=5;i<101;i=i+5){
LCDcontrol(0x01);
LCDcontrol(0x80);


LCDwrites("CT DK DC buoc" );
Xuly(i);


delay(500000);
}



}


</div>
<span class='text_page_counter'>(56)</span><div class='page_container' data-page=56>

<b>Bài 7: Giao tiếp Vi điều khiển với Máy tính </b>
<b>I. Cổng truyền thông nối tiếp </b>


<b>1. Thanh ghi SCON – SBUF </b>
<b>II. Xây dựng chương trình </b>
<i><b>1. Chương trình VB </b></i>


+ Giao diện


+ Thuật tốn
+ Chương trình:


Option Explicit
Dim Mau As Byte


Private Sub cbcolor_Click()


If (cbcolor.Text = "Mau do") Then
Mau = 1


txtchu.ForeColor = &HFF&
lbHienthi.ForeColor = &HFF&
ElseIf (cbcolor.Text = "Mau xanh") Then
Mau = 2


txtchu.ForeColor = vbGreen
lbHienthi.ForeColor = &HFF00&


ElseIf (cbcolor.Text = "Mau cam") Then
Mau = 3


txtchu.ForeColor = &H80FF&
lbHienthi.ForeColor = &H80FF&
End If


End Sub


</div>
<span class='text_page_counter'>(57)</span><div class='page_container' data-page=57>

SendKeys "%{DOWN}"
End Sub


Private Sub cmdCode_Click()
MsgBox Code(txtchu)
End Sub


Private Sub cmdExit_Click()
If MSComm1.PortOpen Then
MSComm1.PortOpen = False
End If


End


End Sub


Function Code(s As String) As String
Dim i As Integer


s = Replace(s, " ", "")
For i = 1 To Len(s)



Code = Code & " " & Asc(Mid(s, i, 1))
Next




End Function


Private Sub OpenPort()
Dim s As String


MSComm1.Settings = "57600,N,8,1"
MSComm1.CommPort = 1


MSComm1.PortOpen = True
MSComm1.InputLen = 0
s = MSComm1.Input
MsgBox "Port did open"
End Sub


Private Sub cmdOpenport_Click()
If MSComm1.PortOpen Then
MSComm1.PortOpen = False
End If


OpenPort


End Sub



</div>
<span class='text_page_counter'>(58)</span><div class='page_container' data-page=58>

Dim s As String


If MSComm1.PortOpen = False Then
MsgBox "Port did not open"
OpenPort


End If


If MSComm1.PortOpen Then
txtchu.Text = UCase(txtchu.Text)


s = Chr(Mau) & Chr(Len(txtchu.Text)) & txtchu.Text & Chr(255)
Do While (MSComm1.OutBufferCount > 0)


Loop


MSComm1.Output = s
End If



End Sub


Private Sub cmdStop_Click()
MSComm1.Output = Chr(250)
MsgBox "Port Stoped"


End Sub


Private Sub Form_Load()



txtchu.ForeColor = vbRed


txtchu.Text = "DO AN GHEP NOI"
Mau = 1



End Sub


Private Sub Form_Resize()
If (Me.WindowState = 1) Then
Me.Height = 4000


Me.Width = 7230
End If


End Sub


Private Sub txtchu_GotFocus()
txtchu.SelStart = 0


</div>
<span class='text_page_counter'>(59)</span><div class='page_container' data-page=59>

2. Chương trình vi điều khiển
+ Thuật tốn


+ Chương trình:


/************Khai bao tien xy ly***************/
#include<regx51.h>


/*********Dinh nghia hang so mau**********/


#define Mdo 1


#define Mxanh 2
#define Mcam 3


/*****Khai bao mang ki tu gom chu so va chu cai****/
unsigned char code Mchar[36][7]={


48,0,126,129,129,129,126,/*0*/
49,0,0,33,65,255,1,/*1*/
50,0,99,135,137,145,97,/* 2 */
51,0,66,129,145,145,110,/* 3 */
52,0,24,40,72,255,8,/* 4 */
53,0,226,145,145,145,142,/* 5 */
54,0,118,137,137,137,70,/* 6 */
55,0,128,135,136,144,224,/* 7 */
56,0,110,145,145,145,110,/* 8 */
57,0,102,145,145,145,110,/* 9 */
65,0,63,72,136,72,63,/* A */
66,0,255,145,145,145,110,/* B */
67,0,126,129,129,129,70,/* C */
68,0,255,129,129,129,126,/* D */
69,0,255,145,145,145,129,/* E */
70,0,255,144,144,144,128,/* F */
71,0,126,129,129,137,78,/* G */
72,0,255,16,16,16,255,/* H */
73,0,129,129,255,129,129,/* I */
74,0,2,129,130,252,128,/* J */
75,0,255,24,36,66,129,/* K */
76,0,255,1,1,1,1,/* L */



</div>
<span class='text_page_counter'>(60)</span><div class='page_container' data-page=60>

84,0,128,128,255,128,128,/* T */
85,0,254,1,1,1,254,/* U */
86,0,252,2,3,2,252,/* V */
87,0,255,12,3,12,255,/* W */
88,0,199,40,16,40,199,/* X */
89,0,224,16,15,16,224,/* Y */
90,0,131,133,153,161,193/* Z */
};


/*******Dinh nghia cac chan va cac cong dieu khien*****/
sfr Pxanh=0x90;


sfr Pdo=0xA0;


sbit Clear=P3^4;
sbit Data=P3^3;
sbit Clock=P3^2;


/**************Khai bao bien toan cuc*************/
unsigned char data Ktnhan,nhanmau,j,i,Maxc,Count,nLap;
unsigned char data Mau,Chay,tam,dem;


unsigned char data MC[76],MQ[32];
/**********Khoi ham chuong trinh**********/
// Ham ngat noi tiep


void Ngatnoitiep(void) interrupt 4 using 0
{



if(RI){
RI=0;
tam=SBUF;
if(tam==250){


Chay=1;i=j=77;dem=8;
Count=0;


Clear=0;
}else{


if(nhanmau){
Mau=tam;


Chay=1;i=j=77;dem=8;
Count=nhanmau=0;
P1=P2=0;


Clear=0;
}else if(tam==255){


Clear=1;
Chay=0;


</div>
<span class='text_page_counter'>(61)</span><div class='page_container' data-page=61>

}else{


if(Ktnhan){


Maxc=tam;
Ktnhan=0;



}else if(Count<76&&Count<Maxc){
MC[Count]=tam;


Count++;
}


}
}


}
}


void Khoitao(void)
{


PCON|=128;
EA=1;
ES=1;
SM0=0;
SM1=1;


Ktnhan=nhanmau=1;
Chay=1;


P0=P1=P2=0;
P3_0=1;
nLap=1;
}



// Ham tao tre
void delay(void)
{


unsigned char data i;
i=10;


while(i--);
}


// Ham hien thi mau cam
void Cam(void)


{


while(nLap--)
{


Data=1;


</div>
<span class='text_page_counter'>(62)</span><div class='page_container' data-page=62>

Clock=0;


Pdo=Pxanh=MQ[j];
delay();


Pxanh=Pdo=0;
}


}



}


// Ham hien thi mau xanh
void Xanh(void)


{


while(nLap--)
{


Data=1;


for(j=0;j<32;j++){
Clock=1;
Data=0;
Clock=0;
Pxanh=MQ[j];
delay();
Pxanh=0;
}


}


}


// Ham hien thi mau do
void Do(void)


{



while(nLap--)
{


Data=1;


for(j=0;j<32;j++){
Clock=1;
Data=0;
Clock=0;
Pdo=MQ[j];
delay();
Pdo=0;
}


</div>
<span class='text_page_counter'>(63)</span><div class='page_container' data-page=63>

// Ham thay doi mang hien thi
void change(void)


{


MQ[0]=MQ[1];MQ[1]=MQ[2];MQ[2]=MQ[3];MQ[3]=MQ[4];
MQ[4]=MQ[5];MQ[5]=MQ[6];MQ[6]=MQ[7];MQ[7]=MQ[8];
MQ[8]=MQ[9];MQ[9]=MQ[10];MQ[10]=MQ[11];MQ[11]=MQ[12];
MQ[12]=MQ[13];MQ[13]=MQ[14];MQ[14]=MQ[15];MQ[15]=MQ[16];
MQ[16]=MQ[17];MQ[17]=MQ[18];MQ[18]=MQ[19];MQ[19]=MQ[20];
MQ[20]=MQ[21];MQ[21]=MQ[22];MQ[22]=MQ[23];MQ[23]=MQ[24];
MQ[24]=MQ[25];MQ[25]=MQ[26];MQ[26]=MQ[27];MQ[27]=MQ[28];
MQ[28]=MQ[29];MQ[29]=MQ[30];MQ[30]=MQ[31];


}



// Ham tim vitri ki tu hien thi trong bang chu cai va chu so
unsigned char Chiso(unsigned char chr)


{


unsigned char data End,Start,Mid,Mctam;
if(chr==Mchar[0][0]){


return 0;


}else if(chr==Mchar[35][0]){
return 35;


}else{


End=35;
Start=0;
while(1){


Mid=(End+Start)/2;
Mctam=Mchar[Mid][0];
if(chr==Mctam){


return Mid;
}else if(chr<Mctam){


End=Mid;
}else{


Start=Mid;


}


}
}


}


void Chaychu(void)
{


unsigned char vitri;


</div>
<span class='text_page_counter'>(64)</span><div class='page_container' data-page=64>

MQ[j]=0;
}


for(i=0;i<Count;i++)
{


if(MC[i]==32){
change();
MQ[31]=0;


if(Mau==Mxanh)Xanh();
else if(Mau==Mdo)Do();
else Cam();


change();
MQ[31]=0;


if(Mau==Mxanh)Xanh();


else if(Mau==Mdo)Do();
else Cam();


}else{


vitri=Chiso(MC[i]);


for(dem=1;dem<7;dem++){
change();


MQ[31]=Mchar[vitri][dem];
if(Mau==Mxanh)Xanh();
else if(Mau==Mdo)Do();
else Cam();


}
}


}


if(!Chay){


for(i=0;i<32;i++){
change();
MQ[31]=0;


if(Mau==Mxanh)Xanh();
else if(Mau==Mdo)Do();
else Cam();



}
}


}


// Chuong trinh chinh
void main()


{


</div>
<span class='text_page_counter'>(65)</span><div class='page_container' data-page=65>

while(1){


while(Chay);
Chaychu();
}


</div>

<!--links-->

×