【问题标题】:Check if number is in range on 8051检查号码是否在 8051 的范围内
【发布时间】:2015-04-08 16:06:35
【问题描述】:

我通过 UART 接收到一个字符,需要验证它是否为数字字符。

通常我会这样做

if (char >= '0' && char <= '9') { /* VALID */ }

但是,我必须在汇编中

我没有找到任何比较指令(所以我假设没有)。

我该怎么做?

    mov A, SBUF    ; load the number

    ; -- pseudocode --
    cmp A, #'0'    ; In AVR, I'd do it this way
    brlt fail      ; but I'm new to 8051
    cmp A, #'9'
    brge fail
    ; -- pseudocode --

    ; number is good

fail:

编辑:好的,这就是我现在拥有的,但它不起作用

;======================================================
; check if r1 is number char -> r0 = 1 or 0
;------------------------------------------------------
fn_isnum:
    PUSH acc
    PUSH 1

    MOV r1,A

    SUBB A,#'0'
    JC isnum_bad

    MOV A,r1

    SUBB A,#'9'+1
    JC isnum_bad

    POP 1
    POP acc

    MOV r0,#1
    RET 

isnum_bad:

    POP 1
    POP acc

    MOV r0,#0
    RET
;======================================================

【问题讨论】:

  • 您可以将SUBBADDJC/JNC 结合使用。提示足够了吗?
  • 是的,我看到了使用进位,然后是 JC 和 JNC 的想法,我只是不太确定该怎么做。
  • 例如,您可以减去'0',如果您有进位,则表示该值较小,因此您应该跳转到无效大小写。同样,减去'9'+1,如果不产生进位,则表示该值大于9,因此再次无效。
  • 你的加减操作可能会设置标志,然后有条件的跳转对其进行操作。
  • 是的,我明白了,谢谢

标签: assembly embedded 8051


【解决方案1】:

使用this techniqueif (a &gt;= '0' &amp;&amp; a &lt;= '9')可以转化为

if ((unsigned char)(a - '0') <= ('9'-'0'))

这可以为您节省比较和跳跃。现在只进行一次比较就足够了

结果可能是这样的

    SUBB A, #'0'  ;  A = a - '0'
    CLR  C
    MOV  R1, A    ; R1 = a - '0'
    MOV  A, #9    ;  A = '9' - '0'
    SUBB A, R1    ;  C = 1 if ('9' - '0') < (a - '0')
    JC   bad:     ; jump when C != 0, i.e. !((a - '0') <= ('9' - '0'))
valid:
    ; do something
bad:

大多数现代编译器都知道如何优化这种范围检查。我找不到 8051 在线编译器,也没有离线编译器,但 AVR 足够接近,可以提供演示。 AVR gcc 为both the original condition and the transformed one 提供相同的输出

    mov r25,r24          ; input in r24
    subi r25,lo8(-(-48)) ; r25 = input - '0'
    ldi r24,lo8(1)       ; r24 = 1
    cpi r25,lo8(10)      ; if r25 < 10
    brlo .L2             ; jump to .L2
    ldi r24,lo8(0)       ; r24 = 0
.L2:
    ret                  ; return value in r24

更新:

Sample output for 8051 来自 SDCC

        mov     r7,dpl
        cjne    r7,#0x30,00110$
00110$:
        jc      00103$
        mov     a,r7
        add     a,#0xff - 0x39
        jnc     00104$
00103$:
        mov     r7,#0x00
        sjmp    00105$
00104$:
        mov     r7,#0x01
00105$:
        mov     dpl,r7
        ret

【讨论】:

    【解决方案2】:

    最简单的方法是用 C 编译它并检查列表文件。这是我的编译器生成的。

    MOV     A, SBUF
    CLR     C
    SUBB    A, #030H
    JC      ?C0026
    MOV     A, SBUF
    SETB    C
    SUBB    A, #039H
    JNC     ?C0026
    
    ; Put instructions here to execute when the code is valid
    
    ?C0026:
    

    【讨论】:

    • 但这不是最优化的方式,需要 2 次检查 + 2 次跳转
    • 如果没有为您优化范围检查,请获得更好的编译器。 GCC 和 clang 使用 phuclv 的答案显示的技术,至少在为主流 CPU 编译时。 (不知道哪一个能针对8051)。
    猜你喜欢
    • 1970-01-01
    • 2023-04-03
    • 2017-07-13
    • 2021-03-30
    • 2016-05-03
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多