Can anyone supply information and implementation on the DMX protocol. I have designed a lighting controler using Pics and CCS and want to add DMX control. Any code snipets to show me the way would be greatly appreciated.
Many thanks.

Dave

Mark

Joined: 07 Sep 2003Posts: 2838Location: Atlanta, GA

Posted: Fri Nov 07, 2003 9:42 am

You want to receive or transmit? Which PIC are you using? What speed are you running? How many dimmers do you need to respond to?

PS: Do you work for a lighting control company? Is so, which one? I work for Lithonia Lighting.

davt

Joined: 07 Oct 2003Posts: 66Location: England

Posted: Fri Nov 07, 2003 9:59 am

Thanks Mark
I do not work for a lighting company just my own personal interest.
I designed the dimmer using a 12f629 using the internal clock. it has a 0-10v control input. I wish now to convert it to dim by means of the DMX512 protocol so it will - recieve only. I understand that I will have to go to a chip with more code space and resources to implement this. I basically need detailed timing, packet information etc. Any code would be well recieved to help me on my way!
Thanks again.
Dave

I will post a couple of snippets when I get a chance. But basically I read the spec and wrote the software from it.

Mark

Joined: 07 Sep 2003Posts: 2838Location: Atlanta, GA

Posted: Mon Nov 10, 2003 7:15 am

Here is the receive routine. It has been a while since I wrote this, but it seems there was a break or mark signal at the start of the DMX stream. I use the framing error to check for this. I removed all (I think) of the code that would not benefit you.

/* Keep reading the data so long as it is present. */
while (PIR1bits.RCIF)
{
/* Read the data and the Rx status reg */
rcsta.byte = RCSTA;
data = RCREG;

/* Check for buffer overrun error */
if (rcsta.bits.OERR)
{
RCSTAbits.CREN=0;
RCSTAbits.CREN=1;
/* we just received a buffer overrun so lets wait
for a good data byte before we look for the break signal. */
Rx_State = WAIT_FOR_NEXT_BYTE;
return;
}

switch (Rx_State)
{
case WAIT_FOR_NEXT_BYTE:
if (!rcsta.bits.FERR)
Rx_State = WAIT_FOR_BREAK;
break;
case WAIT_FOR_BREAK:
/* Check for a framing error */
if (rcsta.bits.FERR)
{
/* If we did receive a framing error, make sure that the data is 0.
This means that we did Rx the break signal for at least 44us. */
if (!data)
Rx_State = WAIT_FOR_START;
}
break;
case WAIT_FOR_START:
/* Check for a framing error. If we receive one then we need to wait
until we receive a good data byte before we begin looking for our
Break signal */
if (rcsta.bits.FERR)
Rx_State = WAIT_FOR_NEXT_BYTE;
/* The start code for our data packet should always start with 0. */
else
{
if (!data)
{
/* Initialize our index to our Rx buffer. */
Rx_Index = 0;

/* Here we determine where in the DMX stream we should begin
receiving data based on our DMX offset address. */
if (DMX_512_Offset == 1)
Rx_State = RECEIVE_DATA;
else
{
Rx_State = WAIT_FOR_DATA;
DMX_512_Count = 1;
}
}
else
{
Rx_State = WAIT_FOR_BREAK;
}
}
break;
case WAIT_FOR_DATA:
/* Check for a framing error. If we receive one then we need to wait
until we receive a good data byte before we begin looking for our
Break signal */
if (rcsta.bits.FERR)
/* This could be a break signal indicating the start of the DMX stream */
if (!data)
Rx_State = WAIT_FOR_START;
else
Rx_State = WAIT_FOR_NEXT_BYTE;
else
{
/* Keep track of the number of bytes received so that we will know
when to start receiving the data */
DMX_512_Count++;
if (DMX_512_Count == DMX_512_Offset)
Rx_State = RECEIVE_DATA;
}
break;
case RECEIVE_DATA:
/* check for framing error - if we receive a framing error then this
might be the begining of the next packet or a true framing error. */
if (rcsta.bits.FERR)
{
/* if this is the beginging of the next frame then data must = 0
else this is a framing error. */
if (!data)
Rx_State = WAIT_FOR_START;
else
Rx_State = WAIT_FOR_NEXT_BYTE;
}
else
{
/* Store the data received in the Rx buffer */
if (Rx_Buffer[Rx_Index] != data)
levels[Rx_Index] |= 0x80;
Rx_Buffer[Rx_Index] = data;

I used the USITT DMX512/1990 AMX192 standard. I only have a printed copy. I did a quick check on the web and could find it in pdf form anywhere. It looks like they want you to buy it. Not sure how I got it. One of our marketing managers handed it to me several years back when we decided that we needed a DMX interface into our system.

The question I then have is how can you generate a break and a mark-after-break when using the usart? The only thing I can think of is to grab control of the C6 pin, make it an output, and write to it directly then make it a usart output again, but this seams inefficient, there must be a better way.

The question I then have is how can you generate a break and a mark-after-break when using the usart? The only thing I can think of is to grab control of the C6 pin, make it an output, and write to it directly then make it a usart output again, but this seams ineffecient, there must be a better way.

Directly controlling the output bit is quite normal, and not 'inefficient'. The alternative, is to reprogram the UART baud rate to a much slower value, and send a '0' byte. The downside to this, is that if any data is received while doing this, it will be garbaged. CCS supports a command to change the baud rate 'on the fly', so this approach is very simple in code terms, and does not require any waits.

Best Wishes

marquez

Joined: 05 Jan 2005Posts: 0Location: spain

dmx512 pwm leds

Posted: Wed Mar 30, 2005 1:33 am

hello everybody,
I just implemented a dmx 512 receiver with pic16f767 based in mark code. The program works fine (thanks mark) but I have some problems.
I used DMX to control the intensity level of High power leds using pwm, and when I am in low intensity levels and making fading the result is not good enough becasue whe can see steps. In High intensity levels it is not a problem, I thing is for the logarithim response of eye.
How anyone found this problem? How I can solve that?
The first Idea is implement the resolution but it is not easy becasue dmx send 8 bits.
For more details Here is my code:

Don't use the actual DMX value. Instead, have a lookup table of 256 entries (0-255). This will allow you to adjust the curve. The PWM is a 10 bit value, you can use all ten bits but that alone won't get you the smoothest response. Instead, allow your value to reach the desired value over a given amount of time. What I mean is say your curve is like

Note the above code isn't complete or really even code but will give you some idea of what the heck I am talking about. BTW, I work for a lighting company and this is how I handle dimming. If you are intending to make a product and sell it, be sure to check out the patents regarding pwm's controlling LEDs.

Guest

Posted: Wed Mar 30, 2005 7:27 am

thanks mark for your quicky answer.
I´ll study your solution.
But In some place I read that better than use PWM for control light leds is better use PFM (Pulse frequency modulation) . The reasons are, that LEds don´t have linear response and PWM are a linear modulation. PFM is not linear and for this reason can be better.
Someone know how to make a PFM (manteining pulse with and change frequency)?

thanks!

Mark

Joined: 07 Sep 2003Posts: 2838Location: Atlanta, GA

Posted: Wed Mar 30, 2005 7:36 am

Just use a curve, it will be easier.

But to do what you want, use the CCP module and generate an interrupt of match. You will have 2 CCP values. The "ON" value which is your pulse and the "OFF" value which will control the frequency. Keeping the ON time the same and vary the OFF time will change the frequency. I would also throw away that 4MHz osc and run at 20MHz.

marquez

Joined: 05 Jan 2005Posts: 0Location: spain

select channel in dmx

Posted: Thu Apr 14, 2005 8:14 am

Hi everybody,
I just Implement a dmx receiver that works fine for the 3 first channels, but when I would like to choose one channel I have problems.
Can anyone help me? I based my code In Mark code (thanks again mark)