終于把板子給焊上了,之所以會這么久是因為做好的PCB還必須集運才送來,得十天八天,影響開發速度,軟件方面就容易得多,因為我之前已經做了兩款掃描電子琴琴鍵的軟件,有88鍵的,包含力度感應,相當復雜,當初幸好有網友yzwzfyz指點一番,不然還真做不出來。
現在這個就非常簡單了,只用到8條X線,5條Y線,可檢測40個鍵,所以把舊軟件簡化,用了兩晚就解決了,編程思路如下:
1. 向某一條Y線送出0, 其他保持1,讀取X線的值(8位),這8位有某個按鍵被按下,該位是0。
2. 由于8位連接的按鍵會同時被按下,所以得用移位逐個檢測每個位,并結合Y的值算出是琴上的那個鍵被按下。
3. 確定被按下的鍵必須在記憶區相應的位置設定標記1,然后送出NOTEON的MIDI碼。
4. 沒有按下的鍵也必須在其記憶區相應的位置檢查標記,若為1表示之前已經送出NOTEON,所以必須送出NOTEOFF的MIDI碼,再把標記設為0.
5. 按鍵不必有防抖程序,因為每一次掃描會有間隔,不會出現連續開關的情況,經過測試的確如此。
注:Y線是連接二極管的負極,X線是連接二極管的正極。
無標題123.jpg (259.94 KB, 下載次數: 71)
下載附件
2023-9-29 18:21 上傳
SCANNER: ;鍵盤掃描主程序
;LCALL DELAY3 ;這個試驗時可開,但正式使用要關。
SCANP1: ;輸出到P1,其中一列是0,然后從P2讀入,8位代表列,如某行有按下則為0,否則為1,8行都有可能同時按下。
MOV 35H, #0 ;THIS WILL ADD TO ROW TO MAKE 0-7
MOV 32H, #5 ;8 BITS TO SHIFT
MOV 50H, #11111111B ;THIS BYTE FOR SHIFT AND OUTPUT TO P1
MOV P1, #11111111B ;CLEAR P1 AFTER EVERY BIT SCAN
LCALL DELAY1
CLR C ;PUSH A ZERO INTO 50H AT FIRST ROTATE
SCANP1A:
MOV A, 50H
RLC A ;改用左移,第一次(C=0)被推入,變成11111110,而C變成1,第二次移0被左移,變成11111101
MOV 50H, A ;保留進50H,下次再用
MOV P1, A ;輸出到P1
;MOV P1, #11101111B ;第一步:這個用來檢測每一根輸出線(逐個放0,只有5根線BIT0-BIT4)
LCALL DELAY0 ;稍等
MOV A, P2 ;READ FROM P2
;LCALL SENTONEBYTE1
LCALL EACHDATA
SETB C ;BEFORE LOOP SET C FOR SHIFT ONE TO 50H
MOV P1, #11111111B ;CLEAR P1 AFTER EVERY BIT SCAN
LCALL DELAY1
;LCALL DELAY3
DJNZ 32H, SCANP1A ;5 TIME LOOP
JMP SCANNER
EACHDATA: ;32H 從8逐漸減到1,代表是那一列被設為0,與監測到0的行相乘就得到掃描號碼。
PUSH PSW
MOV 34H, #8 ;8行檢測
MOV 33H, A ;A 是由P2 讀來的8BIT,每個BIT代表一個掃描線與P1那個被設定為0之間的按鍵是否有按下,按下則為零。
EACHDATA1: ;8次重復由34H控制
MOV A, 33H
LCALL COUNTPOSITION ;先算出當前鍵的位置
MOV 3EH, A ;回來后A是按鍵數目
LCALL KEYMAP ;查表得到該按鍵在鍵盤上的排列號碼
MOV 3AH, A ;保存鍵盤號碼到3AH
MOV A, 33H
RLC A ;向左移,檢查C看是1還是0
MOV 33H, A ;SAVE BACK FOR NEXT ROTATE
JNC DOKEY1 ;CONTACT POINT NOT CONTACT GO NOTEOFF SUBROTINE
LCALL NOTEOFFLAH ;NOTE OFF SUBROUTINE
JMP DOKEY2
DOKEY1:
MOV A, 3AH ;按鍵碼
;LCALL SENTONEBYTE1
LCALL NOTEONLAH ;保存區相應位置放1
DOKEY2:
DJNZ 34H, EACHDATA1 ;8 LOOP NEEDED
DOKEYEXIT:
POP PSW
RET
NOTEOFFLAH:
MOV DPH, #0
MOV DPL, 3AH
MOVX A, @DPTR ;READ OLD DATA
JZ NOTEOFFX
MOV A, #0
MOVX @DPTR, A ;標志為1
LCALL SENTNOTEOFF ;送出NOTEOFF,只限一次
NOTEOFFX:
RET
NOTEONLAH:
MOV DPH, #0
MOV DPL, 3AH
MOVX A, @DPTR ;READ OLD DATA
JNZ NOTEONX
MOV A, #1
MOVX @DPTR, A ;標志為1
LCALL SENTNOTEON ;送出NOTEON,只限一次
NOTEONX:
RET
SENTNOTEOFF:
MOV A, #10000000B ;MIDI NOTEOFF CHANNEL1
LCALL SENTONEBYTE1
LCALL SENTONEBYTE2
MOV A, 3AH
LCALL SENTONEBYTE1
LCALL SENTONEBYTE2
MOV A, #0
LCALL SENTONEBYTE1
LCALL SENTONEBYTE2
RET
SENTNOTEON:
MOV A, #10010000B ;MIDI NOTEON CHANNEL1
LCALL SENTONEBYTE1
LCALL SENTONEBYTE2
MOV A, 3AH
ANL A, #01111111B ;MASKING BIT7 音符
LCALL SENTONEBYTE1
LCALL SENTONEBYTE2
MOV A, #7FH ;力度
LCALL SENTONEBYTE1
LCALL SENTONEBYTE2
RET
COUNTPOSITION: ;這個算法不一般
PUSH PSW
MOV A, 32H ;列ROW POSITION 1-8
MOV B, #8 ;8 CONTACT POINT FOR EACH ROW
MUL AB ;得到的數字是 8,16,24,32,40.......128
CLR C
SUBB A, #8 ;MAKE A 0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120
ADD A, 34H ;加上34H 1-8 行COLUME
POP PSW
RET
KEYMAP: ;由于此款排列順序,無需查表,直接運算
MOV A, #50H ;從小變大!
CLR C
SUBB A, 3EH
RET
|