⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pckb.asm

📁 把PC键盘变成MIDi音符控制适配器电路单片机程序
💻 ASM
📖 第 1 页 / 共 3 页
字号:
;  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 + -