PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : DMX512 empfangen



guenter1604
15.12.2008, 20:27
Hallo NG,

nachdem ich bereits DMX-512 Signale senden kann, kommt nun der Empfang dran.
Folgender erster Ansatz:


$regfile = "m8def.dat"
$crystal = 16000000
$baud = 250000

Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 2 , Databits = 8

Dim Buffer(513)as Byte
Dim Kanal As Word

On Urxc Empfang
Enable Urxc
Enable Interrupts

Do
Loop

Empfang:
If ucsra.Fe = 1 Then
Kanal = 0
Else
If Kanal > 0 Then
Buffer(kanal) = Udr
End If
Incr Kanal
End If
Return

Ist der Code vom Ansatz her korrekt?

Günter

Gento
15.12.2008, 22:00
Senden mag ja 'einfach' sein weil das andere Gerät ja bereit sein muss.

Empfangen geht wohl nur per IRQ & ASM.

Hier im Forum fand ich mal auch Bascomcode mit ASM dazu.

Gento

guenter1604
15.12.2008, 22:32
Hallo Gento,

Interrupt hab ich doch:

On Urxc Empfang

Das Abspeichern des Kanals müsste doch zu schaffen sein, bis das nächste Byte ansteht.

Wo soll hier Basic zu langsam sein?

Günter

Gento
16.12.2008, 08:48
so Code gefunden.
Quelle steht drin.


'--------------------------------------------------------------------
' Original von:
' DMX - Dimmer 512 / by DW-Soft
' Dirk Wegener - 2004 - the_clown@web.de
'--------------------------------------------------------------------
' Bearbeitet von Jochen Steinmann
' DMX - SwitchPack
' AVR-Bascom
'--------------------------------------------------------------------
' "Deklaration" m³sste klar sein
$regfile = "m32def.dat" 'AT90S2313
$crystal = 16000000 '8MHz Quarz
$baud = 250000 'Baudrate 250Kbaud

' ben÷tigete Variablen
Dim Dmx_count As Word 'Pakete die auf Ausgõnge zielen
Dim Dmx_count_temp As Byte 'Gesendete Pakete
Dim Dmx_byte As Byte 'DMX Wert
Dim Dmx_clock As Byte 'Spielerei
Dim Dmx_adr As Word 'DMX-Adresse
Dim Dmx_adr_temp As Byte 'DMX-Adresse (Temp)
Dim Dmx_adr_c As Word 'DMX-Adresse (Counter)
Dim Dmx_off As Byte 'DMX-Signal noch da?

' Uart initialiesieren
Print "Start"
On Urxc Rec_isr
Enable Urxc

' Ports setzen und configurieren
Config Pind.6 = Output 'StatusLED
Config Portb = Output 'Schaltausgõnge
Set Portd.6

' Anfangsvariablen Festlegen
Dmx_count = 0 'kein Paket empfangen
Dmx_clock = 16 '
Dmx_adr = 2 'DMX_Adresse 2

Enable Interrupts

' ************************************************** ****************************
' Hauptschleife
' ************************************************** ****************************
Do
Waitms 10
Decr Dmx_off
If Dmx_off = 0 Then
Set Portd.6
End If
Loop

' ************************************************** ****************************
' Funktion: DMX-Signal emfangen und auswerten
' Dieser Interupt wird beim eintreffen von seriellen Daten ausgef³hrt
Rec_isr:
$asm 'Programmteil f³r das Auswerten der
.def Uart_status = R16 'emfangenen Daten
.def Uart_byte = R17
.def Uart_temp1 = R18

IN Uart_status,USR
IN Uart_byte,UDR

SBRC Uart_status,FE 'Auswertung ob Datenbyte OK
RJMP Asm_reset 'bei ³berlõnge des Datenbyte = DMX Reset
RJMP Asm_Loop1 'Daten OK--->

Asm_reset:
LDI Uart_temp1,$00 'Adesszõhler zur³cksetzen
STS {Dmx_count_temp} , Uart_temp1 'Daten dem Basicvariablen ³bergeben
STS {Dmx_byte} , Uart_byte
RJMP Asm_exit
Asm_loop1:
STS {Dmx_byte} , Uart_byte
Asm_exit:
$end Asm

If Dmx_count_temp <> 0 Then 'emfangene Daten im "Dmx_buf" ablegen
Incr Dmx_count 'und den jeweiligen Kanal zuordnen
If Dmx_adr_c = Dmx_count Then
If Dmx_adr_temp < 9 Then
Select Case Dmx_adr_temp
Case 1:
If 127 <= Dmx_byte Then : Reset Portb.0 : Else : Set Portb.0 : End If
Case 2:
If 127 <= Dmx_byte Then : Reset Portb.1 : Else : Set Portb.1 : End If
Case 3:
If 127 <= Dmx_byte Then : Reset Portb.2 : Else : Set Portb.2 : End If
Case 4:
If 127 <= Dmx_byte Then : Reset Portb.3 : Else : Set Portb.3 : End If
Case 5:
If 127 <= Dmx_byte Then : Reset Portb.4 : Else : Set Portb.4 : End If
Case 6:
If 127 <= Dmx_byte Then : Reset Portb.5 : Else : Set Portb.5 : End If
Case 7:
If 127 <= Dmx_byte Then : Reset Portb.6 : Else : Set Portb.6 : End If
Case 8:
If 127 <= Dmx_byte Then : Reset Portb.7 : Else : Set Portb.7 : End If
End Select
Incr Dmx_adr_temp
Incr Dmx_adr_c
End If
End If
Else 'bei DMX Reset Variablen setzen
Dmx_count = 0 : Dmx_count_temp = 1
Dmx_adr_c = Dmx_adr : Dmx_adr_temp = 1
Decr Dmx_clock
'nur eine Spielerei Toggelt eine LED am PortD.6 beim eintreffen von korrekten DMX Daten
If Dmx_clock = 0 Then : Toggle Portd.6 : Dmx_clock = 16 : End If
End If
Dmx_off



DMX ist recht Zeitkritisch wegen der hohen Baudrate.

Gento

guenter1604
16.12.2008, 09:35
Hallo Gento,

im Interrupt Rec_ISR wird erst mit ASM superschnell das Byte abgeholt um dann mit Basic im selben Interrupt superlangsam das Byte auszuwerten. Also wenn DAS läuft, dann kann ich beruhigt den ersten Prototyp zusammenlöten...

danke für deine Hilfe!

Günter

Vitis
16.12.2008, 12:31
ach was ... asm brauchts nicht unbedingt ...
hab mir nen 4-Kanaligen Dimmer für DMX512 gebastel, der
läuft in Bascom einwandfrei ... gar kein Thema
selbst bei 250000 Baud hat der AVR bei 16MHz noch mächtig
zeit für anderes.
Du brauchst den URXC Interrupt, den haste ja und das
Framing Error Flag der UART
Über das Flag setzt Du dann Deinen Bytezähler auf 0 und
im URXC Int zählste dann diesen wieder hoch und schreibst
auf den entsprechenden Platz Deinen Wert ... fertig ist die Laube

guenter1604
16.12.2008, 20:01
Hallo Vitis, hallo Gento,

jetzt hab ich mal nachgerechnet:

ein Frame des DMX-Signals dauert kürzestenfalls 44µs.
Das bedeutet, mein Interrupt darf maximal 44µs dauern denn dann könnte das nächste Byte anstehen. Bei 16MHz dauert:

$asm
.def Uart_status = R16
.def Temp_var = R17

IN Uart_status,USR
SBRC Uart_status,FE0
RJMP Asm_reset
RJMP Asm_kanal

Asm_reset:
ldi temp_var, $00
sts {Kanal}, temp_var
RJMP Asm_exit

Asm_kanal:
$end Asm
Buffer(kanal) = Udr
Incr Kanal
$asm
Asm_exit:

$end Asm

fast genau so lange wie:

If Ucsr0a.fe0 = 1 Then
Kanal = 0
Elseif Kanal > 0 Then
Buffer(kanal) = Udr
Incr Kanal
End If

nämlich ca. 10,875µs. Darum verbleiben 33µs pro Frame für weiteres.

Gespeichert werden alle Werte aller Kanäle in einem riesigen Array ob sie gebraucht werden oder nicht. Das hält den Interrupt kurz und Platz ist ja genug.
Der Rest kommt jetzt in die Mainloop

Günter

Vitis
16.12.2008, 21:52
sag ich ja ... es bleibt noch massig Zeit.
Zumal das DMX ja meist nicht permanent läuft

Stromi
17.12.2008, 21:50
@Vitis
kannst du den Bascom-Empfänger-Dimmer-Code veröffentlichen, dann kann Guenter und Andere ihn ev. für sich umstricken.
Vielen Dank dafür!

guenter1604
17.12.2008, 22:08
Hallo Stromi,

sobald ich Hardwaretechnisch soweit bin, werde ich meine Fortschritte melden. Es geht mir dabei in erster Linie darum einen sauberen Code hinzulegen, nicht um einen Code der irgendwie läuft.
Bis jetzt sieht das so aus:


$regfile = "m88def.dat"
$crystal = 16000000
$baud = 250000

Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 2 , Databits = 8

Dim Buffer(513)as Byte
Dim Dmx_byte As Byte

Dim Kanal As Word

On Urxc Empfang
Enable Urxc
Enable Interrupts

Do
'Hier werden die Ausgänge von Buffer() bestückt
Loop

Empfang:
If Ucsr0a.fe0 = 1 Then
Kanal = 0
Else
If Kanal = 0 Then
Incr Kanal
Else
Buffer(kanal) = Udr
Incr Kanal
End If
End If
Return

Stromi
17.12.2008, 22:15
Das ist nett, Guenter,
läuft der Code denn?
Ich habe bei Plischka und Darwin geluschert.
Da gibt es schon fertige Module.
zT mit Speicher, mit dem der Bus auch ohne PC weiterläuft.

guenter1604
17.12.2008, 22:31
Hallo Stromi,

bis jetzt ist es graue Theorie...

Das mit dem gespeichertbleiben ergiebt sich automatisch.
In dem oben gezeigten Code werden alle 512 Kanäle in Buffer() abgelegt. Bricht der DMX-Bus weg, bleiben die letzten übertragenen Werte in Buffer() ja erhalten. Die Frage ist, ob das sinnvoll ist.
Aber wie gesagt, wenns mir um ein schnelles Ergebnis ginge, würde ich auch zum Fertigmodul greifen.

In den nächsten Tagen kommt der Hardwaretest...

Stromi
17.12.2008, 22:37
Jo,
lass dir Zeit.
Will ja nur spielen ;-)

Vitis
17.12.2008, 23:40
ui, da hab ich aber tief im Bastelordner suchen müssen ...
naja, war damals fast and dirty zusammengestrickt, aber funktioniert:





' #######################################
' DAS IST DER CODE !!!!!!

$regfile = "m8def.dat"
$crystal = 16000000

$baud = 250000
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 2 , Databits = 8


Dim Timeout_counter As Byte , X As Byte , Y As Byte , Z As Byte , Fe_error As Byte
Dim Adresse As Byte , Adresse2 As Byte , Pointer As Byte At &H82
Dim Timercounter As Byte , Flag As Byte , Summe_pwm As Word
Dim Pwm_werte(5) As Byte
Dim Rotation_byte As Byte , Rotation_zaehler As Byte

On Urxc Zeichenempfang
Enable Urxc

Const Pwm_teiler = 255 / 46

Config Int0 = Falling
On Int0 Nulldurchgang
Enable Int0

Config Timer0 = Timer , Prescale = 64
On Timer0 Timer_irq
Const Timervorgabe = 220
Enable Timer0

Enable Interrupts
Config Portd.2 = Input
Config Portb = Output
Config Portc = Input
' interne Pullups an
Portc = &HFF

485_rw Alias Portc.6
Config 485_rw = Output
485_rw = 0

Led Alias Portb.0

Adresse = Pinc
Adresse = Not Adresse
Adresse = Adresse And &B00111111

For Z = 1 To 4
Pwm_werte(z) = 2
Next

Rotation_byte = &B10001000

Do
If Flag = 1 Then
Flag = 0
Y = Pointer
Shift Y , Right , 2
If Y = Adresse Then
Y = Pointer
Y = Y And &B00000011
Incr Y
Summe_pwm = Summe_pwm + X
Pwm_werte(y) = X / Pwm_teiler
Pwm_werte(y) = 49 - Pwm_werte(y)
End If
End If

If Summe_pwm = 1020 Then
If Rotation_zaehler > 30 Then
Rotation_zaehler = 0
Rotate Rotation_byte , Right , 1
End If

For Y = 1 To 4
If Rotation_byte.y = 0 Then
Pwm_werte(y) = 60
End If
Next
End If

If Timercounter < 48 Then
If Pwm_werte(1) <= Timercounter Then
Set Portb.1
Else
Reset Portb.1
End If
If Pwm_werte(2) <= Timercounter Then
Set Portb.2
Else
Reset Portb.2
End If
If Pwm_werte(3) <= Timercounter Then
Set Portb.3
Else
Reset Portb.3
End If
If Pwm_werte(4) <= Timercounter Then
Set Portb.4
Else
Reset Portb.4
End If
End If
' Pause für Zünden
Waitus 10
Portb = 0

If Timeout_counter > 150 Then
For Z = 1 To 4
Pwm_werte(z) = 100
Next
Summe_pwm = 0
End If
Loop
End

Zeichenempfang:
X = Udr
If Fe_error = 1 And X = 0 Then
Fe_error = 0
Pointer = 0
Summe_pwm = 0
End If
If Ucsra.fe = 1 Then
Fe_error = 1
Ucsra.fe = 0
End If
Incr Pointer
Flag = 1
Timeout_counter = 0
Return
End

Nulldurchgang:
Timercounter = 0
Incr Timeout_counter
Incr Rotation_zaehler
Return
End

Timer_irq:
Timer0 = Timervorgabe
Incr Timercounter
Return
End

Hab aber auch nur bis zu Adresse 255 genutzt, für 512 brauchst Du halt
ne Word Variable

@guenter1604:
Deinen Code kannst Du aber noch ne ganze Ecke kürzen:



$regfile = "m88def.dat"
$crystal = 16000000
$baud = 250000

Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 2 , Databits = 8

Dim Buffer(513)as Byte
Dim Dmx_byte As Byte

Dim Kanal As Word

On Urxc Empfang
Enable Urxc
Enable Interrupts

Do
'Hier werden die Ausgänge von Buffer() bestückt
Loop

Empfang:
If Ucsr0a.fe0 = 1 Then
Kanal = 1
Else
Buffer(kanal) = Udr
Incr Kanal
End If
Return

Stromi
17.12.2008, 23:49
Jo,
vielen Dank!
Beschaltung ist aus dem Code zu erkennen, glaube ich jedenfalls ;-)
100Hz oder 50 Hz finde ich im Code?
Würde es auch mit Solidstate-relais (ohne Nulldurgangsbaustein) gehen und wie warm wurden die Triacs?
Weißt du's noch?

Vitis
18.12.2008, 00:18
Der verwendete Optokoppler für den Nulldurchgang hab beide
Flanken ausgegeben, bzw. beide Nulldurchgänge.
Die Triacs wurden kaum warm, hab mit 200W Je Kanal
ohne Kühlkörper gearbeitet, allerdings im Bereich Show,
sprich die Kanäle waren nicht über Stunden offen und da
hatt ich keine Probleme mit Wärme.
Obs mit Solid State Rel geht weiß ich nicht, hab ich nicht
probiert.

guenter1604
18.12.2008, 08:07
Hallo Vitis,

laut Spezifikation kommt vor dem Kanal 1 ein Startbyte, welches ich mit meinem Code überspringe.
Aber für Codeverbesserungen hab ich immer ein offenes Ohr!
In deinem Code setzt du den FrameError zurück: >>Ucsra.fe = 0 <<
Ist das erforderlich? Dazu hab ich im Datasheet nix gefunden...

Günter

Vitis
18.12.2008, 08:49
mit dem 0-Byte am Anfang stimmt schon, laut Spec
ist das, hab hier aber 2 "Profi" - DMX-Sender, einmal direkt
USB und noch so n Ding, die ignorieren das einfach ...
warum auch immer .....

hmmm .... den FE .... ist schon ne Weile her,
weiß nicht mehr warum ich das damals so gemacht
hab, glaub ich hatt das irgendwo im DB gelesen, kanns
aber nicht mehr beschwören.

guenter1604
18.12.2008, 09:59
Hallo Vitis, hallo NG,

was mir gerade beim Hardware planen ein bisschen stört:
nur um die DMX-Startadresse mit Schaltern einstellen zu können muß ich einige Pins am Controller verheizen. Hat jemand eine clevere Idee?

Günter

Vitis
18.12.2008, 17:49
klar, adresse 513 z.B. könnte die künftige Slaveadresse
des Device werden

guenter1604
18.12.2008, 21:44
Hallo Vitis,

bis auf ein paar Kleinigkeiten läufts jetzt.

Doch bei Kanal 255 ist Schluß.

Gibt es eine Beschränkung die ich übersehen hab?

Günter

Vitis
18.12.2008, 21:53
X As Byte , Y As Byte , Z As Byte
Pointer As Byte At &H82

byte geht halt nur von 0-255
für mehr dann halt word variablen

wkrug
18.12.2008, 22:06
Leider kann ich zu Eueren BASCOM Codes keine Stellung nehmen, dazu kenn ich mich zu wenig damit aus - Bin ein "C" Jünger.

Prinzipiell braucht man nur so viele Bytes des DMX Frames puffern, wie das Gerät Kanäle verwalten kann.

Die USART Abfrage sollte im Interrupt laufen.
Wenn die Frame Synchronisation ( Codeverletzung ) stattgefunden hat, ist das FE ( Framing Error ) Bit gesetzt. Das nächste übertragene Byte müsste dann 0 sein ( ist im DMX Protokoll für Dimmer so festgelegt ).
Das darauf folgende Byte ist der Wert des ersten Kanals des DMX Frames.

Ein DMX Empfänger Programm könnte nun so aussehen.
1. Das USART Statusregister wird im Interrupt abgefragt.
Ist das FE Bit gesetzt, wird der Kanalzähler, sowie die Empfangskanal Hilfsvariable auf 0 gesetzt.
2. Im nächsten USART RX Interrupt wird überprüft, ob der Kanalzähler 0 ist und dann ob auch der übertragene Wert 0 ist ( Startbyte ).
Der Kanalzähler wird um 1 erhöht.
3. In den nächsten Interrupts wird der Kanalzähler jeweils um 1 erhöht und überprüft, ob der eingestellte erste zu verarbeitende Kanal schon erreicht ist.
Ist das der Fall, wird der Wert in einem Puffer abgelegt und eine Hilfsvariable ( Anzahl der zu verarbeitenden Kanäle ) hochgezählt.
Wurden alle zu verarbeitenden Kanäle eingelesen wird ein Flag gesetzt, das es neue Kanalinformationen gibt.
Dieses Flag wird im Hauptprogramm verarbeitet und zurückgesetzt.
Alle noch folgenden Bytes bis zur nächsten Frame Synchronisation werden verworfen.

Somit läuft der komplette DMX Empfang im Interrupt und sollte auch als BASCOM Programm noch mehr als schnell genug laufen.
Es müssen nur so viele Bytes gepuffert werden, wie die Schaltung tatsächlich verwalten muß.
Die komplette Werteverarbeitung kann im Hauptprogramm laufen, ohne den DMX Empfang wirklich zu stören.
Treibt man es auf die Spitze, braucht der Controller überhaupt kein Hauptprogramm ( außer einer Warteschleife ) mehr, weil auch die Phasenanschnittsteuerung in einem Interrupt laufen kann.

Ich Denke das ist eine relativ einfache Methode ein DMX Signal zu dekodieren.

Meine Idee zu Pins sparen ist eigentlich keine, aber -
Zu einem vernünftigen DMX Gerät gehört meiner Meinung nach ein Display.
Ein 1x16 Zeichen Dotmatrix Modul reicht schon und kostet nicht viel.
Dieses Modul braucht aber schon 7 Controllerpins, dazu kommen dann noch 3..4 Tasten. Also Insgesamt min. 10 Ports.
Ein Dip Fix Schalter verbrät aber auch schon 9 Ports und ist wesentlich unkonfortabler in der Anwendung.
Ausserdem kann man das Display super für Diagnosefunktionen verwenden, wenn z.B. ein Kanal parout nicht funktionieren will.

Eine weitere Möglichkeit um Ports zu sparen, wäre die A/D Wandler des Microcontrollers zu nutzen und den Dip Fix Schalter über gewichtete Widerstände in einen Spannungsteiler zu schalten.
Dazu bräuchte man, meiner Meinung nach, 2 A/D Wandler Ports - dann bräuchen die benutzten Widerstände auch nicht unbedingt eng toleriert zu sein.
Die Information, welche Dip Fix Schalter aktiviert sind, kann man so aus den jeweiligen A/D Wandlerwerten gewinnen.

Vitis
18.12.2008, 22:15
man kann den pcf8574 über TWI dran hängen wenn man
vom ATMega Pins sparen möchte ... Das Display u.U.
über SPI ...

ansonsten hab ichs in meinem programm ähnlich gemacht
wie du es vorschlägst wkrug

guenter1604
19.12.2008, 08:13
Hallo Vitis,

anbei mein Code, der geht bis 255. Bei 256 ist Schluß !?



$regfile = "m8def.dat"
$crystal = 8000000

$baud = 250000
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 2 , Databits = 8

On Timer2 Ontimer2
Tccr2 = &B00000010
Timsk.toie2 = 1

Config Portb.5 = Output
Config Portb.4 = Output
Portb.4 = 0
Kanal1 Alias Portb.4

Dim Tick As Byte
Dim Range As Byte
Range = 100
Dim X As Byte
Dim Buffer(514)as Byte
Dim Kanal As Word
Dim Adresse As Word
On Urxc Empfang
Enable Urxc
Enable Interrupts

Adresse = 255 '255 geht noch 256 nicht mehr!!!!!
Do

Loop

Empfang:
X = Udr 'das muss erst abgeholt werden, sonst geht nix 'Die Interruptroutine verheizt 10,875µs bei 16MHz der vorhandenen Framezeit von 44µs
If Ucsra.fe = 1 Then
Kanal = 0
Ucsra.fe = 0 'damit verbleiben 33,125µs für die Mainloop pro Frame
Else
Incr Kanal
Buffer(kanal) = X
End If
Return

Ontimer2:
Tick = Tick + 1
Timer2 = 50
If Tick >= Range Then Tick = 0
If Tick < Buffer(adresse) Then
Kanal1 = 1
Else
Kanal1 = 0
End If
Return


Günter

Vitis
20.12.2008, 10:00
hmmm ... schon mal stack frame usw. probiert zu erhöhen?
sollte eigentlich auch über 256 gehen wie ich das sehe.
Bei arrays bin ich mir aber auch nicht sicher mit mehr als
255. hast du mal probiert ob er überhaupt über 255 zählt,
sprich ob der Sender mehr als 255 sendet?

guenter1604
20.12.2008, 11:17
Hallo Vitis,

es wird immer kurioser, anscheinend liegts an meinem DMX-Sender, den ich nach erfolgreichen Tests nochmal modifiziert habe. Mit dem nächsten DMX-Pult das zur Reparatur reinkommt werde ich das mal gegenchecken.

Die Ein/Ausgabe mache ich jetzt mit Taster und Display zusammen über I2C und PCA9555D

Günter

Vitis
20.12.2008, 15:58
tjaja, hab ich glaub ich schon mal im thread erwähnt,
dass es da "semiprofi" teile gibt, die nur bis 255 senden ;)

Welchen sender benutzt du denn?

guenter1604
20.12.2008, 17:37
Aaaaaaaaaarrrrrrggggghhhhhh,

>Welchen sender benutzt du denn?

MEINEN EIGENEN !!!!!

Mein kleiner DMX-Sender war mit I2C, Inkrementalgeber, serieller Schnittstelle und einem DMX, das nicht mal in einem Interrupt liegt zeitweise überfordert.
Jetzt habe ich den DMX-Generator in den Interrupt des Timer0 gelegt und ein paar µs Bedenkzeit für den Rest eingebaut und schon läufts.

Günter

guenter1604
20.12.2008, 17:50
Hallo Vitis,

der hier:

https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=41090&highlight=dmx512

wir wollen ja schliesslich kein "Semiprofi" Gerät bauen ;-)

Günter

Vitis
21.12.2008, 12:12
ach, auf Basis von meinem dort geposteten Code?

Poste mal Deinen Sender Code, dann kann man evtl. helfen.

guenter1604
21.12.2008, 13:12
Hallo Vitis,

der Sender läuft wieder einwandfrei, der Knackpunkt war, daß ich die Senderoutine nicht in einem Interrupt untergebracht hatte. Dadurch haben meine neuen Gimmecks im Sender (I2C-Display, Inkrementalgeber usw.) mit ihren Interrupts das Protokoll zerschossen.

Anbei die eigentliche Senderoutine. Sie ist für einen 8 MHz-Quarz ausgelegt...


Ontimer0:
Timer0 = 70
Dmxout = 1
Trigger = 0
$asm
.def Tmp1 = R17 'Marker
.def Tmp2 = R18
ldi Tmp1, $5
Make_loop1:
dec Tmp1
brne Make_loop1
nop
nop
$end Asm
For Kanal = 0 To 512 '8 'Anzahl der Kanäle
Temp = Puffer(kanal) '20
$asm
.def Temp1 = R17
.def Temp2 = R18
.def Txbyte = R19
Putchar:
LDS Txbyte, {Temp} '2
LDI Temp1 , 9 '1
COM Txbyte '1
SEC '1
Putchar0:
BRCC Putchar1 '1 oder 2
nop '1
CBI Portd,Pd7 '2
RJMP putchar2 '2
Putchar1:
SBI Portd,Pd7 '2
NOP '1
nop '1
Putchar2:
LDI Temp2 , $7 '1
Sd_loop0:
DEC Temp2 '1
BRNE Sd_loop0

nop
LSR Txbyte '1
DEC Temp1 '1
BRNE putchar0 '1 oder 2
$end Asm
nop
nop
nop
Dmxout = 1 '2 genauso schnell wie SBI PORTD,PD7 in Assembler
$asm
.def Tmp1 = R17
.def Tmp2 = R18
ldi Tmp1, $1 '1
Make_loop0: '2 Stoppbits
dec Tmp1 '1
brne Make_loop0 '1 oder 2
$end Asm
Next Kanal
Trigger = 1 '10
$asm
.def Tmp1 = R17
.def Tmp2 = R18
ldi Tmp1, $7
Make_loop3: 'zusätzlich für Kanal 512
dec Tmp1
brne Make_loop3
$end Asm
Dmxout = 0
Waitus 88
Dmxout = 1
Return


Günter

robobaer
27.12.2008, 19:39
Hi folks,
falls ihr noch Interesse an einer Variante habt, schaut mal hier im Forum unter https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=17694&highlight=dmxtester. Da hab ich mal meinen Code für einen DMX-Tester gepostet. Vielleicht bringt der ja noch ein paar Anregungen.

guenter1604
12.01.2009, 12:24
Hallo NG,

fertig!

http://www.gerold-online.de/cms/index.php?id=157

Günter

hdtvfreak
05.02.2009, 19:24
ich finde DMX eine sehr interessante Methode um gerade auch im Hausbereich eine angenehme Lichtstimmung zu schaffen, vor Allem die sound to Light Möglichkeiten.
Zu diesem Zweck habe ich mir den hier vorgestellen Code angeschaut und gleich ein paar Fragen dazu:

1.)
Tccr2 = &B00000010
Was passiert hier? Wird der Timerprescale auf 2 gestellt also 8000000/2 ?

Timsk.toie2 = 1
Wird damit der Timer2 als Timer aktiviert?

2.)
Ontimer2:
Tick = Tick + 1
Timer2 = 50
If Tick >= Range Then Tick = 0
If Tick < Buffer(adresse) Then
Kanal1 = 1
Else
Kanal1 = 0
End If
Return

Soweit ich heraus gefunden habe dient diese Interrupt Routine zur Kontrolle, ob sich in der eingestellten DMX Adresse (255) auch gesendete Daten befinden, oder???

Vielen Dank im Voraus =D>
Grüße
hdtvfreak

guenter1604
05.02.2009, 20:03
Hallo hdtvfreak,

mit den beiden Codeteilen wird eine PWM für Kanal1 erzeugt.
Das kann auch weggelassen werden und durch was eigenes ersetzt werden...

Günter

hdtvfreak
05.02.2009, 20:11
Hallo hdtvfreak,

mit den beiden Codeteilen wird eine PWM für Kanal1 erzeugt.
Das kann auch weggelassen werden und durch was eigenes ersetzt werden...

Günter

Ok, du erzeugst quasi mit dem Timer ein PWM Signal. Sollte dann vom Prinzip her in etwa äquivalent zu folgendem sein: (Bascom Syntax)

Config Timer1 = Pwm , Pwm = 8 , Compare C Pwm = Clear Down , Prescale = 64

Habe ich das richtig verstanden?

guenter1604
05.02.2009, 20:40
Jaein,

wenn man die PWM "händisch" erzeugt kann man viele Kanäle unterschiedlich dimmbar machen. Da der ATMega aber nur 3 Timer hat, gehen so maximal 3 Kanäle...

In dem Code erzeugt der Timer nur Interrupts. Diese werden mit Tick gezählt. Solange der Wert von Tick kleiner ist wie der gewünschte Wert des DMX-Kanals buffer(adresse) liegt Kanal1 auf high.
Ist Tick größer als buffer(adresse), liegt Kanal1 auf low. Wird Range erreicht, startet Tick von vorne.

Sollten mehrere Kanäle gedimmt werden:

If Tick < Buffer(adresse1) Then
Kanal1 = 1
Else
Kanal1 = 0
End If
If Tick < Buffer(adresse2) Then
Kanal2 = 1
Else
Kanal2 = 0
End If

usw.

Günter

hdtvfreak
05.02.2009, 20:56
Ok ich glaube ich hab es soweit verstanden.

Wenn ich jetzt beispielsweise im Buffer(adresse) der Wert 50 stehen, so ist das "An/Aus" Verhältnis 50% zu 50 %, da Range ja auf 100 eingestellt wurde.

Also insgesamt eine Art Software PWM?

Grüße
hdtvfreak

guenter1604
05.02.2009, 21:08
Ja,

nur würd ich Range auf 255 stellen, da ein DMX-Kanal ja werte von 0 bis 255 haben kann. Somit wären 127 etwa 50%

Günter

hdtvfreak
05.02.2009, 22:11
Ja,

nur würd ich Range auf 255 stellen, da ein DMX-Kanal ja werte von 0 bis 255 haben kann. Somit wären 127 etwa 50%

Günter

Alles klar, Vielen Dank für deine Hilfe =D>