Nun ist es soweit, habe mir mal die Zeit gestohlen.
Da ein 90S1200 nicht da ist, habe ich einen 90S2313 genommen. Also ändert sich die Schaltung geringfügig. Der Quarz ist nun 8Mhz und der µC ist Pinkompatibel zum 90S1200.
Zum Proggi: Es sind max. 5 Karten an den DMX-Bus anzuschließen. Da dies ein Mango ist habe ich es in der Software berücksichtigt. Da steht im Listing:
start_adress:
in dmx_adrL,PinD
andi dmx_adrL, 0b1111110
clc
ror dmx_adrL
ldi temp,0x00 ;Kartenanfangsdresse =0
add dmx_adrL, temp
ret
Die Zeile ldi temp,0x00 ist die entscheidende.
Da wird eine Grundadresse für die Karte vergeben. Hier ist sie Null. Sollen mehr als 5 Karten angeschlossen werden, ist eine neue Grundadresse zu vergeben. Somit ist eine Kaskadierung möglich. Wird da z.B. 0x20 (hex) eingetragen, beginnt diese Karte ab Adresse 32 zu arbeiten.
Also 1. Adresse = 0x00 + Adressschalter = 32 Relais = 4 Karten.
Ab der 5. Karte muss da 0x20 stehen und neu über den Assembler laufen lassen. Dieses *.hex-File wird nun in den 90S2313 gebrannt. Noch einen kleinen Zettel mit der neuen Anfangsadresse draufkleben und die Karte kann in ein bestehendes System eingebunden werden.
;Das Programm DMX - Ausgabe an 8 Relais
;mit Atmel 90S2313 und 8MHz Quarz
.include "2313def.inc"
.EQU channels_all=8 ;8 ist die Anzahl der Kanäle!
.def temp =R16
.def temp1 =R17
.def temp2 =R18
.def byte =R19
.def dmx_status =R20 ;bit counter*
.def dmx_Byte =R21 ;Received data*
.def dmx_countL =R22 ;adress register*
.def dmx_count_in=R23 ;byte counter low*
.def dmx_adrL =R24 ;Dmx-Adresse
.def Raml1 =R28 ;Ramadresse = 0x060
.def Ramh1 =R29 ;Ram Lesen
.def Raml =R30 ;Ramadresse = 0x060
.def Ramh =R31 ;Ram Schreiben
;*****************************************************
.org $000
rjmp init ;Reset handler
reti ;INT0 External Interrupt0 Vector Address
reti ;INT1 External Interrupt1 Vector Address
reti ;ICP1 Input Capture1 Interrupt Vector Address
reti ;OC1 Output Compare1 Interrupt Vector Address
reti ;OVF1 Overflow1 Interrupt Vector Address
reti ;OVF0 Overflow0 Interrupt Vector Address
rjmp get_byte ;URXC UART Receive Complete Interrupt Vector Address
reti ;UDRE UART Data Register Empty Interrupt Vector Address
reti ;UTXC UART Transmit Complete Interrupt Vector Address
reti ;ACI Analog Comparator Interrupt Vector Address
;*****************************************************
init:
ldi temp,0x00 ;set R1 to NULL
mov R1,temp
ldi temp,Low(RamEnd)
out spl,temp
ldi temp, 0b00000000
out DDRD, temp ;Port D = Eingang
ldi temp, 0b11111111
out DDRB, temp ;Port B = Ausgang
ldi dmx_count_in,0x00
ldi dmx_status,0x01
ldi ramh,0x00
ldi raml,0x60
rcall start_adress ;lese Start Adresse
;**** initial uart
ldi temp,0x01 ;setze Uart to 250 kbaud @ 8Mhz
out UBRR,temp ;
ldi temp,0b00000000 ;setze Uart to 8 bit
out UCR,temp ;
ldi dmx_status,0x01 ;setze DMX-Status Byte to 'wait for Reset'
in dmx_Byte,UDR ;clear Uart Receive Interrupt Flag
cbi UCR,FE ;clear Frame Error Flag
sbi UCR,RXCIE ;enable Uart Receive Interrupt
sbi UCR,RXEN ;enable Uart Receive
sei
;*****************************************************
loop:
rcall start_adress ;Kanal von PortD Laden
cpi dmx_adrL,0x00 ;ist Dmxadresse =0 dann ungültig
brne loop1 ;springe wenn es größer als 0 ist
rjmp loop
loop1:
rcall delay ;mal warten
rcall ausgabe ;PortB=Relais schalten
rjmp loop ;auf neuen Wert warten
;*****************************************************
ausgabe:
cli
ldi temp, channels_all ;0x07
ldi RamL1, 0x60 ;das DMX-Byte steht ab der Ramadresse 0x60
ldi RamH1, 0x00
ausgabe1:
ld byte, Y ;Byte aus dem Ram laden
cpi byte,0x7f ;test auf 7F oder größer
brlo ausgabe2 ;springe wenn Wert kleiner
sec ;setze Carryflag
ror temp1 ;Carry in temp1 schieben
rjmp ausgabe3 ;
ausgabe2:
clc ;Lösche Carryflag
ror temp1 ;Carry in temp1 schieben weil kleiner 7F
ausgabe3:
inc RamL1 ;Zähler Ramadresse
dec temp ;Schleifenzähler
brne ausgabe1
out PortB, temp1 ;alle Werte sind gelesen, nun ausgeben
sei
ret
;*****************************************************
get_byte:
cpi dmx_adrL,0x00
breq ret1
in dmx_Byte,UDR
sbic USR,OR ;ist es ein Überlauf -> Reset
rjmp overrun
sbic USR,FE ;check auf Fehler -> Reset
rjmp frame_error
cpi dmx_status,0x01 ;warten auf Reset
breq ret1 ;Return
cp dmx_countL,R1 ;Startbyte?
breq startbyte ;
cp dmx_countL,dmx_adrL ;vergleiche Adresse und Bytenummer
brlo return
breq first
next_t:
cpi dmx_count_in,channels_all ;sind alle Kanäle gelesen?
brsh return
first:
inc dmx_count_in ;Adresszähler +1
st z,dmx_Byte ;DMX-Wert in Ram speichern
inc RamL ;Ramadresse +1
return: inc dmx_countL ;neuer Kanal
ret1: reti
frame_error:
ldi raml,0x60
ldi ramh,0x00
ldi dmx_countL,0x00 ;Reset Counter
ldi dmx_count_in,0x00
ldi dmx_status,0x00 ;Statusbyte auf 'ok' setzen
cbi USR,FE ;lösche frame-error flag
rcall start_adress ;Kanaladresse laden
reti
overrun:
ldi dmx_status,0x01 ;setze Status-Byte 'warte auf Reset'
reti ;return
startbyte:
cp dmx_Byte,R1 ;Startbyte=0
brne overrun ;warte auf nächsten Reset-Cycle
rjmp return
;*****************************************************
start_adress:
in dmx_adrL,PinD
andi dmx_adrL, 0b1111110
clc
ror dmx_adrL
ldi temp,0x00 ;Kartenanfangsdresse =0
add dmx_adrL, temp
ret
;*****************************************************
delay:
push temp2 ;mal warten
push temp1
ldi temp1,0xE1
WGLOOP0:ldi temp2,0xEC
WGLOOP1:dec temp2
brne WGLOOP1
dec temp1
brne WGLOOP0
pop temp1
pop temp2
ret ;wieder zurück
;*****************************************************
Zum Schluss noch das Hex-File zum Brennen im Anhang.
Viel Spass.
Hochgeladene Datei :
dmxrelais.hex
_________________
mfg Jornbyte
Es handelt sich bei dem Tipp nicht um eine Rechtsverbindliche Auskunft und
wer Tippfehler findet, kann sie behalten.