DMX empfang in C funktioniert nicht richtig.

#3521689
Lesenswert?

Hallo liebe Community,


ich habe ein Problem mit dem Empfang von DMX in C...
Quellcode im Anhang :)

Das Programm soll folgendes tun:

Wenn der USART den Break erkennt (allso das FE Bit setzt)
sollen die ersten 10 Kanäle in ein Array geschrieben werden.
Anschließend soll im Hauptprogramm der 4.Kanal ausgewertet werden und 
eine LED entweder an oder ausgeschaltet werden.

Das Problem:

Das Programm empfängt die ersten 10 Bytes, erkennt auch den Break, aber, 
nachdem es diese 10 Bytes empfangen hat werden diese nicht mehr 
aktualisiert...

Ich bin relativer Neuling in C und auch erst 16 Jahre alt und würde 
gerne an diesem Problem weitertüfteln....

Da ich hier nicht weiterkomme, bitte ich um Unterstützung,da ich glaube 
das ich einen Denkfehler in meinem Programm habe.

Vielen Dank für Eure Bemühungen im Voraus,

Christian
Angehängte Dateien:
#3521697
Lesenswert?

Das
1
  if(1<<FE)

ist natürlich Quatsch. Denn dieser WErt ist immer wahr.

Was du oin wirklichkeit wolltest. Du wolltest ein Register befragen, ob 
dort drinnen das bewusste FE Bit auf 1 ist oder nicht.
D.h. in der Abfrage muss sowohl der Registername als auch der Bitname 
vorkommen.

Im Grunde genommen ist das nicht anders, als wie wenn du einen 
Eingangspin abfrägst. Da schreibst du auch nicht
1
   if( 1 << PB0 )

sondern
1
  if( PINB & ( 1 << PB0 ) )
also die Kombination aus: Nimm das Register PINB her und betrachte nur 
das Bit PB0 - ist das 0 oder 1?

Und hier bei dir ist das nicht anders. Das FE Bit ist in einem 
bestimmten Register beheimatet. Daher selbes Schema: Nimm den Inhalt des 
bewussten Registers her, maskiere mit einem & alles weg bis auf das FE 
Bit und dann erhebt sich die Frage: bleibt 0 übrig (dann war auch das 
Bit 0) oder nicht (dann war das Bit 1)

Das ist vom Prinzip her da (UART) wie dort (Input-Pins) genau das 
gleiche. Immer das gleiche Schema.
#3521715
Lesenswert?

1
...
2
int main()
3
{
4
 ...
5

6
  while(arraycomplete==1){
7
    
8
....
9
  }
10
}


nein, nicht weil arraycomplete == 1.
Die Hauptschleife läuft IMMER. Aus der kommt der µC regulär nicht mehr 
raus.
1
...
2
int main()
3
{
4
 ...
5

6
  while( 1 ) {
7

8
    if( arraycomplete == 1 )
9
    {
10
       ....
11

12
       arraycomplete = 0;
13
    }    
14
  }
15
}
#3521735
Lesenswert?

Weil ich gerade darauf gestossen bin und mich gefragt habe, ob man das 
FE Bit wirklich selbst löschen muss.

Das ist was im Datanblatt zum FE Bit steht
1
• Bit 4 – FE: Frame Error
2
This bit is set if the next character in the receive buffer had a
3
Frame Error when received. that is, when the first stop bit of the
4
next character in the receive buffer is zero. This bit is valid until
5
the receive buffer (UDR) is read. The FE bit is zero when the stop bit
6
of received data is one. Always set this bit to zero when writing to UCSRA.

richte dein spezielles Augenmerk auf den Abschnitt
1
... This bit is valid until the receive buffer (UDR) is read. ...

Das heißt: das Bit ist nur solange korrekt, bis du UDR ausliest. Danach 
gilt es nichts mehr (wahrscheinlich wird es von der Hardware mit dem 
Lesen aus UDR zurück gesetzt).
Darauf folgt aber auch: Du musst das FE Bit auslesen BEVOR du dir das 
Byte aus dem UDR holst. Nicht wie hier
1
...
2
ISR(USART_RX_vect)
3
{
4

5
Temp=UDR;
6

7

8

9
  if(1<<FE)
10
  {
11
...
erst hinterher.

Mehr Sorgfalt und weniger exzessive Leerzeilen, dafür aber konsistentere 
Einrückung und bessere Variablennamen und du hast schon mal 50% deiner 
jetzigen Probleme hinter dir gelassen.
#3521745
Lesenswert?

>    array[9] = '\0';

Das behebt jetzt zwar das Problem des Array Zugriffs out of bounds.

Aber die zweite Frage steht immer noch im Raum. Wozu?

Du hast hier sowieso keine Strings! DMX-Daten sind keine Strings und 
werden auch nie welche sein. Du brauchst daher diese Operation hier 
nicht. Alles was du tust ist, du zerstörst dir hier mutwillig Daten. 
Gut, das mag dir egal sein, weil du dieses Byte (den Kanal 10) sowieso 
nie brauchst. Trotzdem erhebt sich die Frage: warum zerstörst du es 
dann?
Du agierst hier wie jemand, der eine Bushaltestelle zerstört, weil er 
sowieso immer mit der Bahn fährt.
#3521762
Lesenswert?

Sind eigentlich die 8 Mhz gesichert?
Hast du das ausprobiert, ob der µC auch wirklich mit 8Mhz läuft? Zb 
indem man eine LED blinken lässt, abhängig von der Taktfrequenz.


Denn im Grunde machst auch du schon wieder den Kardinalfehler nummer 1. 
Du versuchst als Anfänger ein Programm zu schreiben ohne einigermassen 
vernünftige Debugmöglichkeiten zu haben. Kein Mensch weiß, ob deine UART 
auch wirklich korrekt funktioniert oder nicht. Ob die Zeichen da korrekt 
rein kommen oder nicht.
Anfänger gehen immer davon aus, dass das alles ja nicht so schwer sein 
kann und das man ja wohl so ein Programm schreiben kann, so dass es auf 
Anhieb funktioniert. Tja, wie alle anderen das eigentlich erwartet 
haben, das funktioniert nun mal nicht.

Aber egal.
Sind die 8Mhz gesichert?


Mach dir halt mal in die ISR eine Anzeige per LED rein ob
* die ISR überhaupt aufgerufen wird
* das FE Bit jemals gesetzt wird
* die 10 Bytes jemals erreicht werden


PS: du MUSST das UDR in der ISR auslesen! Auch wenn du dann mit dem Byte 
nichts machst, aber auslesen MUSST du es. Du kannst nicht einfach das 
auslesen überspringen, weil irgendwelche Vorbedingungen nicht stimmen. 
Ansonsten präsentiert dir nämlich die USART dieses Byte wieder und immer 
wieder indem es die ISR auslöst.
#3521798
Lesenswert?

Ja, die 8 MHz sind gesichert und Fuses sind richtig gesetzt.
Mir geht es nicht darum mal so auf die Schnelle ein Programm zu 
schreiben,
sondern zu verstehen wieso mein lange überdachtes Programm nicht 
funktioniert...
Außerdem bin ich eigentlich echt stolz auf das was ich da schon 
geschrieben habe...
Nur irgendwo muss ein Denkfehler sein...
#3521800
Lesenswert?

Karl Heinz schrieb:
> Sind eigentlich die 8 Mhz gesichert?

Das ist wichtig, dass die stimmen! Denn sonst stimmt kein einziges 
Timing. Und gerade bei UART ist alles eine Timingfrage.

Probier mal folgendes Programm aus.
1
#define F_CPU  8000000UL
2

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

6
int main(void)
7
{
8
  DDRD = 0b11111111;
9

10
  while(1){
11

12
    PORTD |=  ( 1 << PD7 );
13
    PORTD &= ~( 1 << PD2 );
14
    _delay_ms( 500 );
15

16
    PORTD &= ~( 1 << PD2 );
17
    PORTD |=  ( 1 << PD7 );
18
    _delay_ms( 500 );
19
  }
20
}

deine LED müssen im Halbsekundentakt wechselseitig blinken. Wenn sie das 
nicht tun und zb nur alle 4 Sekunden blinken, dann läuft dein µC nicht 
mit 8Mhz.

Ich trau der Sache nicht. Das haben wir hier schon zu oft erlebt, dass 
jemand Stein und Bein geschworen hat, dass seine Taktfrequenz stimmt.
#3521809
Lesenswert?

Christian Karle schrieb:

> sondern zu verstehen wieso mein lange überdachtes Programm nicht
> funktioniert...

Das mag ja alles sein. Trotzdem hast du darauf vergessen, dir Gedanken 
darüber zu machen, wie du die Dinge kontrollieren kannst.

Eine einsame LED, die am Ende einer langen Kette von Ereignissen an oder 
ausgeht, und bei der alle Zwischenstufen in dieser Kette korrekt 
ablaufen müssen, ist nun mal zu wenig, wenn es nicht funktioniert. Du 
musst in der Lage sein, die Kontrolle viel feiner zu machen, in dem du 
jede einzelne dieser Zwischenstufen kontrollieren kannst.

Man kann dazu LED nehmen, so ist das nicht. Aber man muss dabei schon 
wissen was man tut. Und da liegt eben das Problem. Speziell bei UART ist 
das nämlich nicht so einfach. Denn da erheben sich 2 Fragestellungen: 
wird die ISR überhaupt ausgelöst - sprich: arbeitet die UART. Und die 
2-te lautet: arbeitet sie richtig. Die erste kann man mit einer LED 
einfach verifizieren. Die 2.te Frage ist nur mit einer LED schon 
schwerer zu beantworten.
#3521838
Lesenswert?

Christian Karle schrieb:
> Also...meine LED blinkt im 0.5 sec Takt -> Fuses richtig gesetzt :)

gut.
Das ist schon mal wichtig.

Warum ich da so rumreite - weil ich auf der anderen Seite deines 
Monitors sitze und weder sehen kann noch die Hardware zur Hand nehmen 
kann, die du vor dir hast. Ich muss mich hier über den Zustand deines 
Projekts orientieren mit nichts anderem als das was du im Posting 
erzählst. Und natürlich nehme ich da mal die häufigsten Fehlerfälle 
zuerst. 99% aller UART probleme sind immer die gleichen: die 
Taktfrequenz ist nicht die, die der Programmierer glaubt.


> Ich glaube auch dass, das Problem an der Anweisung arraycomplete=0;
> in der Hauptschleife liegt.

Nö.
Deine Hauptschleife ist zwar maximal-kompliziert geschrieben, aber sie 
ist nicht falsch.
Das Problem liegt in der ISR.

Frage: wie sind deine LED angeschlossen. (du hast doch 2 LED, eine an 
PD2 eine an PD7). Muss der Portpin auf 0 oder auf 1 gestellt werden, 
damit die LED leuchtet?
#3521845
Lesenswert?

Um die LED anzuschalten muss der Pin auf "Low" gesetzt werden
Habe deshalb den von Ihnen gelieferten C-Code wie folgt abgeändert :

#define F_CPU  8000000UL
#include <avr/io.h>
#include <util/delay.h>
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

int main(void)
{
  DDRD = 0b11111111;

  while(1){

    cbi(PORTD,PD7);
    _delay_ms( 500 );
    sbi(PORTD,PD7);
    _delay_ms( 500 );
  }
}
#3521854
Lesenswert?

Karl Heinz schrieb:
> Da fällt mir noch was ein
>
> Wer sendet eigentlich?
>
>> Anschließend soll im Hauptprogramm der 4.Kanal ausgewertet werden
>
> 4. Kanal
> Bei welcher Zählweise? Beginnend bei 0 oder beginnend bei 1

Hmm. da stimmt sowieso in deiner Zählerei etwas nicht.

Denn in deinem Array hast du in der ISR abgelegt
1
Index     Bedeutung
2
--------------------
3
0         Wert der beim Break kam
4
1         DMX Startbyte, immer 0
5
2         Kanal 1
6
3         Kanal 2
7
4         Kanal 3
8
5         Kanal 4
9
6         Kanal 5
10
...

d.h. mit array[4] greifst du sowieso schon mal auf das falsche Byte zu, 
wenn du am Wert von Kanal 4 interssiert bist.
#3521859
Lesenswert?

Christian Karle schrieb:
> Um die LED anzuschalten muss der Pin auf "Low" gesetzt werden

Gut.
Ich überleg mir mal was, wie wir die ISR pimpen können.

> Habe deshalb den von Ihnen gelieferten C-Code wie folgt abgeändert :

Hättest du nicht ändern brauchen.
Denn ob man zuerst einschaltet und dann ausschaltet oder zuerst 
aussschaltet und dann einschaltet, ändert ja nichts daran, dass sich ein 
Blinken ergibt. Hauptsache abwechselnd ein/aus mit der Betonung auf 
abwechselnd.

Kann es sein, dass du einen haufen Vorübungen gespritzt hast?

> Habe deshalb den von Ihnen
Wir sind hier automatisch per du.
#3521862
Lesenswert?

Ja, richtig :) Diese Tabelle habe ich schon die ganze Zeit im Kopf.
Mir ist bewusst das ich Kanal "3" auswerte wenn ich array[4] schreibe :)
Senden tut ein DMX-Pult mit 24 Kanälen :) Habe dort auch den Regler 
Nummer 3 Benutzt, welcher Kanal 3 entspricht. Habe das auch schon mit 
einem gekauften DMX-Gerät getestet :)
#3521882
Lesenswert?

24 Kanäle. Gut zu wissen, denn da muss ich jetzt mal ein bischen 
rechnen.

Wenn du nichts dagegen hast, dann machen wir das ohne großartiger 
Vorüberlegung, sondern wir gehen systematisch vor. Mit einem einfachen 
Programm, welches fast nichts kann und erweitern das dann Schritt für 
Schritt, wobei jeder Schritt mit der LED kontrolliert wird.

Aber erst muss ich ein bischen rumrechnen. Denn eine LED zum debuggen 
ist nicht viel und das DMX Zeugs ist zu schnell, als das wir da mit 
statischen Anzeigen weiter kommen würden. Wir werden also das Heil im 
Blinken suchen, wobei die Blinkfrequenz vom DMX getrieben wird.
#3521898
Lesenswert?

Karl Heinz schrieb:
> Ach, eines noch.
> Weisst du das. Sendet dein Sender ständig oder nur wenn sich Werte
> verändern?


Hintergrund: Ich versuch auszurechnen, mit wievieln Break pro Sekunde 
überhaupt zu rechnen ist.
Hintergrund: die erste Version soll erst mal anzeigen, ob überhaupt 
regelmässig breaks daher kommen. Ich will das aber nicht mit LED 
einschalten realisieren, weil das sonst zu schnell geht. Im Prinzip soll 
bei jedem Break die LED umgeschaltet werden. Nur geht das bei 250kBaud 
und 24 Kanälen viel zu schnell (ca 1000 mal pro Sekunde), so dass man 
erst recht nichts sieht. D.h. wir schalten die LED nur bei jedem 500.ten 
Break um.

Das funktioniert aber nur, wenn der Sender ständig sendet und nicht nur 
bei Bedarf.
#3521906
Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>Hintergrund: Ich versuch auszurechnen, mit wievieln Break pro Sekunde
>überhaupt zu rechnen ist.

<100. Die Wiederholrate bei DMX geht theortisch zwar bis in den kHz 
Bereich, praktisch eher nicht.

>Das funktioniert aber nur, wenn der Sender ständig sendet

Tut er.
#3521917
Lesenswert?

OK.
erstes Programm
1
#define F_CPU 8000000
2

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

6
#define LED  PD7
7

8
void UART_Initialisieren()
9
{
10
  UBRRL  = 1;
11
  UBRRH  = 0;
12
  UCSRC  = (1<<URSEL)|(3<<UCSZ0);
13
  UCSRB  = (1<<RXCIE)|(1<<RXEN);
14
}
15

16

17
int main(void)
18
{
19
  DDRD |= ( 1 << LED );
20

21
  UART_Initialisieren();
22

23
  sei();
24
  while( 1 ) {
25
  }
26
}
27

28
ISR(USART_RX_vect)
29
{
30
  static uint16_t cnt = 0;
31

32
  uint8_t frameError = ( UCSRA & ( 1 << FE ) );
33
  uint8_t nextByte = UDR;
34

35
  if( frameError ) {
36
    cnt++;
37
    if( cnt == 500 )
38
    {
39
      cnt = 0;
40
      PORTD ^= ( 1<<LED );
41
    }
42
  }
43
}

wenn der Sender tatsächlich ständig sendet (was ich nicht weiß, weil ich 
noch nie mit DMX zu tun hatte), dann sollte die LED ca alle halbe 
Sekunde umschalten.
Meine Rechnung:
Wir haben 250kBaud, d.h. 250000 Bits pro Sekunde. Pro Byte sind 11 
fällig (1 Startbit, 8 Datenbits, 2 Stoppbits), d.h. das sind rund 22700 
Bytes pro Sekunde. Der Sender hat 24 Kanäle, also ist davon auszugehen 
dass er auch nur diese 24 sendet und nicht alle 512. mit dem Startbyte 
(und unter ignorieren des Break) sind das rund 900 komplette 
DMX-Nachrichten pro Sekunde. Zwischen jeder kommt ein Break, also auch 
rund 900 Breaks pro Sekunde. Wird die LED also nach jedem 500.ten Break 
umgeschaltet, dann ist das ungefähr eine halbe Sekunde.

Das ill ich erst mal sehen. Vielleicht funkelt die LED, das wär mir noch 
egal. Vielleicht blinkt sie auch langsamerm ist mir auch noch egal 
(könnte ja sein, dass der Sender tatsächlich alle 512 Kanäle überträgt 
und nicht nur 24). Aber wenn sich gar nichts tut, dann wäre das ziemlich 
schlimm.
#3521921
Lesenswert?

Falk Brunner schrieb:
> @ Karl Heinz (kbuchegg) (Moderator)
>
>>Hintergrund: Ich versuch auszurechnen, mit wievieln Break pro Sekunde
>>überhaupt zu rechnen ist.
>
> <100. Die Wiederholrate bei DMX geht theortisch zwar bis in den kHz
> Bereich, praktisch eher nicht.

Ah. Danke Falk.
Rein rechnerisch lande ich bei ihm bei ca 900 kompletten 24-Kanal Frames 
unter der Annahme von 0-Pausen zwischen den Frames (break erst mal 
ignoriert - du weisst was ich meine)

>>Das funktioniert aber nur, wenn der Sender ständig sendet
>
> Tut er.

Wichtige Information für mich!
Danke.
#3521934
Lesenswert?

Christian Karle schrieb:
> Währe das hier eine Möglichkeit für die Verwirklichung der Idee ?

Im Prinzip - ja

Aber sieh dir meinen Code an. Diese ganze Komplikation mit Zähler in die 
Hauptschleife und dort einen delay braucht man gar nicht.
Entweder der break kommt regelmässig, dann reicht es die LED um- zu 
schalten. oder er tut das nicht. Dann rettet dich aber auch der delay 
nicht mehr.
#3521935
Lesenswert?

Die meisten DMX-Sender arbeiten mit ~30 Hz Update Rate.
Dieser Wert stammt nicht von irgendeiner "offiziellen" Seite sondern aus 
Erfahrung und dem rumspielen mit verschiedenen Pulten und USB-Geräten. 
Wenn man keine extra "intelligente" oder schnelle über-hw hat, dann sind 
die 30 Hz ziemlich konsistent. Ich denke das hat damit zu tun, dass in 
preiswerteren DMX-Slaves eher schwache Controller am werkeln sind und 
die sonst überfordert sind.
#3521941
Lesenswert?

Max D. schrieb:
> Die meisten DMX-Sender arbeiten mit ~30 Hz Update Rate.

Danke Max.
(Wer sagts denn. Wenn man es braucht, dann funktioniert das Forum 
erstklassig)

Also auch mal mit
1
...
2
    if( cnt == 15 )
3
...
probieren.

> Dieser Wert stammt nicht von irgendeiner "offiziellen" Seite sondern aus
> Erfahrung und dem rumspielen mit verschiedenen Pulten und USB-Geräten.

Dann traue ich dieser Angabe mehr als dem was ich da unter optimal 
Bedingungen worst case errechnet habe.
30 macht auch irgendwo Sinn. Der Empfänger muss ja mit den Daten auch 
was machen und soooo schnell ändern sich Werte ja nicht, die ein Zuseher 
ja auch noch aufnehmen können muss.
#3521948
Lesenswert?

Christian, nimm aber bitte trotzdem mein Programm.
Hintergrund: Ich hab das bei mir parallel im AVR-Studio geladen und 
werde das mit dir jetzt immer weiter ausbauen. Das ist einfacher, als 
wenn ich von einer Version zur nächsten jedesmal deinen Code absuchen 
muss, was du verändert hast.
Gast #3521975
Lesenswert?

Christian Karle schrieb:
> Außerdem bin ich eigentlich echt stolz auf das was ich da schon
> geschrieben habe...

Wenn du in deinem Leben mal richtig gut sein willst, dann sollte das die 
letzte Aussage sein die du in dieser Richtung von dir gibst. Sonnst 
kannst du dich gleich in die Reihen der Spinner einordnen, die von sich 
selbst glauben die besten Programmieren auf Erden zu sein...
#3521978
Lesenswert?

Christian Karle schrieb:
> Also, folgendes passiert:
>
> Das Programm wird per ISP auf den uC übertragen.
> Direkt nachdem es übertragen wurde fängt die LED im 0.5 sec. Takt an zu
> blinken, ohne das der Controller mit dem DMX Pult verbunden wurde....
> Nach dem Verbinden mit dem DMX-Pult passiert genau das Selbe...

welches Programm?
Deines oder meines

Wenn nichts angeschlossen ist, sollte da eigentlich nichts blinken.
#3521982
Lesenswert?

Äh, warte mal.
Habe ich zumindest übersehen.
PD2 muss aktiv auf 0 geszogen werden, damit der Treiber auf Empfang 
gestellt wird. Keine Ahnung was der macht, wenn der Pin im Tri-State 
ist.
1
#define F_CPU 8000000
2

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

6
#define LED      PD7
7
#define DATA_DIR PD2
8

9
void UART_Initialisieren()
10
{
11
  UBRRL  = 1;
12
  UBRRH  = 0;
13
  UCSRC  = (1<<URSEL)|(3<<UCSZ0);
14
  UCSRB  = (1<<RXCIE)|(1<<RXEN);
15
}
16

17

18
int main(void)
19
{
20
  DDRD |= ( 1 << LED ) | ( 1 << DATA_DIR );
21

22
  PORTD &= ~( 1 << DATA_DIR );    // Treiber auf Empfang stellen
23

24
  UART_Initialisieren();
25

26
  sei();
27
  while( 1 ) {
28
  }
29
}
30

31
ISR(USART_RX_vect)
32
{
33
  static uint16_t cnt = 0;
34

35
  uint8_t frameError = ( UCSRA & ( 1 << FE ) );
36
  uint8_t nextByte = UDR;
37

38
  if( frameError ) {
39
    cnt++;
40
    if( cnt == 15 )
41
    {
42
      cnt = 0;
43
      PORTD ^= ( 1<<LED );
44
    }
45
  }
46
}
#3522030
Lesenswert?

Karl Heinz schrieb:
> Max D. schrieb:
>> Sind es vlt 1,66 Hz ?
>> Dann hast du dir nämlich 50 Hz einstreuungen die die FEs triggern ....
>
> Hmm.
> Wo könnten die her kommen? Er hat ja 75176 und damit differentielle
> Eingänge.
>
> Spannungsversorgung?

Wenn er die Eingänge offen hat, dann können da auch differentielle 
Einstrahlungen passieren (und die Treiber sind ja rel. empfindlich auf 
differentielle spannungen, beim 75176 z.b. 200 mV). Das schafft man 
locker wenn ein längeres Stück Kabel rumbaumelt.....
#3522055
Lesenswert?

@ Christian Karle (christiankarle)

>Also ich verstehe gerade die Welt nicht mehr... mein uC lässt sich nun
>gar nicht mehr per ISP programmieren... egal was ich aufspiele-> Die LED
>blinkt...

Falsches HEX-File ausgewählt?

>Liegt das an AVR Studio ?

Das Problem "liegt" meistens vor der Tastatur.
#3522066
Lesenswert?

Hmm.
Schon mal alles runtergefahren und neu gestartet?

Wenn gar nichts mehr hilft: Lötkolben auspacken und dem AVR zeigen (dem 
PC zeigen schadet auch nicht). Dann spuren die wieder. Sozusagen mit 
vorgehaltener Waffe sanft zur Mitarbeit überreden :-)

Im Ernst: irgendwo ein Kabel gerissen. Wackelkontakt, schlecht 
Verbindung im Pfostenstecker?
#3522112
Lesenswert?

Also habe es jetzt hinbekommen. Es lag tatsächlich an AVR Studio es muss 
sich ein Softwarefehler eingeschlichen haben... nach der Neuinstallation 
funktioniert nun wieder alles :)

Das Programm funktioniert auch :)

1.Die LED ist an.
2.Einstecken in das Pult -> LED fängt an zu blinken:)

Sie blinkt etwas langsamer als 2Hz aber sonst ist alles perfekt :)

Noch eine Detailfrage:
Wenn ich das UDR nicht auslese, würde es dann zu einem DATA OVERRUN 
kommen ?
#3522143
Lesenswert?

Christian Karle schrieb:
> Also habe es jetzt hinbekommen. Es lag tatsächlich an AVR Studio es muss
> sich ein Softwarefehler eingeschlichen haben... nach der Neuinstallation
> funktioniert nun wieder alles :)
>
> Das Programm funktioniert auch :)
>
> 1.Die LED ist an.
> 2.Einstecken in das Pult -> LED fängt an zu blinken:)
>
> Sie blinkt etwas langsamer als 2Hz aber sonst ist alles perfekt :)

Ah gut.
We have lift off


Jetzt wirds spannend. Bis jetzt wissen wir ja nur, dass laufend breaks 
daher kommen. Die Frequenz 2Hz könnte passen. Auf jeden Fall langsam 
genug, dass nicht jedes empfangene Byte einen Frame Error verursacht 
haben kann, denn dann würde das viel schneller blinken. Das stimmt schon 
mal zuversichtlich.

So, wie gehts jetzt weiter?
Jetzt holen wir uns mal die nächsten 10 Bytes nach einem Break in ein 
Array und überprüfen, ob das erste davon 0 ist.
Leider haben wir keine andere Möglichkeit als von dem Wissen gebrauch zu 
machen, dass das erste Byte 0 sein muss. Eine Ausgabe auf LCD wäre mir 
persönlich lieber, aber es wird auch so gehen.
#3522169
Lesenswert?

Mein Vorschlag.

Die Intention ist folgende:

Es werden nach einem break die nächsten Bytes in ein Array geschrieben. 
Wenn geschrieben wird, wir auch geprüft, ob das erste Byte nach dem 
Break ein 0 Byte ist. Das Problem das wir nämlich haben ist, dass wir 
zwar momentan feststellen können, dass zwar Breaks da sind, aber wir 
wissen nicht, ob wir mit der Baudrate daneben liegen, so dass der 
Empfang gestört ist.

Aber wir wissen, dass das erste Byte nach einem Break 0 sein muss. Das 
ist von DMX so vorgeschrieben und das ist etwas das man testen kann.


Die Erwartungshaltung im Programm ist folgende:
Da in der Hauptschleife die LED immer wieder abgeschaltet wird, gibt es 
nur eine Möglichkeit, wie die LED leuchten kann. Nämlich wenn in der ISR 
das erste Zeichen nach einem Break eine 0 ist. Nur dann wird die LED 
eingeschaltet. Liegt die 0 nicht vor, oder fällt die Verbdinung aus, 
dann sorgt die Hauptschleife dafür, dass die LED wieder ausgeht.

Testszenario ist daher:
DMX Stecker ziehen. Programm laufen lassen. Die LED muss aus sein.
Stecker einstecken. die LED muss leuchten.
Stecker wieder abziehen, die LED muss ausgehen.

theoretisch könnte es sein, dass bei eingestecktem DMX Stecker die LED 
leicht flackert. Ich denke allerdings nicht, dass man das grossartig 
sehen wird. Vielleicht ein ganz kurzer Flackerer hie und da.
1
#define F_CPU 8000000
2

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

7
#define LED      PD7
8
#define DATA_DIR PD2
9

10
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
11

12
volatile uint8_t dmxData[10];
13

14
void UART_Initialisieren()
15
{
16
  UBRRL  = 1;
17
  UBRRH  = 0;
18
  UCSRC  = (1<<URSEL)|(3<<UCSZ0);
19
  UCSRB  = (1<<RXCIE)|(1<<RXEN);
20
}
21

22
int main(void)
23
{
24
  DDRD |= ( 1 << LED ) | ( 1 << DATA_DIR );
25

26
  PORTD &= ~( 1 << DATA_DIR );    // Treiber auf Empfang stellen
27

28
  UART_Initialisieren();
29

30
  sei();
31
  while( 1 ) {
32
    // Testled immer wieder abschalten, die ISR wird sie wieder einschalten
33
    // wenn der Empfang korrekt ist
34
    PORTD &= ~( 1 << LED );
35
    _delay_ms( 300 );
36
  }
37
}
38

39
ISR(USART_RX_vect)
40
{
41
  static uint8_t byteCnt = 0;
42

43
  uint8_t frameError = ( UCSRA & ( 1 << FE ) );
44
  uint8_t nextByte = UDR;
45

46
  if( frameError )
47
    byteCnt = 0;
48

49
  else
50
  {
51
    if( byteCnt < ARRAY_SIZE( dmxData ) )
52
    {
53
      dmxData[byteCnt++] = nextByte;
54

55
      if( dmxData[0] == 0 )
56
        PORTD |= ( 1 << LED );
57
    }
58
  }
59
}
#3522185
Lesenswert?

Christian Karle schrieb:
> Also praktischer Ablauf ist etwas anders :)
>
> 1: Stecker ist nicht eingesteckt-> LED ist an

das ist ok. (Siehe mein letztes POsting)

> 2: Stecker ist eingesteckt-> LED flackert/Blinkt

hmm, wie stark ist das Flackern?
Ein bischen flackern ist ok. Mehr so ein Aufblitzen der LED als ein 
regelmässiges Blinken.
Das die LED überhaupt ausgeht, ist schon mal ein gutes Zeichen, denn das 
bedeutet, dass da 0-Bytes nach dem Break reinkommen.

Wenn du den delay_ms in der Hauptschleife vergrößerst, wird dann das 
Flackern weniger?
#3522200
Lesenswert?

Das hier
1
#define F_CPU 8000000
2

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

7
#define LED      PD7
8
#define DATA_DIR PD2
9

10
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
11

12
volatile uint8_t dmxData[10];
13

14
void UART_Initialisieren()
15
{
16
  UBRRL  = 1;
17
  UBRRH  = 0;
18
  UCSRC  = (1<<URSEL)|(3<<UCSZ0);
19
  UCSRB  = (1<<RXCIE)|(1<<RXEN);
20
}
21

22
int main(void)
23
{
24
  DDRD |= ( 1 << LED ) | ( 1 << DATA_DIR );
25

26
  PORTD &= ~( 1 << DATA_DIR );    // Treiber auf Empfang stellen
27

28
  UART_Initialisieren();
29

30
  PORTD |= ( 1 << LED );
31

32
  sei();
33
  while( 1 ) {
34
  }
35
}
36

37
ISR(USART_RX_vect)
38
{
39
  static uint8_t byteCnt = 0;
40

41
  uint8_t frameError = ( UCSRA & ( 1 << FE ) );
42
  uint8_t nextByte = UDR;
43

44
  if( frameError )
45
    byteCnt = 0;
46

47
  else
48
  {
49
    if( byteCnt < ARRAY_SIZE( dmxData ) )
50
    {
51
      dmxData[byteCnt++] = nextByte;
52

53
      if( dmxData[0] == 0 )
54
        PORTD &= ~( 1 << LED );
55
      else
56
        PORTD |= ( 1 << LED );
57
    }
58
  }
59
}

ist eine andere Variante.
Die LED muss die ganze Zeit eingeschaltet bleiben. Keine Flackerer, 
keine Helligkeitsschwankungen.
Allerdings ändert sich nichts, wenn du den Stecker abziehst, daher hab 
ich das auch nicht für den ersten Test benutzt.
Ein Test könnte höchstens sein:
Alles abschalten, DMX Stecker abziehen. µC einschalten. Die LED muss aus 
sein.
Dann den DMX Stecker anstecken. Die LED muss "sofort" leuchten. Ohne 
Flackern.
Ziehst du den Stecker danach ab, dann ändert sich am LED Zustand nichts 
mehr. Sie leuchtet weiter.
#3522238
Lesenswert?

Ich habe das Programm noch erweitert um sicherzustellen dass, das Array 
auch aktualisiert wird wenn mehr als 1000 Datenpakete empfangen wurden 
wird
die LED ausgeschaltet :) Nur zur Überprüfung :)
1
#define F_CPU 8000000
2

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

7
#define LED      PD7
8
#define DATA_DIR PD2
9

10
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
11

12
volatile uint8_t dmxData[10];
13
volatile int x=0;
14

15
void UART_Initialisieren()
16
{
17
  UBRRL  = 1;
18
  UBRRH  = 0;
19
  UCSRC  = (1<<URSEL)|(3<<UCSZ0);
20
  UCSRB  = (1<<RXCIE)|(1<<RXEN);
21
}
22

23
int main(void)
24
{
25
  DDRD |= ( 1 << LED ) | ( 1 << DATA_DIR );
26

27
  PORTD &= ~( 1 << DATA_DIR );    // Treiber auf Empfang stellen
28

29
  UART_Initialisieren();
30

31
  PORTD |= ( 1 << LED );
32

33
  sei();
34
  while( 1 ) {
35
  }
36
}
37

38
ISR(USART_RX_vect)
39
{
40
  static uint8_t byteCnt = 0;
41

42
  uint8_t frameError = ( UCSRA & ( 1 << FE ) );
43
  uint8_t nextByte = UDR;
44

45
  if( frameError ){
46
  byteCnt = 0;
47
  }
48
  else
49
  {
50
    if( byteCnt < ARRAY_SIZE( dmxData ) )
51
    {
52
      dmxData[byteCnt++] = nextByte;
53

54
        if( dmxData[0] == 0 )
55
        {
56
          x++;
57
          if(x<1000){
58
          PORTD &= ~( 1 << LED );
59
        }
60
        if(x>1000)
61
        {
62
        PORTD |= ( 1 << LED );
63
        }
64
      }
65
    }
66
  }
67
}
#3522259
Lesenswert?

Ok, Ich denke wir sind soweit, in die Vollen zu gehen.
Sieht wohl so aus, als ob die Synchronisierung klappt und auch die 
empfangenen Daten korrekt sind.

Kanal 3 abfragen und die LED damit schalten
1
#define F_CPU 8000000
2

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

6
#define LED      PD7
7
#define DATA_DIR PD2
8

9
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
10

11
volatile uint8_t dmxData[10];
12

13
void UART_Initialisieren()
14
{
15
  UBRRL  = 1;
16
  UBRRH  = 0;
17
  UCSRC  = (1<<URSEL)|(3<<UCSZ0);
18
  UCSRB  = (1<<RXCIE)|(1<<RXEN);
19
}
20

21
int main(void)
22
{
23
  DDRD |= ( 1 << LED ) | ( 1 << DATA_DIR );
24

25
  PORTD &= ~( 1 << DATA_DIR );    // Treiber auf Empfang stellen
26

27
  UART_Initialisieren();
28

29
  sei();
30
  while( 1 ) {
31
    if( dmxData[3] < 128 )
32
      PORTD |= ( 1 << LED );
33
    else
34
      PORTD &= ~( 1 << LED );
35
  }
36
}
37

38
ISR(USART_RX_vect)
39
{
40
  static uint8_t byteCnt = 0;
41

42
  uint8_t frameError = ( UCSRA & ( 1 << FE ) );
43
  uint8_t nextByte = UDR;
44

45
  if( frameError && nextByte == 0)
46
    byteCnt = 0;
47

48
  else
49
  {
50
    if( byteCnt < ARRAY_SIZE( dmxData ) )
51
    {
52
      dmxData[byteCnt++] = nextByte;
53
    }
54
  }
55
}
#3522265
Lesenswert?

Christian Karle schrieb:

> die LED ausgeschaltet :) Nur zur Überprüfung :)

:-)
Das ist IMHO die richtige Einstellung.
Wir angeln uns von einem Ziel zum nächsten vor. Auch wenn das manchmal 
etwas umständlich sein mag. Aber: dadurch haben wir die Gewissheit, dass 
die Dinge funktionieren, ehe wir die nächste Schicht drauf setzen.
In Summe geht das nämlich schneller, als einen Codehaufen hinzusetzen, 
der dann nicht funktioniert und dann müssen wir erst recht wieder ganz 
unten anfangen mit Debuggen.

Und, auch ganz wichtig. Wir überlegen uns, wie jede Erweiterung getestet 
werden kann. Dazu ist es auch wichtig, vorab eine Erwartung zu haben. 
D.h. ehe das Programm läuft, sollte man sich darüber im klaren sein, was 
eigentlich passieren müsste.
#3522284
Lesenswert?

Das Programm funktionier super :) Jetzt wurde ein Switch realisiert,
genau dass, das ich erreichen wollte :)

Die einzige Stelle im Programmtext die ich nicht verstehe ist

#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))

Ich würde mich noch über eine kleine Erklärung hierzu freuen :)

Mein Problem würde ich somit als gelöst ansehen, ab hier denke ich, kann 
ich mir selbst über weitere Details und Funktionen Gedanken machen. Das 
Tolle ist: Ich habe jetzt verstanden wie der DMX-Empfang abläuft und 
kann endlich die Schritte bis zum fertigen Programm nachvollziehen :)

Vielen, vielen Dank Karl Heinz :)
Du hast mir sehr weitergeholfen. Ich bin Dir sehr dankbar das Du deine 
Zeit opferst um mir Dein Wissen zu vermitteln. In der heutigen Zeit sind 
Menschen wie du nur noch sehr selten, da normalerweise keiner mehr Zeit 
und Lust hat sich mit Problemen anderer zu beschäftigen.
Ich schätze das wirklich sehr!

Und noch einmal ein fettes Dankeschön von mir :)
#3522322
Lesenswert?

Christian Karle schrieb:
> Das Programm funktionier super :) Jetzt wurde ein Switch realisiert,
> genau dass, das ich erreichen wollte :)

Gut.

> Die einzige Stelle im Programmtext die ich nicht verstehe ist
>
> #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))

sizeof liefert die Größe eines 'Objektes' in Bytes.
1
int data[5];

sizeof(data) würde also die Größe des Arrays in Bytes liefern. da ein 
int aus 2 Bytes besteht, wären das hier daher 10.

Ich will aber nicht wissen, wieviele Bytes das Array hat, sondern aus 
wievielen Einträgen es besteht. Dazu muss ich im Prinzip die Größe des 
Arrays durch die Größe eines Elements des Arrays dividieren. ein int hat 
2 Bytes, also ist ein int Array, das 10 Bytes groß ist 10/2 gleich 5 
Arrayelemente groß.

Wenn x ein Array bezeichnet, dann ist ein einzelnes element davon zb 
x[0]. Oder kürzer geschrieben *x (wegen der Pointer/Array Dualität)
1
sizeof(data) / sizeof(data[0])
liefert daher, die Anzahl an Array Elementen, wenn data als Array 
vorliegt. denn sizeof(data[0]) würde ja 2 ergeben, weil data[0] ja ein 
einzelner int aus dem Array ist.

Oder eben, unter Ausnutzung der Pointer/Array Dualität
1
sizeof(data)/sizeof(*data)

(Du kannst aber auch die Array-Schreibweise benutzen. Ich bin eben 
tippfaul :-)

> Mein Problem würde ich somit als gelöst ansehen, ab hier denke ich, kann
> ich mir selbst über weitere Details und Funktionen Gedanken machen. Das
> Tolle ist: Ich habe jetzt verstanden wie der DMX-Empfang abläuft und
> kann endlich die Schritte bis zum fertigen Programm nachvollziehen :)

Super.
Dann würde ich sagen: Ziel erreicht.
Sowohl bei dir als auch bei mir.
Denn für mich ist das wichtigste, dass du verstehst, wie es 
funktioniert. Das funktioniert bei weitem nicht so gut, wenn man einfach 
nur fertigen Code hinklatscht.
Gib einem Mann einen Fisch und er hat einen Tag lang zu essen. Gib ihm 
eine Angel und lehre ihn fischen und er hat sein Leben lang etwas zu 
essen.
Gast #3522336
Lesenswert?

Karl-Heinz schrub:
>Gib ihm eine Angel und lehre ihn fischen und er hat sein Leben lang etwas >zu 
essen.

Gib ihm ein Buch über C und er ist nach 2 Wochen reif für die 
Heilanstalt.

;-)

schnell fort hier

MfG Paul

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