我刚测定过,空键时扫描一次的时间包括处理为1.584ms, 一键时是1.592ms, 五键同按是1.618ms, 一秒钟能检测到大概500次按键,以电子琴来说速度可以了,这琴键按钮是拆厂家成品电子琴来试的,是16X8的行列,16位两个接口P2P3为输出,8位为输入P0, 所以得根据这样的结构编程, 我在写的时候才发现就算没有什么键按下还得逐个检查记忆体的,因为要查出0FFH再发出noteoff信号,这里面有个忧虑就是担心在检查记忆体时产生时钟中断改变了DPL而读错, 所以开始时先关掉时钟,检查完再开时钟,应该会影响到时钟进位的精度。那个LCALL DELAY2 是个恶梦,不是防抖动用的,原来STC单片机的输出有滞后,在输出0后,再回复1会滞后,造成误读,所以要延时让输出稳定,这现象让我花费了一天时间才发现。关于用IO中断,STC单片机好像没有提供这个功能,无法实现。 这程序若可以用我就会制作一个电路板来试,可以的话就用来取代原来那台电子琴的电路板,变成无线电子琴了。 |
时间中断后,轮查122个计时器。为0的放弃,不为0的+1计时。 扫到第一路键(合理的安排是,61个第一路键放于前两路扫描中;另61个第二路键放在后两路扫描中)置1,扫到第二路键取对应计时器值分析力度,用后清0. |
硬件IO的排列有讲究。你需要用最短的扫描时间,捕捉到是哪个按键按下了。 所以同一个琴键是的两个键,不要放在同一个P口上。 要点: 1、不要用防弹动程序,以节省时间,一次即认可。 2、一次读8个键,无键立即转读下8个键,如此,在无键的情况下,读16次P口即可完成对所有键扫描。 3、如果有键,则再花点时间区分是哪个键,需要起动哪个计时器。 4、另一种更好的方案是,用IO口中断: 正常轮流扫四路通道,中断后先查是哪个Px产生了中断,再查扫描的是哪一路,就能确定是哪个键了。 |
硬件上:你用了5个口,满算是40个IO 你需要:61*2=122个口 建议用:4路扫描,乘以31个口。扫描路数越少,用时越短。这个程序主要矛盾是速度! |
楼主果然聪明,一点就通,悟性好。未来不可限量。祝你春节快乐! |
写了两个晚上才测试妥当,只要逻辑正确,其他可慢慢修改了,这东西难写处在于io口几乎用完,无法用LED灯检查结果,另外运行时T1会中断修改一些寄存器如DPL, 增加调试的困难,无论如何算是写成了,就上载给大家参考了, 再谢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 |
我看你是用汇编写程序的,是真想学好单片机的,故点一下。 |
yzwzfyz你好! 果然有好办法,我这两天试着自己想办法,把计数器的值写在记忆区的笨办法,越写越乱,快要放弃,但作为初学者,这种磨炼还是应该的,现在有好办法了,今晚应该就能写好了,多谢指教。 |
当然-1也可以,看你爱好。 |
你的构思是正确的,精心安排一下是可以实现的。 1、建议你将力度安排为255级,这样一位就够了。 2、时基要重新设计并制作,当计数=255时,设计为最慢的时间,比此时间更慢就不认可。 3、第一个键后计数器设置为1. 4、当计数器=0时,不计数。 5、当计数器<>0时,每个时基+1 6、如此,第二个键时,读到0就作未按处理,不是0就计算速度(力度)。用过了清0。 要点:设计适当的时基,即多久+1. 如果要分得更细,则需增加计数器的位数。 |