4.3.1. Các thành phần cơ bản của ngôn ngữ Assembly
Cấu trúc của một lệnh hợp ngữ có 4 trường như sau:
[nhãn:] [từ gợi nhớ] [các toán hạng] [; chú giải]
Các trường trong dấu ngoặc vuông là tuỳ chọn và không phải dòng lệnh nào cũng có chúng. Các dấu ngoặc vuông không được viết vào. Với dạng thức trên đây cần lưu ý các điểm sau:
a. Trường nhãn cho phép chương trình tham chiếu đến một dòng lệnh bằng tên. Nó không được viết quá một số ký tự nhất định. Hãy kiểm tra quy định này của hợp ngữ mà ta sử dụng.
b. Từ gợi nhớ (lệnh) và các toán hạng là các trường kết hợp với nhau thực thi công việc thực tế của chương trình và hoàn thiện các nhiệm vụ mà chương trình được viết cho chúng. Trong hợp ngữ các câu lệnh như:
“ ADD A, B”
“MOV A, #67H”
thì ADD và MOV là những từ gợi nhớ tạo ra mã lệnh, còn “A, B” và “A, #67H” là những toán hạng thì hai trường có thể chứa các lệnh giả hoặc chỉ lệnh của hợp ngữ. Hãy nhớ rằng các chỉ lệnh không tạo ra mã lệnh nào (mã máy) và chúng chỉ dùng bởi hợp ngữ, ngược lại đối với các lệnh là chúng được dịch ra mã máy (mã lênh) cho CPU thực hiện.
c. Trường chú giải luôn phải bắt đầu bằng dấu chấm phẩy (;). Các chú giải có thể bắt đầu ở đầu dòng hoặc cuối dòng. Hợp ngữ bỏ qua các chú giải nhưng chúng lại rất cần thiết đối với lập trình viên. Mặc dù các chú giải là tuỳ chọn, không bắt buộc nhưng ta
nên dùng chúng để mô tả chương trình để giúp cho người khác đọc và hiểu chương trình dễ dàng hơn.
d. Lưu ý đến nhãn, một nhãn bất kỳ tham chiếu đến một lệnh phải có dấu hai chấm (:) đứng ở sau. Trong câu lệnh nhảy ngắn SJMP thì 8051 được ra lệnh ở lại trong vòng lặp này vô hạn. Nếu hệ thống của chúng ta có một chương trình giám sát thì ta không cần dòng lệnh này và nó có thể được xoá đi ra khỏi chương trình.
Để có thể dịch thành file mã máy dạng HEX-Code trước khi download vào Chip thì một chương trình assembly phải tuân thủ các nguyên tắc sau:
- Mỗi dòng lệnh không vượt quá 255 ký tự
- Mỗi dòng lệnh phải bắt đầu bằng 1 ký tự, nhãn, lệnh hoặc chỉ thị định hướng - chương trình dịch
- Mọi thứ sau dấu “;” được xem là lời giải thích và chương trình dịch sẽ bỏ qua. - Các thành phần của mỗi dòng lệnh cách biệt nhau ít nhất bằng một dấu cách.
4.3.2. Khai báo trong lập trình hợp ngữ cho 8051
• Khai báo biến
Ten_bien DB Gia_Tri_Khoi_Tao
DB là một chỉ lệnh dữ liệu được sử dụng rộng rãi nhất trong hợp ngữ. Nó được dùng để định nghĩa dữ liệu 8 bit. Khi DB được dùng để định nghĩa byte dữ liệu thì các số có thể ở dạng thập phân, nhị phân, Hex hoặc ở dạng thức ASCII. Đối với dữ liệu thập phân thì cần đặt chữ “D” sau số thập phân, đối với số nhị phân thì đặt chữ “B” và đối với dữ liệu dạng Hex thì cần đặt chữ “H”.
Khi dữ liệu có kích thước là 2 byte sử dụng: DW để khai báo biến kiểu nguyên
Ví dụ:
DATA1: DB 2D ; Số thập phân
DATA2: DB 00110101B ; Số nhị phân (35 ở dạng Hex)
DATA3: DB 39H ; Số dạng Hex
DATA4 DB “Ky thuat may tinh” ; Các ký tự ASCII • Khai báo hằng
Ten_Hang EQU Gia_tri
Được dùng để định nghĩa một hằng số mà không chiếm ngăn nhớ nào. Chỉ lệnh EQU không dành chỗ cất cho dữ liệu nhưng nó gắn một giá trị hằng số với nhãn dữ liệu sao cho khi nhãn xuất hiện trong chương trình giá trị hằng số của nó sẽ được thay thế đối với nhãn
Ví dụ:
COUNT EQU 25
MOV R3, # COUNT
Khi thực hiện lệnh “MOV R3, #COUNT” thì thanh ghi R3 sẽ được nạp giá trị 25 (chú ý đến dấu #). Vậy ưu điểm của việc sử dụng EQU là gì? Giả sử có một hằng số (một giá trị cố định) được dùng trong nhiều chỗ khác nhau trong chương trình và lập trình viên muốn thay đổi giá trị của nó trong cả chương trình. Bằng việc sử dụng
chỉ lệnh EQU ta có thể thay đổi một lần và hợp ngữ sẽ thay đổi tất cả mọi lần xuất hiện của nó.
Ký hiệu Thực hiện Ví dụ Kết quả
+ Cộng 10+5 15
- Trừ 25-17 8
* Nhân 7*4 28
/ Chia nguyên 7/4 1
MOD Chia lấy dư 7 MOD 4 3
SHR Dịch phải 1000B SHR 2 0010B
SHL Dịch trái 1010B SHL 2 101000B
NOT Đảo NOT 1 1111111111111110B
AND And bit 1101B AND 0101B 0101B
OR Or bit 1101B OR 0101B 1101B
XOR Xor 1101B XOR 0101B 1000B
LOW Lấy byte thấp LOW(0AADDH) 0DDH
HIGH Lấy byte cao HIGH(0AADDH) 0AAH
EQ, = So sánh bằng 7 EQ 4 or 7=4 0 (false)
NE,<> SS Không bằng 7 NE 4 or 7<>4 0FFFFH (true) GT, > SS lớn hơn 7 GT 4 or 7>4 0FFFFH (true) GE, >= SS nhỏ hơn hoặc bằng 7 GE 4 or 7>=4 0FFFFH (true) LT, < SS nhỏ hơn 7 LT 4 or 7<4 0 (false)
LE,<= SS nhỏ hơn hoặc bằng 7 LE 4 or 7<=4 0 (false) • Các toán tử
Bảng 4-5. Các toán tử
• Tên
Thay vì phải nhớ tên từng thanh ghi, hay từng bit, ta có thể gán cho nó một cái nhãn gợi nhớ tương ứng với chức năng của nó, assembly hỗ trợ việc đặt tên theo quy tắc sau:
Tên được tổ hợp từ các ký tự (A-Z, a-z), các số (0-9), các ký tự đặc biệt (“?” Và “_”) và không phân biệt chữ cái và chữ thường.
Độ dài tên tối đa là 255 ký tự, nhưng chỉ 32 ký tự đầu được dùng để phân biệt Tên phải bắt đầu bằng ký tự.
Không được trùng với các từ khóa sau:
4.3.3. Cấu trúc một chương trình hợp ngữ
ORG (Vị trí bắt đầu con trỏ chương trình ) <đoạn chương trình chính>
<các chương trình con>
END .(Kết thúc chương trình)
Ví dụ:
ORG 00H ;(con trỏ chương trình bắt đầu từ 00h)
LJMP MAIN ; nhảy tới vị trí có nhãn là MAIN) ; (vị trí bắt đầu chương trình chính MAIN):
ORG 0030H ; Nhảy qua vùng ngắt MAIN:
MOV R1,#10 ;(nạp cho R1 giá trị là 10). LAP1:
DJNZ R1, LAP1 ; Nếu R1 khác 0 thì giảm R1 và nhảy tới nhãn LAP1
END ; (Kết thúc chương trình.)
Con trỏ: vị trí mà vi điều khiển bắt đầu thực thi tại đó. Thường khi bắt đầu con trỏ có địa chỉ thấp nhất là 00h, tuy nhiên người lập trình cũng có thể quy định cho nó làm việc tại một vị trí bất kỳ
Ví dụ:
ORG 00H ; Bắt đầu tại vị trí 00h
ORG 0030H ; Bắt đầu tại vị trí 0030h
Chương trình con: Nhãn: ... Các câu lệnh ... RET Ví dụ: ORG 00H LJMP MAIN ORG 0030H MAIN:
MOV R1,#10
LCALL LAP1 ;gọi chương trình con LAP1:
DJNZ R1,LAP1
RET ; kết thúc chương trình con
END
Câu hỏi ôn tập chương 4
Câu 1: Viết chương trình ghi 40H vào ô nhở 30H của RAM nội sử dụng 2 chế độ đánh địa chỉ trực tiếp và gián tiếp.
Câu 2:Viết chương trình xuất 0FH ra cổng P2.
Câu 3: Viết chương trình nhập vào thanh ghi A giá trị cổng P0.
Câu 4: Viết chương trình chuyển một chuỗi dữ liệu gồm 10 byte trong RAM nội có địa chỉ đầu là 30H đến vùng RAM nội có địa chỉ đầu là 40H.
CHƯƠNG 5
BỘ ĐỊNH THỜI, BỘ ĐẾM 5.1. CÁC THANH GHI CƠ SỞ CỦA BỘ ĐỊNH THỜI
Cả hai bộ định thời Timer 0 và Timer 1 đều có độ dài 16 bít được truy cập như hai thanh ghi tách biệt byte thấp và byte cao. Chúng ta sẽ bàn riêng về từng thanh ghi.
5.1.1. Các thanh ghi của bộ Timer 0.
Thanh ghi 16 bít của bộ Timer 0 được truy cập như byte thấp và byte cao. Thanh ghi byte thấp được gọi là TL0 (Timer 0 low byte) và thanh ghi byte cao là TH0 (Timer 0 High byte). Các thanh ghi này có thể được truy cập như mọi thanh ghi khác chẳng hạn như A, B, R0, R1, R2 v.v... Ví dụ, lệnh “MOV TL0, #4FH” là chuyển giá trị 4FH vào TL0, byte thấp của bộ định thời 0. Các thanh ghi này cũng có thể được đọc như các thanh ghi khác. Ví dụ “MOV R5, TH0” là lưu byte cao TH0 của Timer 0 vào R5.
Hình 5-1. Các thanh ghi của bộ Timer 0
5.1.2. Các thanh ghi của bộ Timer 1.
Bộ định thời gian Timer 1 cũng dài 16 bít và thanh ghi 16 bít của nó được chia ra thành hai byte là TL1 và TH1. Các thanh ghi này được truy cập và đọc giống như các thanh ghi của bộ Timer 0 ở trên.
Hình 5-2. Các thanh ghi của bộ Timer 1
5.1.3. Thanh ghi TMOD (chế độ của bộ định thời).
Cả hai bộ định thời Timer 0 và Timer 1 đều dùng chung một thanh ghi được gọi là TMOD để thiết lập các chế độ làm việc khác nhau của bộ định thời. Thanh ghi TMOD là thanh ghi 8 bít gồm có 4 bít thấp được thiết lập dành cho bộ Timer 0 và 4 bít cao dành cho Timer 1. Trong đó hai bít thấp của chúng dùng để thiết lập chế độ của bộ định thời, còn 2 bít cao dùng để xác định phép toán. Các phép toán này sẽ được bàn dưới đây.
Hình 5-3. Timer TMOD
a. Các bít M1, M0
Là các bít chế độ của các bộ Timer 0 và Timer 1. Chúng chọn chế độ của các bộ định thời: 0, 1, 2 và 3. Chế độ 0 là một bộ định thời 13, chế độ 1 là một bộ định thời 16 bít và chế độ 2 là bộ định thời 8 bít. Chúng ta chỉ tập chung vào các chế độ thường được sử dụng rộng rãi nhất là chế độ 1 và 2. Chúng ta sẽ sớm khám phá ra các đặc tính củ các chế độ này sau khi khám phần còn lại của thanh ghi TMOD. Các chế độ được thiết lập theo trạng thái của M1 và M0 như sau:
b. C/ T (Bộ đếm / Bộ định thời).
Bít này trong thanh ghi TMOD được dùng để quyết định xem bộ định thời được dùng như một máy tạo độ trễ hay bộ đếm sự kiện. Nếu bít C/T = 0 thì nó được dùng như một bộ định thời tạo độ trễ thời gian. Nguồn đồng hồ cho chế độ trễ thời gian là tần số thạch anh của 8051. Ở phần này chỉ bàn về lựa chọn này, công dụng của bộ định thời như bộ đếm sự kiện thì sẽ được bàn ở phần kế tiếp.
Ví dụ : Hãy cho biết chế độ nào và bộ định thời nào đối với các trường hợp sau: a) MOV TMOD, #01H b) MOV TMOD, #20H c) MOV TMOD, #12H
Lời giải: Chúng ta chuyển đổi giá trị từ số Hex sang nhị phân và đối chiếu với từng bít trong thanh ghi TMOD ta có:
a) TMOD = 0000 0001, chế độ 1 của bộ định thời Timer 0 được chọn. b) TMOD = 0010 0000, chế độ 2 của bộ định thời Timer 1 được chọn.
c) TMOD = 0001 0010, chế độ 1 của bộ định thời Timer 1 và chế độ 2 của Timer 0 được chọn.
c. Nguồn xung đồng hồ cho bộ định thời
Như chúng ta biết, mỗi bộ định thời cần một xung đồng hồ để giữ nhịp. Vậy nguồn xung đồng hồ cho các bộ định thời trên 8051 lấy ở đâu? Nếu C/T = 0 thì tần số thạch anh đi liền với 8051 được làm nguồn cho đồng hồ của bộ định thời. Điều đó có nghĩa là độ lớn của tần số thạch anh đi kèm với 8051 quyết định tốc độ nhịp của các bộ định thời trên 8051. Tần số của bộ định thời luôn bằng 1/12 tần số của thạch anh gắn với 8051.
Ví dụ:
Đoạn mã dưới đây trình bày tần số thạch anh cho 3 hệ thống dựa trên 8051 khác nhau. Hãy tìm chu kỳ máy của mỗi trường hợp: a) 11.0592MHz b) 16MHz và c) 20MHz.
Lời giải:
b) 11.0592/12 = 921.6kHz; Chu kỳ máy là 1/921.6kHz = 1.085µs (micro giây) c) 16MHz/12 = 1.333MHz; Chu kỳ máy MC = 1/1.333MHz = 0.75µs
d) 20MHz/12 = 1.66MHz ⇒ MC = 1/1.66MHz = 0.60µs
Mặc dù các hệ thống dựa trên 8051 khác với tần số thạch anh từ 10 đến 40MHz, song ta chỉ tập chung vào tần số thạch anh 11,0592MHz. Lý do đằng sau một số lẻ như vậy là phải làm việc với tần suất baud đối với truyền thông nối tiếp của 8051. Tần số
XTAL = 11,0592MHz cho phép hệ 8051 truyền thông với IBM PC mà không có lỗi.
d. Bít cổng GATE.
Một bít khác của thanh ghi TMOD là bít cổng GATE. Để ý trên thanh ghi TMOD ta thấy cả hai bộ định thời Timer0 và Timer1 đều có bít GATE. Vậy bít GATE dùng để làm gì? Mỗi bộ định thời thực hiện điểm khởi động và dừng. Một số bộ định thời thực hiện điều này bằng phần mềm, một số khác bằng phần cứng và một số khác vừa bằng phần cứng vừa bằng phần mềm. Các bộ định thời trên 8051 có cả hai. Việc khởi động và dừng bộ định thời được khởi động bằng phần mềm bởi các bít khởi động bộ định thời TR là TR0 và TR1. Điều này có được nhờ các lệnh “SETB TR1” và “CLR TR1” đối với bộ Timer1 và “SETB TR0” và “CLR TR0” đối với bộ Timer0. Lệnh SETB khởi động bộ định thời và lệnh CLR dùng để dừng nó. Các lệnh này khởi động và dừng các bộ định thời khi bít GATE = 0 trong thanh ghi TMOD. Khởi động và ngừng bộ định thời bằng phần cứng từ nguồn ngoài bằng cách đặt bít GATE = 1 trong thanh ghi TMOD. Tuy nhiên, để tránh sự lẫn lộn ngay từ bây giờ ta đặt GATE = 0 có nghĩa là không cần khởi động và dừng các bộ định thời bằng phần cứng từ bên ngoài. Để sử dụng phần mềm để khởi động và dừng các bộ định thời phần mềm để khởi động và dừng các bộ định thời khi GATE = 0. Chúng ta chỉ cần các lệnh “SETB TRx” và CLR TRx”.
Ví dụ:
Tìm giá trị cho TMOD nếu ta muốn lập trình bộ Timer0 ở chế độ 2 sử dụng thạch anh XTAL 8051 làm nguồn đồng hồ và sử dụng các lệnh để khởi động và dừng bộ định thời.
Lời giải:
TMOD = 0000 0010: Bộ định thời Timer0, chế độ 2 C/T = 0 dùng nguồn XTAL GATE = 0 để dùng phần mềm trong để khởi động và dừng bộ định thời.
5.2. CÁC CHẾ ĐỘ CỦA BỘ ĐẾM / ĐỊNH THỜI (Timer Mode)
Như vậy, bây giờ chúng ta đã có hiểu biết cơ bản về vai trò của thanh ghi TMOD, chúng ta sẽ xét chế độ của bộ định thời và cách chúng được lập trình như thế nào để tạo ra một độ trễ thời gian. Do chế độ 1 và chế độ 2 được sử dụng rộng rãi nên ta đi xét chi tiết từng chế độ một.
Hình 5-4. Timer 0 – Mode 0
Hình 5-6. Timer 0 – Mode 2
5.2.1 Chế độ định thời 13-bít ( chế độ 0)
Chế độ 0 là chế độ định thời 13-bít cung cấp khả năng tương thích với bộ vi điều khiển tiền nhiệm 8048. Chế độ này không được dùng cho các thiết kế mới (xem hình ). Byte cao của bộ định thời THx được ghép cascade với 5bit thấp của byte thấp của bộ định thời TLx để tạo thành một bộ định thời 13-bit. Ba bit cao của TLx không sử dụng.
5.2.2 Chế độ định thời 16-bit ( chế độ 1 )
Chế độ 1 là chế độ định thời 16-bit và có cấu hình giống chế độ định thời 13- bit, chỉ khác nhau ở chỗ bây giờ là bộ định thời 16-bit. Xung clock đặt vào các thanh ghi định thời cao và thấp kết hợp ( TLx/THx ). Khi có xung clock đến, bộ định thời đếm lên : 0000H, 0001H, 0002H, …. Một tràn sẽ xuất hiện khi có sự chuyển số đếm từ FFFFH xuống 0000H, sự kiên này sẽ set cờ tràn bằng 1 và bộ định thời tiếp tục đếm. Cờ tràn là bit TFx trong thanh ghi điều khiển định thời TCON, bit này được đọc hoặc ghi bởi phần mềm.
Bit có ý nghĩa lớn nhất ( MSB ) của giá trị của các thanh ghi định thời là bit 7 của THx và bit có ý nghĩa thấp nhất ( LSB ) là bit 0 của TLx. Bit LSB thay đổi trạng thái và chia 2 tần số xung clock
5.2.3.Chế độ tự nạp lại 8 bít (chế độ 2)
Chế độ 2 là chế độ tự nạp lại 8 bít. Byte thấp của bộ định thời (TLx) hoạt động định thời bít trong khi byte cao của bộ định thời lưu giữ giá trị nạp lại. Khi số đếm