【问题标题】:How to compare a value to be within one of several ranges using a PIC16F877A如何使用 PIC16F877A 比较一个值是否在多个范围之一内
【发布时间】:2019-10-14 12:05:36
【问题描述】:

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

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

板:来自 ODU 的 uC 培训系统手册修订版 3 微芯片:PIC16F877A 编码语言:MPLAB 中的 ASM (MPASM Assembler 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 中 RANGES 中的电压显示到 LCD 上。任何帮助是极大的赞赏!谢谢!

【问题讨论】:

  • 欢迎来到 Stack Overflow。请阅读the help pagesthe SO tour、阅读how to ask good questions,以及this question checklist。最后请学习如何创建一个您自己尝试的minimal reproducible example,重点放在最小的部分。
  • 版主已暂停此主题。该帖子似乎在要求一件事。这就是如何用汇编语言为 Microchip 的 PIC16F877A 控制器编写整数值的关系测试。
  • @Dan1138:您的编辑是一个很大的改进。现在它不再“太宽泛”了。但现在它可能缺少minimal reproducible example;具有 4 个分支链的代码应该实现 if(x&gt;45) goto somewhere 等等看起来是正确的想法(我不具体了解 PIC,所以他们可能做错了。但 cmets 看起来很明智。)如果这个不起作用,我们需要有关此调试问题实际发生的信息才能成为主题。也许有 PIC 标签专业知识的人可以评论这是否可以重新打开,或者它是否是重复的。
  • @Peter:我现在知道问题中的测试代码有什么问题。用 cmets 来解释它似乎不切实际。如果这个主题被打开,我可以发布答案。
  • @Dan1138:好的,我投票决定重新开放。这种调试问题往往具有非常低的未来价值,至少就实际错误的解释而言,因为人们不知道他们的错误是什么并且无法搜索这个。对于想要像标题所说的那样的 4 范围分支链之一的人来说,它可能很有用。

标签: assembly embedded pic mplab


【解决方案1】:

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

用汇编语言与 PIC16F877A 进行关系比较会给新手带来一些问题。以下是我感到困惑的事情。

PIC16F 不进行有符号运算。

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

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

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

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

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

通过对状态标志行为方式的更清晰描述,工作代码如下所示:

; 
; 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

【讨论】:

  • 你可以用sublw d'21'19 代替,这样你就不需要在==&lt; 上单独分支了吗?
  • @Peter,你是对的,尽管这只是学习汇编语言代码的学生应该被允许发现的优化类型之一。此类问题有多种解决方案。我的似乎最不棘手。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-27
  • 1970-01-01
  • 2012-12-09
  • 1970-01-01
相关资源
最近更新 更多