熱門(mén): 51單片機(jī) | 24小時(shí)必答區(qū) | 單片機(jī)教程 | 單片機(jī)DIY制作 | STM32 | Cortex M3 | 模數(shù)電子 | 電子DIY制作 | 音響/功放 | 拆機(jī)樂(lè)園 | Arduino | 嵌入式OS | 程序設(shè)計(jì)
![]() |
發(fā)布時(shí)間: 2018-2-13 14:49
正文摘要:各位好! 我是新手,請(qǐng)大家多關(guān)照,最近想設(shè)計(jì)一臺(tái)用STC單片機(jī)做的61鍵無(wú)線藍(lán)牙電子琴,用現(xiàn)成的廉價(jià)電子琴來(lái)改裝,打算直接掃描16X8行列的狀態(tài)加以處理,這部分程序已經(jīng)寫(xiě)好測(cè)試妥當(dāng)了(附程序),由于這是一個(gè) ... |
我剛測(cè)定過(guò),空鍵時(shí)掃描一次的時(shí)間包括處理為1.584ms, 一鍵時(shí)是1.592ms, 五鍵同按是1.618ms, 一秒鐘能檢測(cè)到大概500次按鍵,以電子琴來(lái)說(shuō)速度可以了,這琴鍵按鈕是拆廠家成品電子琴來(lái)試的,是16X8的行列,16位兩個(gè)接口P2P3為輸出,8位為輸入P0, 所以得根據(jù)這樣的結(jié)構(gòu)編程, 我在寫(xiě)的時(shí)候才發(fā)現(xiàn)就算沒(méi)有什么鍵按下還得逐個(gè)檢查記憶體的,因?yàn)橐槌?FFH再發(fā)出noteoff信號(hào),這里面有個(gè)憂慮就是擔(dān)心在檢查記憶體時(shí)產(chǎn)生時(shí)鐘中斷改變了DPL而讀錯(cuò), 所以開(kāi)始時(shí)先關(guān)掉時(shí)鐘,檢查完再開(kāi)時(shí)鐘,應(yīng)該會(huì)影響到時(shí)鐘進(jìn)位的精度。那個(gè)LCALL DELAY2 是個(gè)惡夢(mèng),不是防抖動(dòng)用的,原來(lái)STC單片機(jī)的輸出有滯后,在輸出0后,再回復(fù)1會(huì)滯后,造成誤讀,所以要延時(shí)讓輸出穩(wěn)定,這現(xiàn)象讓我花費(fèi)了一天時(shí)間才發(fā)現(xiàn)。關(guān)于用IO中斷,STC單片機(jī)好像沒(méi)有提供這個(gè)功能,無(wú)法實(shí)現(xiàn)。 這程序若可以用我就會(huì)制作一個(gè)電路板來(lái)試,可以的話就用來(lái)取代原來(lái)那臺(tái)電子琴的電路板,變成無(wú)線電子琴了。 |
參與人數(shù) 1 | 黑幣 +50 | 收起 理由 |
---|---|---|
![]() | + 50 | 回帖助人的獎(jiǎng)勵(lì)! |
時(shí)間中斷后,輪查122個(gè)計(jì)時(shí)器。為0的放棄,不為0的+1計(jì)時(shí)。 掃到第一路鍵(合理的安排是,61個(gè)第一路鍵放于前兩路掃描中;另61個(gè)第二路鍵放在后兩路掃描中)置1,掃到第二路鍵取對(duì)應(yīng)計(jì)時(shí)器值分析力度,用后清0. |
硬件IO的排列有講究。你需要用最短的掃描時(shí)間,捕捉到是哪個(gè)按鍵按下了。 所以同一個(gè)琴鍵是的兩個(gè)鍵,不要放在同一個(gè)P口上。 要點(diǎn): 1、不要用防彈動(dòng)程序,以節(jié)省時(shí)間,一次即認(rèn)可。 2、一次讀8個(gè)鍵,無(wú)鍵立即轉(zhuǎn)讀下8個(gè)鍵,如此,在無(wú)鍵的情況下,讀16次P口即可完成對(duì)所有鍵掃描。 3、如果有鍵,則再花點(diǎn)時(shí)間區(qū)分是哪個(gè)鍵,需要起動(dòng)哪個(gè)計(jì)時(shí)器。 4、另一種更好的方案是,用IO口中斷: 正常輪流掃四路通道,中斷后先查是哪個(gè)Px產(chǎn)生了中斷,再查掃描的是哪一路,就能確定是哪個(gè)鍵了。 |
硬件上:你用了5個(gè)口,滿(mǎn)算是40個(gè)IO 你需要:61*2=122個(gè)口 建議用:4路掃描,乘以31個(gè)口。掃描路數(shù)越少,用時(shí)越短。這個(gè)程序主要矛盾是速度! |
樓主果然聰明,一點(diǎn)就通,悟性好。未來(lái)不可限量。祝你春節(jié)快樂(lè)! |
寫(xiě)了兩個(gè)晚上才測(cè)試妥當(dāng),只要邏輯正確,其他可慢慢修改了,這東西難寫(xiě)處在于io口幾乎用完,無(wú)法用LED燈檢查結(jié)果,另外運(yùn)行時(shí)T1會(huì)中斷修改一些寄存器如DPL, 增加調(diào)試的困難,無(wú)論如何算是寫(xiě)成了,就上載給大家參考了, 再謝yzwzfyz 總工。 ;THIS IS FOR KEYBOARD TESTING ;32H FOR ROW COUNT LOOP ;33H FOR STORE SCAN DATA(MAY CONAIN FEW 0 THAT MEAN CONTACT) ;34H FOR LOOP ;35H FOR ADD TO ROW FORM 1-8 OR 9-16 ;37H FOR LOOP CONVERT ROW NUMBER TO KEYNUMBER ;3AH FOR KEYNUMBER FIRSTBUFFER EQU 80H LASTBUFFER EQU 0FFH BRT EQU 09CH BRTLOAD EQU 226 ;226(18.432, 38400 SMOD=1) 241(18.432, 38400) 250(3.68, 38400) 247(11.0592, 38400), 251(18.432, 115200) S2CON EQU 9AH ;S2SM0, S2SM1, S2SM2, S2REN, S2TB8, S2RB8, S2TI, S2RI IE2 EQU 0AFH ;X, X, X, X, X, X, ESPI, ES2 S2BUF EQU 9BH P4 EQU 0C0H AUXR EQU 8EH AUXR1 EQU 0A2H WAKE_CLKO EQU 08FH ORG 0000H LJMP MAIN ORG 0003H LJMP EXT_INT0 ;EXTERNAL INTERRUPT0 ORG 000BH LJMP TIMER_0 ;TIMER0 INTERRUPT ORG 0013H LJMP EXT_INT1 ;EXTERNAL INTERRUPT1 ORG 001BH LJMP TIMER_1 ;TIMER_1 INTERRUPT ORG 0023H LJMP UART1 ;UART1 RECEIVED INTERRUPT ORG 002BH LJMP ADC ORG 0033H LJMP LVD ORG 003BH LJMP PCA ORG 0043H LJMP UART2 ;UART2 RECEIVED INTERRUPT ORG 004BH LJMP SPI ORG 0100H ; PROGRAM SET MAIN: MOV P0, #0FFH MOV P1, #0FFH MOV P2, #0FFH MOV P3, #0FFH MOV P4, #0FFH ;MOV 97H, #00000101B ;SLOW DOWN MOV WAKE_CLKO,#00000000B ;ENABLE BRT(=4),T1(=2) T0(=1) HAVE CLOCK OUTPUT BRT@P1.0 T1@P3.5 T0@P3.4 MOV BRT, #BRTLOAD ;RELOAD 1152000 MOV AUXR,#01011101B ;T0x12,T1x12,UART_M0x6,BRTRUN,S2SMOD,BRTx12,EXTRAM,S1BRS ;MOV AUXR1, #00010000B ;MOVE UART2 TO TX2=P4.3 RX2=4.2 MOV TMOD, #00010001B ;TIMER_1 AS MOD1 (16BIT COUNTER) ;TIMER_0 AS MOD 1 (16BIT COUNTER) ;GATE, C/T,M1,M0(T1) GATE, C/T,M1,MO(T0) MOV PCON, #10000000B ;THIS DOUBLE THE BRT AND T0 T1 RATE SETB ET1 ;ENABLE T1 INTERRUPT SETB TR1 ;RUN T1 LCALL INITIAL_UART2 ;USE BRT AS SERIAL BAUD GENERATE FOR UART2 SETB EA ;ENAABLE ALL INTERRUPT MOV P2, #10101010B ;SHOW START LCALL CLEANRAM MOV R0, #FIRSTBUFFER ;INIT THE BTYE TO SENT IN BUFFER POINTER MOV R1, #FIRSTBUFFER ;INIT THE POINTER FOR BYTE CAN STORE IN BUFFER SCANNER: SCANP2: ; SHIFT P2 AND READ P0 MOV 32H, #8 ;8 BITS TO SHIFT MOV 50H, #11111111B ;THIS BYTE FOR SHIFT AND OUTPUT TO P2 MOV 35H, #0 ;THIS WILL ADD TO ROW TO MAKE 0-7 CLR C SCANP2A: MOV A, 50H RRC A MOV 50H, A MOV P2, A ;P2 ONE ROW LOW LCALL DELAY4 ;MUST WAIT STABLE MOV A, P0 ;READ FROM P0 CPL A LCALL STOREDATA SCANNEXT1: DJNZ 32H, SCANP2A MOV P2, #11111111B ;END OF SCANP2 SCANP3: ; SHIFT P3 AND READ P0 MOV 32H, #8 ;8 BITS TO SHIFT MOV 50H, #11111111B ;THIS BYTE FOR SHIFT AND OUTPUT TO P2 MOV 35H, #8 ;THIS WILL ADD TO ROW TO MAKE 0-7 CLR C SCANP3A: MOV A, 50H RRC A MOV 50H, A MOV P3, A ;P2 ONE ROW LOW LCALL DELAY4 ;MUST WAIT STABLE MOV A, P0 ;READ FROM P0 CPL A LCALL STOREDATA SCANNEXT2: DJNZ 32H, SCANP3A MOV P3, #11111111B ;END OF SCANP NOP ;CHECK BUFFER AND SENT MOV A, R0 XRL A, R1 JZ SCANNEREXIT ;R0 R1 EQUAL NO NEW BYTE LCALL OUTBUFFER SCANNEREXIT: JMP SCANNER PUTBUFFER: MOV @R1, A CJNE R1, #LASTBUFFER, NEXTR1 MOV R1, #FIRSTBUFFER JMP PUTBUFFEREXIT NEXTR1: INC R1 ;POINT TO NEXT BUFFER PUTBUFFEREXIT: RET OUTBUFFER: MOV A, @R0 LCALL SENTONEBYTE2 CJNE R0, #LASTBUFFER, NEXTR0 MOV R0, #FIRSTBUFFER JMP OUTBUFFEREXIT NEXTR0: INC R0 ;POINT TO NEXT BUFFER OUTBUFFEREXIT: RET STOREDATA: ;32H CONTAIN ROW UMBER THAT CAUSE LOW PUSH PSW MOV 34H, #8 ;8 BIT TO SHIFT MOV 33H, A ;A CONTAIN 8BITS WITH FEW HIGH(CAUSE BY KEYPRESS) STOREDATA1: LCALL COUNTPOSITION ;CODE BY SCANNER 4C 54 COUNT BY LCALL KEYMAP ;RETURN KEYNUMBER A AFTER LOOKUP THE MAP 3D BD MOV 3AH, A ;SAVE KEYNUMBER TO 3AH, 0-127 IS UPPER KEY, 128-255 IS LOWER KEY MOV A, 33H RLC A ;CHECK EACH BIT OF 33H SEE 0 OR 1 AND DECIDE WHERE TO GO MOV 33H, A JNC DOKEY1 ;CONTACT POINT NOT CONTACT GO NOTEOFF SUBROTINE LCALL NOTEON ;NOTEON CHECK JMP STOREDATANEXT DOKEY1: LCALL NOTEOFF ;NOTEOFFCHECK STOREDATANEXT: DJNZ 34H, STOREDATA1 DOKEYEXIT: POP PSW RET NOTEON: CLR TR1 ;TIMER1 STOP MOV A, 3AH RLC A ;CHECK UPPER OR LOWER JC NOTEON1 ;LOWER KEY SO DO OUTPUT ;----------UPPER MOV DPH, #0 MOV DPL, 3AH MOVX A, @DPTR ;READ OLD DATA JNZ NOTEONEXIT ;ALREADY CONTACTED, DO NOTHNG MOV A, #1 MOVX @DPTR, A ;CONTACT JUST START, PUT 1 FOR COUNT UP BY TIMER EVERY 1MS JMP NOTEONEXIT ;----------------- NOTEON1: MOV A, 3AH ANL A, #01111111B ;MASKING BIT7 MOV DPH, #0 MOV DPL, A MOVX A, @DPTR ;READ VELOCITY JZ NOTEONEXIT ;UPPER KEY NOT YET CONTACTED, DO NOTHING MOV 3BH, A ;SAVE VELOCITY INC A JZ NOTEONEXIT ;IF FFH THEN ZERO MEAN NOTE ALREADY OUTPUT, NEED WAIT FOR NOTEOFF, DO NOTHING MOV A, #10010000B ;MIDI NOTEON CHANNEL1 LCALL PUTBUFFER ;SENT KEY NUMBER MOV A, 3AH ANL A, #01111111B ;MASKING BIT7 LCALL PUTBUFFER ;SENT KEY NUMBER MOV A, 3BH LCALL PUTBUFFER ;SENT VELOCITY MOV A, 3AH ANL A, #01111111B ;MASKING BIT7 MOV DPH, #0 MOV DPL, A MOV A, #0FFH MOVX @DPTR, A ;MARK AS FFH WAIT FOR RELEASE AND SENT NOTEOFF NOTEONEXIT: SETB TR1 RET NOTEOFF: CLR TR1 MOV A, 3AH RLC A ;CHECK UPPER OR LOWER JC NOTEOFFEXIT ;LOWER KEY SO DO NOTHING NOP ;UPPER KEY RELEASE, CHECK 0FFH FOR SENT NOTEOFF MOV DPH, #0 MOV DPL, 3AH MOVX A, @DPTR ;READ OLD DATA INC A JNZ NOTEOFFEXIT ;IF FFH THEN ZERO MEAN NO NOTE OFF NEED, DO NOTHING ;--SENT NOTEOFF MOV A, #10000000B ;MIDI NOTEON CHANNEL1 LCALL PUTBUFFER ;SENT KEY NUMBER MOV A, 3AH LCALL PUTBUFFER MOV A, #0 LCALL PUTBUFFER MOV DPH, #0 MOV DPL, 3AH MOV A, #0 MOVX @DPTR, A ;MARK THAT KEY LOCATION 0 TO RECEIVED NEW CONTACT PRESS NOTEOFFEXIT: SETB TR1 RET COUNTPOSITION: PUSH PSW MOV A, 32H ;ROW POSITION 1-8 ADD A, 35H ;IF P2 THEN ADD 0(REMAIN 1-8), IF P3 THEN ADD 8(BECOME 9-16) MOV B, #8 ;8 CONTACT POINT FOR EACH ROW MUL AB ;NUMBER 8,16,24,32,40.......128 CLR C SUBB A, #8 ;MAKE A 0,8,16,24.....120 ADD A, 34H ;34H CONTAIN 1-8 COLUME NUMBER(EACH BIT OF 33H) FORM 1 TO 128 DEC A ;MAKE AS 0-127 SYSTEM POP PSW RET KEYMAP: MOV DPH, #10H MOV DPL, #00H MOVC A,@A+DPTR RET TIMER_1: ;USE FOR MICRO CLOCK 1MS 184, 30 ,100US=248 250 PUSH ACC PUSH PSW MOV 42H, #128 MOV DPH, #0 TIMERLOOP: MOV DPL, 42H MOVX A, @DPTR JZ TIMER_1NEXT CJNE A, #0FFH, TIMERLOOP1 ;NOTEOFF NEED CPL P1.7 JMP TIMER_1NEXT TIMERLOOP1: CJNE A, #0FEH, TIMER_1A ;NOT YET MAX JMP TIMER_1NEXT TIMER_1A: INC A MOVX @DPTR, A TIMER_1NEXT: DJNZ 42H, TIMERLOOP TIMER_1EXIT: MOV TH1, #248 MOV TL1, #250 POP PSW POP ACC RETI SENTONEBYTE2: ;A SENT OUT PUSH ACC MOV IE2, #00H ;DISABLE THE SECONDARY UART INTERRUPT, ES2=0 MOV S2BUF, A ;LOAD A TO BUFFER MOV A, S2CON ;1111,1101, CLEAR SECONDARY UART TRANSIMIT INTERRUPT FLAG ANL A, #0FDH MOV S2CON, A UART2WAIT: MOV A, S2CON ANL A, #02H ;0000,0010 CJNE A,#02H, UART2WAIT MOV A, S2CON ANL A, #0FDH ;1111,1101, CLEAR SECONDARY UART TRANSIMIT INTERRUPT FLAG MOV S2CON, A MOV IE2, #01H ;ENABLE THE SECONDARY UART INTERRUPT, ES2=1 NOP NOP POP ACC RET DELAY4: NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP RET EXT_INT0: ;IF P3.2 H2L COME HERE SET TIMER, ONLY FIRST H2L WILL ACT RETI TIMER_0: ;CHECK INPUT MIDI SIGNAL AT P3.2 RETI EXT_INT1: ;USE FOR INFRA RED RETI INITIAL_UART2: ;USE FOR SENT MIDI DATA MOV S2CON, #01010000B ;SET AS BAUD VERIABLE, NO ODD/EVEN CHECK MOV IE2, #01H ;ENABLE UART2 INTERRUPT RET UART1: RETI ADC: RETI PCA: RETI LVD: RETI SPI: RETI UART2: ;NO READ RETI CLEANRAM: MOV DPH,#0 MOV DPL, #0 CLEANRAM1: MOV A, #0 MOVX @DPTR, A INC DPL MOV A, DPL JNZ CLEANRAM1 CLEANRAMB: MOV DPH,#1 MOV DPL, #0 CLEANRAMB1: MOV A, #0 MOVX @DPTR, A INC DPL MOV A, DPL JNZ CLEANRAMB1 RET ORG 1000H ;KEY MAPPING CONVERT SCANNER NUMBER TO KEYBOARD PHYSICAL POSITION (MUSIC KEY 1-61) ;UPPER-KEY+128=LOWER-KEY ;OPTAIN UPPER CONTACT POINT'S SCAN CODE MANUALLY AND PUT KEYNUMBER AT SCAN CODE POSITION ;OPTAIN LOWER CONTACT POINT'S SCAN CODE MANUALLY AND PUT KEYNUMBER+128 AT SCAN CODE POSITION ; 00H 01H 02H 03H 04H 05H 06H 07H 08H 09H 0AH 0BH 0CH 0DH 0EH 0FH ; --------------------------------------------------------------- DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 0F DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 1F DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 2F DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 3F DB 00H,00H,00H,00H,00H,00H,00H,00H,39H,3AH,3BH,3CH,3DH,00H,00H,00H ;0 80 4F DB 0B9H,0BAH,0BBH,0BCH,0BDH,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 96 5F DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 6F DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 7F DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 8F DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 9F DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 AF DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 BF DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 CF DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 DF DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 EF DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 FF END |
我看你是用匯編寫(xiě)程序的,是真想學(xué)好單片機(jī)的,故點(diǎn)一下。 |
yzwzfyz你好! 果然有好辦法,我這兩天試著自己想辦法,把計(jì)數(shù)器的值寫(xiě)在記憶區(qū)的笨辦法,越寫(xiě)越亂,快要放棄,但作為初學(xué)者,這種磨煉還是應(yīng)該的,現(xiàn)在有好辦法了,今晚應(yīng)該就能寫(xiě)好了,多謝指教。 |
當(dāng)然-1也可以,看你愛(ài)好。 |
你的構(gòu)思是正確的,精心安排一下是可以實(shí)現(xiàn)的。 1、建議你將力度安排為255級(jí),這樣一位就夠了。 2、時(shí)基要重新設(shè)計(jì)并制作,當(dāng)計(jì)數(shù)=255時(shí),設(shè)計(jì)為最慢的時(shí)間,比此時(shí)間更慢就不認(rèn)可。 3、第一個(gè)鍵后計(jì)數(shù)器設(shè)置為1. 4、當(dāng)計(jì)數(shù)器=0時(shí),不計(jì)數(shù)。 5、當(dāng)計(jì)數(shù)器<>0時(shí),每個(gè)時(shí)基+1 6、如此,第二個(gè)鍵時(shí),讀到0就作未按處理,不是0就計(jì)算速度(力度)。用過(guò)了清0。 要點(diǎn):設(shè)計(jì)適當(dāng)?shù)臅r(shí)基,即多久+1. 如果要分得更細(xì),則需增加計(jì)數(shù)器的位數(shù)。 |
你好!是一次過(guò)掃描16X8共128個(gè)接點(diǎn)的狀態(tài),先儲(chǔ)存在記憶區(qū),再讀取記憶區(qū)作處理,有琴鍵按下就向串口發(fā)出MIDI數(shù)據(jù)。再更新記憶區(qū),如果是沒(méi)有力度感的電子琴,那就很簡(jiǎn)單了,有力度感的就要記錄一個(gè)按鍵的兩個(gè)接點(diǎn)的接觸時(shí)間再作運(yùn)算,相當(dāng)麻煩。 |
參與人數(shù) 1 | 黑幣 +20 | 收起 理由 |
---|---|---|
![]() | + 20 | 回帖助人的獎(jiǎng)勵(lì)! |
你的這個(gè)思路存在一定的問(wèn)題。 1、當(dāng)單片機(jī)檢測(cè)到第一按鍵閉合時(shí),啟動(dòng)定時(shí)器,當(dāng)檢測(cè)到第二按鍵閉合時(shí)停止定時(shí)器,定時(shí)器的運(yùn)行數(shù)就是時(shí)間差,不需要計(jì)算。 2、你有這么多的IO嗎?你需要擴(kuò)展,或者需要模擬開(kāi)關(guān)電路如cd4051之類(lèi)的。 |
參與人數(shù) 1 | 黑幣 +20 | 收起 理由 |
---|---|---|
![]() | + 20 | 回帖助人的獎(jiǎng)勵(lì)! |
Powered by 單片機(jī)教程網(wǎng)