Forum: Mikrocontroller und Digitale Elektronik MIDI-Monitor


von HPT (Gast)


Lesenswert?

Ich suche nach einer Möglichkeit, um z.B. mit einem Atmega8 die 
MIDI-Telegramme, welche von einem MIDI-Keyboard kommen, dahingehend zu 
ananlysieren, a) Welche Taste ist gedrückt und b) die Lautstärke. Nach 
meinen ersten Versuchen bin ich so weit, dass ich über PinD.0 (RXD) 
(Pin2-Atmega8) Signale über den UART lesen kann. Ich benutze BASCOM und 
habe festgestellt, dass Waitkey() und Input bzw. Inkey() nicht brauchbar 
sind. Deshalb warte ich in einer ISR auf ein Byte. Bei der Auswertung 
scheint aber alles zu langsam zu sein, was ich bis jetzt so probiert 
habe.

Jetzt meine Frage: Wer hat Erfahrung mit dem UART und der anschließenden 
Auswertung? Ich bin für jeden Tipp und jede Hilfestellung dankbar.

Schönen Abend wünscht HPT

von Blubber (Gast)


Lesenswert?

Schau mal in Zeile 42 von deinem Programm, das du angehängt hast.

von HPT (Gast)


Lesenswert?

... was meinst du mit Zeile 42 ? Von welchem Programm?

von Crazy Harry (crazy_h)


Lesenswert?

Er meinte damit, daß du dein Programm hier komplett posten sollst, damit 
er abkupfern und es als sein geistiges Eigentum verkaufen kann ..... wie 
immer.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Du kannst dir z.B. zunutze machen, das Command Bytes bei Midi das 8.Bit 
gesetzt haben und Datenbytes nicht.
Deine ISR könnte also darauf achten und bei einem Commandbytes anfangen, 
in einen Buffer zu schreiben. Sobald das nächste Command Byte kommt, ist 
der MIDI Befehl abgeschlossen und fertig zur Ausgabe, während das 
nächste Command im Buffer landet.
Das Problem ist, das der Mega8 nur einen Hardware UART hat, du kannst 
also nur mit 31250 Baud empfangen und senden, wenn du TXD des Mega zur 
Ausgabe benutzt.Wenn du hingegen z.B. ein LCD als Augabe benutzt, 
entsteht dieses Problem nicht. Ein Software Serial geht natürlich auch, 
oder du schickst was auf eine LED (7-Segment) Anzeige oder so.

Es gibt natürlich noch massenweise andere MIDI Empfangsstrategien. Man 
könnte z.B. ein Flag bei einem Command Byte setzen, oder eben bei einem 
Datenbyte usw. Geräte, die nur auf einen MIDI Kanal reagieren, filtern 
alles weg, was nicht mit einem Command für ihren Kanal begonnen hat, 
usw.

: Bearbeitet durch User
von HPT (Gast)


Lesenswert?

Servus Matthias - danke für die Tipps. Eigentlich möchte ich nur nach 
"dez.144" (Noteon) suchen und danach die beiden Bytes auswerten (Ton, 
Lautstärke) alles andere brauche ich gar nicht. Aber wie mache ich das 
so schnell, dass nichts verschluckt wird, wenn eine Taste nur kurz 
gedrückt wird, bzw. ein "Lauf" auf der Tastatur gespielt wird? Gibr es 
Beispiele ?
Bin für alles dankbar!!!

von Peter II (Gast)


Lesenswert?

HPT schrieb:
> . Aber wie mache ich das
> so schnell, dass nichts verschluckt wird, wenn eine Taste nur kurz
> gedrückt wird, bzw. ein "Lauf" auf der Tastatur gespielt wird?

alles was du man Tasten erreichen kannst ist LANGSAM. in Der Zeit kann 
der Controller noch PI neu berechnen.

Keine Ahnung wie es mit BASCOM geht. Bei C würde man den code  einfach 
in der ISR für den UART RX hängen und die Daten abfragen. Das langsamste 
ist die UART(Midi) Übertragung und nicht der Controller.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

HPT schrieb:
> Aber wie mache ich das
> so schnell, dass nichts verschluckt wird, wenn eine Taste nur kurz
> gedrückt wird, bzw. ein "Lauf" auf der Tastatur gespielt wird?

Du könntest in der ISR bspw. nach einem 'NoteOn' eine Flagge setzen und 
solange die Flagge gesetzt ist, Bytes, die kleiner sind als 128 (also 
Datenbytes) speichern. Die Flagge wird gelöscht, wenn ein Byte >128 
kommt, das kein NoteOn ist.
Das langsame ist nicht der Empfang des Zeichens, die ISR meldet sich ja 
erst, wenn ein Zeichen komplett da ist - beim Stopbit. Deswegen hast du 
während des Empfangs Zeit, um dich um andere Sachen zu kümmern. Dein 
Problem ist vermutlich, den Kram auszugeben. Ob ein LCD unter Bascom 
schnell genug ist, weiss ich nicht, aber in C klappt das immer.

von Thomas E. (picalic)


Lesenswert?

HPT schrieb:
> "dez.144" (Noteon) suchen und danach die beiden Bytes auswerten (Ton,
> Lautstärke) alles andere brauche ich gar nicht.

Nur so nebenbei: Das Statusbyte ("Note On") muss nicht zwingend am 
Anfang jeder Noten-Message stehen - u.U. wird das nur einmal gesendet 
und es kommen minutenlang nur Datenbytes 
(Notennummer-Anschlag-Notennummer-Anschlag...)
Das heißt "Running Status".

: Bearbeitet durch User
von HPT (Gast)


Lesenswert?

... liest sich alles interessant! Aber wie geh ich vor? Es gelingt wie 
schon geschrieben, in der ISR das Byte auszulesen. Ich bräuchte ein 
Beispiel wie man prinzipiell Daten in einen Buffer schreibt, bzw. vor 
allem auch wie ich danach im Hauptprogramm nach "144" suche und das 
alles so gestalte, dass ein weiterer Interrupt, der ja zu jeder zeit 
kommen kann und auch wird, wenn die Tasten schnell genug hintereinander 
gedrückt werden!
Von diesem "running status" habe ich noch nichts gelesen Thomas. Ist 
auch interessant, aber momentan sind meine Probleme noch 
grundsätzlicher.
Vielleicht hat doch noch jemand verwertbare Programm-Teile.
Ich würde mich sehr freuen.

von Thomas E. (picalic)


Lesenswert?

Du könntest Dir erstmal ein FIFO (als Ringpuffer) anlegen und in der ISR 
nix anderes machen, als jedes Datenbyte, das über UART hereinkommt, dort 
hineinzuschreiben. Google mal nach FIFO (s.auch: 
https://www.mikrocontroller.net/articles/FIFO)

Im Hauptprogramm holst Du die Bytes aus dem FIFO (wenn welche drin sind, 
d.h. wenn write- und read-Indexe verschieden sind) und verarbeitest sie 
- damit ist schonmal das Timing der Verarbeitung vom Timing des Empfangs 
entkoppelt.

Für die Verarbeitung bietet sich eine State-Machine an. Kommt ein Byte 
mit MSB=1, ist es ein Statusbyte -> Statusbyte abspeichern, State auf 
"erwarte erstes Datenbyte" setzen. Außer, wenn es eine Echtzeit-Message 
(>= 0xF8) ist - die darf immer kommen, auch zwischen Datenbytes einer 
anderen Message -> Du ignorierst sie, ohne den State der Statemachine zu 
ändern. Ist das Statusbyte eines, mit dem Du nix anfangen kannst oder 
willst (z.B. SysEx und co., Bereich 0xF0..0xF7), setzt Du den neuen 
State Deiner Statemachine auf "erwarte Statusbyte"

Kommt ein Datenbyte (MSB = 0) und State ist "erwarte erstes Datenbyte", 
speicherst Du das erste Datenbyte in einer Variablen (z.B. data1).
Wenn das gespeicherte Statusbyte zu einer MIDI-Message gehört, die nur 
ein Datenbyte hat (z.B. Program Change), ist die empfangene MIDI Message 
vollständig (-> verarbeiten), neuer State der Statemachine ist dann 
wieder "erwarte erstes Datenbyte".
Wenn zum Statusbyte zwei Datenbytes gehören: State = "erwarte zweites 
Datenbyte".

Kommt ein Datenbyte (MSB = 0) und State ist "erwarte zweites Datenbyte", 
ist Deine MIDI-Message komplett -> verarbeiten.
State auf "erwarte erstes Datenbyte" setzen - wg. Running Status!

Kommt ein Datenbyte und nach aktuellem State erwartest Du kein 
Datenbyte,  ignorierst Du das Datenbyte einfach.

von HPT (Gast)


Lesenswert?

Hallo picalic
Einiges konnte ich umsetzen. Es läuft mein Ringpuffer und ich kann über 
eine ISR die MIDI-Telegramme hineinschreiben. Es ist mir in BASCOM auch 
gelungen, Bytes aus dem Ringpuffer zu lesen. Nur bei der Realisierung 
der Decodierung nach Status bzw. Daten-Bytes will es mit if-then ... 
nicht gelingen.
Vor allem auch der running-status und wenn andere Statusbytes 
zwischenkommen wird alles komplex.
Wahrscheinlich ist die "state-machine" wohl das Richtige!
Wie geht man da an die Sache? Könnte man das mit "select case" Kommandos 
aufbauen? Noch kann ich mir nicht vorstellen, wie das aussehen könnte.
Kann man dein obiges Prinzip noch etwas veranschaulichen?
Schönen Abend und Danke für die Unterstützung!

von Thomas E. (picalic)


Lesenswert?

HPT schrieb:
> Wie geht man da an die Sache? Könnte man das mit "select case" Kommandos
> aufbauen?

von BASCOM habe ich keine Ahnung - "select case" klingt aber so, als 
wäre es wie "switch case" in C, und somit könnte es schonmal ein 
geeignetes Werkzeug sein. "If"-Abfragen gehen im Prinzip aber auch, nur 
ist es dann halt ggf. etwas unübersichtlicher, als eine einzige 
Verzweigung mit vielen cases.
Die State-Machine kann man mit einer simplen Variablen realisieren, über 
die dann mit "case" auf die entsprechenden Programmteile verzweigt wird.
Da Status- und Datenbytes grundsätzlich leicht zu unterscheiden sind (am 
MSB) und auch grundverschieden verarbeitet werden müssen, bietet sich 
an, zunächst mit "if" in je eine Verarbeitungsroutine für Daten- und 
eine für Statusbyte zu verzweigen. Dort kann es dann anhand von 
gespeicherten Daten (z.B. vorher empfangenes Statusbyte, aktueller Wert 
der "State"-Variablen) entsprechend weiterverarbeitet werden.

: Bearbeitet durch User
von hans-peter.traussnigg@schule.at (Gast)


Lesenswert?

Ich denke, meine Dekodierung der MIDI-Telegramme funktioniert jetzt! 
Habe eine state-machine (glaube ich) zusammengebastelt und im Simulator 
getestet. Jetzt habe ich sie zusammen mit dem Ringpuffer am Atmega 8 im 
Probelauf und es schaut gut aus.
Ich möchte mich nochmal bei allen Ratgebern herzlich bedanken.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.