STS (STorage direc to data Space) •Cú pháp: STS k, Rr

Một phần của tài liệu bai2.cau truc avr (Trang 37 - 41)

• Cú pháp: STS k, Rr

• Chức năng: instruction này hoàn toàn giống LDS nhưng dùng để xuất dữ liệu từ thanh ghi Rr ra RAM, ngươi đọc có thể tham khảo

phần giải thích cho LDS.

Sử dụng địa chỉ trực tiếp thì câu lệnh sẽ đơn giản nhưng rất khó nhớ phần địa chỉ, thông thường SRAM là vùng chúng ta hay sử dụng để chứa biến tạm thời, trong các ngôn ngữ cấp cao ta chỉ cần nhớ tên biến nhưng với ASM chúng ta phải nhớ địa chỉ của chúng. Một cách tốt để tránh việc này là dùng chỉ thị (DIRECTIVE, bạn xem lại bài 1) . EQU để gán tên biến cho 1 địa chỉ, ví dụ .EQU bientam = 0x0060 và sau đó sử dụng bientam thay cho 0x0060.

Một cách khác được dùng để truy cập bộ nhớ mà không dùng địa chỉ tuyệt đối là sử dụng sử dụng con trỏ. Có 2 instruction hỗ trợ con trỏ là LD(LoaD indirec from data Space), và ST (STorage indirec to data Space), LD đọc dữ liệu từ SRAM vào thanh ghi còn ST lưu dữ liệu từ thanh ghi vào SRAM. Cả 3 con trỏ X, Y và Z đều có thể được dùng nhưng có một số điểm lưu ý: cả 3 đều dùng được trong trường hợp truy xuất thông thường nhưng với cách truy cập có offset, con trỏ X không sử dụng được. Để truy xuất bộ nhớ chương trình bằng con trỏ thì Z là giải pháp duy nhất…Dưới đây là 1 số cách sử dụng LD, ST kết hợp với con trỏ, chúng ta xét thông qua các ví dụ.

CLR R27 ; xóa R27, tức xóa byte cao của pointer X

LDI R26, 0x60 ; load giá trị 0x60 vào R26, tức byte thấp của pointer X

; sau 2 dòng trên, giá pointer X là 0x0060, sẵn sàng để trỏ đến vị trí đầu tiên trong SRAM.

LD R1, X+ ; Load giá trị ở ố nhớ 0x0060 vào R1 (vì X trỏ đến 0x0060), sao đó tăng giá trị ;X lên 1, như thế sau lệnh này X=0x0061

LD R2, X+ ; Load giá trị ở ố nhớ 0x0061 vào R2, sao đó tăng giá trị ;X lên 1, như thế sau lệnh này X=0x0062

LD R3, X ; Load giá trị ở ô nhớ 0x0062 vào R3 và không thay đổi X

LD R4, -X ; Giảm giá trị của X trước (X=0x0061), sau đó load giá trị ở ô nhớ 0x0061 vào R4

Từ ví dụ này chúng ta thấy có 3 cách cơ bản để load dữ liệu từ SRAM bằng con trỏ, cách Load trực tiếp trong trường hợp LD R3, X, cách load post-increment (hoặc post-decrement) như trong trường hợp LD R1, X+ và cách load pre- decrement (hoặc pre-increment) trong trường hợp LD R4, -X.

Chúng ta có thể viết lại ví dụ trên nhưng sử dụng con trỏ Y hoặc Z thay cho X. Ví dụ viết cho instruction ST cũng hoàn toàn tương tự.

Tuy nhiên cách truy cập theo cách pre hay post đều làm thay đổi giá trị của con trỏ, điều này có 1 bất lợi là nếu chúng ta muốn quay lại vị trí ô nhớ nào đó, chúng ta phải tiếp tục thay đổi con trỏ. Để tránh việc làm này, 1 cách truy cập khác được hỗ trợ là truy cập “Offset”. Xét ví dụ sau:

LD R1, Y+1

Đây chính là cách truy cập Offset dùng con trỏ Y, cách viết trên là tương đương với cách viết

LD R1, Y+

Nhưng điểm khác biệt ở đây là cách viết Offset không làm thay đổi giá trị của con trỏ Y. Sử dụng Offset có ưu điểm như sử dụng mảng (array) trong các ngôn ngữ lập trình cấp cao. Cần chú ý là giá trị offset không vượt quá 63 và phương pháp này chỉ dùng cho 2 thanh ghi Y và Z.

IV. Rẽ nhánh và vòng lặp.

Không giống như các ngôn ngữ cấp cao, khi lập trình bằng ASM bạn không được hỗ trợ các cấu trúc điều khiển như If, For, While…người lập trình ASM phải tự xây dựng cho mình các cấu trúc này từ những instruction cơ bản. Nếu bạn có trong tay

tài liệu tra cứu instruction cho AVR bạn sẽ thấy có rất nhiều instruction có dạng BRxx, với BR là viết tắt của từ Branch (rẽ nhánh). Đây là các instruction cơ bản giúp bạn xây dựng các cấu trúc điều khiển tương đương If, For, While…cho riêng mình.

Trước hết ta sẽ khảo sát instruction BRNE bằng cách xem lại ví dụ trong bài "Làm quen AVR", đây là đoạn chương trình con DELAY:

DELAY:LDI R20, 0xFF LDI R20, 0xFF DELAY0: LDI R21, 0xFF DELAY1: DEC R21 BRNE DELAY1 DEC R20 BRNE DELAY0 RET

Bạn hãy chú ý 4 dòng lệnh nằm giữa đoạn chương trình trên (bắt đầu từ dòng 4), dòng đầu tiên thì bạn đã biết - load giá trị 255 vào thanh ghi R21, sau đó tôi đặt 1 label DELAY1- xem như là 1 cột mốc, dòng 3, instruction DEC bạn mới được học hôm nay - giảm giá trị thanh ghi R21 đi 1 đơn vị, và cuối cùng BRNE DELAY1, BRNE là viết tắt của BRanch if Not Equal – rẽ nhánh nếu không bằng, thực ra bản chất của lệnh này là rẽ nhánh nếu cờ Zero không bằng 1. Như thế câu lệnh BRNE DELAY1 của chúng ta được AVR thực hiện như sau: kiểm tra cờ Z, nếu Z=1 tiếp tục thực hiện dòng tiếp theo sau mà không quan tâm đến nhãn DELAY1, nhưng nếu Z=0 thì nhảy đến nhãn DELAY1. Bạn thấy rằng ban đầu R21 =255, sau khi giảm 1 bởi DEC, thanh ghi R21=254≠0, cờ Z =0, rẽ nhánh xảy ra, bộ đếm chương trình nhảy về nhãn DELAY1. Quá trình này lặp lại khoảng 255 lần trước khi R21 =0 dẫn đến Z=1.

Bao bên ngoài vòng lặp của nhãn DELAY1 là vòng lặp của nhãn DELAY0, cách hiểu hoàn toàn tương tự nhưng trước khi lệnh DEC R20 được thực thi thì phải chờ cho vòng lặp DELAY1 kêt thúc. Bản thân DELAY0 cũng là 1 vòng lặp 255 lần. kết quả cuối cùng là ta thu được 1 vòng lặp khoảng 255x255 lần mà không làm gì cả, đó chính là ý nghĩa và cách hoạt động của đoạn chương trình con DELAY.

Bên cạnh BRNE chúng ta có 1 số instruction phục vụ rẽ nhánh khác như: -BREQ (BRanch if EQual).

• Cú pháp: BREQ LABEL

• Chức năng: Nhảy đến nhãn LABEL nếu cờ Z =1. Cờ Z chịu tác động của rất nhiều instruction như CP, CPI, SUB, SUBI…vì thế

BREQ thường được sử dụng sau các instruction này.

• Ví dụ:

LDI R16, 0xFF LDI R17, 0xFF

CP R16, R17 ; so sanh 2 thanh ghi R16, R17 BREQ RENHANH

…..

RENHANH:

; thực hiện những việc khi rẽ nhánh.

Kết quả là việc rẽ nhánh xảy ra vì khi so sánh bằng CP, R17=R16 nên cờ Z tự động được set bằng 1, lệnh BREQ được thực thi và nhảy đến nhãn RENHANH. Ví dụ này tương đương cấu trúc if (R16=R17) {thực hiện những việc khi rẽ nhánh}. -BRLO (BRanch if LOwer).

• Cú pháp: BRLO LABEL

• Chức năng: bản chất của câu lệnh là nhảy đến nhãn LABEL nếu cờ C =1. Tuy nhiên, thông thường lệnh này sử dụng theo sau các

instruction như CP, CPI, SUB, SUBI…khi đó việc rẽ nhánh sẽ xảy ra nếu thanh ghi Rd

• Ví dụ:

EOR R16, R16 ;XOR R16 với chính nó, tương đương CLR R16 VONG LAP:

INC R16 ;tăng R16 thêm 1 đơn vị

CPI R16, $10 ;so sánh R16 với số hexadecimal $10 BRLO VONGLAP ;nhảy về VONGLAP nếu R16 <$10

NOP ;câu lệnh này sẽ được thực thi nếu điều kiện rẽ nhánh ở trên không thỏa, ; NOP là 1 instruction, chức năng là không làm gì cả.

Kết quả là phần lệnh bên trong VONGLAP sẽ được thưc hiện khoảng 16 lần ($10=16) trước khi thực hiện lệnh NOP.

Một phần của tài liệu bai2.cau truc avr (Trang 37 - 41)