Asynchronous 按钮不异步工作(8051代码)

Asynchronous 按钮不异步工作(8051代码),asynchronous,microcontroller,interrupt,interrupt-handling,8051,Asynchronous,Microcontroller,Interrupt,Interrupt Handling,8051,这是我目前拥有的代码,应该在按下按钮时检测。如果我创建了一些函数,比如调用同步按钮函数(getkeysync)的firstmenu函数,那么程序就会运行,并返回正确的键。但是,如果我尝试了异步路由(通过getakey),并遵循此示例,在程序启动大约100毫秒后按“右”按钮运行,那么无论我按住它多少次,第二个菜单的选项都会被跳过,然后执行menuthree函数 我知道menuone、menutwo、MenuTree、menufour和menufive函数尚未实现,但这不是我的问题 有没有办法异步解

这是我目前拥有的代码,应该在按下按钮时检测。如果我创建了一些函数,比如调用同步按钮函数(getkeysync)的firstmenu函数,那么程序就会运行,并返回正确的键。但是,如果我尝试了异步路由(通过getakey),并遵循此示例,在程序启动大约100毫秒后按“右”按钮运行,那么无论我按住它多少次,第二个菜单的选项都会被跳过,然后执行menuthree函数

我知道menuone、menutwo、MenuTree、menufour和menufive函数尚未实现,但这不是我的问题

有没有办法异步解决这个问题?我的意思是,我想在我的菜单中更频繁地使用getakey函数,在用户做出选择之后,我不想让CPU进入一个强制的无止境循环,直到按键被释放

事实上,我希望在轮到用户做出选择时能够处理其他函数(稍后我将创建这些函数)

KCENTER equ 3 ;this value is returned if both left and right keys are pressed at once.
KLEFT equ 2 ;left key pressed value
KRIGHT equ 1 ;right key pressed value
KCENTERH equ 7 ;both left and right keys held down

 mov TL1,#0h ;reset timer reload values
 mov TH1,#0h
 mov TMOD,#22h  ;Timer=0-255
 mov SP,#055h   ;set stack
 setb ET1 ;enable timer interrupt
 setb EA  ;enable all interrupts
 clr TF1 ;clear overflow flag
 setb TR1 ;start timer


firstmenu:
  lcall printfirstmenu ;function (not shown) to display first menu
  lcall getfkey ;stall until key is pressed
  cjne R6,#KCENTER,centerb
  ljmp menufour ;go to menufour if center is pressed
  centerb:
  cjne R6,#KLEFT,leftb
  ljmp menufive ;go to menufive if left is pressed
  leftb:
  cjne R6,#KRIGHT,rightb
  ljmp somemenu ;go to somemenu if right is pressed (this works)
  rightb:


somemenu:
  clr KEYDET ;clear detection
  lcall printamenu ;function (not shown) to display a menu
  menu2:
lcall getakey ;try to get key without stalling. Return 0 if no key.
cjne R6,#KCENTERH,nohold
  ;center key held down
  subb A,#33h ;compare hold time to time it takes to execute 51 interrupts
  jc timelow ;if time is high enough...
  ljmp othermenu ;then go to previous menu
  timelow:
  clr C ;clear carry. If center hold doesn't work, then no other key counts.
nohold:
jnc menu2 ;if no static key is pressed, jump back.
cjne R6,#KCENTER,centerk
  ljmp menuone ;go to menuone if center is pressed
centerk:
cjne R6,#KLEFT,leftk
  ljmp menutwo ;go to menutwo if center is pressed
leftk:
cjne R6,#KRIGHT,rightk
  ljmp menuthree ;go to menuthree if right is pressed (but this always executes without waiting for user input!)
rightk:
  ljmp menu2



InterruptHandler:
  clr EA    ;turn interrupts off
  clr TR1   ;turn timer off
  clr TF1   ;clear timer overflow
  push ACC  ;save A
  push PSW  ;save PSW
  lcall prockey ;run key function
  mov TL1,#0h   ;reset reload counters
  mov TH1,#0h
  pop PSW   ;restore PSW
  pop ACC   ;restore A
  setb EA   ;turn interrupts on
  setb TR1  ;turn timer on
reti    ;exit interrupt

;function getkeysync forces stall until key is returned.
;all key values are stored in R6.

getkeysync:
  clr KEYDET
  getkeysync2:
lcall getakey
  jnc getkeysync2
ret

;Get values and return immediately (async function)
getakey:
  mov R6,GOTKEY
  mov C,KEYDET
  mov A,KEYMD
ret

;process key interrupt
;LKEY and RKEY are independant hardware keys with inverted values.
;values: 0=pressed, 1=not pressed
;the KEYS variable stores bit information of captured keys

prockey:
  mov C,LKEY
  cpl C
  mov KEYS.1,C ;2nd LSB of KEYS is LKEY true value
  mov C,RKEY
  cpl C
  mov KEYS.0,C ;LSB of KEYS is RKEY true value
  mov A,KEYS
  anl A,#3h ;Possible values for A: 0=nothing pressed, 1=Right, 2=left, 3=both.
  jz gotnokey
;key detected as pressed.
clr KEYDET
mov KEYTEMP,#0h
inc KEYHOLD ;increment hold counter once per interrupt call
mov A,KEYHOLD ;if counter goes past 255 then assume key press is valid.
jnz keyend
  ;here, the key is alwats held down for 255 interrupt calls 255 times
  ;and can safely assume the user hit the key (and not debounce)
  setb KEYS.2 ;set flag
  mov KEYHOLD,#0FFh ;set to FF so this section executes continuously until key is let go.
  mov KEYTEMP,KEYS ;copy key value with flag to a temporary variable
  inc KEYMD
  mov A,KEYMD ;increase mega delay counter (keymd) to detect long key presses
  jnz keyend
  mov KEYMD,#0FFh
  ljmp keyend
  gotnokey:
;here the system thinks key wasn't pressed
mov KEYMD,#0h ;reset extended counter
dec KEYHOLD ;lower short key hold counter
mov A,KEYHOLD
inc A
jnz keyend
  ;once hold counter is below zero, reset to zero and detect key
  mov KEYHOLD,#0h
  jnb KEYTEMP.2,keyend
    ;here, keypress is valid
    clr KEYTEMP.2 ;so invalidate the bit
    clr KEYS.2    ;in both variables
    setb KEYDET   ;and set key detection flag
  keyend:
  ;this gets executed at the end of prockey
  mov A,KEYTEMP ;get saved key
  anl A,#7h ;only accept lower 3 bits
  mov GOTKEY,A  ;and set output key variable to it
  jnb KEYDET,noreskey
mov KEYTEMP,#0h ;clear temporary key if key is detected
  noreskey:
ret

要处理来自不同来源的多个操作,可以使用状态机。变量定义状态。0可能是初始状态。菜单级别1可以是1000、2000等,子菜单1100。每次调用处理程序时,处理程序都应尽快返回。如果处理需要更多时间,请使用计时器和中断来细分处理时间或使用多个状态

主循环调用按钮和/或传感器处理程序以及菜单处理程序。当用户选择菜单时,状态会发生变化,因此当再次调用菜单时,它知道要做什么,动作和/或再次改变状态


通过这种方式,可以更轻松地跟踪何时发生的情况,保持用户交互异步,并快速响应。

+1了解如何最小化代码大小。我将尝试将按钮处理程序放在主例程中,而不是中断,然后看看会发生什么。