首页 > 解决方案 > 如何使用 PIC16F877A 比较一个值是否在多个范围之一内

问题描述

作业问题: 保持与作业#1 相同的所有内容,设计一个可以读取电位器设置并在 LCD 模块上显示高、中、低实时电压范围的系统。您的程序应显示实时电压 High=4.5 V 及以上,Medium=2.0V 和 3.0V 之间,Low=1.5V 及以下,并每 5 秒更新读数和显示以反映电位器上的变化。如果电压不在范围内,则 LCD 上显示“未知”。

我已经让 ASM 做所有事情,但能够为范围做“大于”、“小于”。我可以看到如何在 PIC 的 C 代码中执行此操作,但在 ASM 中看不到。任何帮助,将不胜感激。

开发板:ODU Microchip 的 uC 培训系统手册第 3 版:PIC16F877A 编码语言:MPLAB 中的 ASM(MPASM 汇编程序 v5.50)

简化的测试代码只关注范围比较:

; 
; File: main.asm
; Target: PIC16F877A
; 
; Description:
;   Simplified range compare test code
; 
    #include <P16F877A.INC>


    __CONFIG  0x3F32                ;This is the control bits for CONFIG register

    ORG     0x0000                  ;RESET or WDT reset vector
    GOTO    START

    ORG     0x0004                  ;Regular INT vector

;This is the area where your interrupt service routine goes

    RETFIE
;
;Table of messages
;
Message_High:
    DT "High"
Message_Mid:
    DT "Mid"
Message_Low:
    DT "Low"
Message_Unknown:
    DT "Unknown"

ValueToCheck EQU    0x20

START:                              ;The starting place of the user codes

    banksel ValueToCheck
    clrf    ValueToCheck

TestLoop:
    movf    ValueToCheck,W
    sublw   d'45'                   ; Do calculation: WREG - ValueToCheck
    btfsc   STATUS,C                ; CARRY not set so ValueToCheck < 45
    goto    ShowHigh

    movf    ValueToCheck,W
    sublw   d'30'                   ; Do calculation: WREG - ValueToCheck
    btfsc   STATUS,C                ; CARRY not set so ValueToCheck < 30
    goto    ShowUnknown

    movf    ValueToCheck,W
    sublw   d'20'                   ; Do calculation: WREG - ValueToCheck
    btfsc   STATUS,C                ; CARRY not set so ValueToCheck < 20
    goto    ShowMid

    movf    ValueToCheck,W
    sublw   d'15'                   ; Do calculation: WREG - ValueToCheck
    btfsc   STATUS,C                ; CARRY not set so ValueToCheck < 15
    goto    ShowUnknown

ShowLow:
    movlw   Message_Low             ; Load WREG with message pointer
    goto    ShowMessage

ShowMid:
    movlw   Message_Mid             ; Load WREG with message pointer
    goto    ShowMessage

ShowHigh:
    movlw   Message_High            ; Load WREG with message pointer
    goto    ShowMessage

ShowUnknown:
    movlw   Message_Unknown         ; Load WREG with message pointer
ShowMessage:
;
; This is test code so no output
;
    nop     ; With breakpoint here. WREG not loaded with expected message pointer.
;
;
;
    incf    ValueToCheck,F
    goto    TestLoop

    END                             ;End program

我只需要帮助弄清楚如何让程序将 ASM 中范围内的电压显示到 LCD 上。任何帮助是极大的赞赏!谢谢你!

标签: assemblyembeddedpicmplab

解决方案


首先,我要感谢 Peter Cordes 重新讨论这个话题。我们将看看我的回答是否值得。

用汇编语言与 PIC16F877A 进行关系比较会给新手带来问题。以下是我发现令人困惑的事情。

PIC16F 不进行有符号运算。

减法指令通过断言 NOT CARRY 来指示 BORROW。

操作码“SUBLW”让我对减法的顺序感到困惑。

从数据表中,我发现 CARRY 和 ZERO 标志是以下结果: (k - WREG) 用于文字常量“k”。

“SUBLW k”语句之后的文字常量“k”和 WREG 之间的关系在状态标志中表示为:

  • 零设置,当'k' = WREG 时设置进位
  • ZERO 清零,当 'k' > WREG 时设置 CARRY
  • ZERO 清零, 'k' < WREG 时 CARRY 清零

通过对状态标志如何表现的更清晰的描述,工作代码如下所示:

; 
; File: main.asm
; Target: PIC16F877A
; 
; Description:
;   Simplified range compare test code
;
;   Bugs corrected 2019-NOV-05
; 
    #include <P16F877A.INC>


    __CONFIG  0x3F32                ;This is the control bits for CONFIG register

    ORG     0x0000                  ;RESET or WDT reset vector
    GOTO    START

    ORG     0x0004                  ;Regular INT vector

;This is the area where your interrupt service routine goes

    RETFIE
;
;Table of messages
;
Message_High:
    DT "High"
Message_Mid:
    DT "Mid"
Message_Low:
    DT "Low"
Message_Unknown:
    DT "Unknown"

ValueToCheck EQU    0x20

START:                              ;The starting place of the user codes

    banksel ValueToCheck
    clrf    ValueToCheck

TestLoop:
    movf    ValueToCheck,W
    sublw   d'45'                   ; Do calculation: 45 - ValueToCheck
    btfss   STATUS,Z                ; ZERO  set so ValueToCheck = 45
    btfss   STATUS,C                ; CARRY set so ValueToCheck < 45
    goto    ShowHigh                ; When ValueToCheck >= 45

    movf    ValueToCheck,W
    sublw   d'30'                   ; Do calculation: 30 - ValueToCheck
    btfss   STATUS,C                ; CARRY set so ValueToCheck < 30
    goto    ShowUnknown             ; When 30 > ValueToCheck < 45

    movf    ValueToCheck,W
    sublw   d'20'                   ; Do calculation: 20 - ValueToCheck
    btfss   STATUS,Z                ; ZERO  set so ValueToCheck = 20
    btfss   STATUS,C                ; CARRY set so ValueToCheck < 20
    goto    ShowMid                 ; When 20 >= ValueToCheck <= 30

    movf    ValueToCheck,W
    sublw   d'15'                   ; Do calculation: 15 - ValueToCheck
    btfss   STATUS,C                ; CARRY set so ValueToCheck <= 15
    goto    ShowUnknown             ; When 15 > ValueToCheck < 20

ShowLow:                            ; When ValueToCheck <= 15
    movlw   Message_Low             ; Load WREG with message pointer
    goto    ShowMessage

ShowMid:
    movlw   Message_Mid             ; Load WREG with message pointer
    goto    ShowMessage

ShowHigh:
    movlw   Message_High            ; Load WREG with message pointer
    goto    ShowMessage

ShowUnknown:
    movlw   Message_Unknown         ; Load WREG with message pointer
ShowMessage:
;
; This is test code so no output
;
    nop     ; With breakpoint here. WREG now loaded with expected message pointer.
;
;
;
    incf    ValueToCheck,F
    goto    TestLoop

    END                             ;End program

推荐阅读