-
DMX512 empfangen
Hallo NG,
nachdem ich bereits DMX-512 Signale senden kann, kommt nun der Empfang dran.
Folgender erster Ansatz:
Code:
$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
-
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
-
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
-
so Code gefunden.
Quelle steht drin.
Code:
'--------------------------------------------------------------------
' 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
-
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
-
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
-
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
-
sag ich ja ... es bleibt noch massig Zeit.
Zumal das DMX ja meist nicht permanent läuft
-
@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!
-
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:
Code:
$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