1

我正在使用专有的 8051 板来学习汇编编程。我目前正在开发一个 LCD 'Hello World' 程序。这是代码。

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 时数据应该是什么格式。

我错过了什么愚蠢的事情吗?

谢谢!

4

2 回答 2

1

dptr包含address要显示的文本。所以,如果你#mesg1用类似的东西替换

mov dptr, #045h

您正在从地址 0x45 的内存中输出(随机)内容,这解释了您看到的加扰字符。

为了输出一些十进制值,您需要先将其转换为 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, @dptr而不是clr 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
于 2013-01-10T16:10:18.440 回答
0

在您的代码中, dptr 包含您的代码内存的地址,其中包含您要输出的字符串。因此,如果您将 #mesg1 更改为某个十六进制值,如下所示:

mov dptr, #mesg1

LCD 将尝试写入此十六进制地址上的 ascii 值。而且你不知道它包含什么。为了在 LCD 上输出变量(就像寄存器值一样),您应该尝试:

1 - 您不能使用 DB 指令将变量数据存储在程序存储器中。它不起作用。您应该将变量值写入内部或外部数据存储器。例如,您不能这样做:

   MOV dptr, #mesg1 ;指向mesg1
   ACALL wr_string ; 将 mesg1 写入 LCD

;很多说明...

消息1:
   数据库“我的字符串”            
   DB R1 ;如果 R1 是你的变量          

在上面的例子中,LCD 将只输出 MY STRING,独立于 R1 的值

2 - 您需要将变量的值(二进制、十进制或十六进制)转换为 ASCII。仅对于 0 到 9,这是一项非常容易的任务。只需将十六进制值 30H 添加到您的变量中。因此,例如:

    mov R1, #9H ;如果 R1 是带有某个数字的变量
    MOV A,R1
    添加一个,#30H
    MOV R1, A ;R1 将存储#39H,即数字 9 的 ascii 值

因此,一种选择是将变量拆分为单独的十进制数字,然后将每个数字转换为 ascii。此处的代码执行此操作,并将每个 ascii 值存储在变量 i、j、k 上。

我以前使用两个函数:一个用于从代码内存中读取字符串,该字符串之前由 DB 指令存储,另一个用于从内部存储器中读取变量值:

    lcd_port EQU P1 ;我向LCD发送数据的端口
    data EQU #41H ;内部数据存储器中的一些随机寄存器

    MOV DPTR,#my_string       
    ACALL lcd_string ;此函数将在 LCD 上写入一些字符串

    MOV A, R1 ;如果 R1 是我的变量
    MOV数据,A
    ACALL lcd_dta ;将 R1 值写入 LCD

液晶字符串:
    移动 A,#0x00
    MOVA,@A+DPTR      
    JZ end_lcd_string    
    移动数据,一个          
    调用 lcd_data        
    INC DPTR             
    JMP lcd_string       
end_lcd_string:        
    RET

液晶数据:
    CALL lcd_busy ; 验证 LCD 是否忙,就像你的函数一样
    SETB LCD_RS ;设置 LCD RS 引脚上的位
    SETB LCD_E ;设置 LCD 使能引脚上的位
    MOV lcd_port ;将数据移至 LCD
    CLR LCD_E ;将 LCD 使能引脚设为 0
    RET

我的字符串:
    DB'你好世界'

上述代码应在 LCD 上输出字符串 HELLO WORLD,然后是 R1 值。

于 2015-10-28T22:38:47.367 回答