Hallo! Ich möchte ein MIDI-Interface aufbauen, das Teil eines Projektes
mit dem MSP430F1611 ist. Es sollen Program Change und Bank
Select-Messages gesendet und empfangen werden. Dafür wird der UART-Modus
der USART0 benutzt. Das ganze soll folgendermaßen implementiert werden:
In einer Routine des Hauptprogramms sollen die MIDI-Parameter
(Kanalnummer, Banknummer, Programmnummer) abgefragt werden. Mit dem Ende
der Abfrage sollen die entsprechenen MIDI-Befehle über die UART gesendet
werden. Der Empfang der gleichen Parameter soll bewirken, daß das
Hauptprogramm darauf reagiert und in eine Subroutine springt.
Ich möchte jetzt mal Tips einholen, wie das ganze am besten zu
realisieren ist. Ich kann zwar einigermaßen in C programmieren, aber
diese µC-Geschichte mit ihren Interrupts ist für mich immernoch Neuland.
Zumindest beim Empfang denke ich, müßte ein Interruptflag abgefragt
werden, auf das das Programm reagiert.
Der Rumpfcode sieht momentan folgendermaßen aus:
Die UART0 wird für MIDI initialisiert; die Routine habe ich aus einem
der TI-Beispielcodes und für meine Zwecke angepasst.
1 | void MIDI_Init()
|
2 | {
|
3 | P3SEL |= 0x30; // P3.4 und P3.5 --> TXD/RXD der USART0
|
4 | U0CTL &= ~(I2C+SYNC+I2CEN) // noch gesetzte Bits des I²C-Modus löschen
|
5 | // (wird in anderer Routine verwendet)
|
6 | U0CTL |= SWRST; // Software-Reset der USART0
|
7 | ME1 |= UTXE0 + URXE0; // TXD/RXD des USART0-Moduls aktivieren
|
8 | UCTL0 |= CHAR; // 8-Bit Zeichenlänge
|
9 | UTCTL0 |= SSEL1; // UCLK = SMCLK (4MHz)
|
10 | UBR00 = 0x80; // Teilerfaktor für Baudrate einstellen
|
11 | UBR10 = 0x00; // (4MHz / 128 = 31250bps)
|
12 | UMCTL0 = 0x00; // keine Teilerkorrektur (Modulation) nötig
|
13 | UCTL0 &= ~SWRST; // Software-Reset der USART0 aufheben
|
14 | IE1 |= URXIE0 + UTXIE0; // RX- und TX-Interrupt für USART0 akt.
|
15 | IFG1 &= ~UTXIFG0; // initales Interrupt-Flag löschen
|
16 | }
|
Das wäre mein Ansatz für eine Senderoutine:
1 | void MIDI_Out(BYTE midi_ch, BYTE midi_bk, BYTE midi_pr)
|
2 | {
|
3 | if (midi_bk != 0xFF) // falls Bank Select vorliegt
|
4 | {
|
5 | while (!(IFG1 & UTXIFG0)); // TX-Buffer der USART0 bereit?
|
6 | TXBUF0 = 0xB0 + midi_ch; // Statusbyte Control Change
|
7 | while (!(IFG1 & UTXIFG0));
|
8 | TXBUF0 = 0x00; // 1. D.Byte Bank Select (Contr. 0 - MSB)
|
9 | while (!(IFG1 & UTXIFG0));
|
10 | TXBUF0 = 0x00; // 2. D.Byte Bank Select (Banknummer MSB)
|
11 | while (!(IFG1 & UTXIFG0));
|
12 | TXBUF0 = 0xB0 + midi_ch; // Statusbyte Control Change
|
13 | while (!(IFG1 & UTXIFG0));
|
14 | TXBUF0 = 0x20; // 1. D.Byte Bank Select (Contr. 32 - LSB)
|
15 | while (!(IFG1 & UTXIFG0));
|
16 | TXBUF0 = midi_bk; // 2. D.Byte Bank Select (Banknummer LSB)
|
17 | }
|
18 | if (midi_pr != 0xFF) // falls Program Change vorliegt
|
19 | {
|
20 | while (!(IFG1 & UTXIFG0));
|
21 | TXBUF0 = 0xC0 + midi_ch; // Statusbyte Program Change
|
22 | while (!(IFG1 & UTXIFG0));
|
23 | TXBUF0 = midi_pr; // Datenbyte Program Change(Programmnr.)
|
24 | while (!(IFG1 & UTXIFG0));
|
25 | IE1 &= ~UTXIE0; // TX-Interrupt für USART0 deaktivieren
|
26 | }
|
27 | }
|
Ich bin allerdings auch auf solche Konstrukte gestoßen:
1 | #pragma vector = UART0TX_VECTOR
|
2 | __interrupt void usart0_tx(void)
|
3 | {
|
4 |
|
5 | }
|
Wie gesagt, ich bin auf dem Gebiet der Interruptprogrammierung völliger
Neuling. Wie würde ich die zu sendenden Parameter denn in dem Fall an
usart0_tx(void) übergeben? Was müßte zwischen den geschweiften Klammern
stehen?
Der Empfang müßte doch sicherlich in jedem Falle in etwa so realisiert
werden:
1 | #pragma vector = USART0RX_VECTOR
|
2 | __interrupt void usart0_rx(void)
|
3 | {
|
4 | // RXBUF0 abfragen und in Variable speichern?
|
5 | }
|
Und wie rufe ich die Interruptroutine aus dem Hauptprogramm auf? Wäre
schön, wenn mir hier jemand ein bißchen Hilfestellung geben könnte.
Danke schonmal!