每次按下按钮时,尝试将输出到 LED 的值递增 1。到目前为止我写的代码如下:
LIST P=16F84A
INCLUDE <P16F84A.INC>
; Set configuration bits
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
; Main Program ------------------------------------------------------------
code1 EQU 0x2
Start
bsf STATUS, RP0 ;Go to bank 1
movlw b'11111111' ;
movwf TRISA ;Set the port pin types of the RA
movlw b'00000000' ;
movwf TRISB ;Set the port pin types of the RB
bcf STATUS, RP0 ;Go to bank 0
MainLoop
btfss PORTA,4
goto Button_Is_Off
Button_Is_On
movlw d'0' ; binary value to output on PORTB
movwf PORTB ; output the binary value on PORTB
goto MainLoop
Button_Is_Off
movlw code1+1 ; binary value to output on PORTB
movwf PORTB ; output the binary value on PORTB
goto MainLoop
end ; end of program
我将如何修改它(我相信
movlw code1+1
行)以正确增加值?目前该值增加 1 一次,而不是每次按下按钮。
谢谢
在汇编语言中,每个操作都是使用相关体系结构指令集的指令指定的,在您的情况下是 8 位 PIC 体系结构。
因此,C 语言中的
a = a+1;
或 a++;
之类的操作可以仅使用一条指令完成:汇编语言中的 incf a, F
,这要归功于底层寄存器的同步加/减计数器特性。使用此指令,CPU 读取 a
的实际值,然后递增该值(向上计数),最后将更新后的值写入 a
,因为我们已经使用了 F
标志或位,它告诉 CPU 将更新后的值保存到变量本身(顺便说一句,变量是内置 RAM 的通用寄存器 (GPR) 中的分配位置)。如果我们将 W
标志而不是 F
,CPU 会将更新后的值保存在 W(工作)寄存器中。
但是,如果您使用 1 以外的值来递增变量,例如
a = a + 5
,那么指令将在汇编语言中发生变化,因为没有一个特定的指令可以像前面的示例那样执行这个简单的数学运算。汇编中的操作如下:
movlw 5
addwf a, F
在这段代码中,CPU会执行以下步骤:
a
a
变量中在简要介绍了 PIC 汇编中的值如何递增之后,您必须了解熟悉每条指令的作用对于能够在汇编中编写代码是多么重要。现在让我们回到您现有的代码并根据您希望它执行的所需操作对其进行更新。
据我了解,您希望它在每次按下和释放按钮时都一一计数。但是等待按钮释放来更新输出会有点烦人。这就是为什么我们理想地在检测到按钮按下时立即更新输出,然后等待另一次按下。然而,要做到这一点,还需要按钮释放的知识。为此,我们需要在每个循环中扫描按钮以确定按钮状态,然后相应地更新输出。如您所见,我们正在将问题分解为更小的问题,以逐个或逐步地处理每个问题。这样做,可以更轻松地为每个小问题编写代码,而不是试图一次解决所有问题。
我们遇到的问题:
如果需要,我们甚至可以进一步分解它们。例如,按钮的扫描需要分几步完成。因此,让我们使用伪算法指定步骤:
现在我们设计了一个伪程序流程,我们可以用代码来实现它:
LIST P=16F84A
INCLUDE <P16F84A.INC>
; Set configuration bits
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
; Main Program ------------------------------------------------------------
Start:
bsf STATUS, RP0 ;Go to bank 1
movlw b'11111111' ;
movwf TRISA ;Set the port pin types of the RA
movlw b'00000000' ;
movwf TRISB ;Set the port pin types of the RB
bcf STATUS, RP0 ;Go to bank 0
MainLoop:
; Wait for a button press
btfss PORTA, 4 ; Read the actual input state
goto MainLoop
; A button press is detected
call delay_50ms ; TODO filter the noise out
btfss PORTA, 4 ; confirm that the press is stable
goto MainLoop ; wait for a stable press
; button press is stable, proceed
; update the output
incf PORTB, F ; increment the value of port B
; Now wait for button to be released
waitForButtonRelease:
btfsc PORTA, 4
goto waitForButtonRelease
call delay_50ms ; TODO filter the noise out
btfsc PORTA, 4 ; confirm the release is stable
goto waitForButtonRelease
; button release is stable, loop back to the main and wait for
; a new button press
goto MainLoop
delay_50ms:
; TODO you are encouraged to implement this 50ms delay
return
END
我鼓励您将这个延迟程序实施 50 毫秒。这就是为什么我会把它留空。它可以正常工作,但会立即返回,没有任何延迟(实际上它会产生大约 4 个指令周期的延迟,但这不足以滤除输入噪声)。您可以在谷歌上搜索 pic assembly delay 或使用以下谷歌搜索在 Stackoverflow 中搜索它:pic assembly delay site:stackoverflow.com。你会看到有很多关于这方面的信息。
尝试理解程序流程和逻辑,在 MPLABX 模拟器中逐步模拟它以更好地理解事物。最后,如果您有什么不清楚的地方,请告诉我。