Anda di halaman 1dari 7

Kỹ thuật bảng

0) Kiến thức cần biết

- Tập lệnh
- Bộ nhớ dữ liệu và bộ nhớ chương trình (Kiến trúc Harvard)
- Con trỏ chương trình
- Tổ chức bộ nhớ của PIC (các BANK)
- Khái niệm Stack

1) Giới thiệu về kỹ thuật bảng

Để hiểu về kỹ thuật bảng, trước tiên chúng ta xem ví dụ sau:

Giả sử chúng ta cần xuất dữ liệu ra màn hình LCD với dãy chữ : “PIC_Tutorial”. Ở
đây, chúng ta không cần quan tâm đến hoạt động của LCD và hình thức xuất dữ liệu
như thế nào. Chỉ cần các bạn nắm được rằng, để xuất dữ liệu như trên ra, chúng ta
phải xuất tuần tự các ký tự “P, I, C, _, T, u, t, o, r, i, a, l” ra. Vậy làm thế nào để xuất
được các chữ này ra?

Ở đây có hai vấn đề, vấn đề thứ nhất là làm sao lưu trữ được các giá trị này, vấn đề
thứ hai là làm sao sắp xếp thứ tự các chữ cái này để chúng ta gọi chúng ra một cách
tuần tự.

Trước tiên, chúng ta giải quyết vấn đề thứ hai trước, bởi vì nó rất đơn giản. Cách giải
quyết là thay vì chúng ta phải tìm các chữ cái trong bảng chữ cái (cả chữ in lẫn chữ
thường) để gọi ra vào đúng thời điểm cần xuất các chữ cái này ra, chúng ta sẽ đánh
dấu các chữ cái này với các chỉ số, và khi gọi thì chúng ta chỉ gọi chỉ số đầu tiên là 0
(hoặc 1, tuỳ theo sự quy định), sau đó, chúng ta cứ tăng chỉ số này lên 1 đơn vị, và
gọi tiếp chữ cái tiếp theo. Công việc này sẽ dừng lại khi nó đạt đến chỉ số cuối cùng.

Tiếp theo, đề giải quyết vấn đề lưu trữ các chữ cái này ở đâu, các bạn cần biết và hiểu
rõ khái niệm về bộ nhớ dữ liệu và bộ nhớ chương trình (hay bộ nhớ lệnh). Các bạn có
thể tham khảo phần bộ nhớ dữ liệu và bộ nhớ chương trình trong phần kiến trúc
Harvard và kiến trúc Von Neumann. Tuy nhiên, chúng ta sẽ nhắc lại rằng, đối với PIC
dòng Mid Range, bộ nhớ chương trình có 14 bit cho mỗi lệnh, vì vậy, cho dù các bạn
thực hiện lệnh nào đi nữa, thì lệnh đó luôn chiếm 14 bit trong bộ nhớ chương trình.
Mặt khác, bộ nhớ dữ liệu thì lại bị giới hạn và một lần tương tác với bộ nhớ dữ liệu,
các bạn phải thông qua thanh ghi W, như vậy, các bạn tốn thêm ít nhất 2 lệnh cho
việc tương tác với thanh ghi W.

Kết quả, cách thông minh nhất là lưu các dữ liệu đó vào trong bộ nhớ chương trình,
thay vì lưu nó vào trong bộ nhớ dữ liệu. Lại nhắc lại về tập lệnh, nếu các bạn để ý kỹ,
các bạn sẽ lại thấy rằng, có một số lệnh cho phép tương tác với giá trị k (8 bit), và giá
trị k này không lưu trữ trong bộ nhớ dữ liệu, mà lưu trong bộ nhớ chương trình.
Tóm lại, kỹ thuật bảng là kỹ thuật lập trình để truy xuất dữ liệu một cách có thứ tự
(thứ tự hiểu theo nghĩa rộng là một quy luật truy xuất nào đó), và khi các dữ liệu đó là
hằng số, thì kỹ thuật này cho phép chúng ta lưu trữ các dữ liệu đó trong bộ nhớ
chương trình, không làm tốn kém bộ nhớ dữ liệu, và việc truy xuất được thực hiện
một cách nhanh nhất.

2) Cách xây dựng bảng

Từ ý tưởng này, có thể có rất nhiều cách lập trình truy xuất dữ liệu bảng. Tuy nhiên,
do sự giới hạn của tài liệu này, chúng tôi chỉ trình bày kỹ thuật bảng tiêu biểu nhất, và
cũng tốt nhất, đồng thời sử dụng tài liệu application note AN556 của Microchip như
một tài liệu tham khảo chính.

Dưới đây là một đoạn code điển hình sử dụng kỹ thuật bảng trong AN556

Trong ví dụ này, chúng ta sẽ phân tích và thấy rằng, từ nhãn [Table] con trỏ chương
trình được cộng với giá trị nằm trong thanh ghi W và lưu lại vào con trỏ chương trình.
Như vậy, vị trí con trỏ chương trình hiện tại đang nằm ở dòng lệnh

addwf PCL, F

Sau khi thực hiện lệnh này PCL = W + PCL


Tiếp theo đó, con trỏ chương trình được tăng thêm một đơn vị; vì mặc định, cứ mỗi
lần thực hiện xong một lệnh, con trỏ chương trình sẽ tăng lên một đơn vị để thực hiện
lệnh tiếp theo.

Giả sử rằng, giá trị nằm trong thanh khi W trước khi nhảy đến nhãn [Table] đang là 1.
Như vậy, con trỏ chương trình sẽ là PCL = 1 + PCL. Có nghĩa là con trỏ chương
trình sẽ nhảy đến dòng lệnh

retlw ‘A’

Tuy nhiên, sau đó, nó mặc định cộng thêm một đơn vị để thực hiện lệnh tiếp theo, và
như vậy, lúc này con trỏ chương trình sẽ nhảy đến dòng lệnh

retlw ‘B’
Như vậy, sau khi thực hiện lệnh addwf, lệnh tiếp theo được thực hiện sẽ là lệnh retlw
‘B’ mà không phải là lệnh retlw ‘A’.

Nhắc lại lệnh RETLW rằng, giá trị k của lệnh sẽ được lưu vào thanh ghi W và sau đó
con trỏ chương trình sẽ nhảy về TOS (top of stack).

Như vậy, thanh ghi W sau khi nhảy về TOS sẽ mang giá trị ‘B’, và chỉ cần thay đổi
giá trị của W trước khi nhảy đến nhãn [Table] chúng ta có thể truy xuất bất kỳ giá trị
nào theo ý chúng ta muốn, vì giá trị của W sau khi trả về sẽ là giá trị ở chỉ số tương
ứng với W ban đầu. Ở đây, chúng ta thấy, giá trị đầu tiên của bảng là ‘A’ sẽ ứng với
chỉ số 0 của W khi nhảy đến bảng.

Chúng ta sẽ gọi giá trị W ban đầu là chỉ số (offset / index) để phân biệt với giá trị W
sau khi trả về. Việc quy định này có thể là hơi muộn trong chương này, nhưng từ nay
về sau, trong các ứng dụng bảng, chúng ta sẽ chỉ quan tâm đến việc thay đổi chỉ số
theo một quy luật nào đó, mà không cần quan tâm nhiều đến giá trị trong bảng nữa.
Chúng ta xem như đã vượt qua giai đoạn đầu của việc xây dựng bảng. Ví dụ trên kia
là ví dụ điển hình nhất cho việc sử dụng bảng.

3) Cách gọi bảng

Bây giờ, chúng ta đã biết cách thiết lập một bảng. Chúng ta hãy tạm gác lại việc sẽ xử
lý dữ liệu bảng ra sao, mà chỉ quan tâm đến việc, nếu biết chỉ số của bảng, làm thế
nào để lấy được giá trị của bảng ra.

Kiến thức về con trỏ chương trình rất cần thiết trong phần này. Do vậy, chúng tôi đề
nghị các bạn xem lại chương về con trỏ chương trình. Ở đây, chúng ta chỉ nhắc lại
rằng, con trỏ chương trình gồm 2 thành phần, PCL và PCH. Trong đó, PCL là 8 bit
thấp, có thể ghi và đọc, còn PCH là 5 bit cao, không thể ghi và đọc, mà chỉ có thể
tương tác một cách gián tiếp qua thanh ghi PCLATH.

Do vậy, khi thay đổi, PCL chỉ có thể mang giá trị từ 0 đến 255 (0x00 đến 0xFF). Nếu
bảng được lập ra mà độ dài bảng lớn hơn 255 thì chúng ta không thể truy xuất được
giá trị cuối cùng trong bảng. Tương tự như vậy, nếu một bảng có độ dài ngắn hơn,
nhưng vị trí bắt đầu của bảng nằm trong vùng từ 0 đến 255, còn vị trí cuối cùng của
bảng lại nằm ngoài 255, thì điều này cũng không thực hiện được.

Khi độ dài bảng, hoặc yêu cầu trình bày chương trình một cách rõ ràng, khiến các bạn
không thể đặt bảng trong bộ nhớ chương trình từ 0 đến 255, các bạn bắt buộc phải
xây dựng 2 bảng riêng biệt.

Trước tiên, chúng ta thực hiện việc gọi bảng thông thường, khi giá trị của bảng nằm
trong vùng từ 0 đến 255 trong bộ nhớ chương trình.
Các bạn vừa làm gì? Các bạn vừa đưa một giá trị được xác định trước từ biến “offset”
vào thanh ghi W. Sau đó các bạn gọi bảng [Table]. Điều đó có nghĩa là các bạn đưa
chỉ số vào trong bảng và gọi bảng.

Chính xác, việc gọi bảng chỉ đơn giản như vậy thôi.

Hoạt động này xảy ra như thế nào?

Nhắc lại rằng, khi chuyển một giá trị vào thanh ghi W, khi gọi bảng [Table], giá trị
trong W sẽ là chỉ số của bảng (xem phần trên), và lệnh địa chỉ của lệnh Call + 1 sẽ
được lưu vào TOS. Như vậy, sau khi thoát khỏi [Table], chương trình sẽ tiếp tục thực
hiện sau lệnh Call. Chúng ta đã biết, sau khi thoát khỏi [Table] giá trị của W sẽ không
phải là chỉ số offset mà chúng ta đưa vào, mà là giá trị của bảng ở vị trí chỉ số offset.
Điều đó có nghĩa là, chúng ta đã lấy được giá trị của bảng ở vị trí có chỉ số chúng ta
đưa vào.

Vậy khi có hai bảng, một bảng nằm trong vùng nhớ 0 đến 255 và một bảng nằm ở địa
chỉ khác?
Với bảng nằm ngoài vùng nhớ từ 0 đến 255, chúng ta phải chuyển con trỏ chương
trình sang PAGE khác bằng cách thay đổi giá trị trong PCH. Tuy nhiên, PCH chỉ có
thể được tương tác một cách gián tiếp qua PCLATH. Do vậy, thay vì tác động vào
PCH, chúng ta tác động vào PCLATH trước khi gọi bảng.

Còn một ví dụ khác để có thể truy cập bảng từ bất kỳ địa chỉ nào, tuy nhiên, chúng tôi
không khuyến khích các bạn mới học sử dụng cách truy xuất này. Hơn nữa, theo kinh
nghiệm thực tế, rất ít khi chúng ta phải lập những bảng quá dài, đến nỗi phải cắt thành
2 bảng hoặc phải đưa các giá trị của bảng sang PAGE khác.

4) Những vấn đề cần lưu ý

a) Xây dựng bảng

Các bạn thấy rằng, khi xây dựng bảng, điều cần thiết nhất là biết được bảng mình xây
dựng ra nằm ở vị trí nào trong bộ nhớ chương trình, để đến khi gọi và viết chương
trình được thuận tiện hơn. Do vậy, điều cần thiết là các bạn phải đánh dấu vị trí bắt
đầu của bảng bằng cách dùng directive ORG 0xAAAA, như ví dụ sau:

ORG 0x80
Table
ADDWF PCL, F
RETLW ‘A’
RETLW ‘B’
RETLW ‘C’
.
.

Như vậy, chúng ta biết được vị trí đầu của bảng, và vị trí cuối của bảng một cách rõ
ràng.

Lời khuyên: Không nên xây dựng bảng nằm ngoài PAGE 0, vì phải mất vài lệnh khác
để điều khiển PCH rồi mới gọi bảng. Trong trường hợp bất khả kháng, nên đặt bảng
trong cùng một PAGE.

b) Gọi bảng

Có chủ yếu ba hình thức gọi bảng. Chúng ta có thể gọi bảng trong PAGE hiện hành
(thường là PAGE 0). Các bạn phải phân biết khái niệm BANK và khái niệm PAGE
thật rõ ràng. Phần này được đề cập trong chương tổ chức bộ nhớ của PIC. Ngoài ra,
chúng ta có thể gọi bảng trong một PAGE khác (ví dụ 2). Trường hợp thứ ba là gọi
một bảng được đặt ở 2 PAGE. Tuy nhiên, trường hợp này chúng tôi không khuyến
khích các bạn sử dụng, và không đề cập trong tài liệu này.

Khi gọi bảng ở một PAGE khác, các bạn phải tương tác với thanh ghi PCLATH để
thay đổi giá trị của PCH.
c) Ghi chú thích cho bảng

Ghi chú cho bảng rất quan trọng. Những ghi chú cần thiết là những ghi chú ban đầu
cho bảng, ghi chú thứ hai là ghi chú cho nội dung của các giá trị trong bảng, ghi chú
thứ ba là ghi chú cho vị trí đầu và vị trí cuối của bảng trong bộ nhớ.

Sau đây là một ví dụ về ghi chú cho bảng


.
.
;----------------------------------------------------------
; Bảng trả về các giá trị mã ASCII của
; bảng chữ cái
; Lưu ý rằng chỉ số đầu tiên để truy cập bảng là 0
; Bảng được đặt trong PAGE 0

ORG 0x80
Table
;----------------------------------------------------------
ADDWF PCL, F ; bắt đầu bảng lại 0x80
RETLW ‘A’ ; ma ASCII cua ‘A’ chỉ số ‘0’
RETLW ‘B’ ; ‘B’ chỉ số ‘1’
RETLW ‘C’ ; ‘C’ chỉ số ‘2’
. ; ket thuc bảng tại 0x83

;----------------------------------------------------------
; Kết thúc bảng chữ cái
;----------------------------------------------------------

Chúng tôi đề nghị các bạn sử dụng cách ghi chú thích này để thống nhất cho tất cả
các chương trình của các bạn. Khi nhìn vào bảng, các bạn chỉ cần quan tâm đến các
giá trị của bảng, mà không cần quan tâm đến các nhãn hoặc vị trí của bảng, nhưng khi
cần tìm thông tin, các bạn biết tìm nó ở đâu.
Nhãn và ORG nên được viết giữa hai dòng ;----- để phân tách khỏi bảng. Chúng ta
nên đặt một chú thích ngắn để xác định vị trí kết thúc bảng.

Chúng ta sẽ sử dụng ký hiệu


;-----------------------------------------------------------
;-----------------------------------------------------------

Để bắt đầu và kết thúc một chương trình con, và dùng ký hiệu :

;==================================
;==================================

Để bắt đầu và kết thúc một đoạn chương trình lớn.


5) Tổng kết chương

Trong chương này, chúng ta đã học và hiểu được bản chất thuật toán xây dựng bảng
bằng MPASM, đó chính là vấn đề lưu các giá trị trong bảng ở đâu, và làm sao xếp thứ
tự cho các giá trị đó. Chúng ta đã biết cách xây dựng bảng và gọi bảng từ bất kỳ vị trí
nào trong bộ nhớ chương trình.

Điều chúng ta quan tâm hơn, đó là làm sao xây dựng được bảng nhiều chiều và bảng
động, dựa vào những ý tưởng của việc xây dựng mảng (array) trong ngôn ngữ lập
trình cấp cao (chúng ta nên dựa vào C++). Phần thuật toán chi tiết sẽ được đề cập
trong tập 2 của cuốn sách.

Cuối cùng, các bạn học được cách ghi chú thích cho một bảng, và cách sắp xếp vị trí
bảng một cách hợp lý trong chương trình.

Anda mungkin juga menyukai