MIDI/UART lesen. Was mache ich falsch?

OP #5533944
Lesenswert?

Hallo,
ich versuche mithilfe eines ATmega328 ein Midi Leser zu bauen.
Für den Anfang wollte ich die Richtigkeit der Empfangenen Daten 
feststellen.
Ich habe eine Standard Eingangsschaltung (siehe Wikipedia: Midi) 
verwendet und den Ausgang direkt auf den UART Pin geschaltet.

Immer wenn ein Byte empfangen wird, wird eine Interruptroutine 
ausgeführt, die einen Wert verändert und das Byte kopiert, sodass es in 
der Hauptschleife abgearbeitet werden kann.

Noch in der ISR überprüfe ich, ob das empfangene Byte ein Active Sense 
Signal (0xFE), was alle 200ms vom Keyboard geschickt wird, ist. Das 
funktioniert.
Deshalb glaube ich, dass alle Einstellungen richtig sein müssten (siehe 
Bild activeSense.jpg)

Wenn ich aber in der Hauptschleife mit dem Byte arbeite kommen immer 
falsche Dinge raus (siehe Bild note_on.jpg).

Immer wenn das Byte mit einer 1 anfängt sollte PB2 für 100µS an sein.

Lese ich die Daten vielleicht falsch herum?
Das kann eigentlich nicht sein, da ich die Active Sense Nachrichten per 
Vergleich ignorieren kann.

Einstellungen Logic analyzer UART decoder:
Baudrate: 31250
Datenbits: 8
Parität: keine
Parität prüfen: Nein
Stop bits: 1,0
Bit reihenfolge: LSB first
Invertiertes Signal: Nein


Code:
1
#define F_CPU 20000000
2

3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6

7
volatile uint8_t receiveComplete = 0;
8
volatile uint8_t recByte;
9

10

11
int main( void )
12
{
13
  // Port init.
14
  DDRB |= (1<<PB2);
15
  
16
  // UART init.
17
  UCSR0A = 0;
18
  UCSR0B = 0b10010000;
19
  UCSR0C = 0b00000110;
20
  UBRR0L = 39;
21
  UBRR0H = 0;
22
  
23
  sei();
24
  
25
    while( 1 )
26
    {
27
    if( receiveComplete )
28
    {
29
      if( (recByte & 0b10000000) )
30
      {
31
          PORTB |= (1<<PB2);
32
          _delay_us(100);
33
          PORTB &= ~(1<<PB2);
34
      }
35

36
      recByte = 0;
37
      receiveComplete = 0;
38
    }
39
    }
40
}
41

42
ISR( USART_RX_vect )
43
{
44
  // Ignore the active sense messages.
45
  if( UDR0 != 0xFE )
46
  {
47
    recByte = UDR0;
48
    receiveComplete = 1;
49
  }
50
}
Angehängte Dateien:
#5533990
Lesenswert?

Ich weiß nicht, wieso es nicht geht. Aber vielleicht hilft das bei der 
Fehlersuche: Ich würde in der ISR (wenn genug Zeit) eine Funktion 
machen, die das empfangene Datenwort mittel Bitbanging seriell zu einem 
freien Pin rausgibt. Dort den Logic Analyzer ran hängen und gucken, ob 
die Daten zusammen passen. Das hilft idR, um den Fehler zu lokalisieren.

Pseudo-Code:
1
char PinNr = ...;
2
char Data = vom UART gelesenes Datenwort;
3

4
setPin( PinNr, 0 ); 
5
wait(1us oder 10 Takte oder ähnlich);
6
for (int i=0; i<8;  i++) {
7
  setPin( PinNr, Data & 1); 
8
  Data = Data >> 1;
9
  wait(1us oder 10 Takte oder ähnlich);
10
}
11
setPin( PinNr, 1 );
#5534026
Lesenswert?

Hallo,
für mich ist gleich merkwürdig, daß du USART ohne Puffer machst.

Als Einregung möchte ich hier ein bißchen Code geben. Das ist für AT 
Mega 1284P, aber notwendige Anpassung ist unkompliziert.
1
// usart.h
2
#ifndef USART_H
3
#define USART_H 1
4

5
#define USART_BAUD_MIDI (((F_CPU/16)/31250)-1)
6
#define USART0_SIZE_RX   16
7
#define USART0_SIZE_TX   16
8
void usart0_rxpuff_null(void); // RX puffer => 0
9
void usart0_txpuff_null(void); // TX puffer => 0
10
unsigned char usart0_rxsymbol_count(); // Zustand von RX Puffer
11
unsigned char usart0_txsymbol_count(); // Zustand von TX Puffer
12
void usart0_rxpuffein(unsigned char data); // byte aus RX0 in puffer lesen
13
unsigned char usart0_rxpuffaus(void);  // byte aus Puffer lesen
14
void usart0_txpuff_null(void); // TX puffer = 0
15
void usart0_txpuffein(unsigned char data); // byte in TX puffer lesen
16
void usart0_txpuffaus(void);// byte aus TX Puffer senden, in interrupt tx
17

18
static inline void usart0_init(void){
19
  UBRR0H = (uint8_t)(USART_BAUD_MIDI>>8);
20
  UBRR0L = (uint8_t)USART_BAUD_MIDI;
21
  UCSR0A = 0;
22
  UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
23
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
24
  usart0_rxpuff_null();
25
  usart0_txpuff_null();
26
}
27

28
#endif  /* USART_H */
29

30
// usart.c
31
#include <avr/io.h>      // Muss immer sein
32
#include <inttypes.h>     // Fuer Datentyp
33
#include <avr/pgmspace.h>   // Fuer Flash 
34

35
#include "main.h"   // Allgemeine Programmablauf 
36
#include "usart.h"   // USART 
37
#include "lcd.h"  // LCD
38

39
static unsigned char rx_kopf;
40
static unsigned char rx_schwanz;
41
static unsigned char rx_symbol_count;
42
static unsigned char rx_puffer[USART0_SIZE_RX];
43

44
static unsigned char tx_kopf;
45
static unsigned char tx_schwanz;
46
static unsigned char tx_symbol_count;
47
static unsigned char tx_puffer[USART0_SIZE_TX];
48

49
void usart0_rxpuff_null(void){ // puffer = 0
50
  
51
  rx_schwanz = 0; 
52
  rx_kopf = 0;
53
  rx_symbol_count = 0;
54
}
55

56
void usart0_txpuff_null(void){ // puffer = 0
57
  
58
  tx_schwanz = 0; 
59
  tx_kopf = 0;
60
  tx_symbol_count = 0;  
61
}
62

63
unsigned char usart0_rxsymbol_count(){
64

65
  return rx_symbol_count;
66
}
67

68
unsigned char usart0_txsymbol_count(){
69

70
  return tx_symbol_count;
71
}
72

73
static void count_inc(unsigned char *count, unsigned char wert){
74
  (*count)++;
75
  if(*count >= wert){
76
      *count = 0;
77
    }
78
}
79

80
void usart0_rxpuffein(unsigned char data){ // byte aus RX0 in puffer lesen
81

82
  if(rx_symbol_count < USART0_SIZE_RX){  
83
  // Wenn puffer noch Platz hat
84

85
    rx_puffer[rx_schwanz] = data;  
86
    rx_symbol_count++;
87

88
    count_inc(&rx_schwanz, USART0_SIZE_RX);
89
  }  
90
  FLAGG &= ~(1<<F_RX0);  // Flag fuer Empfang auf Null
91
}
92

93
void usart0_txpuffein(unsigned char data){ // byte in TX puffer legen
94

95
  if(tx_symbol_count < USART0_SIZE_TX){  
96
  // Wenn puffer noch Platz hat
97

98
    tx_puffer[tx_schwanz] = data;  
99
    tx_symbol_count++;
100

101
    count_inc(&tx_schwanz, USART0_SIZE_TX);
102
  }
103
}
104

105
unsigned char usart0_rxpuffaus(void){  // byte aus RX Puffer lesen
106

107
  unsigned char data = 0;
108
  data = rx_puffer[rx_kopf];
109
  rx_symbol_count--;
110
  count_inc(&rx_kopf, USART0_SIZE_RX);
111

112
  return data;;
113
}
114

115
void usart0_txpuffaus(void){  // byte aus TX Puffer senden
116

117
  UDR0 = tx_puffer[tx_kopf];
118
  tx_symbol_count--;
119
  count_inc(&tx_kopf, USART0_SIZE_TX);
120
}
121

122
// midi.h
123
#ifndef MIDI_H
124
#define MIDI_H 1
125

126
#define ACTIVE_SENSING 0xfe
127

128
void midi_lcd(unsigned char midi_byte); 
129
// Gibt auf Indikator Leerzeichen und Ziffer
130

131
void midi_puff_schieb(unsigned int data ); 
132
// schieben fuer MIDI: int=2x char und Leerzeichen
133
#endif  /* MIDI_H */ 
134

135
// midi.c
136
#include <avr/io.h>      // Muss immer sein
137
#include <inttypes.h>     // Fuer Datentyp
138
#include <avr/pgmspace.h>   // Fuer Flash 
139

140
#include "main.h"   // Allgemeine Programmablauf
141
#include "lcd.h"  // LCD
142
#include "midi.h"   // MIDI
143
#include "led.h"  // LED, fuer LED_F_NUM
144

145
void midi_lcd(unsigned char midi_byte){ // Gibt auf Indikator Leerzeichen und Ziffer
146
  if(midi_byte != ACTIVE_SENSING){ // Synchro-Byte ausschliessen
147
    unsigned int midizif;
148
    midizif = lcd_ziffer(midi_byte);
149
    midi_puff_schieb(midizif);
150
  } else { // Led F kurz einschalten, wenn ACTIVE_SENSING
151
    led_ein_time((1<<LED_F_NUM),50);
152
  }
153
}
154

155
void midi_puff_schieb(unsigned int data ){ // schieben fuer MIDI: int=2x char und Leerzeichen
156
  unsigned int a;
157
  unsigned char b;
158
  a = (data >> 8);
159
  b = (unsigned char)a;
160
  lcd_puff_schieb_links(b);  // Dec
161
  b = (unsigned char)data;
162
  lcd_puff_schieb_links(b);  // Eins
163
  lcd_puff_schieb_links(' ');  // Leerzeichen
164
}
165

166
// main.h
167
#ifndef MAIN_H
168
#define MAIN_H 1
169

170
#ifndef  F_CPU  // Quarz 16 MHz.
171
#define F_CPU 16000000UL    // CPU_F fuer Verzoegerungen
172
#endif 
173

174
#ifndef FLAGG
175
  #define FLAGG GPIOR0 /* fuer Ereignisse */
176
  #define F_PULS 0  /* Puls 1000 Hz, timer 3 interrupt */
177
  #define F_RX0 1    /* MIDI-Nachricht gekommen */
178
  #define F_TX0 2    /* MIDI-Nachricht versandt */
179
#endif
180

181
/**********************************************************/
182

183

184
#endif  /* MAIN_H */
185

186
// main.c
187
#include <avr/io.h>  // Muss immer sein
188
#include <stdio.h>  // Die Ein- und Ausgabefunktionen, 
189
// Typen und Makros
190
#include <stdlib.h>  // Funktionen zur Umwandlung von Zahlen, 
191
// fuer Speicherverwaltung und aehnliche Aufgaben.
192
#include <string.h>  // Funktionen fuer Zeichenketten
193
#include <inttypes.h>     // Fuer Datentyp
194
#include <avr/interrupt.h>   // Fuer Interrupts
195
#include <avr/eeprom.h>    // Fuer EEPROM
196
#include <avr/pgmspace.h>   // Fuer Flash
197
#include <util/delay.h>    // Fuer Verzoegerungen
198

199
#include "main.h"   // Allgemeine Programmablauf
200
#include "led.h"  // LED
201
#include "knopf.h"   // Knopf
202
#include "drehgeber.h"   // Drehgeber
203
#include "timer.h"   // Systempuls
204
#include "spi.h"   // SPI
205
#include "lcv1024.h"   // NVRAM
206
#include "lcd.h"  // LCD
207
#include "usart.h"   // USART  
208
#include "midi.h"   // MIDI
209
#include "logik.h"  // Logik
210

211
ISR(USART0_RX_vect){ // USART0, Rx Complete
212

213
  FLAGG |= (1<<F_RX0);  // Flag fuer Empfang einsetzen
214
  usart0_rxpuffein(UDR0);  // In Puffer
215
}
216

217
int main(void){
218

219
/******* init *******/
220

221
  system_init();
222

223
  sei();  // Interrupts erlauben 
224

225
/* * * */
226

227
while(1){ 
228

229
  // Bedienung von Puls 1 ms
230
  if( FLAGG & (1<<F_PULS) ){
231

232
    FLAGG &= ~(1<<F_PULS); // Flag fuer Puls = 0
233
    
234
    /* * etwas, was jede 1 ms gemacht sein sollte * */
235
  }
236

237
  // Pruefen, ob TX-Puffer etwas hat.
238
  // Wenn TX-Puffer nicht leer und fruehere Sendung zu Ende
239
  if((usart0_txsymbol_count()) && (UCSR0A & (1<<UDRE0))){    
240
    usart0_txpuffaus();
241
  }
242

243
  
244

245
  /* RX bedienen */ 
246
  if(usart0_rxsymbol_count()){ // wenn rx-Puffer nicht leer
247
    unsigned char data;
248
    data = usart0_rxpuffaus();
249
    if(data != ACTIVE_SENSING){
250
      midi_puff_schieb(lcd_ziffer(data));
251
    } else {
252
      led_ein_time((1<<LED_F_NUM),70);
253
    }
254
  }
255

256
}
257
return 0;
258
}
OP #5534049
Lesenswert?

Das Projekt ist ja offensichtlich noch lange nicht fertig :)
Puffer und so kommen später.

Der Controller läuft wirklich mit 20MHz ich habe das flasche Bild 
angehängt bzw. den flaschen Code gepostet. Der Puls auf PB2 ist 
tatsächlich 100µS lang.

Das testen des Frame Error Bits hat auch nichts ergeben. Das scheint zu 
funktionieren.

Ich werde jetzt versuchen die Daten wieder auszugeben.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren