| ??? 11/23/06 21:58 Read: times Msg Score: +1 +1 Good Answer/Helpful |
#128469 - DMX Responding to: ???'s previous message |
DMX is a strange protocol - it was adapted from the original AMX192 protocol which was like a video signal, long pulse frame, short pulse channel then analog level. Anyway, DMX frames start with a break signal which is a '0' bit for longer than 1 character time. The DMX spec outlines how wide this break signal should be, my recollection is 88uS but this was from the original spec when I wrote my code back in 1990! A normal character has a start bit,8 data bits and a stop bit - this stop bit is a '1' (also termed an idle). In the case of a break, we get a start bit, 8 data bits of '0' and the stop bit is still '0' - in this instance the stop bit appears in the uart bit RB8. If this bit is '0', it is most likely a break, if it is '1' it is a character.
The basic format of a DMX frame is: [BREAK] [0x00 for start code] [channel level]......up to 512 channel levels I just dug up my old code for a demux unit:
;
;
; CODE IS FOR INTEL 80C31 CPU @16MHZ
;
; PORT DEFINITIONS../=ACTIVE LOW
;
; P1.0 /BCD SWITCH BIT0,MUX ADDRESS 0
; P1.1 /BCD SWITCH BIT1,MUX ADDRESS 1
; P1.2 /BCD SWITCH BIT2,MUX ADDRESS 2
; P1.3 /BCD SWITCH BIT3,MUX ADDRESS 3
; P1.4 /ENABLE 100'S BCD SWITCH
; P1.5 /ENABLE 10'S BCD SWITCH
; P1.6 /ENABLE 1'S BCD SWITCH
; P1.7 /ENABLE SAMPLE & HOLD
;
; P3.0 RXD. DMX INPUT
; P3.1 TXD. NOT USED YET
; P3.2 /AMX SYNC IN
; P3.3 /START CONVERSION ON ADC
; P3.4 MUX OK LED (RED)
; P3.5 AMX RECEIVED,/DMX RECEIVED
; P3.6 /RD
; P3.7 /WR
;
ADA EQU 0000H ;analog to digital to analog converter AD7569
MEM EQU 8000H ;optional external ram-not used for this code.
;
; internal ram allocation..
;
CHANNEL EQU 40H
CHAN1 EQU CHANNEL+0 ;channel storage
CHAN2 EQU CHANNEL+1
CHAN3 EQU CHANNEL+2
CHAN4 EQU CHANNEL+3
CHAN5 EQU CHANNEL+4
CHAN6 EQU CHANNEL+5
CHAN7 EQU CHANNEL+6
CHAN8 EQU CHANNEL+7
CHAN9 EQU CHANNEL+8
CHAN10 EQU CHANNEL+9
CHAN11 EQU CHANNEL+10
CHAN12 EQU CHANNEL+11
LODIM EQU 050H ;base channel number storage
HIDIM EQU 051H
TIMEOUT EQU 052H ;count for no mux timeout
;
COMSTAT EQU 20H ;incoming dmx&amx status
AD EQU COMSTAT.0 ;1 means AMX is being received
SBRK EQU COMSTAT.1 ;1 means we got a break
STRT EQU COMSTAT.2 ;1 means we have got a valid start code
MUXOK EQU COMSTAT.3 ;1 means mux is ok
;
; others..
;
PCON EQU 087H ;this assembler doesn't know about PCON
TOUT EQU 60 ;time out for no mux *50ms @16mhz
;TOUT EQU 30 ;time out for no mux *100mS@8 mhz
TOUT1 EQU 10 ;timeout for mux input select *50mS @ 16mhz
;
ORG 0000H
LJMP START ;GOTO START OF CODE
;
; INTERUPT VECTORS
;
ORG 0003H
IRQ0 LJMP AMX ;amx receive routine
ORG 000BH
;
; if timer0 rolls over, we have lost mux input
;
TIM0 LJMP TIME
ORG 0013H
IRQ1 ;not used
ORG 001BH
TIM1 ;not used
ORG 0023H
LJMP DMX ;goto dmx routine
;
; Timer zero has timed out as we have had no mux.
; Decrement timer count and reload the timer
; If the timer count gets to zero,then we take action
;
TIME DJNZ TIMEOUT,TIME1 ;dec timeout count
; timeout=0..
CLR TCON.4 ;stop timer0
CLR P3.4 ;turn off mux ok led
CLR SBRK ;reset comms system
CLR STRT ;clear start status
CLR MUXOK ;mux is definitely not ok
CPL AD ;goto alternate input
JB AD,GAMX ;setup amx for input
;
; setup dmx for input
;
MOV TIMEOUT,#TOUT1 ;reload select timeout
CLR P3.5 ;turn off AMX led
MOV IE,#092H ;start DMX
SJMP TIME1
;
; setup amx for input
;
GAMX MOV TIMEOUT,#TOUT1 ;reload select timeout
SETB P3.5 ;turn on AMX led
MOV IE,#83H ;start AMX
SJMP TIME1
;
;
TEX RETI
TIME1 CLR TCON.4 ;stop timer
MOV TL0,#00
MOV TH0,#00 ;reload timer0
SETB TCON.4 ;start timer0
RETI
;
; the show starts here...
;
START MOV IE,#00 ;turn off all ints
MOV R0,#CHANNEL ;setup channel pointer
MOV P1,#0FFH ;disable s/h
ACALL READSW ;read switches,set dimmer base number
CLR P3.4 ;turn off MUX-OK led
CLR P3.5 ;turn off AMX/DMX led
MOV TMOD,#31H ;setup timer0
MOV TCON,#01 ;stop timers,select edge detect for int0
MOV IP,#10H ;set serial int to higher priority
MOV SCON,#90H ;set serial port to mode 2
; MOV PCON,#80H ;set to divide by clk by 32,baud rate=250kbs
MOV PCON,#00H ;set to divide clk by 64,baud rate=250kbs @16mhz
MOV DPTR,#ADA ;DPTR->analog converter
;
; setup interupts,clear channel levels and go!
;
MOV IE,#00 ;stop everything!!
MOV TIMEOUT,#TOUT1 ;load select timeout
CLR TCON.4 ;stop timer0
MOV TH0,#00
MOV TL0,#00 ;reload timer0
SETB TCON.4 ;start timer0
MOV COMSTAT,#00 ;clear comms status
MOV A,#00 ;clear Acc
MOV R0,#CHANNEL ;clear channel storage
CCHAN MOV @R0,A ;clear channel
INC R0 ;goto next
CJNE R0,#(CHAN12+1),CCHAN ;check for last channel
MOV IE,#82H ;enable timer0 ints
;
;
; we should be receiving DMX or AMX by this point..
; even if we're not,output the channel levels to the sample & holds
;
GO MOV R7,#250 ;do 250 outputs till we update
OUTCHAN MOV R1,#CHANNEL ;R1->channels
CLOOP MOV A,@R1 ;get channel level
MOVX @DPTR,A ;output it to the dac
MOV A,R1 ;channel into a
ANL A,#0FH ;only the lower 4 bits for mux address
ORL A,#0F0H ;set switch enable bits
MOV P1,A ;output mux address
CLR P1.7 ;enable s/h
NOP ;allow capacitor to charge to channel level
NOP
SETB P1.7 ;disable s/h
INC R1 ;next channel
CJNE R1,#(CHAN12+1),CLOOP ;see if its the last channel
DJNZ R7,OUTCHAN ;output 100 times then update dimmer base etc.
;
; update dimmer base number & see if mux is still ok
;
LCALL READSW ;read dimmer base number from switches
JB MUXOK,GO ;keep on outputting channels if muxok
;
; NO MUX SIGNAL RECEIVED
;
MOV A,#00 ;clear A
MOV R0,#CHANNEL ;R0->CHANNELS
CCLOOP MOV @R0,A ;clear channel level
INC R0 ;next channel
CJNE R0,#(CHAN12+1),CCLOOP ;until all channels done
SJMP GO ;look for input again
;
; read dimmer base number switches and store them into lodim &hidim
; we also kick the watchdog whilst doing this
;
READSW MOV R6,#00 ;R6 has dimmer base hi
MOV R7,#00 ;R7 has dimmer base low
;
; GET 100'S SWITCH SETTING
;
MOV P1,#0FFH ;set bits high(input),& disable s/h
CLR P1.4 ;enable 100's switch
MOV A,P1 ;read switch setting
CPL A ;invert it (hardware thing)
ANL A,#0FH ;we only want low 4 bits
MOV B,#100 ;multiply it by 100
MUL AB ;result in b(hi) A(low)
ADD A,R7 ;add into base number low
MOV R7,A ;save result into base num low
MOV A,B :get msb of multiply into a
ADDC A,R6 ;add into base number hi
MOV R6,A ;save into dimmer base number
SETB P1.4 ;turn off 100s switch
;
; GET 10'S SWITCH SETTING
;
CLR P1.5 ;enable 10's switch
MOV A,P1 ;read switch
CPL A ;invert it
ANL A,#0FH ;mask for low 4 bits
MOV B,#10 ;multiply by 10
MUL AB ;result in b(hi),A(low)
ADD A,R7 ;add to dimmer base number
MOV R7,A ;save result into dimmer base number
CLR A ;A=0. we never get a result above 90 dec
ADDC A,R6 ;add in the carry (if any)
MOV R6,A ;save into dimmer base number
SETB P1.5 ;turn off 10's switch
;
; GET 1'S SWITCH SETTING
;
CLR P1.6 ;turn on units switch
MOV A,P1 ;read switch
CPL A ;turn it upside down
ANL A,#0FH ;lower nibble only
ADD A,R7 ;add into dimmer base number
MOV R7,A ;save it
MOV A,#00 ;add in carry (if any)
ADDC A,R6 ;
MOV R6,A ;save it
;
; MINUS 1 TO CORRECT THINGS
;
CLR C ;clear borrow(carry)
MOV A,R7 ;get dimmber base low
SUBB A,#1 ;minus 1
MOV R7,A ;save result
MOV A,R6 ;get dimmber base hi
SUBB A,#00 ;subtract borrow (if any)
MOV R6,A ;save it
;
; UPDATE GLOBAL DIMMBER BASE NUMBER
;
CLR IE.7 ;stop interupts for a tick
MOV LODIM,R7
MOV HIDIM,R6
SETB IE.7 ;start interupts again...
RET
;
; dmx reception routine.
;
DMX PUSH 0D0H ;save PSW
CLR SCON.0 ;reset recv int
CLR SCON.1 ;reset tx int
MOV R2,SBUF ;read receive date into A
JNB SCON.2,BRKORBAD ;IF RECV BIT8=0,EITHER A BREAK OR OVERRUN
;
; received char must be good then..
;
JB SBRK,BROK ;jump if we've received a break
POP 0D0H ;restore PSW
RETI ;we haven't got a break yet,do nothing
;
BROK JB STRT,STOK ;jump if we've got a good start code
;
; we haven't yet received a start code,check for byte=00
;
CJNE R2,#00,BADST ;jump if we got a bad start code
;
; start code is good,set start flag
;
SETB STRT ;set start code ok flag
POP 0D0H ;restore PSW
RETI
;
; start code was bad,go back to looking for a break
;
BADST CLR SBRK ;no break
CLR STRT ;just in case
POP 0D0H ;restore PSW
RETI
;
; we've already got a break and a start code
; figure out if we want this channel..
;
; on break we load channel countdown with our dimmer base number
; on each dimmer level received,we decrement this count
; upon reaching zero,we then grab the next 12 channels
; and put them into ram
;
STOK
CJNE R4,#00,CDEC ;SEE IF CHANNEL COUNTDOWN HI=0
CJNE R3,#00,CDEC ;see if channel countdown low=0
;
; the countdown=0,time to grab the channels we want.
;
CJNE R0,#(CHAN12+1),GETCHAN ;compare channel count with last channel
;
; we've got all the channels we want,so discard all others
;
POP 0D0H ;restore PSW
RETI
;
; decrement the channel countdown
;
CDEC
CJNE R3,#00,COUNTHI ;R3=00?
DEC R3 ;decrement count low
CJNE R4,#00,COUNTZ ;jump if count hi=0
POP 0D0H ;restore PSW
RETI ;if R4=00 return
COUNTZ
DEC R4
POP 0D0H ;restore PSW
RETI
;
COUNTHI DEC R3 ;decrement count low
POP 0D0H ;restore PSW
RETI
;
; channel countdown=0 and we haven't got all our channels yet
;
GETCHAN JC GTCHAN1 ;R0<=CHAN12
POP 0D0H ;restore PSW
RETI ;R0>CHAN12
;
GTCHAN1 PUSH 0E0H ;save accumulator
MOV A,R2 ;get channel level into A
MOV @R0,A ;move received channel to ram
INC R0 ;R0->next channel
POP 0E0H ;restore accumulator
POP 0D0H ;restore PSW
RETI
;
; now we process either data overrun or break
;
BRKORBAD MOV R5,#8 ;number of loops =4@8mhz,=8 @16mhz
; see if RxD changes within 30 us. If it does,there
; was a data overrun error,else it must be a break
;
LOOP JB P3.0,OVER ;jump if RxD changes
DJNZ R5,LOOP ;try again until R5=0
;
; must be a break,as RxD has been marking >88us
;
CLR STRT ;so that we look for a start code
SETB SBRK ;we got a break
SETB MUXOK
SETB P3.4 ;Turn on MUX-OK led
MOV TIMEOUT,#TOUT ;reload timeout
CLR TCON.4 ;stop timer 0
MOV TL0,#00
MOV TH0,#00 ;reload timer0
SETB TCON.4 ;start timer0
MOV R0,#CHAN1 ;reset channel pointer
MOV R4,HIDIM ;reload countdown
MOV R3,LODIM ;with dimmer base number
POP 0D0H ;restore PSW
RETI
;
; data must have overrun
;
OVER CLR STRT ;go back to looking for a
CLR SBRK ;break/start code
POP 0D0H ;restore PSW
RETI
;
; AMX reception routine.
;
AMX NOP ;delay 6us @ 16mhz
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP ;delay 6 us @ 16mhz
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP ;delay 6us @ 16mhz
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP ;delay 6 us @ 16mhz
NOP
NOP
NOP
NOP
NOP
NOP
NOP
JB P3.2,GETAMX ;if sync=1 must be a channel sync
;
; sync must still be low, frame sync it is
;
CLR STRT ;so that we look for a start code
SETB SBRK ;we got a break(frame sync)
SETB P3.4 ;Turn on MUX-OK led
SETB MUXOK ;MUX is ok
MOV TIMEOUT,#TOUT ;reload timeout
CLR TCON.4 ;stop timer 0
MOV TL0,#00
MOV TH0,#00 ;reload timer0
SETB TCON.4 ;start timer0
MOV R0,#CHAN1 ;reset channel pointer
MOV R4,HIDIM ;reload countdown
MOV R3,LODIM ;with dimmer base number
RETI
;
; we got a channel sync
;
GETAMX CLR P3.3 ;start analog->digital conversion
SETB P3.3
NOP ;wait 3us approx
NOP
NOP
NOP
PUSH 0D0H ;push psw
PUSH 0E0H ;push acc
MOVX A,@DPTR ;read adc value
JB SBRK,ASTOK ;we've already got the frame sync
; discard level until we've got frame sync
POP 0E0H ;restore accumulator
POP 0D0H ;restore psw
RETI
;
; on break we load channel countdown with our dimmer base number
; on each dimmer level received,we decrement this count
; upon reaching zero,we then grab the next 12 channels
; and put them into ram
;
ASTOK CJNE R4,#00,ACDEC ;SEE IF CHANNEL COUNTDOWN HI=0
CJNE R3,#00,ACDEC ;see if channel countdown low=0
;
; the countdown=0,time to grab the channels we want.
;
CJNE R0,#(CHAN12+1),AGETCHAN ;compare channel count with last channel
;
; we've got all the channels we want,so discard all others
;
POP 0E0H ;restore accumulator
POP 0D0H ;restore psw
RETI
;
; decrement the channel countdown
;
ACDEC CJNE R3,#00,ACOUNTHI ;R3=00?
DEC R3 ;decrement count low
CJNE R4,#00,ACOUNTZ ;jump if count hi=0
POP 0E0H ;restore accumulator
POP 0D0H ;restore PSW
RETI
ACOUNTZ DEC R4
POP 0E0H ;restore accumulator
POP 0D0H ;restore psw
RETI
;
ACOUNTHI DEC R3 ;decrement count low
POP 0E0H ;restore accumulator
POP 0D0H ;restore psw
RETI
; channel countdown=0 and we haven't got all our channels yet
;
AGETCHAN JC AGTCHAN1 ;R0<=CHAN12
POP 0E0H ;R0>CHAN12
POP 0D0H ;restore psw
RETI
AGTCHAN1 MOV @R0,A ;move received channel to ram
INC R0 ;R0->next channel
POP 0E0H ;restore accumulator
POP 0D0H ;restore psw
RETI
END
|
| Topic | Author | Date |
| Kathy Quinlan's DMX | 01/01/70 00:00 | |
| I guess... | 01/01/70 00:00 | |
| Any help? | 01/01/70 00:00 | |
| Any help? | 01/01/70 00:00 | |
DMX | 01/01/70 00:00 |



