TITLE "piano.asm: midi piano trainer @4.0000MHz" LIST p=16C84 ERRORLEVEL 0, -302 ; The piano trainer has a midi input and a 2 lines x 40 characters lcd. ; A piano keyboard is shown. The keys that have to be played next are ; indicated. When those keys have been played the next accord is shown. ; This is useful to learn playing a song (without reading notes) and ; to check whether a song is played with all the required keyhits. ; The device is controlled from the midi piano with two user defined ; keys which are stored in internal EEPROM of the PIC16C84. ; A new song may be recorded to the external 2k-byte serial EEPROM. ; In monitor mode midi data is just displayed in hexadecimal format. ; ; The device has very low power consumption. I use a diode and a 47uF ; capacity to supply the device from the midi output of my keyboard and ; some resistors and an NPN transistor for data signal conditioning. ; Realisation of this circuit will vary depending on the midi output. ; ********** ********** ; * *** * ; NC A2 ** 1 18 ** A1 SCL ; * * ; NC A3 ** 2 17 ** A0 SDA ; * * ; NC A4 ** 3 16 ** Xin X1 ; * * ; pullup MCLR ** 4 15 ** Xout X0 ; * * ; GND ** 5 14 ** VCC ; * * ; RX B0 ** 6 13 ** B7 D7 ; * * ; ENA B1 ** 7 12 ** B6 D6 ; * * ; R/W B2 ** 8 11 ** B5 D5 ; * * ; D/C B3 ** 9 10 ** B4 D4 ; * PIC16C84 * ; *********************** ; ----------------------------------------- GND--01 02--VCC ; | | V0--03 04--D/C ; | | R/W--05 06--ENA ; | LM092 2x40 Char LCD-Module | D0--07 08--D1 ; | | D2--09 10--D3 ; | | D4--11 12--D5 ; ----------------------------------------- D6--13 14--D6 ; ; V0 over 150 Ohm to GND, D0..D3 not used in 4-Bit Mode ; ********** ********** ; * *** * ; NC A0 ** 1 8 ** VCC +5V ; * * ; NC A1 ** 2 7 ** WP GND ; * * ; NC A2 ** 3 6 ** SCL input ; * * ; GND VSS ** 4 5 ** SDA open drain ; * * ; * LM24C16 * ; *********************** ; midi note on: H'9x', H'nn', H'vv' ; channel x=0..15, note nn=0..127, velocity 0 lokey? BTFSS STATUS,C ; GOTO loop0 ; INCF hikey,W ; SUBWF tmp3,W ; <= hikey? BTFSC STATUS,C ; GOTO loop0 ; MOVLW B'00011' ; PCLATH to table data MOVWF PCLATH ; RLF tmp3,F ; set the appropriate bit in buf SWAPF tmp3,W ; ANDLW H'0F' ; ADDLW buf ; BCF INTCON,4 ; disable interrupt MOVWF FSR ; MOVF tmp3,W ; ANDLW H'0E' ; CALL setbit ; BSF INTCON,4 ; enable interrupt GOTO loop0 ; dispkb CALL line0 ; display byte position in ext. eeprom MOVF eeblk,W ; CALL disphex ; MOVF eewrd,W ; CALL disphex ; MOVLW D'36' ; delete to end of line MOVWF pos ; dispkd MOVLW ' ' ; CALL dispch ; DECFSZ pos,F ; GOTO dispkd ; CALL line0 ; mark notes of next accord CLRF pos ; char position MOVLW D'29' ; note counter MOVWF tmp2 ; dispkn MOVLW B'00011' ; PCLATH to table data MOVWF PCLATH ; MOVF pos,W ; CALL getkey ; XORLW H'04' ; white key only? BTFSC STATUS,Z ; GOTO whtkey ; CALL tstbit ; black key only? BTFSS STATUS,C ; GOTO blkkey ; CALL tstbit ; both keys? BTFSS STATUS,C ; GOTO dispkw ; MOVLW H'07' ; mark white and black key GOTO dispkx ; blkkey CALL tstbit ; BTFSS STATUS,C ; GOTO dispke ; MOVLW H'06' ; mark black key GOTO dispkx ; whtkey CALL tstbit ; BTFSS STATUS,C ; GOTO dispke ; dispkw MOVLW H'05' ; mark white key dispkx MOVWF tmp3 ; MOVF pos,W ; ADDLW H'80' ; CALL outcmd ; MOVF tmp3,W ; CALL dispch ; dispke INCF pos,F ; next char position MOVF pos,W ; at line end? XORLW D'40' ; BTFSS STATUS,Z ; GOTO dispkn ; ckplay MOVF lokey,W ; check for terminate key (lokey) XORWF notenr,W ; BTFSC STATUS,Z ; GOTO menu ; MOVLW D'16' ; 16 bytes (128 bits) MOVWF tmp3 ; ckpl0 MOVF tmp3,W ; ADDLW buf-1 ; BCF INTCON,4 ; disable interrupt MOVWF FSR ; MOVF 0,W ; get byte BSF INTCON,4 ; enable interrupt XORLW 0 ; BTFSS STATUS,Z ; GOTO ckplay ; try again if not zero DECFSZ tmp3,F ; GOTO ckpl0 ; next byte GOTO loop0 ; all requested notes played tstbit MOVF tmp2,W ; test note state and return in carry MOVWF tmp1 ; RLF tmp1,F ; get appropriate byte from buf SWAPF tmp1,W ; ANDLW H'0F' ; ADDLW buf ; BCF INTCON,4 ; disable interrupt MOVWF FSR ; MOVF 0,W ; BSF INTCON,4 ; enable interrupt MOVWF tmp0 ; MOVF tmp2,W ; bit nr ANDLW H'07' ; MOVWF tmp1 ; INCF tmp1,F ; tstbit0 RRF tmp0,F ; DECFSZ tmp1,F ; GOTO tstbit0 ; INCF tmp2,F ; select next note RETURN ; mode1 CALL clrdisp ; record song to external eeprom MOVLW '[' ; CALL dispch ; MOVLW msghiky-msg0 ; CALL dispstr ; MOVLW ']' ; CALL dispch ; MOVLW msgsta-msg0 ; CALL dispstr ; CALL waitrx ; MOVF hikey,W ; check for start key (hikey) XORWF notenr,W ; BTFSS STATUS,Z ; GOTO menu ; CALL clrdisp ; record song to external eeprom MOVLW msgrec-msg0 ; CALL dispstr ; loop1 MOVF lokey,W ; check for terminate key (lokey) XORWF notenr,W ; BTFSC STATUS,Z ; GOTO menu ; MOVLW H'93' ; display nr of bytes in ext eeprom CALL outcmd ; MOVF eeblk,W ; CALL disphex ; MOVF eewrd,W ; CALL disphex ; CALL waitrx ; moreky CALL eewrite ; MOVLW D'160' ; set timeout (:4 = ca ms) MOVWF tmp3 ; CLRF RTCC ; BCF INTCON,2 ; waitxx MOVF rdptr,W ; wait for more keys or timeout XORWF wrptr,W ; BTFSC STATUS,Z ; GOTO cktout ; CALL bufrd ; GOTO moreky ; cktout BTFSS INTCON,2 ; check timeout GOTO waitxx ; BCF INTCON,2 ; DECFSZ tmp3,F ; GOTO waitxx ; MOVLW H'FF' ; CALL eewrite ; GOTO loop1 ; mode2 CALL curson ; home2 CALL line0 ; monitor midi data MOVLW D'40' ; MOVWF tmp3 ; loop2 CALL waitrx ; CALL disphex ; MOVWF tmp2 ; store current byte BTFSC tmp2,7 ; test if this is a data byte GOTO mod2cm ; no: command BTFSS state,1 ; 2nd data byte of 'note on' command? GOTO mod2d1 ; MOVLW H'01' ; stay in note on mode MOVWF state ; GOTO mod2ex ; mod2d1 BTFSS state,0 ; 1st data byte of 'note on' command? GOTO mod2ex ; INCF state,F ; next byte will be 2nd data MOVF lokey,W ; check for terminate key (lokey) XORWF tmp2,W ; BTFSC STATUS,Z ; GOTO menu ; GOTO mod2ex ; mod2cm CLRF state ; idle state ANDLW H'F0' ; is it a 'note on' command XORLW H'90' ; BTFSC STATUS,Z ; INCF state,F ; note on state mod2ex DECFSZ tmp3,F ; GOTO loop2 ; GOTO home2 ; intserv MOVWF sav0 ; [8] save working register MOVF STATUS,W ; [9] save status register MOVWF sav1 ; [10] BCF STATUS,P ; [11] set page 0 MOVLW H'80' ; [12] startbit MOVWF rxshft ; [13] MOVLW D'2' ; [14] adjust to poll middle of bits [48] MOVWF bitdly ; [W*3] ints0 DECFSZ bitdly,F ; [.] GOTO ints0 ; [.] ints1 MOVLW D'8' ; [1] bit time delay [32] MOVWF bitdly ; [W*3] ints2 DECFSZ bitdly,F ; [.] GOTO ints2 ; [.] RRF rxshft,F ; [26] shift in new bit BCF rxshft,7 ; [27] BTFSC PORTB,0 ; [28] poll midi in BSF rxshft,7 ; [29] BTFSS STATUS,C ; [30] startbit rotated to carry? GOTO ints1 ; [32] BTFSC mode,1 ; [1] mode=2 ? GOTO bufwr ; [3] BTFSC rxshft,7 ; [3] test if this is a command byte GOTO tstcmd ; [5] BTFSS state,1 ; [5] 2nd data byte of 'note on' command? GOTO tstdat ; [7] MOVF rxshft,F ; [7] note on command if data>0 BTFSC STATUS,Z ; [8] GOTO noteon ; [10] if data=0 stay in note on state BTFSC mode,0 ; [10] mode=1 ? GOTO bufwon ; [12] MOVLW B'00011' ; [12] PCLATH to table data MOVWF PCLATH ; [13] RLF notenr,F ; [14] clear the appropriate bit in buf SWAPF notenr,W ; [15] ANDLW H'0F' ; [16] ADDLW buf ; [17] MOVWF FSR ; [18] MOVF notenr,W ; [19] ANDLW H'0E' ; [20] CALL clrbit ; [26] noteon MOVLW H'01' ; [27] switch to note on state MOVWF state ; [28] intend BCF INTCON,1 ; [29] clr int flag for next startbit MOVF sav1,W ; [30] restore status register MOVWF STATUS ; [31] MOVF sav0,W ; [32] restore working register BCF STATUS,Z ; [33] BTFSC sav1,Z ; [34] restore zero bit BSF STATUS,Z ; [35] RETFIE ; [37] exit (short path for longest code) tstcmd MOVLW H'F0' ; [6] is it a 'note on' command ANDWF rxshft,W ; [7] XORLW H'90' ; [8] BTFSC STATUS,Z ; [9] GOTO noteon ; [11] CLRF state ; [11] switch to idle state GOTO intend ; [13] bufwr MOVF wrptr,W ; [4] write rx data to buf ADDLW buf ; [5] MOVWF FSR ; [6] INCF wrptr,W ; [7] ANDLW H'0F' ; [8] MOVWF wrptr ; [9] MOVF rxshft,W ; [10] MOVWF 0 ; [11] GOTO intend ; [13] bufwon MOVF wrptr,W ; [13] write note on data to buf ADDLW buf ; [14] MOVWF FSR ; [15] INCF wrptr,W ; [16] ANDLW H'0F' ; [17] MOVWF wrptr ; [18] MOVF notenr,W ; [19] MOVWF 0 ; [20] GOTO noteon ; [22] tstdat BTFSS state,0 ; [8] 1st data byte of 'note on' command? GOTO intend ; [10] MOVF rxshft,W ; [10] copy rxshft to notenr MOVWF notenr ; [11] INCF state,F ; [12] GOTO intend ; [14] eeburn MOVWF EEDATA ; W to eeprom at EEADR (set _EECON1,2!) BCF INTCON,4 ; disable interrupt BSF STATUS,P ; set page 1 MOVLW H'55' ; MOVWF _EECON2 ; MOVLW H'AA' ; MOVWF _EECON2 ; BSF _EECON1,1 ; BCF STATUS,P ; set page 0 BSF INTCON,4 ; enable interrupt BSF STATUS,P ; set page 1 eerdy BTFSC _EECON1,1 ; GOTO eerdy ; BCF STATUS,P ; set page 0 RETURN ; waitrx MOVF rdptr,W ; [1] wait here until char received XORWF wrptr,W ; [2] BTFSC STATUS,Z ; [3] GOTO waitrx ; [5] bufrd MOVF rdptr,W ; [1] read data from buf ADDLW buf ; [2] BCF INTCON,4 ; [3] disable interrupt MOVWF FSR ; [4] INCF rdptr,W ; [5] ANDLW H'0F' ; [6] MOVWF rdptr ; [7] MOVF 0,W ; [8] BSF INTCON,4 ; [9] enable interrupt RETURN ; [11] ORG H'1E0' ; 24C16 EEPROM routines eeinc INCFSZ eewrd,F ; select next byte in eeprom 24C16 RETLW 0 ; INCF eeblk,W ; XORLW H'08' ; BTFSC STATUS,Z ; GOTO eeend ; INCF eeblk,F ; RETLW 0 ; eeend DECF eewrd,F ; RETLW H'FF' ; eeread BSF PORTA,SDA ; SDA high GOTO $+1 ; BSF PORTA,SCL ; GOTO $+1 ; GOTO $+1 ; BCF PORTA,SDA ; SDA low (start condition) GOTO $+1 ; GOTO $+1 ; BCF PORTA,SCL ; RLF eeblk,W ; control byte with block address ANDLW H'0E' ; IORLW H'A0' ; CALL eebyte ; send BSF PORTA,SCL ; ignore ack GOTO $+1 ; GOTO $+1 ; BCF PORTA,SCL ; MOVF eewrd,W ; word address CALL eebyte ; send BSF PORTA,SCL ; ignore ack GOTO $+1 ; GOTO $+1 ; BCF PORTA,SCL ; GOTO $+1 ; GOTO $+1 ; BSF PORTA,SDA ; SDA high GOTO $+1 ; BSF PORTA,SCL ; GOTO $+1 ; GOTO $+1 ; BCF PORTA,SDA ; SDA low (start condition) GOTO $+1 ; GOTO $+1 ; BCF PORTA,SCL ; RLF eeblk,W ; control byte with block address ANDLW H'0E' ; IORLW H'A1' ; CALL eebyte ; send BSF PORTA,SCL ; ignore ack GOTO $+1 ; GOTO $+1 ; BCF PORTA,SCL ; BSF STATUS,P ; set page 1 BSF _TRISA,SDA ; data to input BCF STATUS,P ; set page 0 MOVLW H'08' ; bit counter MOVWF tmp1 ; eerd0 BCF STATUS,C ; BSF PORTA,SCL ; clock high GOTO $+1 ; BTFSC PORTA,SDA ; read bit BSF STATUS,C ; BCF PORTA,SCL ; clock low RLF tmp0,F ; DECFSZ tmp1,F ; GOTO eerd0 ; BSF PORTA,SDA ; data low BSF STATUS,P ; set page 1 BCF _TRISA,SDA ; data to output BCF STATUS,P ; set page 0 GOTO $+1 ; BSF PORTA,SCL ; stop condition GOTO $+1 ; GOTO $+1 ; BSF PORTA,SDA ; SDA high (stop condition) CALL eeinc ; MOVF tmp0,W ; result to W RETURN ; eewrite MOVWF tmp2 ; store data BSF PORTA,SDA ; SDA high GOTO $+1 ; BSF PORTA,SCL ; GOTO $+1 ; GOTO $+1 ; BCF PORTA,SDA ; SDA low (start condition) GOTO $+1 ; GOTO $+1 ; BCF PORTA,SCL ; RLF eeblk,W ; control byte with block address ANDLW H'0E' ; IORLW H'A0' ; CALL eebyte ; send BSF PORTA,SCL ; ignore ack GOTO $+1 ; GOTO $+1 ; BCF PORTA,SCL ; MOVF eewrd,W ; word address CALL eebyte ; send BSF PORTA,SCL ; ignore ack GOTO $+1 ; GOTO $+1 ; BCF PORTA,SCL ; MOVF tmp2,W ; data CALL eebyte ; send BSF PORTA,SCL ; ignore ack GOTO $+1 ; GOTO $+1 ; BCF PORTA,SCL ; GOTO $+1 ; GOTO $+1 ; BSF PORTA,SCL ; stop condition GOTO $+1 ; GOTO $+1 ; BSF PORTA,SDA ; SDA high (stop condition) MOVLW D'10' ; CALL delayw ; CALL eeinc ; MOVF tmp2,W ; restore W RETURN ; eebyte MOVWF tmp0 ; write W to I2C bus MOVLW H'08' ; bit counter MOVWF tmp1 ; eebt8 RLF tmp0,F ; BTFSS STATUS,C ; GOTO eebt0 ; GOTO eebt1 ; eebt0 BCF PORTA,SDA ; SDA low GOTO eebt2 ; eebt1 BSF PORTA,SDA ; SDA high GOTO eebt2 ; eebt2 BSF PORTA,SCL ; clock GOTO $+1 ; GOTO $+1 ; BCF PORTA,SCL ; DECFSZ tmp1,F ; GOTO eebt8 ; BCF PORTA,SDA ; SDA low RETURN ; ORG H'270' ; LM092 LCD routines initlcd MOVLW B'00110000' ; bit3..0,dat/cmd,rd/wr,ena,0 MOVWF PORTB ; command, write, ena low BSF STATUS,P ; set page 1 MOVLW B'00000001' ; 7..1 outputs, 0 input MOVWF _TRISB BCF STATUS,P ; set page 0 MOVLW D'20' CALL delayw CALL latch MOVLW D'5' CALL delayw CALL latch MOVLW D'1' CALL delayw CALL latch CALL pollbsy MOVLW B'00100000' ; 4-Bit interface MOVWF PORTB CALL latch MOVLW H'28' ; 4 bit, 2 lines, 5x7 matrix CALL outcmd MOVLW H'08' ; display off CALL outcmd MOVLW H'01' ; display on CALL outcmd MOVLW H'06' ; increment, no shift CALL outcmd CALL curson ; display on, cursor on CALL clrdisp ; clear display, cursor home RETLW 0 delayw MOVWF tmp0 ; delay w * 1000 cycles (w/o call and ret) dlyw0 MOVLW D'249' MOVWF tmp1 dlyw1 NOP DECFSZ tmp1,F GOTO dlyw1 DECFSZ tmp0,F GOTO dlyw0 RETLW 0 latch BSF PORTB,1 ; ena high BCF PORTB,1 ; ena low RETLW 0 pollbsy BSF STATUS,P ; set page 1 MOVLW B'11110001' MOVWF _TRISB ; data inputs BCF STATUS,P ; set page 0 MOVLW B'00000100' ; command, read, ena low MOVWF PORTB pollbs0 BSF PORTB,1 ; ena high (higher nibble) MOVF PORTB,W MOVWF tmp0 BCF PORTB,1 ; ena low BSF PORTB,1 ; latch lower nibble BCF PORTB,1 ; ena low BTFSC tmp0,7 GOTO pollbs0 CLRF PORTB ; ena low, write, command BSF STATUS,P ; set page 1 MOVLW B'00000001' MOVWF _TRISB ; data outputs BCF STATUS,P ; set page 0 RETLW 0 outcmd MOVWF tmp1 ; tmp0 is used by pollbsy CALL pollbsy ; command, write, ena low GOTO outbyte dispch MOVWF tmp1 ; tmp0 is used by pollbsy CALL pollbsy MOVLW B'00001000' ; data, write, ena low outbyte MOVWF PORTB MOVF tmp1,W ; high nibble first ANDLW H'F0' IORWF PORTB,F BSF PORTB,1 ; ena high BCF PORTB,1 ; ena low MOVLW H'0F' ANDWF PORTB,F SWAPF tmp1,W ; low nibble ANDLW H'F0' IORWF PORTB,F BSF PORTB,1 ; ena high BCF PORTB,1 ; ena low MOVF tmp1,W ; restore W RETURN clrdisp MOVLW H'01' ; clear display, cursor home CALL outcmd RETLW 0 curson MOVLW H'0D' ; cursor blink CALL outcmd RETLW 0 cursoff MOVLW H'0C' ; cursor invisible CALL outcmd RETLW 0 line0 MOVLW H'80' ; cursor to line 0 (home) CALL outcmd RETLW 0 line1 MOVLW H'C0' ; cursor to line 1 CALL outcmd RETLW 0 hexchr ANDLW H'0F' ; 0..15 to '0'..'F' MOVWF tmp0 ; store SUBLW D'09' ; check if >= 10 (carry clr) MOVLW D'48' BTFSS STATUS,C ; add 7 if carry clr ADDLW D'07' ADDWF tmp0,W RETURN disphex MOVWF tmp2 ; display as two hex chars, save SWAPF tmp2,W CALL hexchr CALL dispch MOVF tmp2,W CALL hexchr CALL dispch MOVF tmp2,W ; restore RETURN dispstr MOVWF tmp2 ; string display (W is offset from msg0) MOVLW B'00011' ; PCLATH to pattern MOVWF PCLATH MOVF tmp2,W dispst0 CALL message ; get char XORLW 0 ; test if zero BTFSC STATUS,Z RETLW 0 ; return if char is zero CALL dispch ; display INCF tmp2,F ; next char MOVF tmp2,W GOTO dispst0 loadcgr MOVLW B'00011' ; PCLATH to pattern MOVWF PCLATH MOVLW H'40' ; character generator rom CALL outcmd CLRF tmp2 ; byte counter loadcg0 MOVF tmp2,W XORLW D'64' ; test if all 64 bytes out BTFSC STATUS,Z RETLW 0 ; return if so MOVF tmp2,W CALL pattern ; get byte from table, write to cgr CALL dispch INCF tmp2,F ; point to next byte GOTO loadcg0 ORG H'300' ; rom tables message ADDWF PC,F ; return char from table below msg0 RETLW 'm' RETLW 'o' RETLW 'd' RETLW 'e' RETLW '=' RETLW 0 msgcis RETLW '[' RETLW 'C' RETLW '#' RETLW ']' RETLW ' ' RETLW 0 msgset RETLW 's' RETLW 'e' RETLW 't' RETLW 'u' RETLW 'p' RETLW 0 msgsav RETLW 's' RETLW 'a' RETLW 'v' RETLW 'e' RETLW 0 msgm0 RETLW 'p' RETLW 'l' RETLW 'a' RETLW 'y' RETLW 0 msgm1 RETLW 'r' RETLW 'e' RETLW 'c' RETLW 'o' RETLW 'r' RETLW 'd' RETLW 0 msgm2 RETLW 'm' RETLW 'o' RETLW 'n' RETLW 'i' RETLW 't' RETLW 'o' RETLW 'r' RETLW 0 msgloky RETLW 'l' RETLW 'o' RETLW 'w' RETLW 'e' RETLW 's' RETLW 't' RETLW ' ' RETLW 'k' RETLW 'e' RETLW 'y' RETLW 0 msghiky RETLW 'h' RETLW 'i' RETLW 'g' RETLW 'h' RETLW 'e' RETLW 's' RETLW 't' RETLW ' ' RETLW 'k' RETLW 'e' RETLW 'y' RETLW 0 msgsta RETLW ' ' RETLW 's' RETLW 't' RETLW 'a' RETLW 'r' RETLW 't' RETLW 0 msgrec RETLW 'b' RETLW 'y' RETLW 't' RETLW 'e' RETLW 's' RETLW ' ' RETLW '(' RETLW 'm' RETLW 'a' RETLW 'x' RETLW ' ' RETLW '0' RETLW '7' RETLW 'F' RETLW 'F' RETLW ')' RETLW ':' RETLW 0 ;; static small keyboard (40 chars: 41 white keys, 29 black keys) getkey ADDWF PC,F ; return key type of char position msgkey RETLW H'03' ; F# RETLW H'03' ; G# RETLW H'03' ; A# RETLW H'04' ; RETLW H'03' ; C# RETLW H'03' ; D# RETLW H'04' ; RETLW H'03' ; F# RETLW H'03' ; G# RETLW H'03' ; A# RETLW H'04' ; RETLW H'03' ; C# RETLW H'03' ; D# RETLW H'04' ; RETLW H'03' ; F# RETLW H'03' ; G# RETLW H'03' ; A# RETLW H'04' ; RETLW H'03' ; C# RETLW H'03' ; D# RETLW H'04' ; RETLW H'03' ; F# RETLW H'03' ; G# RETLW H'03' ; A# RETLW H'04' ; RETLW H'03' ; C# RETLW H'03' ; D# RETLW H'04' ; RETLW H'03' ; F# RETLW H'03' ; G# RETLW H'03' ; A# RETLW H'04' ; RETLW H'03' ; C# RETLW H'03' ; D# RETLW H'04' ; RETLW H'03' ; F# RETLW H'03' ; G# RETLW H'03' ; A# RETLW H'04' ; RETLW H'03' ; C# RETLW 0 ;; floating big keyboard not implemented (not enough space for code) ; RETLW H'20' ; C ; RETLW H'01' ; C# ; RETLW H'20' ; D ; RETLW H'02' ; D# ; RETLW H'00' ; E ; RETLW H'20' ; F ; RETLW H'01' ; F# ; RETLW H'20' ; G ; RETLW H'02' ; G# ; RETLW H'20' ; A ; RETLW H'02' ; A# ; RETLW H'00' ; B ; RETLW 0 getmsg ADDWF PC,F ; return offset of mode message RETLW msgm0-msg0 RETLW msgm1-msg0 RETLW msgm2-msg0 jmpmod ADDWF PC,F ; goto selected mode GOTO mode0 ; GOTO mode1 ; GOTO mode2 ; pattern ADDWF PC,F ; return char from table below cgrtb0 RETLW B'00001' ; big keyboard: E, B RETLW B'00001' RETLW B'00001' RETLW B'00001' RETLW B'00001' RETLW B'00001' RETLW B'00001' RETLW B'00001' cgrtb1 RETLW B'11110' ; big keyboard: C#, F# RETLW B'11110' RETLW B'11110' RETLW B'11110' RETLW B'11110' RETLW B'00100' RETLW B'00100' RETLW B'00100' cgrtb2 RETLW B'11110' ; big keyboard: D#, G#, A# RETLW B'11110' RETLW B'11110' RETLW B'11110' RETLW B'11110' RETLW B'01000' RETLW B'01000' RETLW B'01000' cgrtb3 RETLW B'00111' ; small keyboard: gap with black key RETLW B'00111' RETLW B'00111' RETLW B'00111' RETLW B'00111' RETLW B'00010' RETLW B'00010' RETLW B'00010' cgrtb4 RETLW B'00010' ; small keyboard: gap w/o black key RETLW B'00010' RETLW B'00010' RETLW B'00010' RETLW B'00010' RETLW B'00010' RETLW B'00010' RETLW B'00010' cgrtb5 RETLW B'00000' ; sel white key on small keyboard RETLW B'00000' RETLW B'00000' RETLW B'10000' RETLW B'10000' RETLW B'10000' RETLW B'10000' RETLW B'10000' cgrtb6 RETLW B'00000' ; sel black key on small keyboard RETLW B'00000' RETLW B'00000' RETLW B'00010' RETLW B'00010' RETLW B'00010' RETLW B'00010' RETLW B'00000' cgrtb7 RETLW B'00000' ; sel white & black key on small keyboard RETLW B'00000' RETLW B'00000' RETLW B'10010' RETLW B'10010' RETLW B'10010' RETLW B'10010' RETLW B'10000' setbit ADDWF PC,F ; set bit from table below BSF 0,0 ; RETLW 0 ; BSF 0,1 ; RETLW 0 ; BSF 0,2 ; RETLW 0 ; BSF 0,3 ; RETLW 0 ; BSF 0,4 ; RETLW 0 ; BSF 0,5 ; RETLW 0 ; BSF 0,6 ; RETLW 0 ; BSF 0,7 ; RETLW 0 ; clrbit ADDWF PC,F ; clear bit from table below BCF 0,0 ; RETLW 0 ; BCF 0,1 ; RETLW 0 ; BCF 0,2 ; RETLW 0 ; BCF 0,3 ; RETLW 0 ; BCF 0,4 ; RETLW 0 ; BCF 0,5 ; RETLW 0 ; BCF 0,6 ; RETLW 0 ; BCF 0,7 ; RETLW 0 ; END;