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

📄 pckb.asm

📁 把PC键盘变成MIDi音符控制适配器电路单片机程序
💻 ASM
📖 第 1 页 / 共 3 页
字号:
;  ****************************************************************
;  *   PCkb.asm 
;  *
;  *     version 1.32   Oct 12, 2003   Alan Probandt   Portland Oregon USA
;  *
;  *  [ Use TimesNewRoman font in text editor to format this file correctly ]
;  *
;  *  [ when programming the AVR chip, don't forget to include the EEPROM file]
;  *
;  *    Read keypresses from PC Keyboard into Atmel AVR 90S2313
;  *        -Assemble logic changes on AVR pin 6 into PC keyboard scan codes.
;  *    	-Decode keyboard scancodes into MIDI note numbers.
;  *     	-Send MIDI messages out the MIDI out port  31250/8/N/1
;  *
;     Key Pad - pressing two digits on the keypad changes the voice number.
;   			for example,  pressing '3' then '7' selects voice number 37 (in decimal).
;
;  *   PC keyboard clock signal on AVR pin 6 (INT1)
;  *   PC keyboard data signal on AVR pin 7 (PORTD bit 4)
;  *	MIDI out (31250 baud - 8/N/1) on AVR pin 8 (PB4)
;    
;					Atmel AVR 2313
;   	RESET low	PIN 1 		| VCC  PIN 20 +5V
;   				PIN 2 PD0	| PB7  PIN 19  SCK 
;   				PIN 3 PD1 	| PB6  PIN 18  
;   	3.579MHz 	PIN 4 XTAL1	| PB5  PIN 17  
;    must use only  PIN 5 XTAL2	| PB4  PIN 16  
;  	INT0 kbd clk	PIN 6 PD2 	| PB3  PIN 15  
;   INT1 kbd data 	PIN 7 PD3 	| PB2  PIN 14  
;   	MIDI out	PIN 8 PD4  	| PB1  PIN 13  
;   	 			PIN 9 PD5  	| PB0  PIN 12 
;   				PIN 10 GND	| PD6  PIN 11 
;    
;  ************************************************************

.nolist
.include "2313def.inc"
.list


.equ	MIDItx				= 4	 ; MIDI Transmit pin 8 (PB4)
.equ	INITIAL_BITCOUNT 	= 11   ;  used by Get_Scan
.equ	PARITY_BITCOUNT 	= 3    ;  used by Get_Scan
.equ	NOTEOFFSET			= 34  ; check for adjustment -- Is 'Z' key really Middle C?
.equ	CHANGE_VOICE_OFFSET = $2e
.equ	SPACEBAR_OFFSET		= $2d
.equ	REGISTER_AVAILABLE	= $FF
.equ	POSSIBLE_NOTES 		= 8
.equ	NOTE_ON_VELOCITY  	= 0x50
.equ	NOTE_OFF_VELOCITY  	= 0
.equ	NOTE_ON_MSG 		= $90
.equ	CHANGE_VOICE_MSG 	= $c0
.equ	MIDI_CONTROLLER_MSG = $b0
.equ	ALL_NOTES_OFF_BYTE 	= 123 ; standard cmd $7b doesn't work on TQ5
.equ	ALL_NOTES_OFF_2nd 	= 0
.equ	CapsToggleValue		= 0b01000000

.equ	T_flag 		= 6
.equ	Sign_flag	= 4
.equ	KeyboardClock  = 2
.equ	KeyboardData= 3
.equ	SM_flag		= 4 ; Sleep Mode (unused) - delay loop counter bit flag { 0 = long period is timed out}
.equ PushSwitch1  	= 4

; keyflag register's bit values
.equ	Edge_flag	= 7 	; use up or down edge while inputting char from keyboard
.equ	Caps_flag	= 6   ; Caps Lock pressed on -- no NoteOff transmitted
.equ	Shift_flag	= 5	; the shift key (either right or left) is being pressed  
.equ	Break_flag	= 4	; the last scancode was an $f0 - the break code sent when a key is released
.equ	OnOff_flag	= 3	; set means turn on the note whose MIDI number was decoded from the most recent scancode
.equ	Alt_flag	= 2	;  the Alternate (Alt) key (either right or left) is being pressed  
.equ	E0_flag		= 1	; the extended scancode $E0 was sent


;*********************************************************************************************
;  Register definitions
;
;  lower registers  r0 - r15
; r0 is temporary storage of byte retrieved from LPM instruction
.def	OctaveOffset		= r1 
.def  	CurrentVoiceNumber 	= r2
.def  	txbitcnt			= r3		; used by PutMIDI
.def	TableOffset 		= r5		;  used by PCKB_main to keep track of where a keypress has been found in a table
.def	MIDIcounter			= r6		; FastMIDINumbers, SlowMIDINumbers - which MIDI number is being sent
.def	regcnt				= r6		;  used by PCKB_main to keep track of which notes are playing by having keys held down
.def	OverflowCount		= r6		;  used by T0_overflow IRQ to time a quarter-second
.def	KPtemp				= r6		; used by PCKB_main to multiply keypad digit by 10
.def	ParityCounter		= r7        ; count the number of logic hi bits transmitted by the keyboard command output routine
.def	SustainValue		= r7

;  upper registers
.def	temp				= r16	; scratch register
.def	irqtemp				= r17  	; interrupt's scratch register
.def	bitcount			= r18	; used by INT0 irq  [getscan]	
.def  	scancode			= r19	; storage of data bits received from PC keyboard 
.def	scanbits			= r20 	; shift register for holding PC keyboard data while being assembled
.def	keyflags			= r21	; status of previous scancodes. used to decode multiple scancode keypresses
.def	DecodeValue			= r22  	; PC keyboard char decoded to NoteOn value, ChangeVoice value, or AllNotesOff cmd
.def	KPvalue				= r23	; the binary value of the pressed keypad digits. Used for new voice value.
.def	Velocity			= r24	; the MIDI note-On volume value
.def  	TxData  			= r25  	; the byte being sent out the MIDI port - PutMIDI

.dseg
.org 0x60
FNtable:			.BYTE	12
SoundingNotes:		.BYTE	POSSIBLE_NOTES

.cseg
.org $0000     
; AT90S2313 interrupt table                                                    
	rjmp		reset		; Reset handler   $000

.org INT0addr
	rjmp		get_scan	; External interrupt 0 handler  $001 (pin 6)  PC keyboard clock

.org INT1addr
	reti					; External interrupt 1 handler  $002

.org ICP1addr
	reti					; Timer1 capture event handler  $003     

.org OC1addr
	reti					; Timer1 compare match     $004

.org OVF1addr
	reti					; Timer1 overflow handler  $005

.org OVF0addr
	reti					; Timer0 overflow handler  $006

.org URXCaddr
	reti					; UART Rx Complete	$007

.org UDREaddr
	reti					; UART Data Register empty $008

.org UTXCaddr
	reti					; UART Tx Complete	$009

.org ACIaddr
	reti					; Analog comparator handler $00a

reset:
		ldi		temp, RAMEND
		out		SPL ,temp			; init Stack Pointer 
        	
; set-up ports for input/output and pull-up resistors
		ser		temp
		out		portb,temp	; port B pull-up resistors are all on
		out		portd,temp	; port D pull-up resistors are all on 
		clr		temp
		out		ddrb,temp  ; port b is all inputs  
		ldi		temp,(1<<MIDItx) 
		out		ddrd,temp  ; port D4 is output for MIDI


;*******************************************************************************************
;
;    	Get keypresses from standalone PC keyboard - convert to notes and send to MIDI port
;
;    	Subroutines:	'decode_data'
;
;	Interrupt procedures:	external interrupt int0 -- 'getscan'
;
;   Most time spent in 'GetChar' which checks T flag for fully received keypress from PC keybrd
;   When T is set, 'decode_data' called to convert keypress to note or cmd.
;*******************************************************************************************
;
PCkb_Main:
		ldi		temp,(1<<ISC01) ; setup INT0 interrupt on falling edge
		out		MCUCR, temp  	
		ldi		temp, (1<<INT0)
		out		GIMSK,temp      ;  enable external INT0 - General Interrupt Mask Register
		sei		; switch on the AVR general interrupt enabler
		clr		keyflags 
		clr		KPvalue
		ldi		bitcount,INITIAL_BITCOUNT ; = 11
		clt		;   T flag used to indicate that a char from kybd is ready to transmit
		ldi		temp, NOTEOFFSET
		mov		OctaveOffset, temp
		
		clr		temp				; set up the Function key voice select table with voices 00 - 0b
		ldi		ZH, high (FNtable)
		ldi		ZL, low (FNtable)
rst2:	st		z+, temp
		inc		temp
		cpi		temp, 12			; the number of Function keys on a PC keyboard
		brlo	rst2
		
		clr		CurrentVoiceNumber		; set synth voice to 00h on AVR reset
		rcall	ChangeVoice

		
; setup completed -------- enter MAIN LOOP here
	    
GetChar:in		temp, SREG ; MAIN LOOP of program  99.9% of time spent here
	   ; if T flag (SREG bit 6) is set, then char from keyboard is ready to transmit
		sbrs	temp,T_flag   ; if T flag (SREG bit 6) is set, then char from keyboard is ready to transmit
		rjmp	GetChar

		clt			 ; clear T flag - prepare for next char
		rcall	decode_data  ; convert the scancode from the keyboard into an ASCII character
								; send scancode and keyflags - return DecodeValue
		tst		DecodeValue    ; if DecodeValue =0, then ignore scancode - it's a shift character or break scancode
		brne	Valid_key     
		rjmp	GetChar

; DecodeValue less than $3f turns on/off note, $80-$89 are keypad numbers, $40-$4b map function keys F1 to F12, $c0 is spacebar
Valid_key:
		cpi		DecodeValue, $c0	; space bar key
		breq	DoSubAllNotesOff
		
		mov		temp, DecodeValue
		andi	temp,0xc0
		cpi		temp,0x40			; is the scancode a Function key activation?
		brne	VkyKP			; no, check for keypad press
		rjmp	FnKeyChangeVoice
		
VkyKP:	mov		temp, DecodeValue	; is the scancode a keypad press?
		andi	temp,0xc0			;  isolate the two most significant bits   1100 0000
		cpi		temp,0x80			;  test if the two most sig bits are '10'
		brne	VkyMN			; no, not a keypad press. So must be a note on/off.
		rjmp	DoKeyPad		; yes, scancode is a keypad activation.
		
VkyMN:	andi	DecodeValue,0b00111111 ; DecodeValue is lower than $3f
		rjmp	DoNote  
	
DoSubAllNotesOff:
		rcall	AllNotesOff
		rjmp	GetChar
		
;*********************************************************
;  Function Key Press  -  Assign Voice number to Fn key
;*********************************************************
FnKeyChangeVoice:
		mov 	temp,DecodeValue  ; DV will be $40 to $4b
		andi	temp, 0b00001111
		; check Alt flag, if set then assign the Current Voice Number into the selected Function key.
		;  if Alt flag is clear, then change voice to the number assigned to the selected Function key.
		sbrs	keyflags, Alt_Flag
		rjmp	FKCV0			; Alt_flag is set so jump to FKCV0
		ldi		ZH, high (FNtable)   ; get the Function key's voice number
		ldi		ZL, low (FNtable)
		add		ZL, temp			; ZL plus Function key number will never be greater than $ff
		st		z, CurrentVoiceNumber
		rjmp	FKCV2
FKCV0:	ldi		ZH, high (FNtable)   	; Alt_key is not pressed - Fn key pressed by itself
		ldi		ZL, low (FNtable)	;- send to the synth the number assigned to the pressed Function key
		add		ZL, temp			; ZL plus Function key number will never be greater than $ff
FKCV1:	ld		temp, z
		mov		CurrentVoiceNumber, temp
		rcall	ChangeVoice
FKCV2:	rjmp	GetChar	
	
;***************************************************************************
;   Key Pad  - pressing two digits on the keypad changes the voice number.
;   for example,  pressing '3' then '7' selects voice number 37 (in decimal).
;****************************************************************************
DoKeyPad: 
		mov 	temp,DecodeValue  ; DV will be $80 to $8f
		andi	temp, 0b00001111
;  check if keypress is a digit.  If yes, then check if 1st, 2nd, or third digit of voice number in base10
		cpi		temp, 10
		brlo	KP_digit    ; yes it's a digit (0 to 9)
		cpi		temp, $0a ; was the NumLock key pressed
		brne	KP_isStar  ; no
		rjmp	GetChar	; yes,  do nothing for now
KP_isStar: cpi	temp, $0b  ; was the multiply on the keypad pressed?	
		brne	KP_isMinus  ; no
		rjmp	GetChar	; yes,  do nothing for now	
KP_isMinus: cpi	temp, $0c ; was the minus sign on the keypad pressed?	
		brne	KP_isPlus ; no
		rjmp	GetChar	; yes,  do nothing for now	
KP_isPlus: cpi	temp, $0d  ; was the plus sign on the keypad pressed?	
		brne	KP_isPoint ; no
		rjmp	GetChar	; yes,  do nothing for now		
KP_isPoint: cpi	temp, $0d  ; was the decimal point on the keypad pressed?	
		brne	KP_exit 	; no

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -