Hallo Forum,
ich weiß ja, dass das Thema mit den "alten" 89c52 uC´s und Dmx schon
sehr oft hier behandelt wurde, ich komme aber trotzdem nicht weiter.
Nachdem ich nun DMX mit dem 8052 empfangen konnte, will ich nun wissen
wie man DMX Daten mit dem 8052 sendet. Ich habe dazu dem Henning seine
Seite, sowie diverse andere Seiten plus dieses Forum durchforstet. Zu
beginn, ich kann nicht gut Assembler programmieren, deshalb suche ich
eine Lösung in C, ich habe versucht das Skript von hier:
http://www.hoelscher-hi.de/hendrik/light/ressources.htm anzupassen.
Heraus kam dieser C Code:
1
#include<REG52.h>
2
3
enum{BREAK,STARTB,DATA};
4
volatileunsignedchargCurDmxCh;
5
volatileunsignedchargDmxState;
6
volatileunsignedcharDmxField[6];//array of DMX vals
if(CurDmxCh==sizeof(DmxField))gDmxState=BREAK;//wieder zurück zu break
49
elsegCurDmxCh=CurDmxCh;
50
}
51
52
}
53
54
intx=0;
55
56
voidmain(void){
57
58
PCON=0x00;// 250 Baud bei 16MHz
59
SCON=0x88;// 10001000
60
IE|=0x90;// Interrupt freigeben
61
TI=1;// TxD setzen
62
gDmxState=BREAK;//start with break
63
64
DmxField[0]=88;
65
DmxField[1]=200;
66
DmxField[2]=50;
67
DmxField[3]=90;
68
DmxField[4]=127;
69
DmxField[5]=30;
70
71
72
while(1){
73
for(x=0;x<6;x++){
74
DmxField[x]=~DmxField[x];
75
}
76
}
77
78
}
Der 8052 ist angeschlossen an einen Differentialbus TI SN75176A, Pin 3.1
zu SN75176A Pin 4 (D) , Pin 3+2 (DE/RE) auf Masse, VCC an 5V, Gnd auf
Masse, und 6+7 an DMX stecker gehen. (Die müssten stimmen da ich mit der
selbern Verbindung auch senden kann, vorausgesetzt natürlich Pin 1 auf
Port 3.0 am uC)
Es kommt nur nix dabei raus... Ich wäre für jede Art von Hilfestellung
so dankbar, denn ich hänge da einfach völlig in der Luft, mangels
Kenntnisse. Ich würde aber sehr gerne dazulernen.
Bin für jeden Tipp, wo Fehler in meinem Aufbau / Code sind offen.
Viele Grüße Andre
Hallo peda,
vielen Dank erstmal für die Hilfe.
Ich weiß das uint evtl zu viel RAM nimmt, wobei ja DMX 512 Kanäle haben
könnte und da käme ich mit einem unsigned char nur bis 255, oder habe
ich da schon was falsch verstanden? Denn mein "Gerät" könnte ja auch auf
dem Kanal 500 hängen. Ich habe das Array DmxField auf uchar geändert
sowie die "States", denn hier können nur Werte bis 255 kommen, das ist
die einzige Optimierung die mir hier ins Auge gefallen ist.
Delay in Interrupts ist sehr schlecht, das weiß ich leider auch, aber
ich habe noch keine andere Lösung dafür, mangels Fachwissen. Ich würde
den delay auch lieber anderst machen, nur weiß ich ehrlich gesagt nich
nicht wie. Theoretisch schon, nur kann ich es nicht umsetzen. Ich bin
schon froh das es im Keil-Simulator tatsächlich 88ms und 10ms bei 16.0
Mhz waren, denn die sind für das DMX Protokol wichtig.
Was mich nun stark interessiert ist der Quote "Interrupts wieder
freigeben", ich möchte ja das Signal immer senden, also ständig. Falls
du das auf die Zeile
1
voiddmxSender(void)interrupt4
beziehst, dass ist eigentlich gewollt. Ich will das Signal, wenn es mal
beim "SLAVE" ankommt, immer senden und verändern können.
Ich bin für mehr Tipps wirklich dankbar. Auch was die 88ms + 10ms
Verzögerung betrifft, ich würde das gerne anderst lösen.
Gruß Andre
DMX beschreibt als Standard, das du mindestens 24 Kanäle senden musst,
bis dann eben zu max. 512. 6 Kanäle sind also zu wenig.
Andre Thomas schrieb:> Ich bin> schon froh das es im Keil-Simulator tatsächlich 88ms und 10ms bei 16.0> Mhz waren, denn die sind für das DMX Protokol wichtig.
Alle meine Unterlagen sagen, das der Break eine Länge von min. 88µs hat,
nicht 88ms. Kann aber auch 100µs werden:
https://en.wikipedia.org/wiki/File:Annotated_trace_of_DMX-512_signal.pnghttp://www.theater-technisch-lab.nl/dmxdu.htm
Soweit ich die DMX Sender von Henning verfolgt habe, sendet er den Break
mit einer niedrigeren Baudrate (sendet die 0) und stellt dann wieder auf
250kBaud vor dem ersten Nutzbyte (Kanal 0). Dann brauchst du nämlich gar
keine Delays im Interrupt, sondern wartest einfach in der Hauptschleife,
bis der Sendebuffer leer ist, bzw. der Interrupt wieder zuschlägt, weil
das Breakbyte weg ist.
Jetzt müsste man mal rechnen, wie hoch die Baudrate für den Break sein
muss...
88µs/9bit (Denn das Stopbit geht auf High und markiert das Ende von
'Break') sind 9,7µs - rechnerisch eine Baudrate von 102 kBit/s.
Praktisch wäre es zudem, wenn die Länge des Stopbit gleich die 12µs hat,
die das Ende von Break markieren. Also ist eine Baudrate von 83kBits/s
gar nicht so unpassend.
@ Andre Thomas (andret)
>Nachdem ich nun DMX mit dem 8052 empfangen konnte, will ich nun wissen>wie man DMX Daten mit dem 8052 sendet.
Das ist fast noch einfacher als Empfangen.
>beginn, ich kann nicht gut Assembler programmieren, deshalb suche ich>eine Lösung in C,Beitrag "Re: CTC-Modus beim ATmega32 ?1us mit 10MHz?"
ISt für AVR, aber kann man leicht anpassen.
Andre Thomas schrieb:> Was mich nun stark interessiert ist der Quote "Interrupts wieder> freigeben"
Steht nirgends, sondern überhaupt erstmal freigeben.
Stichwort IE-Register.
Andre Thomas schrieb:> wobei ja DMX 512 Kanäle haben> könnte und da käme ich mit einem unsigned char nur bis 255, oder habe> ich da schon was falsch verstanden?
Nimm int nur wenn nötig.
Ein Break sendet man am einfachsten, indem man P3.1. für die gewünschte
Zeit auf Low setzt.
Gibt es im Web wirklich kein DMX mit 8051 Beispiel?
Peter Dannegger schrieb:> Gibt es im Web wirklich kein DMX mit 8051 Beispiel?
Ich habe nur 2 Beispiele in ASM gefunden, alle anderen Fragen oder
Threats oder Tutorials sind entweder offline, ungeklärt oder für andere
Prozessoren. Ich habe das vom Henning genommen, da dies das einzig
komplette C script ist, welches auch läuft (jedoch nur auf AVR).
Matthias Sch. schrieb:> Alle meine Unterlagen sagen, das der Break eine Länge von min. 88µs hat,> nicht 88ms. Kann aber auch 100µs werden:
Oh mein Gott, ich verspreche besseren Code zu schreiben, denn das ist
ein großer Patzer... Du hast vollkommen recht, und eigentlich wollte ich
auch es genau so machen. Ich habe es dann vor lauter Timer ausrechnen
auf 1ms berechnet statt auf 1uS.
Falk Brunner schrieb:> Beitrag "Re: CTC-Modus beim ATmega32 ?1us mit 10MHz?">> ISt für AVR, aber kann man leicht anpassen.
Ich schaue es mir gerne mal an, aber meine Konvertierung von Hennings
script ging ja mangels Verständnis für Timer,Interrupts und SFR´s ja
auch schon in die Hose.
Trotzdem @ alle, vielen Dank für eure Unterstützung.
Gruß Andre
Peter Dannegger schrieb:> Steht nirgends, sondern überhaupt erstmal freigeben.> Stichwort IE-Register.
Danke, das müsste dann geOdert werden mit IE |= 0x90;
um den Interrupt auf die serielle Schnittstelle zu legen, das heisst
dann immer wenn gesendet wurde wird ein Interrupt ausgelöst, was im
Moment nicht passiert.
Und als ich dann noch TI=1 eingesetzt habe, hat mir der Debugger sogar
mal was auf UART ausgegeben.
So lächerlich es klingen mag, aber das nun die RX-Led flackert ist für
mich schon was. Wieder etwas näher am Ziel. Vielen Dank !
Matthias Sch. schrieb:> 88µs/9bit (Denn das Stopbit geht auf High und markiert das Ende von> 'Break') sind 9,7µs - rechnerisch eine Baudrate von 102 kBit/s.> Praktisch wäre es zudem, wenn die Länge des Stopbit gleich die 12µs hat,> die das Ende von Break markieren. Also ist eine Baudrate von 83kBits/s> gar nicht so unpassend.
Danke für den Tipp: 83kBits/s wäre dann ja einfach bei 16.0Mhz
von Serial Port Mode 2 auf Mode 3 umschalten und Timer 1 / Mode 2
(Smod=1)
TH1 auf 0xFF (255) macht 83.33333
das versuche ich mal.
Es geht, wunderbar. Ich möchte mich für die Hilfe bei allen im Threat
bedanken.
Richtig geholfen haben mir die Tipps von Peter Danneger und den Wink mit
dem Zaunpfahl (ms != uS) von Matthias.
Ein Problem habe ich noch,
es geht nur wenn man kurz das DMX-Kabel aus dem Slave zieht, ob das nun
am Slave liegt oder nicht, weiß ich erst wenn ich einen anderen
anschliesse. Falls jemand da noch eine Idee hätte, wäre ich dankbar.
Viele Grüße von einem glücklichen Dilletant !
Leider zu früh gefreut, ich habe nun noch einen anderes DMX Gerät hier.
Das erste ging zwar, wenn man den Stecker kurz zog. Und dann lief es auf
den ersten Werten die durchgegeben wurden. Das zweite reagiert gar
nicht.
Hier ist mal wieder mein Code, vielleicht mag sich den jemand mal
ansehen und mir nochmal einen Tipp geben:
1
#include<REG52.h>
2
3
enum{BREAK,STARTB,DATA};
4
volatileunsignedintgCurDmxCh;
5
volatileunsignedintgDmxState;
6
volatileunsignedintDmxField[24];//array of DMX vals
7
volatileunsignedintCurDmxCh;
8
9
10
//Delay - Warte x Millisekunden
11
voiddelay_10uS(constunsignedintms){
12
unsignedintx;
13
for(x=0;x<ms;x++){
14
//SCON = 0x50;
15
TMOD=0x01;//Timer Mode 1 = 16-bit timer
16
TL0=0xF4;//
17
TH0=0xFF;//
18
TR0=1;// starte timer0
19
while(TF0==0);// Warte bis fertig
20
TR0=0;// stop timer
21
TF0=0;// reset timer flag
22
}
23
}
24
25
voiddmxSender(void)interrupt4{
26
27
unsignedintDmxState=gDmxState;
28
29
if(DmxState==BREAK)
30
{
31
TMOD=0x20;//Timer Mode 2
32
TH1=0xFF;//
33
TR1=1;// starte timer1
34
SCON=0xC8;// 11001000
35
PCON=PCON|128;// SMOD = 1
36
SBUF=0;//sende break
37
EA=1;
38
while(!TI);
39
gDmxState=STARTB;
40
TR1=0;// stop timer
41
TF1=0;// reset timer flag
42
43
}
44
elseif(DmxState==STARTB)
45
{
46
PCON=PCON&0x01;// SMOD = 0
47
SCON=0x88;
48
SBUF=0;//sende startbyte
49
while(!TI);
50
gDmxState=DATA;
51
gCurDmxCh=0;
52
}
53
else
54
{
55
delay_10uS(3);////interbyte gap
56
SCON=0x88;
57
CurDmxCh=gCurDmxCh;
58
SBUF=DmxField[CurDmxCh++];//sende data
59
while(!TI);
60
if(CurDmxCh==sizeof(DmxField))gDmxState=BREAK;//wieder zurück zu break
61
elsegCurDmxCh=CurDmxCh;
62
}
63
64
}
65
66
intx=0;
67
68
voidmain(void){
69
70
PCON=0x00;// 250 Baud bei 16MHz
71
SCON=0x88;// 10001000
72
gDmxState=BREAK;//start with break
73
74
for(x=0;x<24;x++){
75
DmxField[x]=0;
76
}
77
78
x=0;
79
80
81
IE|=0x90;// Enable RX I
82
TI=1;
83
while(1){
84
85
if(x<15000){
86
DmxField[0]=100;
87
DmxField[1]=200;
88
DmxField[2]=0;
89
DmxField[3]=90;
90
DmxField[4]=127;
91
DmxField[5]=0;
92
x++;
93
}else{
94
DmxField[0]=230;
95
DmxField[1]=80;
96
DmxField[2]=6;
97
x++;
98
}
99
100
if(x==30000){x=0;}
101
102
103
}
104
105
}
Ich habe im Debugger mal die Zeiten angeschaut.
in der Funktion dmxSender beim Break wo es 88uS sein sollten geht es von
0.00037050 sec - 0.00050400 sec , also 134uS oder ? Das wäre dann
zuviel, was müsste ich den ändern.
und bei dem 10uS interbyte gap sinds 0.000826 - 00091575 nahezu 9 uS ...
Ich denke daran wird es wohl liegen, könnte mir dabei jemand helfen.
Hrüße Andre
Andre Thomas schrieb:> delay_10uS(3); ////interbyte gap
Normalerweise reicht bei der Übertragung ein 2tes Stopbit, ein extra gap
ist nicht nötig. Du machst dir auch das Leben unnötig schwer, indem du
Timer 1 sowohl für die Baudrate als auch für die Delay Schleife
einsetzt. Wenn du einen 8052 hast, nimm besser Timer2 für die Baudrate,
der läuft dann völlig unabhängig und du musst nicht ständig rumschalten.
Der serielle Port läuft dann in Mode 3 und als 9. Bit sendest du eine 1.
Mit dem folgenden Stopbit hast du effektiv die nötige Lücke.
Wenn der Break zu lang ist, erhöhe die Baudrate im Breakmode, bis es
stimmt. Vermutlich wäre es sinnvoll, den Baudratengenerator schon nach
dem letzten Datenbyte umzustellen, damit das Timing besser wird, ist
aber nicht entscheidend.
Behalte nur im Hinterkopf, das der MC mit 1/12 der Quarzfrequenz intern
läuft, er ist also (wenn es kein WARP 51 ist) nicht der schnellste.
Hallo Matthias,
danke für die Unterstützung, ich habe wie empfohlen das ganze mal mit
dem Timer 2 versucht. ich habe an allen DMX-Slaves leider immernoch das
Problem das ich erst das Kabel ziehen muss, dann übernimmt der Slave
einmalig den Wert. Also fehlt meiner Meinung nach noch irgendeine
Unterbrechung. Evtl das Mark After Break - das sollte glaube ich das 9te
bit (TB8=1) sein.
Ich habe bei ein paar anderen Scripten ( AVR und Arduinos ) gesehen,
dass die teilweise den Port abschalten nach dem Break. Vielleicht hilft
das ? Nur wie schalte ich "kurz" mal den Port aus/an ?
Hier der verbesserte Quelltext mit Timer 2 60 Werten alles chars +
weniger gewurschtel hoffentlich.
Matthias Sch. schrieb:> Der Vektor für den seriellen Interrupt liegt auf 0x0023, wie man das bei> deinem Kompiler einstellt, weiss ich aber nicht.
Ich denke das habe ich schon so, bei der Zeile:
1
voiddmxSender(void)interrupt4{...
interrupt 4 ^= Serial Port 0023h
Vielen Dank, Matthias, für den weiteren Tipp mit dem Sendeinterrupt des
UART, ich probiere es später am mC selber aus. Wo ich noch ein bisschen
mit hadere, und das könnte evtl auch der Fehler sein, sind die Timings
im Debugger. Habe nun noch einen anderen Debugger genommen und da kommt
so ziemlich das gleich raus. Mit den Änderungen am SendeIR von oben wäre
dann 133.5 uS für das BREAK inkl. 9.bit bei 88.000b, dann dauert es
6.5uS bis zum gesendeten Startbit (9.bit), und dann von Ende Startbit
bis Ende Ch1. 8,5 uS - wobei der eigentliche Sendevorgang 4,35uS dauert.
Leider steht mir kein Oszilloskop zur Verfügung, damit könnte ich
schneller sehen was los ist. Ich probiere heute abend einfach weiter es
zum laufen zu bekommen.
Grüße André
du musst dich beim Break senden noch entscheiden, ob du auch ein 8 bit
mit 2 Stopbit senden willst, oder ein 8bit mit einem Stopbit. Wenn du
weiterhin die 9 bit aussenden willst mit einem Stopbit, musst du nochmal
neu rechnen. Mark soll 12µs sein. Würdest du jetzt mit 1/12µs = 83kBaud
sendest, bleibt für Break 9 * 12µs (du sendest ja weiterhin 9 bit,
wobei diesmal das 9te Bit 0 sein sollte) = 108µs.
Entscheidend ist im Moment die Frage, wann das UART sein IRQ setzt.
Müsste im Datenblatt stehen.
Wenn es schon während des Stopbit zündet, wären die 108µs vermutlich
akzeptabel, anderenfalls käme das Startbyte der Daten zu spät. Es ist
also evtl. sinnvoll, zwar bei den 83kbit/s zu bleiben (um MARK gut
einzuhalten), aber das Datenformat auf 8bit, 1 Stopbit zu setzen.
Das sind dann 8*12µs = 96µs Breakzeit.
So jetzt bin ichs wieder. Ich habe rumprobiert und versucht alle Tipps
zu berücksichtigen. Rausgekommen ist im Moment ein recht übersichtliches
C-Skript was aber leider immernoch den Dienst versagt.
Es funktioniert mit beipspielsweise 10 Werten die von diversen
DMX-Slaves auch richtig eingelesen werden, jedoch nur wenn man am ersten
Slave das Kabel zieht und wieder einsteckt.
Und es ist schon eine Weile so. Das lässt mich vermuten das irgendwo so
etwas wie ein "Unterbrecher" fehlt. Ich bin aber ziemlich am Ende meines
Verständnisses, sowie besitze ich leider kein Oszilloskop um mal
anzuschaun was da rauskommt.
An der Schaltung an sich ist ein SN75176bp mit einem
Stützkondensator(104) zum DMX Kabel. Ich habe noch einen 100 Ohm
Widerstand zw Pin1 und Masse sowie die anderen Pins des 75176 mit
Sicherheit richtig angeschlossen.
Hier ist das aktuelle Skript, vielleicht kann mir nochmal jemand helfen.
Vielen Dank an dieser Stelle an Matthias der mir geduldig gute Tipps
gab.
Ich habe auf jedenfall bis jetzt eine Menge über DMX, Timer und Serielle
Schnittstellen gelernt - von daher was es nicht ganz sinnlos sich damit
zu beschäftigen.
1
#include<REG52.h>
2
3
enum{BREAK,STARTB,DATA};
4
volatileunsignedchargCurDmxCh;
5
volatileunsignedchargDmxState;//
6
volatileunsignedchardmxField[24];//Array aus DMX Werten
Andre Thomas schrieb:> An der Schaltung an sich ist ein SN75176bp mit einem> Stützkondensator(104) zum DMX Kabel
Natürlich meinte ich zw VCC und GRD, nicht am DMX Kabel...
24 DMX Kanäle sind zwar das erlaubte Minimum, es kann aber sein, das
dann die Wiederholrate für die Slaves zu schnell wird, wenn sie sich
nicht genau an die Specs halten. Sende doch einfach mal ein paar mehr
Kanäle, 100 oder so, damit sinkt die Framerate ab.
@ Matthias Sch. (Firma: Matzetronics) (mschoeldgen)
>nicht genau an die Specs halten. Sende doch einfach mal ein paar mehr>Kanäle, 100 oder so, damit sinkt die Framerate ab.
Wer sagt denn, dass die DMX-Sender immer mit maximal möglicher
Wiederholrate arbeiten? Und mit 1 kHz schon gar nicht, auch wenn es
prinzipiell möglich ist.
Falk Brunner schrieb:> Wer sagt denn, dass die DMX-Sender immer mit maximal möglicher> Wiederholrate arbeiten?
Der aus diesem Thread tut es jedenfalls. Deswegen ja mein Vorschlag. Man
kann jetzt die Zeit zwischen zwei Datenbytes strecken, mehr Bytes senden
oder bis zu einer gewissen Grenze den Break verlängern, allerdings sind
mehr als 100-120µs für Break anscheinend nicht üblich.
Endlich ! Habe den Fehler,
das c-script geht einwandfrei.
Ich weiß nicht warum, aber an meinem hardwareseitigen Versuchsaufbau war
ein Massefehler. Als ich alles neu gesteckt habe, ging auf einmal alles
wie gewollt. Also das og script kann als DMX-sender eingesetzt werden.
Es können/sollten noch ein paar Änderungen mit einfliessen, ich habe
eine interrupt unabhängige version geschrieben die ca. 10x / sec einen
DMX-Frame sendet, die ging auch.
Grüsse Andre.
PS: Matthias, vielen Dank fürs helfen ! Ohne Deine Tipps wäre ich nicht
soweit gekommen.