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
Er meinte damit, daß du dein Programm hier komplett posten sollst, damit
er abkupfern und es als sein geistiges Eigentum verkaufen kann ..... wie
immer.
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.
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!!!
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.
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.
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".
... 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.
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.
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!
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.
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.