📄 pckb.asm
字号:
; AllNotesOff - subroutine
; 1) Put Note_Available sentinel into the SRAM MIDI note bank for all possible notes.
; This indicates that all possible note spaces are available because all notes are off.
; 2) Send the All_Notes_Off MIDI control message to the synthesizer.
; 3) return to the GetChar routine
;*********************************************************************************************
AllNotesOff:
clr ZH
ldi ZL,SoundingNotes - 1
ldi temp, POSSIBLE_NOTES
mov regcnt, temp
; Put Note_Available sentinel into every location of the SRAM MIDInote bank.
ANO1: inc zl
; ld DecodeValue,z
; sub DecodeValue, OctaveOffset
; ldi velocity, NOTE_OFF_VELOCITY
; rcall NoteOnMessage
ldi temp, REGISTER_AVAILABLE
st z,temp
dec regcnt
brne ANO1 ; make every SRAM MIDI note location available for new notes at space-bar press
ldi temp, MIDI_CONTROLLER_MSG
mov TxData, temp
rcall putMIDI
ldi Temp, ALL_NOTES_OFF_BYTE
mov TxData, temp
rcall putMIDI
clr TxData
rcall putMIDI
ret
; *********************************************************************************************
; ChangeVoice - subroutine -- receives 'CurrentVoiceNumber' register with the MIDI voice number (00-7f)
; 1) Put Note_Available sentinel into the register bank for all possible notes.
; This indicates that all possible note spaces are available because all notes are off.
; 2) Send the MIDI program change message to the synthesizer. This will turn off all
; sounding notes for the selected MIDI channel (channel 1 by default).
;
;*********************************************************************************************
ChangeVoice:
clr ZH
ldi ZL,SoundingNotes - 1
ldi temp, POSSIBLE_NOTES
mov regcnt, temp
ser temp
CV1: inc zl ;a change voice command turns off all sounding notes
st z,temp
dec regcnt
brne CV1 ; make all storage registers available for new notes when voice changes
ldi temp, CHANGE_VOICE_MSG
mov TxData, temp
rcall putMIDI
mov TxData, CurrentVoiceNumber
rcall putMIDI
ret
;*********************************************************
;. playMIDInote subroutine -- receives the Keypress offset in 'DecodeValue'.
; To this value gets added the Octave offset value to get the final MIDI note number.
;
; receives: keyflags, DecodeValue
; registers used: TxData
playMIDInote:
; if the OctaveOffset is not added to the MIDI note value before this value is stored into the SoundingNotes array,
; then every note that is one or more octaves above or below that note will not be able to be sounded.
add DecodeValue, OctaveOffset
ldi temp, 44
add temp, OctaveOffset
cp DecodeValue, temp
brsh PMN_Out
clr ZH
ldi ZL,SoundingNotes - 1
ldi temp, POSSIBLE_NOTES
mov regcnt, temp
PMN1: inc zl ; first check SRAM array of SoundingNotes to see if the note is already playing
ld temp,z
cp temp, DecodeValue
breq PMN_Out ; found identical note number, which means that the Note had been already playing.
; The key was held down long enough trigger typematic auto-repeat.
dec regcnt
breq NewNote
rjmp PMN1
; the DecodeValue is not the number of a MIDI note being sounded
NewNote: ldi ZL,SoundingNotes - 1
ldi temp, POSSIBLE_NOTES
mov regcnt, temp
PMN2: inc zl
dec regcnt
breq PMN_Out
; now check the SRAM array of SoundingNotes to see if there is a voice available
ld temp,z ; to play the new note
cpi temp,REGISTER_AVAILABLE
brne PMN2
st z,DecodeValue
ldi velocity, NOTE_ON_VELOCITY
rcall NoteOnMessage
PMN_Out:
ret
;*********************************************************
;. TurnOffMIDInote -- subroutine
; receives: keyflags, DecodeValue
; registers used: TxData,keyflags, regcnt
TurnOffMIDInote:
; if the OctaveOffset is not added to the MIDI note value before this value is stored into the SoundingNotes array,
; then every note that is one or more octaves above or below that note will not be able to be sounded.
add DecodeValue, OctaveOffset
; Search the SRAM array from the beginning to find the note that corresponds to the key that was just released.
clr ZH ; set up Z pointer to the beginning of the SRAM array
ldi ZL,SoundingNotes - 1
ldi temp, POSSIBLE_NOTES ; size of the SRAM array
mov regcnt, temp
ToMN1: inc zl
ld temp, z ; test each value in the SRAM array to see if it is the note
cp temp, DecodeValue
breq ToMN2 ; found it, now turn it off
dec regcnt
breq ToMN_Out
rjmp ToMN1 ; note was not found in this SRAM location, so check next location in the array
ToMN2: ; found note number in SRAM array storage, so send the MIDI Note-Off message to the synthesizer
ser temp ; put the Note_Available sentinel into the SRAM array position that held the note being turned off.
st z,temp ; let program that this reg is available
sbrc keyflags, Caps_Flag
rjmp toMN_Out
ldi Velocity, NOTE_OFF_VELOCITY
rcall NoteOnMessage
ToMN_Out: ret
NoteOnMessage:
ldi temp,NOTE_ON_MSG
mov TxData, temp
rcall putMIDI
mov TxData,DecodeValue
rcall putMIDI
mov TxData, Velocity
rcall putMIDI
ret
;***************************************************************************
;*
;* "putMIDI" Data bits are fed to an output using a timing loop, not an interrupt.
;* This is a subroutine. It returns to the code that called it after the data is finished
;* transmitting (after about 325 microseconds).
;*
;* This subroutine transmits the byte stored in the "TxData" register
;*
;* Number of words :14 including return
;* Number of cycles :Depends on bit rate
;* Low registers used :None
;* High registers used :2 (txbitcnt,TxData)
;* Pointers used :None
;*
;* time used == 10 * halfbit_delay + @120 cycles
;* subroutine does not exit until finished
;
;delay----|----|----|----|---|----|-----|---|----|----|------
;data-\___/----\___/-----\___/-----\___/----\___/-----------
;Txbit 10 9 9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 0
;Tx start 0 1 2 3 4 5 6 7 stop
.equ b = 36 ; ((b-1)*3) +10 = 116 cycles = 32uSec [clock period = 279.4nS]
;***************************************************************************
putMIDI: ldi temp, 10 ; 1+8+sb (sb is # of stop bits)
mov txbitcnt,temp
com TxData ; Invert everything [the lsr always puts a 0 into the carry]
sec ; Start bit
putMIDI0: brcc putMIDI1 ; 1 or 2
cbi PORTD,MIDItx ; 2 send a '0' (clear bit I/O)
rjmp putMIDI2 ; 2 else
putMIDI1: sbi PORTD,MIDItx ; 2 send a '1'
nop ; 1
putMIDI2: ldi temp,b ; 1 cycle
bit_delay1: dec temp ; 1 cycle
brne bit_delay1 ; 2 if true, 1 if false
lsr TxData ; 1 Get next bit
dec txbitcnt ; 1 If not all bit sent
brne putMIDI0 ; 2 send next
ret
ClearNoteArray:
clr zh
ldi zl, (low (SoundingNotes)) - 1 ; fill SRAM array for note storage with REGISTER_AVAILABLE sentinels
ldi temp, POSSIBLE_NOTES
mov regcnt, temp
ldi temp, REGISTER_AVAILABLE
CNA1: inc zl
st z, temp
dec regcnt
brne CNA1
ret
;********************************************************************************
; GET_SCAN: ; signal handler for external interrupt int0 (AVR pin 6)
; called by each transition of the keyboard clock signal
; assemble the scancode from keyboard data signal- data valid when clock is low
; ( use Terminal font to see correctly )
;clk---|_|--|_|--|_|--|_|--|_|--|_|--|_|--|_|--|_|---|_|---|_|---------- (---- = logic high +5v)
;data-\___/-----\___/-----\___/-----\___/-----\___/--------------------
; 11 10 9 8 7 6 5 4 3 2 1 bitcount on falledg
; start 0 1 2 3 4 5 6 7 P stop data bit
; Bitcnt 3 to 10 is data. start bit = 11, parity bit=bit 2; stop bit = bit 1
;*********************************************************************************
get_scan: ; Routine first entered at falling edge; then on both edges
sbrc keyflags,Edge_flag ; test edge flag
rjmp up_edge ; bit 7 (edge) = 0 => falling ;; bit 7 (edge) = ff => rising
cpi bitcount,INITIAL_BITCOUNT ; falling edge of the FIRST clock pulse from the PC keyboard ; start bit so do nothing
breq I1two
cpi bitcount,PARITY_BITCOUNT ; = 3 ; test for parity bit and stop bit
brlo I1two ; must use bitcount 3 for compare because branch tests only for lower
lsr scanbits ; shift data right one bit - data bit 7 gets 0
sbic PIND,PD3 ;set scancode bit if bit 3 on input port D is set (pin 7 on 2313 chip)
ori scanbits,$80 ; if data from kbrd is 1, then set bit 7 only and let other bits unchanged
ldi irqtemp, ( (1<<ISC01) | (1<<ISC00) )
out MCUCR, irqtemp ; Set interrupt on rising edge - INT0
sbr keyflags,(1<<Edge_flag) ; set edge flag
reti
I1two: ldi irqtemp, ( (1<<ISC01) | (1<<ISC00) ) ; just exit if bitcnt is 11, 2, or 1
out MCUCR, irqtemp ; Set interrupt on rising clock edge - INT0
sbr keyflags,(1<< Edge_flag) ; set edge flag
reti
up_edge: ldi irqtemp, 1<<ISC01
out MCUCR, irqtemp ; Set interrupt on falling clock edge - INT0
cbr keyflags,1<<Edge_flag ; clear edge flag
dec bitcount
brne exit_int1 ; All bits received?
ldi bitcount,INITIAL_BITCOUNT
set ; set T flag to let main program know a new char is ready
mov scancode,scanbits ; scanbits can be used to assemble new char while scancode is being decoded
exit_int1: ; clear any pending interrrupt
clr irqtemp
out GIMSK,irqtemp ; disable external INT0 - General Interrupt Mask Register
out MCUCR,irqtemp
ldi irqtemp, (1<<ISC01) ; interrupt on falling edge
out MCUCR,irqtemp
ldi irqtemp, (1<<INT0)
out GIMSK,irqtemp ; enable external INT0 - General Interrupt Mask Register
reti
; shows program and version information when code data downloaded from an AVR is viewed with a hex editor
;ID: .db " **** PCKB3.asm v1.31 Alan Probandt Oct 12, 2003"
ID: .db " **** CPBK.3sa mv.113A al nrPbonatdO tc1 ,22 00 3"
;;********************************************************************
;; EEPROM keypress table
; scancode is offset into table
; table value < $3f keyboard note (octave offset added to get MIDI note value)
; table value $40 - $4f function key
; table value $80 - $8f keypad press
; table value $c0 space (All Notes Off)
; table value $f0 - $fe special key
; table value $ff filler value ignore
;;*********************************************************************
.eseg
.org 0
EEPROMtable:
; 0 1 2 3 4 5 6 7 8 9 a b c d e f
.db $ff,$48,$ff,$44,$42,$40,$41,$4b,$ff,$49,$47,$45,$43, 01, 00,$ff ; 00-0f
.db $ff,$ff, 25,$ff,$f1, 02,$ff,$ff,$ff,$ff, 26, 27,$ff, 04, 03,$ff ; 10-1f
.db $ff, 30, 28, 29, 06,$ff, 05,$ff,$ff,$c0, 31,$ff, 9, 7, 8,$ff ; 20-2f
.db $ff, 35, 33, 34, 32, 11, 10,$ff,$ff,$ff, 37, 36, 13, 12,$ff,$ff ; 30-3f
.db $ff, 38,$ff, 14, 16, 17, 15,$ff,$ff, 40, 42, 39, 41, 18,$ff,$ff ; 40-4f
.db $ff,$ff, 43,$ff, 19, 20,$ff,$ff, 24,$f3,$f4, 21,$ff, 23,$ff,$ff ; 50-5f
.db $ff,$ff,$ff,$ff,$ff,$ff, 22,$ff,$ff,$81,$ff,$84,$87,$ff,$ff,$ff ; 60-6f
.db $80,$8e,$82,$85,$86,$88,$f4,$8a,$8b,$8d,$83,$8c,$8b,$89,$f4,$ff ; 70-7f
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -