Ví dụ lệnh sau cộng nội dung R7 vào thanh ghi tích luỹ: ADD A, R7; Mã lệnh là 001011111B. Trong đó 5 bit cao 00101 chỉ mã lệnh 3 bit thấp 111 chỉ thanh ghi R7. Một vài lệnh xác đònh trực tiếp trên thanh ghi như thanh ghi tích luỹ, con trỏ dữ liệu …do đó không cần đến các bit đòa chỉ. Bản thân mã lệnh đã mô tả thanh ghi. Đònh vò trực tiếp : Đònh vò trực tiếp có thể truy xuất bất kỳ byte nào trong vùng nhớ nội hoặc các thanh ghi chức năng. Một byte được thêm vào mã lệnh để xác đònh vò trí thanh ghi được dùng. Opcode 8-bit Direct Adress 8-bit Tùy thuộc vào bit cao nhất của byte đòa chỉ trực tiếp, một trong hai vùng nhớ sẽ được chọn. Khi bit 7 của đòa chỉ trực tiếp bằng 0: đòa chỉ trực tiếp có giá trò từ 0 đến 127 (00H – 0FH) và 128 bytes thấp của on chip RAM được tham khảo đến, Tất cả các I/O port, thanh ghi chức năng. Thanh ghi điều khiển, thanh ghi trạng thái có đòa chỉ từ 128 đến 255 (80H-FFh). Khi bit 7=1 byte đòa chỉ trực tiếp nằm trong giới hạn này, tương ứng với thanh ghi chức năng sẽ được truy xuất. Ví dụ port 0 và port 1 có đòa chỉ tương ứng là 80H và 90H. Ta không cần phải biết đòa chỉ của những thanh ghi này, trình biên dòch luôn hiểu các mã gợi nhớ ngắn gọn của nó như P0, P1, TMOD… Đònh vò gián tiếp: Làm thế nào để nhận dạng một biến, nếu đòa chỉ của nó được xác đònh, tính toán, thay đổi khi chương trình đang chạy. Vấn đề này được đặt ra khi thao tác các vò trí nhớ liên tục, chuỗi số, hay xâu ký tự. Thanh ghi và đòa chỉ trực tiếp không thể dùng vì toán hạng đòa chỉ phải được nhân biết trong thời gian biên dòch. Để giải quyết vấn đề trên 8051 sử dụng đòa chỉ gián tiếp. R1 và R0 được coi như những con trỏ. Nội dung của chúng chỉ đến một đòa chỉ nào đó trong RAM khi đọc hoặc ghi dữ liệu. Bit thấp nhất trong byte mã lệnh xác đònh thanh ghi nào (R0 hay R1) được dùng làm con trỏ. Ngôn ngữ assembly của 8051 dùng ký hiệu @ đặt trước R0 hay R1 để mô tả đònh vò gián tiếp. Ví dụ, nếu R1 chứa 40H và tại vò trí 40H trong bộ nhớ nội chứa giá trò 55H, lệnh: MOV A, @R1; Chuyển giá trò 55H vào thanh ghi tích luỹ. Opcode 7-bit i Đònh vò gián tiếp trở nên quan trọng khi phải thao tác từng byte bộ nhớ nội một cách liên tục. Ví dụ những lệnh sau sẽ xóa vùng RAM từ đòa chỉ 60H đến 70H: MOV R0, #60H; MOV @R0, #0; LOOP: INC R0; CJNE R0, #80H, LOOP; Lệnh đầu tiên khởi động thanh ghi với đòa chỉ đầu tiên của khối bộ nhớ. Lệnh thứ hai dùng lệnh gián tiếp để chuyển giá trò 00H vào vò trí được trỏ bởi R0. Lệnh thứ 3 tăng giá trò con trỏ đến đòa chỉ tiếp theo. Và lệnh cuối kiểm tra xem con trỏ đến cuối khối chưa. Lệnh kiểm tra dùng giá trò 80H chứ không phải giá trò 7FH vì việc xảy ra sau việc dòch chuyển gián tiếp. Như vậy chắc chắn cuối cùng sẽ được ghi trước khi kết thúc. Đònh vò tức thời : Khi một toán hạng nguồn là một hằng số không phải là một biến. Hằng số có thể được gom vào trong lệnh như một dữ liệu tức thời. Byte được thêm vào sẽ chứa giá trò. Trong ngôn ngữ assembly toán hạng tức thời được đặt trước bằng ký hiệu số (#). Toán hạng có thể là một hằng số, ký hiệu hoặc toán tử. Trình biên dòch sẽ tính toán giá trò và gán dữ liệu tức thời vào lệnh. Tất cả các lệnh dùng đònh vò tức thời đều sử dụng hằng dữ liệu 8 bit. Ngoại trừ khi khởi động thanh ghi con trỏ dữ liệu (DPTR) MOV DPTR, #40000H; Là một lệnh 3 bytes nạp số 16 bit vào thanh ghi con trỏ. Đònh vò tương đối: Đònh vò tương đối chỉ dùng trong các lệnh jump. Đòa chỉ tương đối (offset) là một số 8 bit có dấu được cộng vào thanh ghi đếm chương trình để chỉ ra đòa chỉ của lệnh tiếp theo phải thi hành. Vì offset là một số 8 bit có dấu nên tầm nhảy chỉ giới hạn trong khoảng cách +127 và –128 vò trí. Trước khi cộng, thanh ghi đếm chương trình tăng lên đến đòa chỉ sau lệnh jump. Vì vậy, đòa chỉ mới là tương đối so với đòa chỉ lệnh kế tiếp chứ không phải đòa chỉ lệnh jump. Thông thường chi tiết này không liên quan đến người lập trình, khi mà đích nhảy đến được mô tả bằng một nhãn. Trình biên dòch sẽ đònh giá trò offset tương đối tương ứng. Opcode Immediate data Relative offset Opcode Ví dụ nếu nhãn THERE được đặt tại lệnh có đòa chỉ 1040H và lệnh SJMP THERE Ở tại vò trí 1000H và 1001H. Trình biên dòch sẽ gán giá trò offset tương đối là 3EH tại byte thứ hai của lệnh. Đònh vò tuyệt đối: Đònh vò tuyệt đối chỉ dùng đối với các lệnh ACALL, AJMP. Lệnh 2 byte này cho phép rẽ nhánh trong phạm vi 2Kbytes bộ nhớ. 5bit cao của đòa chỉ đích là 5 bit cao hiện thời trong thanh ghi đếm chương trìng. Vì vậy lệnh theo sau lệnh rẽ nhánh và lệnh kết thúc rẽ nhánh kết thuác nằm trong phạm vi 2Kbytes. Addr 10 – Addr8 Opcode 5-bit Đònh vò xa: Đònh vò xa chỉ sử dụng cho các lệnh LCALL và LMP. Các lệnh 3-byte này có đòa chỉ đích là số 16-bit đặt trong byte 2 và byte 3. Điều thuận tiện là toàn bộ vùng mã lệnh đều có thể được sử dụng. Nhưng một điều bất tiện là lệnh 3-byte quá dài và phụ thuộc vò trí (position-dependent). Phụ thuộc vò trí là một điệu bất tiện bởi vì chương trình không thể thi hành tại một đòa chỉ khác. Opcode Addr15 – Addr8 Addr7 – Addr0 Đònh vò chỉ số : Đònh vò chỉ số dùng một thanh ghi cơ sở (PC hoặc DPTR) và một thanh ghi làm offset (ACC) tạo ra một đòa chỉ sẽ bò tác động bởi các lệnh JMP hoặc MOVC. Thanh ghi nền offset đòa chỉ tác động PC or DPTR + ACC = Các ví dụ được cung cấp trong phụ lục cho các lệnh: MOVC A, @A+ <thanh ghi nền> JMP @A+DPTR III – PHÂN LOẠI LỆNH: Các lệnh 8051 được chia thành 5 nhóm như sau: Số học Logic Trao đổi dữ liệu Addr7 - Addr0 Luận lý Rẽ nhánh chương trình Các lệnh số học Các lệnh số học thường sử dụng 4 mode đònh vò. Lệnh ADD A có thể được viết bằng nhiều cách khác nhau: ADD A, 7FH (Đònh vò trực tiếp) ADD A, @R0 ( gián tiếp) ADD A, R7 ( thanh ghi) ADD A, #35H ( tức thời) Tất cả các lệnh số học thi hành trong một chu kỳ máy, ngoại trừ lệnh INC DPTR (2 chu kỳ máy), MUL AB và DIV AB (4 chu kỳ máy). 8051 cung cấp cách đònh vò rất mạnh cho vùng RAM nội của nó. Bất kỳ byte nhớ nào cũng đều có tể tăng, giảm bằng đònh vò trực tiếp mà không cần thông qua thanh ghi tích luỹ. Lệnh INC có thể thao tác trên con trỏ dữ liệu (16 bit). Nhưng lệnh DEC không được đònh nghóa trên con trỏ. Do đó để thực hiện được điều này ta có các lệnh sau: DEC DPL ; giảm byte thấp DPTR MOV R7, DPL ; chuyển vào DPL CJNE R7, #0FFH, SKIP ; nếu vượt quá FF DEC DPH ; giảm luôn byte cao SKIP : (tiếp tục) Các lênh MUL AB và DIV AB chỉ thao tác trên các thanh ghi A và B. Lệnh Logic : Các lệnh logic biểu diễn các toán tử luận lý như AND, OR, EA-OR và NOT … Các lệnh này trên từng bit của byte dữ liệu. Ví dụ thanh ghi ACC chứa số 10101101B thì lệnh: ANL A, #10110010B Chứa kết quả 10100000 vào thanh ghi ACC. Các mode đònh vò trong lệnh logic cũng giống như trong lệnh số học. Tất cả các lệnh logic dùng đến thanh ghi ACC như một toán hạng đều là những lệnh một chu kỳ. Các lệnh khác đều chiếm 2 chu kỳ máy. Lệnh logic có thể thao tác trực tiếp bất cứ byte nào trong vùng nhớ nội. Lệnh XRL <thanh ghi>, #data đảo nhanh và dễ dàng các bit của port. XRL P1, #0FFH; Lệnh này mô tả hoạt động read-modify-write. 8 bit của port 1 được đọc, sau đó mỗi bit của XOR với bit tương ứng trong byte dữ liệu tức thời đều là 1, XOR sẽ đảo mỗi bit được đọc. Kết quả được viết trở lại port 1. Các lệnh chuyển dòch dữ liệu: RAM nội Các lệnh chuyển dòch dữ liệu trong vùng RAM nội chỉ chiếm 1 hoặc 2 chu kỳ máy. Lệnh có dạng: MOV <đích>, <nguồn> Một nét đặc trưng của họ MSC-51 là stack nằm trong vùng RAM nội và lớn dần lên phía tên của bộ nhớ. Lệnh PUSH trước tiên tăng con trỏ stack, sau đó mới sao chép byte vào stack. PUSH và POP chỉ dùng đònh vò trực tiếp. Thế nhưng bản thân stack lại dùng đònh vò trực tiếp thông qua con trỏ stack (SP). 8031/8051 không dùng 128 byte cao trong vùng nhớ nội làm stack. Nếu SP vượt quá 127 bytes được push bò mất và byte được pop không xác đònh. Lệnh dòch chuyển dữ liệu 16-bit (MOV dùng để khởi động con trỏ dữ liệu. Lệnh XCV A, <source> Chuyển đổi dữ liệu giữa A và byte được đònh vò. Lệnh XCHD A, @R1 chuyển đổi 4 bit thấp của thanh ghi ACC với byte được R1 chỉ đến. RAM ngoài Dòch chuyển dữ liệu giữa bộ nhớ trong và ngoài sử dụng mode đònh vò gián tiếp. Đòa chỉ gián tiếp có thể là một byte hay 2 byte (DPTR). Các lệnh dòch chuyển dữ liệu thao tác trên bộ nhớ ngoài đều chiếm hai chu kỳ máy và dùng thanh ghi tích luỹ làm toán hạng nguồn hoặc đích. Look-Up Tables Hai lệnh được cho sẵn để đọc một bảng dữ liệu trong bộ nhớ chương trình. Khi truy xuất đến vùng nhớ chương trình thì nội dung của bảng chỉ được đọc mà không được ghi. Từ gợi nhớ MOVC tức là “move constant”. MOVC dùng thanh ghi đếm chương trình cũng như con trỏ dữ liệu kàm thanh ghi nền và thanh ghi tích luỹ làm offset. MOVC A,@A+DPTR ; Có thể đọc được một số trong bảng 256 phần tử vào thanh ghi tích luỹ. Trong đó thanh ghi tích luỹ chỉ đến một vò trí trong còn con trỏ DPTR chỉ đến vò trí đầu bảng. MOVC A,@A+PC ; Cũng tương tự như trên, chỉ khác là thanh ghi PC được dùng làm thanh ghi nền và bảng được truy xuất thông qua chương trình con. Trước tiên chỉ số yêu cầu được nạp cho thanh ghi tích luỹ sau đó chương trình con được gọi. Việc khởi động và gọi cụ thể như sau: MOV A,ENTRY_NUMBER CALL LOOK_UP . . . LOOK_UP : INC A MOVC A, @A+PC Ret TAB: DB data, data, data … Bảng được đặt ngay sau lệnh RET của chương trình con. Lệnh INC cần thiết vì PC sẽ chỉ đến lệnh RET sau khi thi hành MOVC. Việc tăng thanh ghi A cho phép nhảy qua khỏi lệnh RET. Các lệnh luận lý Các lệnh luận lý của 8051 thao tác trên bit đơn. RAM nội cung cấp 128 bit và các thanh ghi chức năng cung cấp 128 bit khác. Lệnh truy xuất đến các bit thông thường như set, xóa, đảo, AND, OR … Tất cả các bit đều truy xuất bằng đònh vò trực tiếp với các bit có đòa chỉ từ 00H – 7Fh trong 128 đòa chỉ thấp và 80H-FFH trong SFRs. Các bit trong vùng đòa chỉ thấp đạt tại 20F đến 2FH, được đánh số lần lượt từ bit 0 của đòa chỉ 200H (bit 00H) đến bit 7 của đòa chỉ 2FH (bit 7Fh). Ví dụ SETB P.1.7 set bit 7 port 1 Bit carry trong PSW được sử dụng như single-bit accumulator. Ví dụ CLR C CLR CY ; xóa carry Test bit Các lệnh test bit thường là các lệnh rẽ nhánh chương trình. Chúng kiểm tra trạng thái các bit để nhảy đến chương trình tương ứng nếu thỏa điều kiện. Lệnh rẽ nhánh chương trình Có một số lệnh điều khiển dòng chương trình, chúng gồm các lệnh gọi chương trình con và trả về từ một chương trình con hoặc rẽ nhánh có điều kiện và không có điều kiện. Những khả năng này có thể được cải tiến hơn nữa khi sử dụng 3 mode đònh vò trong các lệnh rẽ nhánh chương trình. Có 3 kệnh JMP khác nhau:SJMP, LJMP và AJMP (tương ứng là đònh vò tương đối, đònh vò xa và đònh vò tuyệt đối). Trình biên dòch Intel chấp nhận lệnh chung chung JMP nếu người lập trình không quan tâm đến sự thay đổi biên dòch. Trong khi trình biên dòch của những hãng khác không có đặc tính này. JMP được biên dòch thành AJMP nếu đích nằm ở trước và khoảng nhảy nằm trong phạm vi 2Kbytes. Trong các trường hợp khác có thể dòch thành LJMP. Lệnh CALL cũng tương tự như vậy. Lệnh SJMP đònh đòa chỉ đích như một offset tương đối. Vì vậy lệnh này dài 2 bytes. Khoảng cách nhảy bò giới hạn từ –128 đến +127 bytes tương đối so lệnh sau lệnh SJMP. Lệnh LJMP xác đònh một đòa chỉ đích là một số 16 bit. Vì vậy lệnh này dài 3 bytes. Đòa chỉ đích có thể ở bất kỳ trong vùng nhớ chương trình 63KB. Lệnh AJMP xác đònh đòa chỉ đích là một số 11 bit. Giống như SJMP, lệnh này dài 2 bytes, nhưng được biên dòch khác. Mã lệnh chứa 3 bit trong vòng 11 bit đòa chủ và byte thứ hai chứa 8 bit còn lại của đòa chỉ đích. Khi lệnh được thi hành 11 bit này được đặt vào 11 bit thấp trong thanh ghi PC và 5 bit cao trong thanh ghi PC không đổi. Vì vậy đích phải nằm trong phạm vi 2 Kbytes. Trong tất cả các trường hợp, người lập trình xác đònh đòa chỉ bit bằng một nhãn hoặc như một số 16 bit. Trình biên dòch sẽ đặt đòa chỉ đích vào vò trí đúng trong lệnh được biên dòch. Jump Tables Lệnh “JMP @ A+DPTR” cung cấp lệnh nhảy phụ thuộc điều kiện theo một bảng nhảy (jump tables). Đòa chỉ đích sẽ được tính trong khi thi hành chương trình như tổng của DPTR và thanh ghi tích luỹ. Đầu tiên DPTR được nạp đòa chỉ của bảng và thanh ghi tích luỹ được dùng làm chỉ số. Ví dụ nếu có 5 trường hợp nhảy, giá trò từ 0 đến 4 được nạp cho thanh ghi tích luỹ và lệnh nhảy tương ứng với từng trường hợp được mô tả như sau: MOV DPTR, #JUMP_TABLE ; MOV A, INDEX_NUMBER ; RL A JMP @A+DPTR Lệnh RL ở trên đổi chỉ số (từ 0 đến 4) thành các số chẵn từ 0 đến 8, vì mỗi điểm xâm nhập trong bảng là một đòa chỉ 2-byte. JNP_TABLE : AJMP CASE0 AJMP CASE1 AJMP CASE2 AJMP CASE3 Chương trình và con ngắt Có hai lệnh CALL khác nhau: ACALL và LCALL dùng đònh vò tuyệt đối và xa. Giống như lệnh JMP, lệnh CALL đưôc trình biên dòch của Intel dùng khi người lập trình không quan tâm đến đòa chỉ được biên dòch. Lệnh này đẩy thanh ghi PC vào stack và nạp PC với giá trò được chỉ ra trong lệnh. Lưu ý PC sẽ được trả lại giá trò đòa chỉ sau lệnh CALL khi nó chấm dứt chương trình con. Các lệnh LJMP và ACALL đều có những hạn chế giống như LJMP và AJMP được mô tả ở trên. Chương trình con kết thúc bằng lệnh RET, nó sẽ trả điều khiển lại cho chương trình chính. Không có gì bí ẩn khi RET trả điều khiển lại cho chương trình chính, nó chỉ đơn giản lấy 2 bytes cuối cùng của stack và đặt chúng vào thanh ghi PC. Lệnh RETI dùng để quay trở về chương trình chính từ trong chương trình phục vụ ngắt. Sự khác nhau giữa RET và RETI chỉ là RETI ký hiệu cho ngắt điều khiển hệ thống. Lệnh nhảy có điều kiện 8051 cung cấp một số lệnh nhảy có điều kiện. Tất cả những lệnh này đều xác đònh đòa chỉ đích bằng đònh vò tương đối. Giới hạn khoảng cách nhảy từ –128 đến +127 bytes kể từ sau lệnh nhảy có điều kiện. Tuy nhiên người lập trình cũng có thể đònh một đòa chỉ bằng nhhãn hoặc một số 16 bit. Không có bit zero trong thanh ghi PSW. JZ và JNZ test nội dung thanh ghi ACC cho điều khiển nhảy. Lệnh DJNZ (nhảy nếu khác 0) được dùng để điều khiển vòng lặp. Để vòng lập thi hành N lần, nạp biến đếm với N và đặt DJNZ ở cuối vòng lặp để bắt đầu vòng lặp. Ví dụ vòng lặp sau thi hành 10 lần: MOV R0,#10 ; LOOPP: (bắt đầu vòng lặp) . . . (kết thúc vòng lặp) DJNZ R7, LOOP ; (tiếp tục) Lệnh CJNZ (so sánh và nhảy nếu không bằng) cũng dùng để điều khiển vòng lặp. Hai bytes được xác đònh trong vùng toán hạng của lệnh và lệnh nhảy sẽ thi hành nếu hai bytes này khác nhau. Ví dụ, nếu một ký tự được đọc vào thanh ghi ACC từ cổng nối tiếp và nhảy đến nhãn TERMINAL nếu ký tự đọc vào là CONTROL-C (03H) . CJNE A, #03, SKIP ; SJMP TERMINAL ; SKIP: (tiếp tục) Lệnh jump chỉ xảy ra khi A=03H. Một ứng dụng khác của lệnh này là so sánh lớn hơn và bé hơn. Hai byte trong miền toán hạng là những số không dấu. Nếu toán hạng đầu nhỏ hơn toán hạng thứ hai thì cờ carry được set. Nếu toán hạng đầu lớn hơn hoặc bằng toán hạng thứ hai thì cờ carry được xóa. Ví dụ nếu muốn nhảy đến BIG nếu ACC lớn hơn hoặc bằng 20H, ta có các lệnh sau: CJNE A,#20H,$+3 JNC BIG Ký hiệu dollars “$” là một ký hiệu đặt biệt của trình biên dòch thay thế cho đòa chỉ của lệnh hiện thời. Vì CJNE là một lệnh 3-bytes, “$+3” là đòa chỉ của lệnh tiếp theo. Chương V GIỚI THIỆU VỀ KIT VI ĐIỀU KHIỂN 8051 I –CHỨC NĂNG CÁC PHÍM: 1 – Bàn phím: Kít vi điều khiển có tất cả là 26 phím nhấn như hình 1 được chia thành các nhóm như sau: 16 phím nhập dữ liệu của chương trình dạng số thập lục phân từ 0 đến F. Các phím chức năng Hình 1 Q G T P K I C D E F R 8 9 A B S 4 5 6 7 0 1 2 3 2 – Chức năng của phím: Khi mới cấp điện cho máy 4 Led bên trái sẽ hiển thò 4 số 0000, bốn led bên phải tắt Nếu không hiển thò đúng hãy nhấn phím “Q”. Phím “Q” có chức năng Reset mạch khi khởi động hoặc khi muốn thoát khỏi chương trình vi điều khiển đang thực hiện (chức năng như phím RESET của máy vi tính) 3 – Chức năng của phím: Muốn nhập dữ liệu mới vào ô nhớ có đòa chỉ ví dụ 4000, hãy dùng các phím nhập dữ liệu đánh số 4000, đòa chỉ này sẽ xuất hiện ở 4 led bên phải. Nhấn phím “S” thì đòa chỉ 4000 sẽ thay thế cho đòa chỉ trước đó ở 4 led bên trái. 4 led còn lại chỉ có 2 led sáng đó chính là nội dung của ô nhớ tương ứng với đòa chỉ 4 led bên trái 4 – Chức năng của phím: Dùng để lưu trữ dữ liệu vào ô nhớ có đòa chỉ ở 4 led bên trái, ví dụ muốn lưu trữ dữ liệu là “3F” vào ô nhớ có đòa chỉ là 4000, hãy S Q . chỉ dùng đònh vò trực tiếp. Thế nhưng bản thân stack lại dùng đònh vò trực tiếp thông qua con trỏ stack (SP). 8031/8051 không dùng 128 byte cao trong vùng nhớ nội làm stack. Nếu SP vượt quá. Lệnh dòch chuyển dữ liệu 16-bit (MOV dùng để khởi động con trỏ dữ liệu. Lệnh XCV A, <source> Chuyển đổi dữ liệu giữa A và byte được đònh vò. Lệnh XCHD A, @R1 chuyển đổi 4 bit thấp. lại cho chương trình chính, nó chỉ đơn giản lấy 2 bytes cuối cùng của stack và đặt chúng vào thanh ghi PC. Lệnh RETI dùng để quay trở về chương trình chính từ trong chương trình phục vụ