Arduino Projekten

Sat 20-Apr-24
13:53:33


Midi In

Datum: Sun 03 August 2014
Samenvatting: Midi In testen van de Midi Module


Na de Midi Out moet de Midi In worden getest. Een bijkomende moeilijkheid is dat de ontvangende aansluiting op de Arduino gedeeld wordt met de communicatie via de USB-port. Dat verklaart meteen de aanwezigheid van de 2-polige jumper op de Midi Module. De Midi In moet losgekoppeld kunnen worden, wanneer er een nieuw programma naar de Arduino gestuurd wordt. De schakelaar op de experimenteer-behuizing naast de Reset voert deze functie uit - dat is een stuk makkelijker dan elke keer een jumper los/ vastzetten, of een draadje los/ vastmaken.

Het Midi Out testen was relatief eenvoudig. Alles wat gestuurd moet worden, wordt gewoon door de Midi connector gestuurd.

Maar Midi In testen is een stuk lastiger. Om eerlijk te zijn, het enige dat voldoende was om te testen, was om te zien of de Midi signalen binnen komen en of de Arduino ze interpreteert. Een eenvoudig tellertje en de inhoud hiervan op de Leds aangeven vergt maar een kort programma. Op dat punt is de conclusie dat de Midi Module volledig werkt zoals bedoeld is.

Maar Midi bestaat uit meer dan alleen maar enkele bytes. Net als bij de Midi Out worden op de 8 Leds van de decoder (74hct138) aangegeven welk commando er doorkomt ($8 tot en met $F). De 16 Leds op de voorkant van de experimenteer behuizing geven aan welke parameters (vanaf $00 tot en met $7F) er meekomen.

Dit klinkt eenvoudig, maar dat is het niet. Mijn Midi Keyboard geeft een "storend" "signaal" door. Dit blijkt een Common Commando te wezen, met de waarde $FE (van System Sensing). Het Keyboard geeft hiermee aan dat het aan staat en dat de Midi verbinding goed is.

Ook kan elk Common Commando tussen en midden in de Midi Commando's komen, ook al wordt er een parameter verwacht, een Common Commando krijgt alle voorrang. Op zich heel logisch, aangezien in de Common Commando's ook een Start ($FA), Stop ($FC) en een Tijdklok ($F8) Commando voorkomen, waarmee het tempo van een Midi compositie gegarandeerd moet blijven. Deze moeten zo snel mogelijk uit de Data worden gefilterd, wat in het programma ook duidelijk is te zien (bij MidiComCom).

Tevens zal het programma de overige Midi Commando's (MidiCommand) ($80 tot en met $EF) moeten uitsplitsen om het aantal nog-te-verwachten parameters te bepalen. Na er eerst een grote IF-THEN-ELSE-statement voor gebruikt te hebben, is er uiteindelijk voor gekozen om dit via een array te doen (AantalMidiParms[16]). Hoewel er hiervoor eigenlijk maar 8 waardes nodig zijn, is er voor 16 waardes gekozen. Dit bied meer snelheid en meer overzichtelijkheid, dan eerst nog de Commando-waarde met 8 te verminderen. PLUS in C beginnen array's altijd bij 0 (NUL) ... of ik weet (nog) niet hoe array's ook bij een andere waarde kunnen beginnen, zoals dat in Pascal wel kan.

Voor de parameters zelf wordt er een teller-constructie gebruikt. Na elke parameter wordt deze teller opgehoogd tot het benodigde aantal (1 of 2 stuks) is binnengehaald (MidiParm1 en MidiParm2).

Het Midi Kanaal (MidiChannel) is hier wel al aanwezig ter voorbereiding, maar deze wordt nog niet gebruikt. Alles wat binnenkomt wordt gedecodeerd en verwerkt, de zogenaamde Omni werking.

Het Midi Commando wordt op de decoder-Leds getoond vlak voor het aantal parameters wordt bepaald. De parameters worden op de front-Leds getoond, na het lezen van alle benodigde parameters.

Nu is er (vaag) in de Midi-norm beschreven dat er parameters kunnen binnen komen, zonder dat er een Commando vooraf gegeven is. Deze parameters hebben dan betrekking op de laatst gegeven Commando, inclusief het aantal parameters. Zonder deze kennis lijkt het alsof Midi stottert en dat er gegevens onderweg kwijt raken, hoewel andere Midi-apparatuur de gegevens wel juist lijken te verwerken. Hier is dat opgelost door te kijken of het benodigde aantal parameters binnen zijn en dan meteen de parameter teller weer op NUL te zetten.

if (ParmCount == AantalParms) { ParmCount = 0; }

Projekt Conclusie.

Dit zal de hoofdstructuur van Midi programma's worden van verdere projekten, zoals het Midi-Paneel en de Sid Synthesizer.


Broncode: [1: Midi In]

1: De broncode van Midi In

(Sun 03 August 2014) Eenvoudig testprogramma voor Midi in - De Led's geven Midi-data aan.

Deze broncode heeft 87 regels met programma-code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//
// Midi In test
// A simple program to receive Midi Data from a Midi Machine
//

byte Channel  = 0;
byte SerialByte  = 0;
byte MidiChannel = 0;
byte MidiCommand = 0;
byte MidiComCom  = 0;
byte MidiParm1   = 0;
byte MidiParm2   = 0;
byte AantalParms = 0;
byte ParmCount   = 0;

void setup()
{ Init_Led();
  Serial.begin(31250);
}

void loop()
{ ReadMidi();
}


// Array with Number of Parameters of a Command
const byte AantalMidiParms [16] = {0,0,0,0,0,0,0,0,2,2,2,2,1,1,2,0};

void ReadMidi()
{ if (Serial.available() > 0)
     {  SerialByte = Serial.read();
        if (SerialByte & 0x80) != 0)
           { // Its a Command Byte
             Led_Out(SerialByte >> 4 );
             if ( SerialByte >= 0xF0 )  // System Common Commando
                { MidiComCom = SerialByte; }
             else
                { MidiComCom = 0;  // Its No Common Commando, So Clear it
                  ParmCount=0;
                  // Split Channel and Command
                  MidiChannel = ( SerialByte & 0x0F );
                  MidiCommand = ( SerialByte & 0xF0 );
                  // Get the Number of Parms of the Command.
                  AantalParms = AantalMidiParms[ MidiCommand >> 4 ];
                }
           }
        else
           { // Its a Parameter Byte
             MidiComCom = 0;
             if (ParmCount < AantalParms)
                { // Count the number of Parameters
                  ParmCount = ParmCount + 1;
                  if (ParmCount == 1)
                     { MidiParm1 = SerialByte;  // Read First Parameter
                       MidiParm2 = 0;
                     }
                  if (ParmCount == 2)
                     { MidiParm2 = SerialByte;  // Read Second Parameter
                     }
                }
             if (ParmCount == AantalParms)
                { // When All Parms are read, set the counter to NUL.
                  // Maybe only Parms of the next (but same) Command is comming.
                  ParmCount = 0;
                  Status(MidiParm1,MidiParm2);  // Sent (both) Parms to Front-Leds
                }
           }
     }
}

void Status(byte S1, byte S2)
{ digitalWrite(13, LOW);            // Hold Data
  shiftOut( 11, 12, MSBFIRST, S1);  // Send first byte
  shiftOut( 11, 12, MSBFIRST, S2);  // Send second byte
  digitalWrite(13, HIGH);           // Show Data
}

void Init_Led()
{ DDRC = DDRC | B00000111;    // pinMode(a , OUTPUT); pinMode(b , OUTPUT); pinMode(c , OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
}


void Led_Out(byte Nr)
{ PORTC = ( PORTC & B11111000 ) | (Nr & 0x07);


Broncode: [1: Midi In]

Afbeeldingen

midi_in_1.jpg
1/3: midi_in_1.jpg.
midi_in_2.jpg
2/3: midi_in_2.jpg.
midi_in_3.jpg
3/3: midi_in_3.jpg.

De aansluitingen van Midi In

Arduino Uno

Pwr USB ?
 
?
aref
gnd Gnd's (4x)
? d13 Latch (Front Leds)
ioreff d12 Clock (Front Leds)
reset d11 Data  (Front Leds)
+3.3v d10
+5v d9
Gnd's (4x) gnd d8
Gnd's (4x) gnd
Vin d7
d6
(Decoder Leds) A  (A0) a0 d5
(Decoder Leds) B  (A1) a1 d4
(Decoder Leds) C  (A2) a2 d3
a3 d2
a4 d1
a5 d0 Rx Midi in