; **************************************************************** ; * PCkeybrd.asm for Atmel AVR 90S1200 ; * ; * 1. Play MIDI notes using a detached PC keyboard ; * 2. Put sequencial numbers out the MIDI port every half second ; * 3. Continous MIDI output at full speed - 0x00 to 0xFF then rollover ; * 4. Block MIDI output at keyswitch press - send 128 bytes (0x00 to 0x7F) to MIDI at full speed ; * ; * version 1.27 Aug 28, 2003 Alan Probandt Portland Oregon USA ; * ; * [ Use TimesNewRoman font in text editor to format this file correctly ] ; * ; * ; * Read keypresses from PC Keyboard into AVR 1200 ; * -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 ; * ; * PC keyboard clock signal on AVR pin 6 (INT1) ; * PC keyboard data signal on AVR pin 7 (PORTD bit 4) ; ; RESET- active low PIN 1 | VCC PIN 20 +5V ; RTS PIN 2 PD0 | PB7 PIN 19 ; TXD PIN 3 PD1 | PB6 PIN 18 ; 3.579545MHz PIN 4 XTAL1 | PB5 PIN 17 ; must use only PIN 5 XTAL2 | PB4 PIN 16 ; INT0 kbd clock PIN 6 PD2 | PB3 PIN 15 ; kbd data PIN 7 PD3 | PB2 PIN 14 ; MIDI out PIN 8 PD4 | PB1 PIN 13 ; PIN 9 PD5 | PB0 PIN 12 ; PIN 10 GROUND | PD6 PIN 11 ; ; ************************************************************ .nolist .include "1200def.inc" .list ; crystal-dependent timer values 3.579545 MHz (TV color burst crystal) ; 0.279uS * 1024 = 285.7uS timer prescaled increment period ; 73,138 microseconds per Timer Overflow .equ Quarter_second = 5 ; approx number of timer overflows (using sysclk/1024 prescaler) per 250 milliseconds .equ TwentyMilliseconds = 70 ; approx number of timer counts (using sysclk/1024 prescaler) per 20 milliseconds .equ MIDItxpin = 4 ; MIDI Transmit pin .equ INITIAL_BITCOUNT = 11 ; used by Get_Scan .equ PARITY_BITCOUNT = 3 ; used by Get_Scan .equ NOTEOFFSET = 33 .equ CHANGE_VOICE_OFFSET = $2d .equ ALL_NOTES_OFF_DECODE = $2d .equ REGISTER_AVAILABLE = $FF .equ NUMBER_of_POSSIBLE_NOTES = 8 .equ FIRST_STORAGE_REGISTER = 8 .equ NOTE_ON_VELOCITY = 0x60 .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 ; $7b .equ ALL_NOTES_OFF_BYTE_2nd = 0 .equ PSEUDO_STACK = $65 ; imitate a real stack when using ICE200 for 1200 chip .equ PSEUDO_STACK_POINTER = $3d .equ KBD_ACK = $0fa .equ T_flag = 6 .equ Sign_flag = 4 .equ Toggler6 = 6 .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 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 ACK_flag = 2 ; the most recent scancode received was $FA - keyboard acknowledge .equ E0_flag = 1 ; the extended scancode $E0 was sent - use the E0table to decode scancode ;********************************************************************************************* ; Register definitions ; ; upper registers .def bitcount = r16 ; used by INT0 irq [getscan] .def scancode = r17 ; storage of data bits received from PC keyboard .def scanbits = r18 ; shift register for holding PC keyboard data while being assembled .def keyflags = r19 .def DecodeValue = r20 ; PC keyboard char decoded to NoteOn value, ChangeVoice value, or AllNotesOff cmd .def txbitcnt = r21 ; used by PutMIDI .def TxData = r22 ; the byte being sent out the MIDI port - PutMIDI .def temp = r23 ; scratch register .def irqtemp = r24 ; interrupt's scratch register .def EEPROM_Ptr = r25 .def regcnt = r26 .def OverflowCount = r27 .def MIDIcounter = r28 ; lower registers r0 - r15 ; r0 is temporary storage of byte retrieved from EEPROM .def newvoice = r1 .def NoteOffsetValue = r2 .cseg .org $0000 rjmp reset ; Reset handler $000 .org INT0addr rjmp get_scan ; External interrupt 0 handler .org OVF0addr reti ; Timer0 overflow handler .org ACIaddr reti ; Analog comparator handler RESET: ; ldi temp,PSEUDO_STACK ; imitate a real stack when using ICE200 for 1200 chip ; out PSEUDO_STACK_POINTER,temp ;init Stack Pointer - does nothing on real 1200 chip ; 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 the DIP switches are here Pb0 to PB3 ldi temp,(1< 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< $80 ( function keys) == change voice ; ; A key pressed down will send the one-byte scancode to the PC for most characters. ; When the key is released (key is let up after being pressed down), the keyboard ; sends an $f0 byte followed by the scancode of the key being released. ; This routine uses a flag called Break to determine if the scancode comes from a keypress down or release. ; Break == clear means that scancode just received is a keypress down and should be decoded to Note On for that keypress. ; Break == set means that the scancode just received was $f0 and the next scancode means turn Note Off for that keypress. ;************************************************************************************************************************** decode_data: ; first check if the scancode is the keyboard acknowledge byte cpi scancode,KBD_ACK brne chkBreakFlag rjmp ACKset ; first check that Break flag is clear *** chkBreakFlag: sbrc keyflags, Break_flag ; Break flag is bit 4 rjmp Break_set ; Break is clear, so do check the first three special conditions cpi scancode,$f0 ; $F0 =Breakcode finger-off-the-key identifier brne notF0 sbr keyflags, (1<