PIC16Fxx 中 LCD 显示的数字
A number to LCD display in assembly in PIC16Fxx
我用的是PIC16
我对如何将汇编中的数字 (binary/hex/decimal) 转换为 ASCII 以显示在 LCD 显示器上感到困惑,例如:
我在寄存器中存储了一个号码
数字 = 0x04d2(十进制为 1234)
0x30 = 0x04
0x31 = 0xd2
我如何将它转换为 ASCII,以便 LCD 在显示屏上显示 1234?
不使用除法。
这是一个用 C 语言编写的示例,但只需稍加改动就可以在汇编中完成同样的操作。
static void Console_printNum(
uint32_t num,
uint8_t base,
uint8_t point)
{
#define CHAR_BUFSIZE 33
const char* const numchars[] = {"0","1","2","3","4","5","6","7","8","9",
"A","B","C","D","E","F"};
const char* buf[CHAR_BUFSIZE];
const char** pStr = &(buf[CHAR_BUFSIZE-1]);
do {
*(--pStr) = numchars[num % base];
num /= base;
} while( num != 0 );
while( pStr < &buf[CHAR_BUFSIZE-1] ) { //copy the buffer into the queue
if((&buf[CHAR_BUFSIZE-1] - pStr) == point) {
Console_printStr("."); //print decimal point
}
Console_printStr(*pStr++);
}
}
要将数字转换为 ASCII,您只需添加 0x30
。
0 十进制 0x30 ASCII
1 个十进制 0x30 ASCII
2 十进制 0x32 ASCII
...
但是当然你必须将你的号码分成一位数。
在 PIC16 汇编程序中,16 位除以 10 就像...
;Input RegA2 as low byte RegA1 as High byte
;Result of division by 10 is stored back to RegA2 and RegA1
;Remainder of division is stored in RegA0
;RegAE is temporary storage
clrf RegA0
movlw 16
movwf RegAE
lslf RegA2, f
divI16by_c10_
rlf RegA1, f
rlf RegA0, f
movlw 10
subwf RegA0, f
btfsc Carry
bra divI16by_c10_OK
addwfc RegA0, f
bcf Carry
divI16by_c10_OK
rlf RegA2, f
decfsz RegAE, f
bra divI16by_c10_
return
直接复制到C语言...
我就是这样做的。
B_HIGH_BYTE 和 B_LOW_BYTE 是你要转换成 ASCII 的数字,这里的其他一切只是一个临时变量
我手动将数字除以 d'10000'、d'1000'、d'100'、d'10',剩下的就是最后一个 :)
可能不是购买满足我需求的最快方式。谢谢大家的建议。
;====================================SPECIAL DIVISION========================
SPECIAL_DIVISION
clrf SPECIAL_DIV_COUNTER
clrf SPECIAL_DIV_HIGH_BYTE
clrf SPECIAL_DIV_LOW_BYTE
clrf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
clrf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movf B_HIGH_BYTE, 0
movwf SPECIAL_DIV_HIGH_BYTE
movf B_LOW_BYTE, 0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD ;getting 5th digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0x10
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+7
movlw 0x27
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD2 ;getting 4th digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0xe8
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+7
movlw 0x03
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD2
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD3 ;getting 3rd digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0x64
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD3
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD4 ;getting 2nd digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0x0a
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD4
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
movf SPECIAL_DIV_LOW_BYTE,0 ;getting 1st digit
addlw 0x30
call display_digit
return
How would i go about to convert it to ASCII so that the LCD would
display the 1234 in the display?
without using division.
"without using division" 是棘手的部分。第一步是将 16 位二进制数转换为 BCD 表示法。最好的可用方法有多个名称,最常见的是 "double dabble" 算法。这是 PIC16F 的示例:
;
; See:
; https://en.wikipedia.org/wiki/Double_dabble
;
BIN2BCD_VAR UDATA
A_reg: res 2
D_reg: res 3
mBits: res 1
BIN2BCD_CODE CODE
;
; Function: Bin2BCD
; Input: A_reg, 16-bit binary
;
; Output: D_reg, 3 bytes of packed BCD digits
;
Bin2BCD:
banksel D_reg
clrf D_reg+0 ; Clear result
clrf D_reg+1
clrf D_reg+2
movlw D'16' ; Set bit counter
movwf mBits
ConvertBit:
movlw H'33' ; Correct BCD value so that
addwf D_reg+0,F ; subsequent shift yields
btfsc D_reg+0,.3 ; correct value.
andlw H'F0'
btfsc D_reg+0,.7
andlw H'0F'
subwf D_reg+0,F
movlw H'33'
addwf D_reg+1,F
btfsc D_reg+1,.3
andlw H'F0'
btfsc D_reg+1,.7
andlw H'0F'
subwf D_reg+1,F
rlf A_reg+0,F ; Shift out a binary bit ...
rlf A_reg+1,F
rlf D_reg+0,F ; ... and into BCD value.
rlf D_reg+1,F
rlf D_reg+2,F
decfsz mBits,F ; Repeat for all bits
goto ConvertBit
return
下一部分是一次将 BCD 表示转换为 ASCII 字符 4 位。
我将把这个工作留给原发帖者。祝你好运。
我用的是PIC16
我对如何将汇编中的数字 (binary/hex/decimal) 转换为 ASCII 以显示在 LCD 显示器上感到困惑,例如:
我在寄存器中存储了一个号码
数字 = 0x04d2(十进制为 1234)
0x30 = 0x04
0x31 = 0xd2
我如何将它转换为 ASCII,以便 LCD 在显示屏上显示 1234?
不使用除法。
这是一个用 C 语言编写的示例,但只需稍加改动就可以在汇编中完成同样的操作。
static void Console_printNum(
uint32_t num,
uint8_t base,
uint8_t point)
{
#define CHAR_BUFSIZE 33
const char* const numchars[] = {"0","1","2","3","4","5","6","7","8","9",
"A","B","C","D","E","F"};
const char* buf[CHAR_BUFSIZE];
const char** pStr = &(buf[CHAR_BUFSIZE-1]);
do {
*(--pStr) = numchars[num % base];
num /= base;
} while( num != 0 );
while( pStr < &buf[CHAR_BUFSIZE-1] ) { //copy the buffer into the queue
if((&buf[CHAR_BUFSIZE-1] - pStr) == point) {
Console_printStr("."); //print decimal point
}
Console_printStr(*pStr++);
}
}
要将数字转换为 ASCII,您只需添加 0x30
。
0 十进制 0x30 ASCII
1 个十进制 0x30 ASCII
2 十进制 0x32 ASCII
...
但是当然你必须将你的号码分成一位数。
在 PIC16 汇编程序中,16 位除以 10 就像...
;Input RegA2 as low byte RegA1 as High byte
;Result of division by 10 is stored back to RegA2 and RegA1
;Remainder of division is stored in RegA0
;RegAE is temporary storage
clrf RegA0
movlw 16
movwf RegAE
lslf RegA2, f
divI16by_c10_
rlf RegA1, f
rlf RegA0, f
movlw 10
subwf RegA0, f
btfsc Carry
bra divI16by_c10_OK
addwfc RegA0, f
bcf Carry
divI16by_c10_OK
rlf RegA2, f
decfsz RegAE, f
bra divI16by_c10_
return
直接复制到C语言...
我就是这样做的。
B_HIGH_BYTE 和 B_LOW_BYTE 是你要转换成 ASCII 的数字,这里的其他一切只是一个临时变量
我手动将数字除以 d'10000'、d'1000'、d'100'、d'10',剩下的就是最后一个 :)
可能不是购买满足我需求的最快方式。谢谢大家的建议。
;====================================SPECIAL DIVISION========================
SPECIAL_DIVISION
clrf SPECIAL_DIV_COUNTER
clrf SPECIAL_DIV_HIGH_BYTE
clrf SPECIAL_DIV_LOW_BYTE
clrf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
clrf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movf B_HIGH_BYTE, 0
movwf SPECIAL_DIV_HIGH_BYTE
movf B_LOW_BYTE, 0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD ;getting 5th digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0x10
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+7
movlw 0x27
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD2 ;getting 4th digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0xe8
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+7
movlw 0x03
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD2
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD3 ;getting 3rd digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0x64
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD3
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
loop_SD4 ;getting 2nd digit
movf SPECIAL_DIV_HIGH_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_HIGH_BYTE
movf SPECIAL_DIV_LOW_BYTE,0
movwf SPECIAL_DIV_PREV_ANS_LOW_BYTE
movlw 0x0a
subwf SPECIAL_DIV_LOW_BYTE,1
btfss STATUS,0
goto $+2
goto $+3
movlw 0x01
subwf SPECIAL_DIV_HIGH_BYTE,1
btfss STATUS,0
goto $+3
incf SPECIAL_DIV_COUNTER
goto loop_SD4
movf SPECIAL_DIV_COUNTER,0
addlw 0x30
call display_digit
clrf SPECIAL_DIV_COUNTER
movf SPECIAL_DIV_PREV_ANS_HIGH_BYTE,0
movwf SPECIAL_DIV_HIGH_BYTE
movf SPECIAL_DIV_PREV_ANS_LOW_BYTE,0
movwf SPECIAL_DIV_LOW_BYTE
movf SPECIAL_DIV_LOW_BYTE,0 ;getting 1st digit
addlw 0x30
call display_digit
return
How would i go about to convert it to ASCII so that the LCD would display the 1234 in the display?
without using division.
"without using division" 是棘手的部分。第一步是将 16 位二进制数转换为 BCD 表示法。最好的可用方法有多个名称,最常见的是 "double dabble" 算法。这是 PIC16F 的示例:
;
; See:
; https://en.wikipedia.org/wiki/Double_dabble
;
BIN2BCD_VAR UDATA
A_reg: res 2
D_reg: res 3
mBits: res 1
BIN2BCD_CODE CODE
;
; Function: Bin2BCD
; Input: A_reg, 16-bit binary
;
; Output: D_reg, 3 bytes of packed BCD digits
;
Bin2BCD:
banksel D_reg
clrf D_reg+0 ; Clear result
clrf D_reg+1
clrf D_reg+2
movlw D'16' ; Set bit counter
movwf mBits
ConvertBit:
movlw H'33' ; Correct BCD value so that
addwf D_reg+0,F ; subsequent shift yields
btfsc D_reg+0,.3 ; correct value.
andlw H'F0'
btfsc D_reg+0,.7
andlw H'0F'
subwf D_reg+0,F
movlw H'33'
addwf D_reg+1,F
btfsc D_reg+1,.3
andlw H'F0'
btfsc D_reg+1,.7
andlw H'0F'
subwf D_reg+1,F
rlf A_reg+0,F ; Shift out a binary bit ...
rlf A_reg+1,F
rlf D_reg+0,F ; ... and into BCD value.
rlf D_reg+1,F
rlf D_reg+2,F
decfsz mBits,F ; Repeat for all bits
goto ConvertBit
return
下一部分是一次将 BCD 表示转换为 ASCII 字符 4 位。
我将把这个工作留给原发帖者。祝你好运。