我正在使用专有的8051板来学习汇编编程。我目前正在制作液晶'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时数据应该是什么格式。
我错过了什么蠢事?
谢谢!
答案 0 :(得分: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
答案 1 :(得分: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仅输出MY STRING,独立输出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上。
我以前使用的是两个函数:一个用于从代码存储器读取字符串,一个先前由DB指令存储,另一个用于从内部存储器读取变量值:
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'
以上代码应在LCD上输出字符串HELLO WORLD,然后输出R1值。