0

這是我當前有的代碼,當按下按鈕時應該檢測到這些代碼。如果我創建函數,比如我調用同步按鈕函數(getkeysync)的firstmenu函數,那麼程序將工作並返回正確的密鑰。但是,如果我嘗試了異步路由(通過getakey)並遵循此示例,並在程序啓動後約100毫秒按「右鍵」運行它,那麼無論我按住多少鍵,第二個菜單的選項被跳過,然後執行menuthree功能。按鈕不是異步工作的(8051代碼)

我明白menuone,menutwo,menuthree,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 

回答

1

要處理來自不同來源的多個操作,您可以使用狀態機。一個變量定義了狀態。 0可能是初始狀態。菜單級別1可以是1000,2000等,子菜單1100.每次處理程序被調用時,處理程序應該儘快返回。如果處理需要更多時間,請使用計時器和中斷來細分處理時間或使用多個狀態。

主循環調用按鈕和/或傳感器處理程序以及菜單處理程序。當用戶選擇一個菜單時,狀態會發生改變,所以當菜單被再次調用時,它知道該做什麼,再次執行某個動作和/或更改狀態。

通過這種方式,可以更輕鬆地跟蹤發生什麼情況並保持用戶交互異步,並快速響應。

+0

+1思考一種方法來最小化代碼大小。我將嘗試將按鈕處理程序放在主例程中而不是中斷,並查看會發生什麼。 – Mike