2013-01-10 102 views
1

我正在使用專有的8051板來學習彙編編程。我目前正在研究LCD'Hello World'計劃。這是代碼。8051 LCD'Hello World' - 用變量替換DB

lcd_cmd equ 0800h   ;Write COMMAND reg address 0800h 
lcd_st equ 0801h   ;Read STATUS reg address 0801h 
lcd_wr equ 0802h   ;Write DATA reg address 0802h 
lcd_rd equ 0803h   ;Read DATA reg address 0803h 

ORG 08100h 

hello: 
mov P2, #(lcd_cmd SHR 8)   ;load P2 with high address 
mov R0, #(lcd_cmd AND 255)   ;load R0 with command reg addr 
mov R7, #03h      ;set LCD position, line=1, char=3 
mov dptr, #mesg1     ;point to mesg1 
acall wr_string     ;write mesg1 to LCD 

mov R7, #41h      ;set LCD position, line= 2, char=1 
mov dptr, #mesg2     ;point to mesg2 
acall wr_string     ;write mesg2 to LCD 

stop: ajmp stop    ;soft halt 

wr_string: 
acall lcd_busy  ;wait until LCD not busy 
mov a, R7       ;get LCD position 
orl a, #080h      ;msb set for LCD RAM address 
movx @R0, a      ;write lcd_cmd to set line & char 
nxt_char: 
acall lcd_busy     ;wait until LCD not busy 
clr a 
movc a, @a+dptr   
inc dptr       ;point to next byte in string 
jz str_end       ;if 0 then end of string 

mov R1, #(lcd_wr AND 255)   ;Load R1 with wr_data address 
movx @R1, a      ;Write char to LCD 
sjmp nxt_char     ;get next char in string 
str_end: ret 

lcd_busy: 
mov R1, #(lcd_st AND 255)  ;Load R1 with status address 
movx a, @R1       ;read LCD status 
jb acc.7, lcd_busy   ;keep checking until busy bit clear 
ret 

mesg1: db "Hello ",0 
mesg2: db "World ",0 
END 

一切工作正常。但是,我無法向LCD輸出變量。將#mesg1替換爲十六進制值(ascii以簡化事情)只是在屏幕上顯示亂碼字符。因此,每次調用一個只增加一個值的子程序,所以我不確定數據移入dptr時的數據格式。

我錯過了什麼蠢事?

謝謝!

回答

1

dptr包含要顯示的文字的address。所以,如果你的東西替換#mesg1

mov dptr, #045h 

你在地址0×45,這說明你看到亂碼輸出從存儲器(隨機)內容。

爲了輸出一些十進制值,您需要先將其轉換爲ASCII字符串,然後您可以使用現有的wr_string例程來打印它。有關代碼示例,請參見http://www.electro-tech-online.com/microcontrollers/14371-hex-decimal-then-ascii.html(i,j,k包含您的wr_string例程仍需要終止的結果字符串)。


以下代碼顯示了一個類似的例程。 注意wr_string需要進行修改,以讀取XDATA數據,而不是從代碼存儲器(而不是movx a, @dptrclr a/movc a, @a+dptr):

ORG  08100h 

hello: 
    mov  r7, #42  ; value to convert 
    mov  dptr, #buffer ; destination buffer 
    acall str2ascii  ; convert value 

    mov  P2, #(lcd_cmd SHR 8) ; load P2 with high address 
    mov  R0, #(lcd_cmd AND 255) ; load R0 with command reg addr 
    mov  R7, #03h  ; set LCD position, line=1, char=3 
    mov  dptr, #buffer ; point to buffer 
    acall wr_string  ; write buffer to LCD 

... 

str2ascii: 
; Converts a one byte decimal value into its ASCII string representation. 
; Result is prepended with leading zeroes. 
; 0 becomes "000" 
; 42 becomes "042" 
; 255 becomes "255" 
; 
; @param r7 Input value to convert (1 byte, 0 .. 255) 
; @param dptr Destination buffer, at 4 bytes (3 digits plus \0) 
; 
    mov  a, r7 
    mov  b, #100 
    div  ab  ; leftmost digit in a 
    add  a,#30h ; convert to ASCII 
    movx @dptr, a 
    inc  dptr 

    mov  a,b  ; get reminder 
    mov  b,#10 
    div  ab  ; middle digit in a, rightmost digit in b 
    add  a,#30h ; convert to ASCII 
    movx @dptr, a 
    inc  dptr 

    mov  a,b 
    add  a,#30h ; convert to ASCII 
    movx @dptr,a 
    inc  dptr 

    mov  a,#0 
    movx @dptr, a ; terminate string 
    ret 

    xseg 
buffer:  ds 17  ; one LCD line plus terminating \0 

    end 
+0

謝謝,現在的第一點是完全合理的。 但是,我很努力地理解數據應該在哪個寄存器中,以便wr_string可以輸出它。命中率? –

+0

我已經添加了一個代碼示例(以前沒有可用的8051環境,並且不想發佈未經驗證的代碼:-))代碼假定您的主板包含一些外部內存。 (十進制)數據需要在r7中進行轉換。 'wr_string'仍然從@dptr讀取,但需要從XDATA讀取(如果xdata與代碼ram完全相同,但這取決於您的主板,則不需要)。順便說一句:我使用這個IDE,其中包括一個8051模擬器:http://mcu8051ide.sourceforge.net,以防萬一你仍然在尋找一個... –

+0

這是有益的,謝謝!我目前無法進入董事會進行測試,但我認爲我現在可以計算出發生了什麼。 –

0

在你的代碼,DPTR包含有你的代碼存儲器的地址你想要輸出的字符串。所以,如果你改變#mesg1一些十六進制值,如:

mov dptr, #mesg1 

LCD會嘗試寫的ASCII值是這個十六進制地址。你不知道它包含什麼。爲了在LCD上輸出變量(就像寄存器值一樣),您應該嘗試執行以下操作:

1 - 不能使用DB指令在程序存儲器中存儲可變數據。它不起作用。您應該在內部或外部數據存儲器上寫入變量值。例如,你可以這樣做:

 
    MOV dptr, #mesg1     ;point to mesg1 
    ACALL wr_string     ;write mesg1 to LCD 

;LOTS OF INSTRUCTIONS... 

mesg1: 
    DB 'MY STRING'    
    DB R1        ;In case that R1 is your variable   

在上面的例子中,LCD將只輸出我的字符串,R1

的獨立價值

2 - 你需要你的變量的值(其轉換將採用二進制,十進制或十六進制)轉換爲ASCII。只是0到9,這是一個非常簡單的任務。只需在變量中添加十六進制值30H即可。因此,舉例來說:

 
    mov R1, #9H    ;in case that R1 is your variable with some number 
    MOV A, R1 
    ADD A, #30H 
    MOV R1, A     ;R1 will store #39H, which is the ascii value for number 9 

因此,選擇是你的變量分成獨立的十進制數,然後轉換爲ASCII每一個人。 code here這樣做,並將每個ascii值存儲在變量i,j,k上。

我用什麼,是使用兩個功能:

 
    lcd_port EQU P1    ;The port that I send data to LCD 
    data EQU #41H     ;Some random register in internal data memory 

    MOV DPTR, #my_string  
    ACALL lcd_string    ;This function will write on LCD some string 

    MOV A, R1      ;In case that R1 is my variable 
    MOV data, A 
    ACALL lcd_dta     ;Writes R1 value on LCD 

lcd_string: 
    MOV A, #0x00 
    MOVC A, @A+DPTR  
    JZ end_lcd_string  
    MOV DATA, A   
    CALL lcd_data   
    INC DPTR    
    JMP lcd_string  
end_lcd_string:   
    RET 

lcd_data: 
    CALL lcd_busy    ;verify if the LCD is busy, just like your function 
    SETB LCD_RS     ;Set bit on LCD RS pin 
    SETB LCD_E     ;Set bit on LCD Enable pin 
    MOV lcd_port    ;Move your data to LCD 
    CLR LCD_E     ;Turn LCD Enable pin to 0 
    RET 

my_string: 
    DB 'HELLO WORLD' 

以上:一個用於從代碼存儲器讀串,這是以前通過DB指令存儲,並且另一個以從內部存儲器讀出的變量的值代碼應該在LCD上輸出字符串HELLO WORLD,然後是R1值。