You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PIC汇编实现按键按下时LED输出值逐次递增的问题

问题分析&修改方案

原代码为啥只能实现一次递增?核心俩问题:

  1. 用了编译时固定的常量code1,code1+1是死值0x3,每次按键都往PORTB写同一个数,自然没法逐次往上加
  2. 只检测按键的电平状态,没做边沿触发检测,按住按键会一直重复无效操作,而且没处理机械按键的抖动问题

关键修改点

1. 用RAM变量存当前计数值

  • 定义COUNT作为RAM变量(地址0x0C,属于PIC16F84A的通用寄存器区),专门用来存要输出到LED的数值
  • 初始化时把COUNT设为0,同时让PORTB输出0

2. 给按键加边沿检测+消抖

  • 加个PREV_KEY变量存上一次按键的状态,只有当按键从**没按(高电平)变按下(低电平)**的时候,才执行加1操作,按住的时候不会重复触发
  • 加了个Delay_10ms延时子程序,用来消抖,去掉机械按键按下去时的抖动干扰

3. 把固定值改成动态累加

  • 用incf COUNT,F指令让计数值每次加1(这个是修改RAM里的变量,不是固定死的数值)
  • 加完之后把COUNT里的数读到W寄存器,再输出到PORTB

4. 修正按键逻辑

  • 原代码的按键分支搞反了,调整成:RA4高电平是按键没按,低电平是按键按下(符合常用的下拉式按键接法)

修改后的完整代码

LIST P=16F84A
INCLUDE <P16F84A.INC>

; 设置配置位
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC

; 定义通用寄存器:存计数值和按键状态
COUNT   EQU     0x0C
PREV_KEY EQU    0x0D ; 存上一次按键状态,用于检测按下事件

; 主程序 ------------------------------------------------------------
Start
        bsf STATUS, RP0         ; 切到Bank1
        movlw b'11111111'       
        movwf TRISA             ; PORTA全设为输入
        movlw b'00000000'       
        movwf TRISB             ; PORTB全设为输出
        bcf STATUS, RP0         ; 切回Bank0

        movlw d'0'
        movwf COUNT             ; 计数值初始化为0
        movwf PORTB             ; PORTB初始输出0
        movlw b'1'
        movwf PREV_KEY          ; 初始按键状态设为高(未按下)

MainLoop
        btfsc PORTA,4           ; 读RA4当前状态(按下时为低)
        goto Key_Not_Pressed    ; 高电平=没按,跳去处理未按分支

        ; 检测到按键按下,先看是不是刚按下去
        btfsc PREV_KEY,0        ; 检查上一次状态是不是高
        goto Process_Key_Press  ; 上一次是高=刚按下,去处理加1

        goto MainLoop           ; 上一次已经是按下状态,跳过防重复

Process_Key_Press
        ; 按键消抖:等10ms再确认
        call Delay_10ms
        btfsc PORTA,4           ; 再查一次按键是不是还按住
        goto MainLoop           ; 已经弹起=干扰,返回主循环

        ; 执行加1操作
        incf COUNT,F            ; 计数值加1,结果存回COUNT
        movf COUNT,W            ; 把计数值读到W寄存器
        movwf PORTB             ; 输出到PORTB

        movlw b'0'
        movwf PREV_KEY          ; 更新按键状态为按下
        goto MainLoop

Key_Not_Pressed
        btfss PREV_KEY,0        ; 检查上一次是不是按下状态
        goto Reset_Key_State    ; 上一次是按下=现在弹起,重置状态

        goto MainLoop           ; 一直没按,返回主循环

Reset_Key_State
        call Delay_10ms         ; 消抖延时
        btfss PORTA,4           ; 再确认是不是真的弹起
        goto MainLoop           ; 没弹起,返回主循环

        movlw b'1'
        movwf PREV_KEY          ; 更新按键状态为未按下
        goto MainLoop

; 延时子程序:约10ms(4MHz时钟下,指令周期1us)
Delay_10ms
        movlw d'250'
        movwf 0x0E
Delay_Loop1
        movlw d'19'
        movwf 0x0F
Delay_Loop2
        decfsz 0x0F,F
        goto Delay_Loop2
        decfsz 0x0E,F
        goto Delay_Loop1
        retlw 0

end

运行逻辑

  1. 初始化时把PORTA设成输入、PORTB设成输出,计数值和PORTB都设为0
  2. 主循环里盯着RA4:
    • 按键没按的时候,重置按键状态标记
    • 按键刚按下去(确认不是抖动),就把计数值加1,输出到LED
    • 按住按键的时候,不会重复加1,只有松开再按才会触发下一次递增

内容的提问来源于stack exchange,提问作者joepool

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 16:37:48