เนื่องจาก MCS-51 มี DPTR เพียงตัวเดียวเท่านั้น ในงานบางอย่างเรามีความจำเป็นต้องใช้ Index หลายตัว ซึ่งเราอาจจะแก้ปัญหาได้ด้วยการเก็บค่า Index ให้อยู่ใน Internal RAM และใช้วิธีสลับค่าไปมาระหว่าง DPTR กับค่าใน RAM นั้นซึ่งก็ใช้งานได้ดี แต่อาจจะใช้เวลาอยู่บ้างและค่อนข้างจะต้องเขียนคำสั่งยาวสักหน่อย
เคยอ่านบทความแนะนำของ SILA Research ที่ได้เขียนเป็นบทความแนะนำเทคนิคการเพิ่ม DPTR ไว้ด้วยการนำ Register R0 และ R1 ไว้ดังนี้ครับ
โดยใน MCS-51 จะมีคำสั่งที่เกี่ยวข้องไว้ให้เรียบร้อยแล้วคือ
MOVX A,@R0
MOVX @R0,A
และทั้งสองคำสั่งนี้สามารถใช้ได้กับ r1 ด้วย
ปัญหาอยู่ที่ว่า การนับ Address ขนาด 16 bit จะเป็นไปได้อย่างไรในเมื่อ r0 และ r1 มีค่าเพียง 8 bit เท่านั้น
คำตอบก็คือ MCS-51 จะได้ค่า Address High อีก 8 bit (A8-A15) จากค่าล่าสุดที่ได้มีการอ้างเอาไว้ หรืออีกนัยหนึ่งก็คือเราสามารถกำหนดค่า 8 bit แรกได้โดยการ move ค่าไปไว้ที่ P2 ของ SFR นั่นเอง
ตัวอย่างของ Subroutine ต่อไปนี้จะเขียนโดยใช้ R0 เป็น Index ร่วมกับค่า IXHIGH ซึ่งจะเป็นที่ใดก็ได้ใน Internal Ram และแยกเป็น 4 Subroutine ด้วยกัน จุดสำคัญในการเรียกใช้ก็คือการกำหนดค่า address ครั้งแรก จะต้องกำหนดทั้ง 2 ตัวคือ IXHIGH และ R0
IXWR: MOV P2,IXHIGH
MOVX @R0,A
RET
IXR0: MOV P2,IXHIGH
MOV A,
RET
IXINC: INC R0
CJNE R0,#0,IXINC1
INC IXHIGH
IXINC1: RET
IXDEC: DEC R0
CJNE R0,#0FFH,IXDEC1
DEC IXHIGH
IXDEC1: RET
เมื่อก่อนตอนที่ยังไม่รู้เทคนิคนี้ เวลาที่เขียนโปรแกรมที่ต้องมีการอ่านเขียนข้อมูลกับอุปกรณ์ภายนอกที่ต้องใช้ DPTR เป็นตัวชี้ตำแหน่ง หลายๆ ที่ ก็มักจะต้องใช้การ push และ pop เพื่อเก็บค่า DPH และ DPL ปัจจุบันไว้ก่อนแล้วก็โหลดค่าใหม่เข้าไปเพื่อสลับกันไปมา
หลังจากได้รู้เทคนิควิธีนี้แล้ว ผมได้นำไปทดลองใช้กับการเขียนโปรแกรมเล่นมาบ้างดังตัวอย่างที่ตัดบางส่วนมาให้ดูดังนี้ครับ
การทำงานของโปรแกรมคือผมได้สร้าง data ไว้ที่ memory ส่วนหนึ่งของหน่วยความจำแล้วทำการโหลดค่าของมันเข้ามาที่ acc โดยใช้ r0 เป็นตัวชี้ตำแหน่งของหน่วยความจำ จากนั้นจึงส่งค่าของ acc ออกไปที่ port a, b และ c ของ 8255 โดยใช้ DPTR เป็นตัวชี้ตำแหน่งอย่างเดียว
led_dance: mov p2,#90h
mov r0,#00h
;———————–
lp2: inc r0
movx a,@r0
mov dptr,#port_A
movx @dptr,a
;———————–
inc r0
movx a,@r0
mov dptr,#port_B
movx @dptr,a
;———————–
inc r0
movx a,@r0
mov dptr,#port_C
movx @dptr,a
;———————–
mov r5,#200
lcall dmsec
cjne r0,#081h,lp2
sjmp led_dance
;——————————————————————