Hallo, im Moment sitze ich an einem kleinen DMX-Switchpack. Es besteht im Wesentlichen aus einem Attiny2313, einem 75176 und deine 16MHz-Quarztoszillator. Die Startadresse habe ich im Quellcode fest auf 1 einstellt. Den DMX-Code habe ich von Hendrik Hölscher übernommen. Als DMX-Sender verwende ich ein JMS-USB-Interface und DMXControl. Grundsätzlich funktioniert die Schaltung. Allerdings ist mir folgendes aufgefallen. Obwohl ich im Code eine 1 als Startadresse definiert habe, wird der "erste Ausgang" des Attiny durch den zweiten Kanal im DMXControl angesprochen. Wird im DMXControl der Wert des ersten Kanals auf einen Wert > 0 geändert, reagiert der Attiny auf Änderungen der anderen Kanäle nicht mehr. Erst wieder, wenn im DMXControl der Wert des ersten Kanals auf 0 gestellt wird. Kennt jemand so ein Verhalten? Im Netz habe ich bislang noch nichts gefunden. Danke matt
Matt B. schrieb: > Wird im DMXControl der Wert des ersten Kanals auf einen Wert > 0 > geändert, reagiert der Attiny auf Änderungen der anderen Kanäle nicht > mehr. Erst wieder, wenn im DMXControl der Wert des ersten Kanals auf 0 > gestellt wird. Dann würde ich doch mal einen Blick in den Quellcode werfen und mit dem Simulator ansehen, wo es denn hakt. Matt B. schrieb: > DMX-Code habe ich von Hendrik Hölscher Den kennt ja auch jeder und der hat auch nur einen veröffentlicht ... :-(
> Die Startadresse habe ich im Quellcode fest auf 1 einstellt.
Ist das die interne Adresse oder die DMX Adresse?
Hintergrund:
Die DMX Adressierung beginnt grundsätzlich bei 1.
C Programmierer beginnen allerdings bei 0 zu zählen.
D.h. für einen C Programmierer trägt das erste Datenbyte einer Sequenz
die Nummer 0. Aus DMX Sicht ist das aber das Byte mit der Nummer 1.
Also ganz einfach im Code nachsehen, was mit dieser Einstellung gemacht
wird. Dann ist man schlauer.
Hier noch die Codes zum DMX-Empfang. Initialisierung:
1 | void init_DMX_RX(void) |
2 | {
|
3 | DDRD |= (1<<PD2); |
4 | PORTD &= ~(1<<PD2); |
5 | UBRRH = 0; //enable reception |
6 | UBRRL = ((F_OSC/4000)-1); //250kbaud, 8N2 |
7 | UCSRC = (3<<UCSZ0)|(1<<USBS); |
8 | UCSRB = (1<<RXEN)|(1<<RXCIE); |
9 | gDmxState= IDLE; |
10 | }
|
UART-ISR:
1 | ISR (USART_RX_vect) |
2 | {
|
3 | static uint16_t DmxCount; |
4 | uint8_t USARTstate= UCSRA; //get state before data! |
5 | uint8_t DmxByte = UDR; //get data |
6 | uint8_t DmxState = gDmxState; //just load once from SRAM to increase speed |
7 | |
8 | if (USARTstate &(1<<FE)) //check for break |
9 | {
|
10 | UCSRA &= ~(1<<FE); //reset flag (necessary for simulation in AVR Studio) |
11 | DmxCount = DmxAddress; //reset channel counter (count channels before start address) |
12 | gDmxState = BREAK; |
13 | }
|
14 | |
15 | else if (DmxState == BREAK) |
16 | {
|
17 | if (DmxByte == 0) gDmxState = STARTB; //normal start code detected |
18 | else gDmxState = IDLE; |
19 | }
|
20 | |
21 | else if (DmxState == STARTB) |
22 | {
|
23 | if (--DmxCount == 0) //start address reached? |
24 | {
|
25 | DmxCount = 1; //set up counter for required channels |
26 | DmxRxField[0] = DmxByte; //get 1st DMX channel of device |
27 | gDmxState = STARTADR; |
28 | }
|
29 | }
|
30 | |
31 | else if (DmxState == STARTADR) |
32 | {
|
33 | DmxRxField[DmxCount++] = DmxByte; //get channel |
34 | if (DmxCount >= sizeof(DmxRxField)) //all ch received? |
35 | {
|
36 | gDmxState = IDLE; //wait for next break |
37 | }
|
38 | }
|
39 | }
|
Die von mir einstellte Startadresse ist tatsächlich '1'. Der Wert des ersten Kanals wird im ersten Element des Arrays 'DmxRxField' abgelegt ( DmxRxField[0]). Es ist so, dass der als Startkanal eingestellte Kanal als Startbyte verwendet wird. Besitzt der einen Wert ungleich 0, erkennt der Empfänger kein Startbyte und setzt "gDmxState = IDLE". Es werden kann keine weiteren Kanäle eingelesen. Aber im Code konnte ich bislang nichts finden, das so eine Funktion erklärt.
:
Bearbeitet durch User
Matt B. schrieb: > Hier noch die Codes zum DMX-Empfang. Hmm. Der Code sieht gut aus. Wenn ich mich im Kopf nicht vertan habe, dann entspricht er der DMX Spezifikation, in dem er die über die UART reinkommenden Bytes korrekt verteilt. > Es ist so, dass der als Startkanal eingestellte Kanal als Startbyte > verwendet wird. Das entspricht dann aber nicht der DMX Spezifikation. Die verlangt zwingend, dass nach dem langen Puls (der über den Frame Error ausgewertet wird) erst mal ein Byte mit dem Wert 0 kommen muss. > Besitzt der einen Wert ungleich 0, erkennt der Empfänger > kein Startbyte und setzt "gDmxState = IDLE". Es werden kann keine > weiteren Kanäle eingelesen. Logisch. So ist das im Empfänger programmiert. Im Moment deutet für mich vieles darauf hin, dass sich zwar dieser Empfangscode an den DMX Standard hält, aber anscheinend dieses DMXControl nicht. Hast du eine Möglichkeit, dir die übergebenen Werte anzusehen (LCD, Terminal?) > > Aber im Code konnte ich bislang nichts finden, das so eine Funktion > erklärt.
Ich glaube nicht, dass der Fehler beim DMXControl liegt. Dann wäre ich bestimmt nicht der einzige, der damit Probleme hat. Die aktuelle Version von dem Programm habe ich übrigens installiert. Wenn ich die Startadresse im Attiny z.B. auf 10 umstelle, dann wird der 10. Kanal als Startbyte und der 11. Kanal als tatsächlicher Startkanal verwendet. Die Kanäle 1 bis 9 haben dann keinen Einfluss auf den Attiny... Ein Gerät um die vom Interface ausgegebenen Werte anzuzeigen kann ich auf die Schnelle nicht auftreiben. Für die Darstellung von Werte am Attiny habe ich insgesamt 10 LEDs zur Verfügung. Darüber kann also auch 8-Bit-Werte (oder auch 10-Bit-Werte) darstellen
:
Bearbeitet durch User
Matt B. schrieb: > Ich glaube nicht, dass der Fehler beim DMXControl liegt. Dann wäre ich > bestimmt nicht der einzige, der damit Probleme hat. Die aktuelle Version > von dem Programm habe ich übrigens installiert. > > Wenn ich die Startadresse im Attiny z.B. auf 10 umstelle, dann wird der > 10. Kanal als Startbyte und der 11. Kanal als tatsächlicher Startkanal > verwendet. Die Kanäle 1 bis 9 haben dann keinen Einfluss auf den > Attiny... > > Ein Gerät um die vom Interface ausgegebenen Werte anzuzeigen kann ich > auf die Schnelle nicht auftreiben. Dann sehe ich eigentlich nur noch die Möglichkeit, dass der Code für 2 hintereinander folgende Byte einen Frame Error bekommt. Er also das 0-Startbyte als weiteres 'Synchronisationsbyte'-Break ansieht, welches über den generierten Frame Error alles weitere ins Rollen bringt, wodurch sich die ganze Zählung verschiebt.
:
Bearbeitet durch User
Nach dem "langen Puls bzw. Frame-Error" kommt laut DMX-Specs ein Type-Byte, danach folgen die Daten. Type=0x00 bedeutet "Dimmer", der verwendete code ist vermutlich dafür ausgelegt auch andere Typen weiterzuverarbeiten: Also: Frame Error - 1 Byte 0x00 für Dimmer - 1 bis 512 Bytes für die Kanäle 1 bis 512. Hoffe die Info hilft weiter! PS.: und DMX-Control ist als Fehlerrquelle zu 99,9% auszuschließen ;-)
Karl Heinz schrieb: > Dann sehe ich eigentlich nur noch die Möglichkeit, dass der Code für 2 > hintereinander folgende Byte einen Frame Error bekommt. Er also das > 0-Startbyte als weiteres 'Synchronisationsbyte'-Break ansieht, welches > über den generierten Frame Error alles weitere ins Rollen bringt, > wodurch sich die ganze Zählung verschiebt. Sowas in der Art stelle ich mir auch vor... Aber wie gehe das Problem an? @Klaus: Das von dir erwähnte Type-Byte ist doch das allgemeine Startbyte, das immer den Wert 0 besitzt!?
:
Bearbeitet durch User
Was mit gerade noch einfällt: Ist es möglich, dass das DMXControl davon ausgeht, dass das Interface selbstständig ein Startbyte vor die Datenbytes stellt, das JMS Interface aber davon ausgeht, dass die vom DMX-Programm erhaltenen Bytes mit einem Startbyte beginnen und die Datenbytes diesem folgen? Dann wäre zumindest das Verhalten bei mir plausibel. Leider habe ich momentan keine anderen DMX-Geräte da um das prüfen zu können...
:
Bearbeitet durch User
Hallo matt! In den Standards DMX512, DMX512/1990 und dem deutschen Standard nach DIN 56930-2 wird noch von Startbyte (=0x00) gesprochen. Seit DMX512A, bzw. E1.11-2008, USITT DMX512-A gibt es zwei gravierende Änderungen: Mark-After-Break von 4 auf 8µs verlängert. Start-Byte (=0x00) zu Start-Code erklärt: 0x00 dimmers and lighting fixtures 0x17 text packets 0xCF system information packets 0xCC RDM extension grüße leo
@Klaus: danke für die Info. Gerade konnte ich den Attiny an einem ArtNet und einer anderen Software betreiben. Der Fehler lag weiterhin vor. Deswegen gehe ich jetzt tatsächlich von einem Fehler im Programm aus... Edit: Ich habe die ISR etwas angepasst. Die Abfrage auf das Startbyte habe ich komplett weggelassen. Seither funktioniert es. Das Startbyte/Type-Byte kommt bei mir irgendwie gar nicht an. Hier die ISR:
1 | ISR (USART_RX_vect) |
2 | {
|
3 | static uint16_t DmxCount; |
4 | uint8_t USARTstate= UCSRA; //get state before data! |
5 | uint8_t DmxByte = UDR; //get data |
6 | uint8_t DmxState = gDmxState; //just load once from SRAM to increase speed |
7 | |
8 | if (USARTstate &(1<<FE)) //check for break |
9 | {
|
10 | UCSRA &= ~(1<<FE); //reset flag (necessary for simulation in AVR Studio) |
11 | DmxCount = 0; //reset channel counter (count channels before start address) |
12 | gDmxState = BREAK; |
13 | }
|
14 | |
15 | else if (DmxState == BREAK) |
16 | {
|
17 | if(DmxCount >= DmxAddress - 1) |
18 | DmxRxField[DmxCount - (DmxAddress - 1)] = DmxByte; |
19 | |
20 | DmxCount++; |
21 | if(DmxCount > DmxAddress + sizeof(DmxRxField)) |
22 | DmxState = IDLE; |
23 | }
|
24 | }
|
:
Bearbeitet durch User
Hallo matt, liest du für Kanal 1 DmxRxField[0] oder DmxRxField[1] aus? wenn ich die ISR richtig lese steht mit DmxAddress = 1 in DmxRxField[0] .. DMX Slot 0 (=0x00 für Licht und Dimmer) DmxRxField[1] .. DMX Slot 1 = Kanal 1 usw. bei der letzten if-Abfrage sollte wohl gDmxState = IDLE; stehen? Slot 0 nicht auszulesen halte ich für mutig, über kurz oder lang wird sich RDM durchsetzen und dann blinkt dein Empfänger lustig vor sich hin. Grüße leo
Hallo Klaus, deine Bedenken bezüglich RDM verstehe ich. Bislang bin ich immer davon ausgegangen, dass in DmxRxField[0] der Wert des ersten Datenbytes (1. Kanal) liegt. Das habe ich gerade auch nochmal nachvollzogen. Das ist wirklich so. In DmxRxField[2] liegt dementsprechend der Wert des zweiten Datenbytes (2. Kanal), usw. Der Originalcode betrachtet aber tatsächlich das 1. Datenbyte als Startbyte. Das ist das Symptom. Aber wie schon erwähnt, kann ich nicht nachvollziehen, warum das so ist. Es scheint, als ob kein Startbyte ausgesendet wird. Aber das kann ich mitlerweile ausschließen! Braucht der UART eventuell nach einem Frame Error eine gewisse Zeit, bis er wieder Daten einlesen kann und das Startbyte eventuell "zu schnell" kommt? In der letzten If-Abfrage muss tatsächlich
1 | gDmxState = IDLE |
stehen! Danke für eure Hilfe!!!
:
Bearbeitet durch User
Hier mal noch die restlichen Informationen die eventuell interessant sein könnten: - externer 16MHz-Oszillator: laut Datenblatt bei 250k ein Fehler von 0,0% - Fuse CKDIV8: deaktiviert - Fuse SUT_CKSEL: EXTCLK_14CK_65MS Edit: Wird wenn ein Frame Error erkannt wurde ein Interrupt ausgelöst? Im Datenblatt konnte ich nichts konkretes finden...
:
Bearbeitet durch User
> Braucht der UART eventuell nach einem Frame Error eine gewisse Zeit, > bis er wieder Daten einlesen kann und das Startbyte eventuell > "zu schnell" kommt? Das frage ich mich auch schon die ganze Zeit. Kannst du mal verifizieren, ob tatsächlich 2 Bytes hintereinander mit einem Frame-Error klassifiziert werden? D.h. hier
1 | if (USARTstate &(1<<FE)) //check for break |
2 | {
|
3 | UCSRA &= ~(1<<FE); //reset flag (necessary for simulation in AVR Studio) |
4 | DmxCount = DmxAddress; //reset channel counter (count channels before start address) |
5 | gDmxState = BREAK; |
6 | }
|
mitzählen, bzw.
1 | if (USARTstate &(1<<FE)) //check for break |
2 | {
|
3 | UCSRA &= ~(1<<FE); //reset flag (necessary for simulation in AVR Studio) |
4 | DmxCount = DmxAddress; //reset channel counter (count channels before start address) |
5 | |
6 | // .............
|
7 | |
8 | if( gDMXState == BREAK ) |
9 | mach was |
10 | else
|
11 | nimms zurück, alles ok |
12 | |
13 | // ..............
|
14 | |
15 | gDmxState = BREAK; |
16 | }
|
irgendeine Form von Kennung /zb. Fehler-LED einschalten dazwischenhängen. Bis lang ist das ja nur eine Hypothese, dass das Startbyte fälschlicherweise als Break angesehen wird, auch wenn es IMHO sehr plausibel ist und auch zum Fehlerbild passen würde.
:
Bearbeitet durch User
Hier der Code den ich hierfür verwende:
1 | if (USARTstate &(1<<FE)) //check for break |
2 | {
|
3 | if(DmxState == BREAK) |
4 | LED_red(1); |
5 | |
6 | UCSRA &= ~(1<<FE); //reset flag (necessary for simulation in AVR Studio) |
7 | DmxCount = DmxAddress; //reset channel counter (count channels before start address) |
8 | gDmxState= BREAK; |
9 | }
|
Die Ansteuerung der "roten LED" habe ich in eine Funktion gepackt. Ist der Parameter 1, wird die LED eingeschaltet, bei 0 entsprechend ausgeschaltet. Im Falle von zwei aufeinanderfolgenden Breaks wird die LED eingeschaltet und bleibt dann dauerhaft an. Aber die LED bleibt aus. Das heisst keine zwei aufeinanderfolgenden Breaks.
:
Bearbeitet durch User
Matt B. schrieb: > Aber die LED bleibt aus. Das heisst keine zwei aufeinanderfolgenden > Breaks. Hmm. Jetzt wirds immer mysteriöser
Nochmal zu meiner vorherigen Frage (etwas ausführlicher): Über die UART wird dem Controller ein Break gesendet. Wird durch den damit verbundenen Frame Error der RX-Interrupt ausgelöst? Im Datenblatt konnte ich nichts konkretes finden. Falls nicht, dann wird der Break erst beim nächsten korrekt empfangenen Byte vom Programm erkannt. Dieses korrekt empfangene Byte wäre in unserem Fall das Start-/Type-Byte. In der If-Abfrage zur Prüfung des Breaks wird dieses aber nicht ausgewertet. Erst das nächste empfangene Byte wird als Start-/Type-Byte ausgewertet... Könnte da was dran sein?
:
Bearbeitet durch User
Matt B. schrieb: > Nochmal zu meiner vorherigen Frage (etwas ausführlicher): > Über die UART wird dem Controller ein Break gesendet. Wird durch den > damit verbundenen Frame Error der RX-Interrupt ausgelöst? Müsste eigentlich. Wenn dem nicht so wäre, wäre das extrem unlogisch. > Könnte da was dran sein? Ich kanns mir nicht recht vorstellen, dass in so einem Fall ein Receive Interrupt nicht ausgelöst werden würde. Das würde Interrupts de facto unbrauchbar machen, wenn da nur einwandfrei empfangene Bytes durchkommen würden.
Der Meinung bin ich auch, aber langsam gehen mir die Ideen aus.
@ Matt B. (mattb) >- externer 16MHz-Oszillator: laut Datenblatt bei 250k ein Fehler von >0,0% Aber nur, wenn dein RC-Oszillator 0,0% Fehler hat. Die 0,0% beziehen sich auf dein systemtisch Fehler durch Frequenzteilung. Bei einem ganzzahligen Teiler ist der logischerweise 0 ;-) Ich wäre da vorsichtig. Ein 8 oder 16 MHz Quarz(oszillator) bringt hier auf jeden Fall Sicherheit. >Wird wenn ein Frame Error erkannt wurde ein Interrupt ausgelöst? Sicher. >Falls nicht, dann wird der Break erst beim nächsten korrekt empfangenen >Byte vom Programm erkannt. Nein. Der wird im fehlerhaft empfangenen BYte sofort erkannt. >Breaks wird dieses aber nicht ausgewertet. Erst das nächste empfangene >Byte wird als Start-/Type-Byte ausgewertet... DMX ist doch eigentlich nicht so schwer. Schau dir mal das Beispiel an, das funktioniert sogar ohne explizite statemachine. Beitrag "DMX512 Empfänger mit Relaisansteuerung für 20 Kanäle"
@ Karl Heinz (kbuchegg) (Moderator) >> Über die UART wird dem Controller ein Break gesendet. Wird durch den >> damit verbundenen Frame Error der RX-Interrupt ausgelöst? >Müsste eigentlich. Wird auch. >Wenn dem nicht so wäre, wäre das extrem unlogisch. Eben.
Es ist ein Quarzoszillator verbaut, kein RC-Oszillator. Den Quellcode von deinem DMX-Empfänger habe ich gerade vor mir: Hier ein Ausschnitt aus der ISR:
1 | if (status & (1<<FE)) { // frame error |
2 | if (data==0) { // break -> DMX Reset |
3 | dmx_channel=0; |
4 | dmx_base = (~PINB & 0xFF)+1; // read dip switches which define DMX base address |
5 | if (~PIND & (1<<PD6)) dmx_base +=256; |
6 | flag=1; // trigger update |
7 | }
|
8 | else // rx error |
9 | dmx_channel++; |
10 | }
|
Verstehe ich das richtig, dass wenn ein Frame Error erkannt wurde, du mit der Zeile
1 | if (data==0) |
das Startbyte prüfst?
:
Bearbeitet durch User
Hi, ich hatte mal ein ähnliches Problem, welcher hier im Forum gelöst wurde. War allerdings ASM. Vielleicht hilft es trotzdem weiter. Beitrag "DMX Empfang mit Assembler Problem" Gruß Benedikt
Matt B. schrieb: > Verstehe ich das richtig, dass wenn ein Frame Error erkannt wurde, du > mit der Zeile >
1 | > if (data==0) |
2 | >
|
> das Startbyte prüfst?
Die ganze Sequenz sieht ja so aus
1 | if (status & (1<<FE)) { // frame error |
2 | if (data==0) { // break -> DMX Reset |
3 | dmx_channel=0; |
4 | dmx_base = (~PINB & 0xFF)+1; // read dip switches which define DMX base address |
5 | if (~PIND & (1<<PD6)) dmx_base +=256; |
6 | flag=1; // trigger update |
7 | }
|
8 | else // rx error |
9 | dmx_channel++; |
10 | }
|
11 | else { |
12 | index = dmx_channel-dmx_base; |
13 | if (index>=0 && index<dmx_size) |
14 | dmx_array[index]=data; |
15 | dmx_channel++; |
16 | }
|
Das übergehen des Startbytes ist implizit hier
1 | index = dmx_channel-dmx_base; |
2 | if (index>=0 && index<dmx_size) |
mit enthalten. Beim ersten Startbyte nach dem Break hat dmx_channel den Wert 0, während dmx_base zb 1 ist. index wird zu -1 und damit wird das Byte übersprungen. Das hier
1 | if (status & (1<<FE)) { // frame error |
2 | if (data==0) { // break -> DMX Reset |
ist eigentlich der Normalfall. Denn so wie der Break erzeugt wird, mündet er automatisch darin, dass sich an der UART ein Byte-Wert von 0 ergibt.
:
Bearbeitet durch User
Beitrag "Re: Attiny2313 - DMX-Receiver - eingestellte Startadresse != reale Startadresse" Naja, diese statemachine benötigt zwingen ein 0x00 Byte als Startbyte, sonst geht sie nicht weiter. Das kann man ja einfach mal überbrücken.
1 | else if (DmxState == BREAK) |
2 | {
|
3 | gDmxState = STARTB; |
4 | }
|
DmxAddress ist hoffentlich volatile definiert.
DmxAddress ist volatile definiert. Kurze Frage zwischendurch: Wenn ich RXD vom Attiny2313 hart auf Masse lege, dann sollte doch ein Frame Error eintreten!?
Matt B. (mattb) >Verstehe ich das richtig, dass wenn ein Frame Error erkannt wurde, du >mit der Zeile >if (data==0) >das Startbyte prüfst? Nein. Schon mal den Kommentar angeschaut? BREAK = FE && data==0 Das Startbyte interssiert diesen Empfänger gar nicht, es wird wie jedes andere DMX-Byte einfach im Array abgelegt und fertig.
Hallo Matt, Wenn du es mit Bascom versuchen möchtest schau mal hier "COOL-DMX.DE" in der Bastelecke. Dort veröffenliche ich so nach und nach meine Bauselprojekte. MfG Dirk
es soll natürlich "Bastelprojekte" heissen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.