CONVERSIONE SERIALE/DMX CON AVR
Ecco come realizzare un convertitore da seriale verso il protocollo DMX tipicamente usato nel campo del controllo dei sistemi di illuminazione. L’hardware è piuttosto semplice: un AVR (90S2313) il cui UART (PD0 e PD1) sono connessi ad un MAX232, mentre il PB0 connesso ad un MAX485. Il sistema funziona con un cristallo da 4MHz e l’UART dovrà essere impostato su 19200bps, 8 bit dati, 1 stop bit e nessuna parità. Connettendo il sistema ad un PC via RS232 il protocollo di comunicazione consiste nei seguenti passi:
- Il PC invia all’AVR il byte 0xFF (comando START);
- Quindi viene inviato un byte compreso tra 0x01 e 0x6C (costituisce il canale DMX);
- Quindi inviato il valore vero e proprio (un byte compreso tra 0x00 e 0xFF).
In caso di successo l’AVR risponderà con 0x00, altrimenti verrà restituito 0xFF. Di seguito il codice sorgente.
.include “2313def.inc”
.DEVICE AT90S2313
.def Temp = r16
.def Count = r17
.def FrameCount = r18
.def DMXByte = r19
.def BitCount = r20
.def RXBufferA = r21
.def RXBufferB = r22
.def RXBufferC = r23
.org 0x0000
rjmp RESET
RESET:
ldi Temp, 0xFF
out DDRB, Temp
sbi PORTB, 0
ldi Temp, RAMEND
out SPL, Temp
sbi UCR, RXEN
sbi UCR, TXEN
ldi Temp, 4000000/(19200*16)-1
out UBRR, Temp
ldi XH, 0x00
ldi XL, 0x61
ldi Temp, 0x00
ldi Count, 0x6C
ZEROMEM:
st X+, Temp
dec Count
brne ZEROMEM
ldi RXBufferA, 0x00
ldi RXBufferB, 0x00
ldi RXBufferC, 0x00
MAINLOOP:
rcall SENDPACKETSTART
ldi DMXByte, 0x00
rcall SENDFRAME
ldi XH, 0x00
ldi XL, 0x61
ldi FrameCount, 0x6C
POLLNEXTFRAME:
sbis USR, RXC
rjmp LOADBYTE
rjmp STOREBYTE
SENDNEXTFRAME:
rcall SENDFRAME
dec FrameCount
brne POLLNEXTFRAME
rjmp MAINLOOP
LOADBYTE:
ld DMXByte, X+
rjmp SENDNEXTFRAME
STOREBYTE:
in Temp, UDR
cpi RXBufferA, 0x00
brne CHECKBUFFERB
mov RXBufferA, Temp
ld DMXByte, X+
rjmp SENDNEXTFRAME
CHECKBUFFERB:
cpi RXBufferB, 0x00
brne SYNC
mov RXBufferB, Temp
ld DMXByte, X+
rjmp SENDNEXTFRAME
SYNC:
mov RXBufferC, Temp
cpi RXBufferA, 0xFF
brne RETRANSMIT
cpi RXBufferB, 0xFF
breq RETRANSMIT
cpi RXBufferB, 0x6E
brge RETRANSMIT
push XL
ldi XL, 0x60
add XL, RXBufferB
st X, RXBufferC
pop XL
ldi RXBufferA, 0x00
ldi RXBufferB, 0x00
ldi RXBufferC, 0x00
ldi Temp, 0x00
out UDR, Temp
CMDOKWAIT:
sbis USR, UDRE
rjmp CMDOKWAIT
ld DMXByte, X+
rjmp SENDNEXTFRAME
RETRANSMIT:
ldi RXBufferA, 0x00
ldi RXBufferB, 0x00
ldi RXBufferC, 0x00
ldi Temp, 0xFF
out UDR, Temp
RTRQWAIT:
sbis USR, UDRE
rjmp RTRQWAIT
ld DMXByte, X+
rjmp SENDNEXTFRAME
SENDPACKETSTART:
cbi PORTB, 0
ldi Count, 0x90
BRKDELAY:
dec Count
brne BRKDELAY
sbi PORTB, 0
ldi Count, 0x0b
MABDELAY:
dec Count
brne MABDELAY
ret
SENDFRAME:
cbi PORTB, 0
ldi BitCount, 0x08
nop
nop
NEXTBIT:
ror DMXByte
brcs SENDONE
nop
nop
SENDZERO:
nop
nop
nop
nop
nop
nop
nop
cbi PORTB, 0
dec BitCount
brne NEXTBIT
rjmp STOPBITS
nop
nop
nop
nop
nop
nop
nop
nop
sbi PORTB, 0
dec BitCount
brne NEXTBIT
nop
nop
STOPBITS:
ror DMXByte
nop
nop
nop
nop
nop
nop
nop
nop
sbi PORTB, 0
ldi Count, 0x0b
STOPDELAY:
dec Count
brne STOPDELAY
ret
| Listato 1 |



Il protocollo DMX è praticamente diffuso in varie situazioni di architettura circa l’illuminazione. Permette di gestire numerosi punti luce RGB grazie all’ottima velocità di trasmissione dati. Il codice proposto mi sembra una buona soluzione per interfacciare la seriale con dispositivi Digital Multiplex.