elektronik
programmieren

messie.ch
tm
home

startseite

intro

intro elektronik & programmieren

prints

printherstellung

robots

robots

div

diverse Schaltungen


proc

prozessoren

ass
embler

el5

DOS
Linux

javascripts

diverse Schaltungen

MIDI an einem Notebook

NOTA auf dass es denn gesagt sey:
Die hier zur Verfügung gestellten Informationen dürfen nur für den Eigenbedarf genutzt werden, es ist absolut NICHT zulässig, sich auf Grund dieser Informationen selbst zu bereichern !
Das hier präsentierte Projekt funktioniert erfahrungsgemäss ausgezeichnet und die zur Verfügung gestellte Information ist nach bestem Wissen & Gewissen recherchiert. Ich übernehme aber rein keinerlei Haftung für Schäden irgendwelcher Art an was und wie auch immer (auch nicht psychischer Natur), die beim Nachbau & Einsatz dieses Projektes entstehen könnten.

MIDI (Musical Instrument Digital Interface = „Digitale Schnittstelle für Musikinstrumente“) ist ein Datentransferprotokoll zwischen (hierzu vorgesehenen) manuell spielbaren Musikinstrumenten und einem PC. Dabei werden nicht wie bei üblichen Audio-Verbindungen die elektrischen Werte des Tones selbst übermittelt sondern reine Informationen, welcher Ton auf welchem Instrument bei welcher Anschlagsstärke gedrückt oder losgelassen wurde und mehr. MIDI-files entsprechen daher mehr einer Partitur, sind vergleichsweise enorm schlank und bieten - wenn qualitativ hochwerige Instrumente angeschlossen sind - sensationellen Klang (was nun rein gar nichts zu tun hat mit dem Abspielen eines ebensolchen MIDI-files mit einem reinen Software-Mediaplayer, was meist furchtbar äetzend tönt und MIDI entsprechend völlig in Verruf gebracht hat).

Bis anhin verfügte jede Soundkarte über einen sog. 'gameport' - einen 15-poligen SubD-Anschluss. Hier können Joysticks und eben auch MIDI-instrumente angeschlossen werden (oft ist dennoch ein kleiner Pegelwandler erforderlich !). Ist die Soundkarte im Motherboard des PCs integriert, braucht es meist ein zusätzliches Anschlusspanel hierzu und bei Notebooks endlich ist der gameport vollends verloren gegangen - Joysticks werden über USB angeschlossen und MIDI ist vor die Hunde gegangen oder wird auch über USB abgewickelt, vorausgesetzt man verfügt über die hierzu kompatiblen Geräte oder Wandler. Dies ist unverständlich und schade, denn das MIDI-protokoll ist nun nichts anderes als eine ganz gewöhnliche, serielle Verbindung wie jede andere RS232-Schnittstelle auch - mit dem pikanten Unterschied, dass MIDI die exotische Baudrate von 31'250 Bits/s verwendet und dies von keiner gewöhnlichen seriellen Schnittstelle bewerkstelligt werden kann - hier ist der nächstmögliche Übertragungswert 38'400 Bps und das ist toleranzmässig jenseits jeder Verständigung. Der Keyboardhersteller Roland (und andere auch) sind sich offensichtlich des Problems bewusst und bieten einen Treiber an, der die MIDI-Daten mit entsprechend geänderter Baudrate an die serielle Schnittstelle sendet/empfängt - ihre passenden MIDI-Instrumente hierzu verfügen dann über einen adequaten Umschalter MIDI/seriell.

Was aber macht man, wenn man
a) über ein Notebok verfügt, das noch einen seriellen Anschluss hat (heutzutage auch schon selten)
b) hier gerne ein x-beliebiges MIDI-Instrument anschliessen möchte

---> man baut sich folgenden Baudraten-Wandler:

- er besteht aus 2 Microcontroller der 8051-serie (ATMEL AT89C2051 - Preis aktuell < 4 Fränkli)
- voll Duplex wandelt er die Baudrate entsprechend zwischen 31'250 <-> 38'400 Bits/sec um
- gleicht die Pegel entsprechend an

KURZ: der eine Prozessor wird mit einem Quarz von 14'745'600 Hz (--> 38'400 Bps) betrieben, der andere mit 24'000'000 HZ (--> 31'250 Bps). Daten zwischen den Prozessoren werden jeweils parallel über Port1 ausgetauscht und dann in der entsprechend passenden Geschwindigkeit seriell weitergegeben. Da der Port 1 von beiden Controllern sowohl als Aus- wie auch als Eingang genutzt wird ist ein präzises handshake erforderlich um Datenkollisionen zu vermeiden. Zudem braucht der MIDI-controller eine Zwischenspeicherfunktion, da der serielle Port um einen knappen Viertel schneller serviert als der MIDI-port weiterleiten kann. MIDI-daten kommen meist in Päckchen von 3 bytes. Die Schaltung ist noch insofern erweitert, als dass sie auch als reiner Pegel-Anpasser zwischen einem realen gameport und einem MIDI-Instrument eingesetzt werden kann.
Softwaremässig läuft alles quasi rein Interruptgesteuert und ergibt je ein kleines Assemblerprogrämmchen von unter hundert Quelltextzeilen...

Im Blockschaltbild sieht das etwa so aus:

s2m blockschaltbild

Und als Schaltplan etwa so (draufklicken öffnet ein vergrösser-, druck-, speicherbares .pdf)

schema

Das Teil ist Messiemässig etwas zu universell ausgefallen und für konkrete Anwendungen muss nicht alles bestückt werden. So kann etwa der Spannungsregelteil weggelassen werden und stattdessen lötet man ein umherliegendes & verwaistes USB-Kabel derart richtig an, dass die Platine mit reinen 5V vom sowieso benutzten PC / Laptop her versorgt wird (ein solcher Anschluss dient dann einzig der bequemen Spannungsversorgung und hat mit dem USB-Datatransfer aber auch rein gar nichts zu tun !). Zudem kann der gesamte Teil mit den 4 Transistoren gestrichen werden: er dient lediglich zum Anschluss eines weiteren PCs über den 15-pol-gameport der Soundkarte (sog. SB-PCI - der Datentransfer geschieht mit MIDI-takt, einzig die Pegel werden angepasst. Achtung: +5V werden einerseits von der Soundkarte geliefert, aber ohne geschickten Lötpatch braucht die Platine weiterhin die erforderliche Versorgungsspannung, da hiermit auch der benötigte Optokoppler gespiesen wird). Im weiteren findet man ein pdf-file eines funktionierenden Prints, den man sich in Anregung der hier befindlichen Anleitung selbst herstellen kann. Der print hat gerade platz auf 1/4-Europlatine = 5x8 cm.

layout print

Und so sieht der bestückte print in Funktion aus:

top view

Folgende Bemerkungen sind zu berücksichtigen:

-

MIDI-Controller: Anstelle des 24 Mhz-Quarzes kann hier auch ein solcher von 12 oder 6 Mhz verwendet werden. Die software ist entsprechend anzupassen:
Load & Reload-value für timer_1 (baudrategenerator) TL1, TH1:
24'000'000 : #0FCH - getestet
12'000'000 : #0FEH ( ungetestet)
  6'000'000 : #0FFH ( ungetestet)

-

Seriell-Controller: Anstelle des 14'745'600 Hz- Quarzes kann auch ein solcher mit 1.5-facher (22'118'400 Hz) oder halber Frequenz (7'372'800 Hz) angewendet werden. Der legendäre und aus jedem weggeworfenen Motherboard auszulötende 14'318'180-Quarz würde vermutlich auch funktionieren, da er nur knappe 3% unter der erwarteten Soll-baudrate liegt
Load & Reload-value für timer_1 (baudrategenerator) TL1, TH1:
22'118'400 : #0FDH ( ungetestet)
14'745'600 : #0FEH - getestet
(14'318'180: #0FEH = -2.9% ungetestet)
  7'372'800 : #0FFH ( ungetestet)

- Es braucht einen hochwertigen, schnellen Optokoppler. Bewährt haben sich der PC900 oder der 6N136.
Der Print ist an sich ist für den 6-beinigen PC900 ausgelegt, wobei pins 1 & 8 eines eingelöteten 8-pol-Sockels unbelegt bleiben. Man kann aber auch den 8-beinigen 6N136 einsetzen - allerdings nur mit chirurgischem Eingriff ! Beim 6N136 müssen die Zuleitungen zu den Pins 5/6 vertauscht werden. Der print ist hierzu vorgesehen und man kann die Zuleitungen einerseits mit einem Japanmesser auftrennen und dann jeweils wieder übers Kreuz verlöten.
- Die Spannungsversorgung kann den verfügbaren Möglichkeiten angepasst werden. Werden 5V direkt von einem USB- oder PS2-Anschluss bezogen, so erübrigt sich der Spannungsregler 7805 mit seinen 2 Elkos
- Die Zahlen bei den Anschlussreihen beziehen sich auf die Stiftnummer des jeweils anzuschluiessenden Steckers/Buchse
- Die Vorwiderstände der Leuchtdioden müssen je nach Farbe der verwendeten LED entsprechend angepasst werden.
- Beim Bestücken die 2 Brücken nicht vergessen...

Anschlüsse:
Spannungsversorgung über USB:
Das Bild zeigt den Anschluss am PC / Notebook.

USB connector

PIN Signal
1 5 Volt +
2 (--- USB -)
3 (--- USB +)
4 GND

Auf dem Schrottplatz findet man zuhauf USB-Geräte, denen man getrost das Kabel abschneiden und hier zur Spannungsversorgung anlöten kann. Die Kabel müssen mit dem Ohmmeter ausgemessen werden und dann wird man die richtige Verbindung zur benötigten Spannungsversorgung schon finden. Vorsicht ist dennoch geboten um nicht irgendwelch unauffindbare, eingelötete Sicherungen im Innersten eines Laptops zu knallen...

MIDI-Anschluss - es werden männliche DIN-Stecker verwendet.

midi connector

Wenn ich jetzt von MIDI-IN / MIDI-OUT rede, so meine ich das ausdrücklich vom hier besprochenen Projekt aus gesehen. Das ist verwirrlich, weil eben immer MIDI-OUT mit MIDI-IN verbunden werden muss - jedenfalls nach meinem Verständnis aber dies ist wohl falsch - item.
Also: 'current source' heisst nichts anderes als 'Stromquelle' und hier kommt bei MIDI-IN die Anode der Optokoppler-LED dran (über entsprechenden Vorwiderstand - sage mal 220 Ohm). Bei MIDI-OUT liegen hier üblicherweise feste +5V über einen 220-Ohm-Widerstand an)

.midi in

'current sink' ist der Gegenpol und wird bei MIDI-IN mit der Kathode der Optokoppler-LED verbunden oder entsprechend bei MIDI-OUT (auch wiederum über 220 Ohm) mit dem desigmierten Portausgang (oder sonst einem open collector driver).

midi out

Shield ist einfach die Kabelabschirmung, die geerdet (GND) wird.
Pins 1 & 3 bleiben unbelegt!

Serieller Anschluss - es wird eine weibliche SubD-9-Pol-Buchse verwendet.

9-pol-RS232 DTE

Ähnlich verwirrlich ist der serielle Anschluss: hier müssen jeweils Sendedaten mit Empfangsdaten verkabelt werden und Pins 2/3 werden beliebig mal so oder so mit RXD resp. TXD bezeichnet. Kommt halt drauf an, ob man fachchinesisch von einem DTE (data terminal equipment (=PC o.ä.)) oder DCE (data communication equipment (=Modem o.ä.)) spricht.
Also: RX auf der Platine angeschrieben wird mit SubD-Pin-3 (TXD vom Notebook) verbunden und analog der mit TX angeschriebene mit SubD-Pin-2 (RXD vom Notebook).
Pin 5 ist GND und wird mit 0 Volt verbunden. Alle anderen Anschlüsse bleiben hier unbelegt.
Es hat auf der Platine noch RX2 und TX2: TX2 kann (zusammen mit GND) an den RX-Eingang eines COM-ports eines weiteren Computers angeschlossen werden und überträgt ebenfalls die gleichen seriellen Daten von der Tastatur des MIDI-Instrumentes her - wie bereits gehabt. RX2 jedoch ist nicht wirklich angeschlossen und könnte für Spezialanwendungen auf der Platine weiter verkabelt werden. Wenn es noch halbwegs Sinn macht, von einem MIDI-Instrument aus 3 PCs anzusprechen (2 über serielle Verbindungen und einen 3. über den gameport) so ist es halt umgekehrt eher fragwürdig, von 3 PC-Tastaturen aus ein und dasselbe MIDI-Instrument anspielen zu wollen....

gameport connector

Gameport - es wird ein männlicher SubD-15-Pol-Stecker verwendet.
+5Volt werden mit Pins 1/8/9 verbunden (also einer von den 3en reicht)
GND wird mit pins 4 oder 5 verbunden
pin 12 ist eigentlich MIDI OUT (hier mit MIDI RxD angeschrieben) und
pin 15 entspricht MIDI IN (MIDI TxD - was soll's)

Irgendwie schnalle ich das nicht vollständig, wann was wo mit IN / OUT /TxD / RxD bezeichnet wird. Hauptsache, zuletzt funktionierts und beruhigenderweise geht auch bei falschem Anschliessen eigentlich nichts echt kaputt...

Auch die folgende software könnte man sicher noch optimieren & kürzen - es hat da einige unnötige Befehle & labels drin, da ich meist bereits vorhandene Programmteile einbaue & entsprechend modifiziere. Aber eben: wäre es in C geschrieben, dann hätte es so oder so 300 unnütze Zeilen mehr...(das soll KEIN Geläster über C sein - wer damit glücklich wird, soll es. Ich schreibe für den x51 ja sicher auch keine floating-point Routinen in assembler...)

        Die Software: Controller I, serieller teil
       



; serial 2 midi interface 89xx51
; ==============================
; TM 6 - 06
; (c) by Thomas Moll, Berne, CH
; AT89C2051


; NAME ser2mis.a51


;_______________________________
;
; serial in/out part 38'400 baud
;_______________________________


$NOMOD51
$INCLUDE (89c2051.mcu)



;14'745'600-crystal !!!

start CODE 0H
begin CODE 028h



recf BIT 02fh.7

p30 equ P3.0
p31 equ P3.1
ACKR equ P3.2
STBR equ P3.3
ACKS equ P3.4
STBS equ P3.5
p36 equ P3.6
led equ P3.7





















;include ATMEL 89C2051 SFR symbol definitions





;start address of user programs
;program start adress
; (behind interrupt-jump-adresses)


;set if serial-38'400-byte received

;RX
;TX
;EXT 0 Receieve acknowledge --> rise strobe
;EXT 1 Receive data strobe low
;send acknowledge --> h-low-h transition
;send data strobe low
;soft only ---- comparator output
;low will light serial led (blu)
       

ORG start
ljmp begin

org exti0
ljmp ext0_int

org timer0
ljmp tim0_int

org exti1
ljmp ext1_int

org timer1
ljmp tim1_int

org sint
ljmp serial_int

;program start address


;org 03h


;org 0bh


;org 13h


;org 1bh


;org 23h
       

ORG begin

clr EA
mov SP,#0fh
mov P3,#0ffh
mov P1,#0ffh
mov SCON,#50h
mov TMOD,#21h

mov TL1,#0FEh
mov TH1,#0FEh
mov PCON,#80h
setb TR1
setb IT0
setb IT1
mov IP,#0
setb PX0
setb ES
setb EX0
setb EX1
setb EA



;stop all ints
;reg bank 1 ev. used...
;all bits input
;all bits input
;uart in mode 1 (8 bit), REN=1
;timer 0 16-bit-mode,
;timer 1 mode 2 (8 bits auto reload)
;19200 Bds at 14'745'600 crystal
;set as reload value
;double baudrate = 38400
;start timer 1 = baudrategenerator
;external int 0 on falling edge
;external int 1 on falling edge
;reset any priority level
;external int 0 has highest priority
;allow serial ints
;allow external 0 ints now (acknowledge)
;allow external 1 ints now (receive midi)
;Enable global interrupts
      donix: jnb recf,donix
clr recf
clr led
mov TH0,#080h
setb TR0
setb ET0
sjmp donix

;just wait...

;blue led on
;load 16-bit-timer 0 high byte (ignore LSB)
;run timer 0 for led light on
;allow timer 0 int now
      tim0_int:

setb led
clr TR0
clr ET0
reti

;timer0 int (software) / blue led off
;stop timer 0
;disable timer-0-ints
      tim1_int: reti ;timer1 int (software)
      ext0_int: mov P1,#0ffh
setb STBS
reti

; = acknowledge from MIDI -> release P1
;rise strobe now if acknowledge received
      ext1_int:

push acc
push PSW
mov a,P1
clr ACKS
mov sbuf,a
pop PSW
pop acc
setb ACKS
reti

; = Data strobe from MIDI - controller

;read byte from midi input
;signalize byte read
;send it with baudrate 38'400


;rise acknowledge

      serial_int: push acc
push psw
jnb ri,emit_it
clr ri
mov a,sbuf



;test if it is a 38'400-reception
;clear reception flag for next reception
;read byte

      testro: jnb STBR,testro
mov P1,a
clr STBS
setb recf
sjmp end_it

;do not alter P1 if still in use - wait
;give the received byte out to port 1
;set strobe low to signalize data present
;mark byte received

      emit_it: clr ti ;clear transmition flag for next one
      end_it: pop psw
pop acc

 

      nothing: reti  
           
        end

 

 

     
Die Software: Controller II, MIDI teil
       



; serial 2 midi interface 89xx51
; ==============================
; TM 6 - 06
; (c) by Thomas Moll, Berne, CH
; AT89C2051


; NAME ser2mim.a51


;______________________________
;
; MIDI in/out part 31'250 baud
;______________________________


$NOMOD51
$INCLUDE (89c2051.mcu


; 24'000'000-crystal !!!


start CODE 0H
begin CODE 028h


recbp EQU 040h
sndbp EQU 040h

sendf BIT 02fh.7
recf BIT 02fh.6

p30 equ P3.0
p31 equ P3.1
ACKR equ P3.2
STBR equ P3.3
ACKS equ P3.4
STBS equ P3.5
p36 equ P3.6
led equ P3.7




















;include ATMEL 89C2051 SFR symbol definitions





;start address of user programs
;program start adress
; (behind interrupt-jump-adresses)

;receive buffer pointer
;send buffer pointer

;bit set if sending to MIDI device
;set if midi reception

;RX
;TX
;EXT 0 Receieve acknowledge --> rise strobe
;EXT 1 Receive data strobe low
;send acknowledge --> h-low-h transition
;send data strobe low
;soft only ---- comparator output
;low will light serial led (red)
       

ORG start
ljmp begin

org exti0
ljmp ext0_int

org timer0
ljmp tim0_int

org exti1
ljmp ext1_int

org timer1
ljmp tim1_int

org sint
ljmp serial_int

;program start address


;org 03h


;org 0bh


;org 13h


;org 1bh


;org 23h
       

ORG begin

clr EA
mov SP,#0fh
mov P1,#0ffh
mov P3,#0ffh
mov SCON,#50h
mov TMOD,#21h

mov TL1,#0FCh
mov TH1,#0FCh
mov PCON,#80h
mov R0,#recbp
mov R1,#sndbp
clr recf
clr sendf
setb TR1
setb ES
setb IT0
setb IT1
setb EX0
setb EX1
setb EA



;stop all ints
;reg bank 1 ev. used...
;port 1 input
;all bits input
;uart in mode 1 (8 bit), REN=1
;timer 0 16-bit-mode,
; timer 1 mode 2 (8 bits auto reload)
;15'625 Bauds at 24'000'00 Hz crystal
;set reload value
;double baudrate = 31'250
;R0 is receive buffer pointer
;R1 is send buffer pointer


;start timer 1
;allow serial ints
;external int 0 on falling edge
;external int 1 on falling edge
;allow external 0 ints (receive midi)
;allow external 1 ints (data acknowledge)
;Enable global interrupt
      donix: cjne R0,#recbp,sendit
jnb recf,donix
clr recf
clr led
mov TH0,#040h
setb TR0
setb ET0
sjmp donix

;reception int will increment pointer value
;if recf set --> light control-LED

;red led on
;load 16-bit-timer 0 high byte
;run timer 0
;allow timer 0 int

 

      sendit: jb sendf,sendit
setb sendf
mov a,@R1
inc R1
mov sbuf,a
mov a,R0
clr C
subb a,R1
jnz donix
mov R0,#recbp
mov R1,#sndbp
sjmp donix
;if previous transmission not finished, wait
;mark new transmission starts
;read from transmission pointer
;advance transmission pointer
;send it with 31'250 baud


;reception / transmission pointer equal ??
;If not, continue transmission
;else reset buffer pointers


      tim0_int:

setb led
clr TR0
clr ET0
reti

;timer0 int (software) / red led off
;stop timer 0
;disable timer-0-ints
      tim1_int: reti
;timer1 int (software)
      ext0_int: mov P1,#0ffh
setb STBS
reti

; = acknowledge from MIDI -> release P1
;rise strobe now if acknowledge received
      ext1_int:

push acc
push PSW
mov a,P1
mov @R0,a
inc R0
clr ACKS
pop PSW
pop acc
setb ACKS
reti

; = Data strobe from serial - controller

;read byte from serial input
;store it at receive buffer pointer
;advance pointer
;acknowledge reception


;rise acknowledge

      serial_int: push acc
push psw
jnb ri,emit_it
clr ri
setb recf
mov a,sbuf



;test if it is a MIDI-reception
;clear reception flag for next reception
;mark midi reception
;read byte

      testro:

jnb STBR,testro
mov P1,a
clr STBS
sjmp end_it

;do not alter P1 if still in use - wait
;give the received byte out to port 1
;set strobe low to signalize data present

      emit_it: clr ti
clr sendf
;clear transmition flag for next one
;mark transmission complete
      end_it: pop psw
pop acc

 

      nothing: reti  
           
        end

 

Die Programmdateien sind reine Textdateien mit der Endung .a51 und vorgesehen zur Assemblierung mit dem ASEM-51- Assembler - habe damit gute Erfahrungen gemacht. Sicher können sie etwas angepasst auch mit jedem anderen x51-fähigen assembler bewältigt werden - Hürde sind wohl nur include-files mit Namen der SFRs und ähnlichem....

Zum 'brennen' der progis braucht es natürlich irgend einen Universalprogrammierer oder selbstgebasteltes - Anleitungen dazu gibt es im Internet genügend. Ich habe mir mal das Teil von W. Sirichote gebaut und bin damit und einem uralt-Laptop unter DOS (Contura Aero) am sonnigen Strand von Sizilien echt gut zurechtgekommen...

Hat man alle x51er-hard- & softwarehürden genommen, dann braucht es natürlich noch einen Treiber, der die MIDI-Daten zur seriellen Schnittstelle sendet. Mein Favorit ist der von Roland: je nach Betriebssystem W95-2000 muss man den geeigneten wählen auf dieser Seite. Ich benutze die Version 3.1 unter W98SE und zumindest hier funzt alles prima. MAC & Linux-user müssen sich wieder mal selbst nach seriellen MIDI-Treiber umsehen - die Schaltung an sich funktioniert an jedem beliebigen RS-232-port, der MIDI-daten mit 38'400 Baud versprüht.

Vom Einsatz eines USB-->seriell-wandlers für dieses Projekt kann ich nur abraten. Solche Teils kümmern sich erfahrungsgemäss einen Dreck um die Realzeit und gerade in der Musik ist das eher ein wichtiger Aspekt...

Um's Experimentieren wird man so oder so nicht herumkommen und da ist das Superprogramm MIDI_OX äusserst hilfreich. Damit kann man alles einstellen & austesten & kontrollieren - nicht ganz einfach aber auch sehr lehrreich!

Alle benötigten files zum Nachbau dieses Projektes kannst du als .zip downloaden.

Bei Fragen & Anregungen email an info@messie.ch - damit's nicht im Nirwana landet muss die Betreffszeile(subject) mindestens auch das Stichwort 's2m' enthaltem !!