You are on page 1of 18

CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

FAQ Forum Help Official CCS Support Search Register

Profile Log in to check your private messages Log in

DMX protocol
Goto page 1, 2 Next

CCS Forum Index -> General CCS C Discussion

View previous topic :: View next topic

Author Message

davt DMX protocol


Posted: Fri Nov 07, 2003 8:34 am

Joined: 07 Oct 2003 Hi all


Posts: 76
Location: England
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 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
Joined: 07 Sep 2003
Posts: 3511 many dimmers do you need to respond to?
Location: Atlanta, GA
PS: Do you work for a lighting control company? Is so, which one? I work for Lithonia Lighting.

davt Posted: Fri Nov 07, 2003 9:59 am

Thanks Mark
Joined: 07 Oct 2003
Posts: 76 I do not work for a lighting company just my own personal interest.
Location: England 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

Humberto Posted: Fri Nov 07, 2003 2:34 pm

You will get such info at:


Joined: 08 Sep 2003
Posts: 813 [url]
Location: Buenos Aires la http://www.usitt.org/DMX/DMX512.htm
Reina del Plata
[/url]

Best wishes

1 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

Humberto

Mark Posted: Fri Nov 07, 2003 2:36 pm

I will post a couple of snippets when I get a chance. But basically I read the spec and wrote the
Joined: 07 Sep 2003
Posts: 3511 software from it.
Location: Atlanta, GA

Mark 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
Joined: 07 Sep 2003
Posts: 3511 or mark signal at the start of the DMX stream. I use the framing error to check for this. I
Location: Atlanta, GA removed all (I think) of the code that would not benefit you.

Code:

void Interrupt_USART_Rx(void)
{
#define WAIT_FOR_NEXT_BYTE 0
#define WAIT_FOR_BREAK 1
#define WAIT_FOR_START 2
#define WAIT_FOR_DATA 3
#define RECEIVE_DATA 4

/* Data that we are receiving */


char data;
/* State machine for determining the begining of the DMX stream */
static char Rx_State = WAIT_FOR_BREAK;
/* Duplicate of the RCSTA reg used due to the double buffering of the
fifo. Reading the RCREG reg will cause the second RCSTA reg to be
loaded if there is one. */
union
{
unsigned char byte;
struct {
unsigned char RX9D:1;
unsigned char OERR:1;
unsigned char FERR:1;
unsigned char ADDEN:1;
unsigned char CREN:1;
unsigned char SREN:1;
unsigned char RX9:1;
unsigned char SPEN:1;
} bits ;
}rcsta;

/* DMX frame counter */


static unsigned int DMX_512_Count=0;
/* receive buffer index */
static char Rx_Index = 0;

/* 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)

2 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

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;

/* Point to the next byte */


++Rx_Index;

/* Check to see if we have received all of our data */


if (Rx_Index >= MAX_BUFFER)
Rx_State = WAIT_FOR_BREAK;

3 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

}
break;
// default:
/* Unknown start code */
}
}
return;
}

davt Posted: Mon Nov 10, 2003 8:19 am

Thanks Mark for the code for DMX512.


Joined: 07 Oct 2003
Posts: 76 Do you have a copy of the DMX512 protocol that I could use, so I can progress further.
Location: England My e-mail address is:

i.d.teece@hull.ac.uk

Many thanks for your kind attention!

Mark Posted: Mon Nov 10, 2003 8:39 am

I used the USITT DMX512/1990 AMX192 standard. I only have a printed copy. I did a quick
Joined: 07 Sep 2003
Posts: 3511 check on the web and could find it in pdf form anywhere. It looks like they want you to buy it.
Location: Atlanta, GA 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.

jmann Posted: Mon Dec 27, 2004 1:34 pm

Here is a good link with the most important details of DMX:


Joined: 27 Dec 2004
Posts: 12 http://www.euro-pa.be/dmx.html

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.

Ttelmah Posted: Mon Dec 27, 2004 3:25 pm


Guest

jmann wrote:
Here is a good link with the most important details of DMX:
http://www.euro-pa.be/dmx.html

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 dmx512 with leds


Posted: Wed Mar 30, 2005 1:26 am

Joined: 05 Jan 2005 hello everybody,


Posts: 2
Location: spain 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

4 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

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:

Code:

/************************************************************************
* FUSES *
* NOPROTECT=Code not protected from reading *
* CCP2C1=CCP2 input/output multiplexed with RC1 *
* NODEBUG=No Debug mode for ICD *
* BORV20=Brownout reset at 2.0V *
* MCLR=Master Clear pin enabled *
* Habilitamos el pin de clear *
* NOWDT=No Watch Dog Timer *
* INTRC_IO=Internal RC Osc, no CLKOUT *
* NOIESO=Internal External Switch Over mode disabled *
* NOFCMEN=Fail-safe clock monitor disabled *
* Desabilitamos la opcion de deteccion de que cuando hay una perdida *
* de clock externo el clock interno proporciona los clock al sistema*
* NOBROWNOUT=Reset when brownout detected *
************************************************************************/
#fuses NOPROTECT,CCP2C1,NODEBUG,MCLR,NOWDT,INTRC_IO,NOBROWNOUT
#include <16F767.h>
#use delay(clock=4000000) //Indicamos al compilador que los retardos los calcule
//en funcion de una base de tiempos con un clock de 4Mhz
#include <string.h>
#include <stdio.h>
/************************************************************************
* Puertos I/O *
************************************************************************/

struct PA_pin_map {
boolean unusedRA0; //bit 0
boolean unusedRA1;
boolean unusedRA2;
boolean unusedRA3;
boolean unusedRA4;
boolean unusedRA5; //bit 4
} Puerto_A;
#byte Puerto_A = 5

struct PB_pin_map {
boolean unusedRB0; //bit 0
boolean unusedRB1;
boolean unusedRB2;
boolean unusedRB3;
boolean unusedRB4;
boolean unusedRB5;
boolean unusedRB6;
boolean unusedRB7; //bit8
} Puerto_B;
#byte Puerto_B = 6

struct PC_pin_map {
boolean unusedRC0; //bit 0
boolean unusedRC1;
boolean unusedRC2;
boolean unusedRC3;
boolean unusedRC4;
boolean test_osc;
boolean unusedRC6;
boolean rx; //bit8
} Puerto_C;
#byte Puerto_C = 7

#CASE

#byte porta=0x05
#byte portb=0x06
#byte portc=0x07

/************************************************************************
* Registros USART *
************************************************************************/

#byte SPBRG = 0x99


#byte RCSTA = 0x18 //Registro de recepcion de la usart
#byte TXSTA = 0x98
#byte RCREG = 0x1a
#byte PIR1 = 0x0c
#byte PIE1 = 0x8c
#byte INTCON = 0x0b

5 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

#bit SPEN = RCSTA.7 //Serial port enable bit


#bit RX9 = RCSTA.6 // 9-bit receive enable
#bit SREN = RCSTA.5 //En modo asyncrono no se tiene en cuenta
#bit CREN = RCSTA.4 // Continuos receive enable bit
#bit ADDEN = RCSTA.3
#bit FERR = RCSTA.2 //Frame error bit
#bit OERR = RCSTA.1 //Overrun error bit
#bit RX9D = RCSTA.0 //El noveno bit

#bit BRGH = TXSTA.2


#bit SYNC = TXSTA.4

#bit RCIF = PIR1.5


#bit RCIE = PIE1.5
#bit GIE = INTCON.7
#bit PEIE = INTCON.6

/************************************************************************
* Variables globales *
************************************************************************/

#define MAX_PWMS 3 //antes 24

/*Rx Buffer for dmx stream */


int8 Rx_Buffer[MAX_PWMS];
/*Current levels -0 to 255 */
int8 DMX_Levels[MAX_PWMS];

int1 Check_levels=0;

/************************************************************************
* Declaracion de funciones *
************************************************************************/

void Interrupt_USART_Rx(void);

/************************************************************************
* Rutina de atencion a la interrupcion *
************************************************************************/

#int_rda
void Interrupt_USART_Rx(void)
{
#define WAIT_FOR_NEXT_BYTE 0
#define WAIT_FOR_BREAK 1
#define WAIT_FOR_START 2
#define RECEIVE_DATA 3

/* Maquina de estados para determinar el inicio de la trama dmx*/


static int8 Rx_State = WAIT_FOR_BREAK;

int8 data; //El dato que estamos recibiendo

/*Definimos una union que es como una struct pero con la diferencia de
que sus componentes se almacenan en la misma posicion de memoria.
Esto significa que el byte rcsta.byte esta formado por 8 bits los cuales
hemos definido idénticos a los bits del registro de estado de la usart: RCSTA */
union
{
unsigned char byte;
struct {
unsigned char RX9D:1; //bit0
unsigned char OERR:1;
unsigned char FERR:1;
unsigned char ADDEN:1;
unsigned char CREN:1;
unsigned char SREN:1;
unsigned char RX9:1;
unsigned char SPEN:1; //bit7
} bits ;
}rcsta;

/* ÍNDICE AL BUFFER DE RECEPCION */


static int8 *ptr_Rx;

while (RCIF) //Nos quedamos leyendo el dato tanto tiempo como este presente
{
/*Leemos el registro de estado de la usart y se lo asignamos
al byte rcsta.byte. Leemos el dato */

rcsta.byte = RCSTA;
data = RCREG;

6 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

if (rcsta.bits.OERR) //Miramos si hay un buffer overrun


{
//Si hay Overrun entonces hay que resetear la lógica de recepcion
CREN = 0;
CREN = 1;
/* Como hemos recibido un overrun hemos de esperar un byte correcto
antes de buscar la señal de break */
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:
if (rcsta.bits.FERR) //Miramos si hay un error de trama
{
/*Si recibimos un error de trama, hay que asegurarse que el dato es 0.
Esto significa que hemos recibido una señal de break de como mínimo 44us.
Hay que acordarse que trabajamos a 250Kbits lo cual implica un tbit de 4us
SI enviamos 11 bits( start+8bit datos+2stop)esto son 44us*/
if (!data)
Rx_State = WAIT_FOR_START;
}
break;
case WAIT_FOR_START:
/*Comprobamos si hay error en la trama. Si recibimos un error
tenemos que esperar a recibir un byte correcto antes de que
empezemos a buscar nuestra señal de break */
if (rcsta.bits.FERR)
Rx_State = WAIT_FOR_NEXT_BYTE;
/* El byte de start de nuestro paquete siempre empieza por 0. */
else
{
if (!data)
{
/*Inicializamos nuestro índice a nuestro buffer de recepcion */
ptr_Rx = Rx_Buffer;
/*En este punto debermos determinar donde de la trama DMX queremos empezar
a recibir datos basandonos en una direccion de offset. Este primer programa
solo contempla recoger los tres primeros canales*/
Rx_State = RECEIVE_DATA;
}

}
break;

case RECEIVE_DATA:
/*Comprobamos si hay error de trama. Si nosotros recivimos un error de trama
esto puede ser el inicio de un nuevo paquete o un verdadero error de trama */
if (rcsta.bits.FERR)
{
/* Si es el inicio de un nuevo paquete el dato debe ser 0 sino es un error
en la trama */
if (!data)
Rx_State = WAIT_FOR_START;
else
Rx_State = WAIT_FOR_NEXT_BYTE;
}
else
{
/* ALmacenamos el dato recibido en el buffer de recepcion */
*ptr_Rx=data;
ptr_Rx++;
/*Comprobamos si hemos recibido todos nuestros datos */
if(ptr_Rx > &Rx_Buffer[MAX_PWMS-1] )
{
/* Hemos recibido todos los datos*/
Check_levels=1;
Rx_State= WAIT_FOR_BREAK;
}

}
break;

}
}
return;
}

/************************************************************************
* Programa Principal *

7 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

************************************************************************/

void main (void) {

int8 i;

//////////////////Configuramos los puertos ////////////////////////


set_tris_a(0x00);
set_tris_b(0x00);
set_tris_c(0b10000000);

setup_oscillator(OSC_INTRC|OSC_4MHZ); //pone el oscilador interno a 4Mhz

//un 1 es como entrada y 0 como salida


/////////////////////////////////////////

SPBRG=0x00; // SPBRG=0 implica que a 4Mhz el baudrate=250.000


BRGH=1; // BRGH=1 implica High speed.
SYNC=0; // enable aSYNChronous reception
SPEN=1; // serial port enabled - rc7/rx/dt , rc6/tx/ck pins as serial port pins

/////////////////////////////////////////

RX9=1; // 9 bit reception


CREN=1; // enable reception
ADDEN=0;
FERR=1;
OERR=1;
/////////////////////////////////////////
delay_ms(3000);
///////////////////////////////////////////////////////////////////
//// Configuramos los tres PWM ////
///////////////////////////////////////////////////////////////////

setup_ccp1(CCP_PWM); //Configure CCP1 as a PWM


//El tiempo de ciclo sera (1/clock)*4*t2div*(period+1)
//Si el clock es de 4Mhz y el periodo 255 (debajo)
// (1/4000000)*4*1*256=256us freq=3.9KHz
// (1/4000000)*4*4*256=1024us freq=975.56Hz
// (1/4000000)*4*16*256=4096us freq=244.14Hz
//Si el clock es de 16Mhz y el periodo 255 (debajo)
// (1/16000000)*4*1*256=64us freq=15.625Hz
// (1/16000000)*4*4*256=256us freq=3.906Hz
// (1/16000000)*4*16*256=1024us freq=976.5625Hz

setup_ccp2(CCP_PWM); //Configure CCP2 as a PWM


setup_ccp3(CCP_PWM); //Configure CCP2 as a PWM

setup_timer_2(T2_DIV_BY_16,255,1); //configuramos a 200Hz aprox

//// Inicializamos los tres pwm ////


set_pwm1_duty(127);
set_pwm2_duty(127);
set_pwm3_duty(127);
delay_ms(1000);
/////////////////////////////////////////

GIE=1; // enable all interrupts


PEIE=1; // enable peripheral interrupts
RCIE=1; // enable receive interrupt

while (1)
{
/*Despues de cada paquete, el receptor actualiza este flag para
permitirnos detectar un cambio.*/
if (Check_levels)
{
Check_levels=0;

DMX_Levels[0]=Rx_Buffer[0];
DMX_Levels[1]=Rx_Buffer[1];
DMX_Levels[2]=Rx_Buffer[2];
set_pwm1_duty(DMX_Levels[0]); //CANAL 1 ->CCP1 (PIN 13) RC2
set_pwm2_duty(DMX_Levels[1]); //CANAL 2 ->CCP2 (PIN 12) RC1
set_pwm3_duty(DMX_Levels[2]); //CANAL 3 ->CCP3 (PIN 26) RC3

8 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

thanks!!

Last edited by marquez on Wed Mar 30, 2005 1:36 am; edited 1 time in total

marquez dmx512 with leds


Posted: Wed Mar 30, 2005 1:29 am

Joined: 05 Jan 2005 hello everybody,


Posts: 2
Location: spain 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:

Code:

/************************************************************************
* FUSES *
* NOPROTECT=Code not protected from reading *
* CCP2C1=CCP2 input/output multiplexed with RC1 *
* NODEBUG=No Debug mode for ICD *
* BORV20=Brownout reset at 2.0V *
* MCLR=Master Clear pin enabled *
* Habilitamos el pin de clear *
* NOWDT=No Watch Dog Timer *
* INTRC_IO=Internal RC Osc, no CLKOUT *
* NOIESO=Internal External Switch Over mode disabled *
* NOFCMEN=Fail-safe clock monitor disabled *
* Desabilitamos la opcion de deteccion de que cuando hay una perdida *
* de clock externo el clock interno proporciona los clock al sistema*
* NOBROWNOUT=Reset when brownout detected *
************************************************************************/
#fuses NOPROTECT,CCP2C1,NODEBUG,MCLR,NOWDT,INTRC_IO,NOBROWNOUT
#include <16F767.h>
#use delay(clock=4000000) //Indicamos al compilador que los retardos los calcule
//en funcion de una base de tiempos con un clock de 4Mhz
#include <string.h>
#include <stdio.h>
/************************************************************************
* Puertos I/O *
************************************************************************/

struct PA_pin_map {
boolean unusedRA0; //bit 0
boolean unusedRA1;
boolean unusedRA2;
boolean unusedRA3;
boolean unusedRA4;
boolean unusedRA5; //bit 4
} Puerto_A;
#byte Puerto_A = 5

struct PB_pin_map {
boolean unusedRB0; //bit 0
boolean unusedRB1;
boolean unusedRB2;
boolean unusedRB3;
boolean unusedRB4;
boolean unusedRB5;
boolean unusedRB6;
boolean unusedRB7; //bit8
} Puerto_B;
#byte Puerto_B = 6

struct PC_pin_map {
boolean unusedRC0; //bit 0
boolean unusedRC1;
boolean unusedRC2;
boolean unusedRC3;
boolean unusedRC4;
boolean test_osc;
boolean unusedRC6;
boolean rx; //bit8
} Puerto_C;
#byte Puerto_C = 7

9 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

#CASE

#byte porta=0x05
#byte portb=0x06
#byte portc=0x07

/************************************************************************
* Registros USART *
************************************************************************/

#byte SPBRG = 0x99


#byte RCSTA = 0x18 //Registro de recepcion de la usart
#byte TXSTA = 0x98
#byte RCREG = 0x1a
#byte PIR1 = 0x0c
#byte PIE1 = 0x8c
#byte INTCON = 0x0b

#bit SPEN = RCSTA.7 //Serial port enable bit


#bit RX9 = RCSTA.6 // 9-bit receive enable
#bit SREN = RCSTA.5 //En modo asyncrono no se tiene en cuenta
#bit CREN = RCSTA.4 // Continuos receive enable bit
#bit ADDEN = RCSTA.3
#bit FERR = RCSTA.2 //Frame error bit
#bit OERR = RCSTA.1 //Overrun error bit
#bit RX9D = RCSTA.0 //El noveno bit

#bit BRGH = TXSTA.2


#bit SYNC = TXSTA.4

#bit RCIF = PIR1.5


#bit RCIE = PIE1.5
#bit GIE = INTCON.7
#bit PEIE = INTCON.6

/************************************************************************
* Variables globales *
************************************************************************/

#define MAX_PWMS 3 //antes 24

/*Rx Buffer for dmx stream */


int8 Rx_Buffer[MAX_PWMS];
/*Current levels -0 to 255 */
int8 DMX_Levels[MAX_PWMS];

int1 Check_levels=0;

/************************************************************************
* Declaracion de funciones *
************************************************************************/

void Interrupt_USART_Rx(void);

/************************************************************************
* Rutina de atencion a la interrupcion *
************************************************************************/

#int_rda
void Interrupt_USART_Rx(void)
{
#define WAIT_FOR_NEXT_BYTE 0
#define WAIT_FOR_BREAK 1
#define WAIT_FOR_START 2
#define RECEIVE_DATA 3

/* Maquina de estados para determinar el inicio de la trama dmx*/


static int8 Rx_State = WAIT_FOR_BREAK;

int8 data; //El dato que estamos recibiendo

/*Definimos una union que es como una struct pero con la diferencia de
que sus componentes se almacenan en la misma posicion de memoria.
Esto significa que el byte rcsta.byte esta formado por 8 bits los cuales
hemos definido idénticos a los bits del registro de estado de la usart: RCSTA */
union
{
unsigned char byte;
struct {
unsigned char RX9D:1; //bit0
unsigned char OERR:1;
unsigned char FERR:1;
unsigned char ADDEN:1;
unsigned char CREN:1;

10 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

unsigned char SREN:1;


unsigned char RX9:1;
unsigned char SPEN:1; //bit7
} bits ;
}rcsta;

/* ÍNDICE AL BUFFER DE RECEPCION */


static int8 *ptr_Rx;

while (RCIF) //Nos quedamos leyendo el dato tanto tiempo como este presente
{
/*Leemos el registro de estado de la usart y se lo asignamos
al byte rcsta.byte. Leemos el dato */

rcsta.byte = RCSTA;
data = RCREG;

if (rcsta.bits.OERR) //Miramos si hay un buffer overrun


{
//Si hay Overrun entonces hay que resetear la lógica de recepcion
CREN = 0;
CREN = 1;
/* Como hemos recibido un overrun hemos de esperar un byte correcto
antes de buscar la señal de break */
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:
if (rcsta.bits.FERR) //Miramos si hay un error de trama
{
/*Si recibimos un error de trama, hay que asegurarse que el dato es 0.
Esto significa que hemos recibido una señal de break de como mínimo 44us.
Hay que acordarse que trabajamos a 250Kbits lo cual implica un tbit de 4us
SI enviamos 11 bits( start+8bit datos+2stop)esto son 44us*/
if (!data)
Rx_State = WAIT_FOR_START;
}
break;
case WAIT_FOR_START:
/*Comprobamos si hay error en la trama. Si recibimos un error
tenemos que esperar a recibir un byte correcto antes de que
empezemos a buscar nuestra señal de break */
if (rcsta.bits.FERR)
Rx_State = WAIT_FOR_NEXT_BYTE;
/* El byte de start de nuestro paquete siempre empieza por 0. */
else
{
if (!data)
{
/*Inicializamos nuestro índice a nuestro buffer de recepcion */
ptr_Rx = Rx_Buffer;
/*En este punto debermos determinar donde de la trama DMX queremos empezar
a recibir datos basandonos en una direccion de offset. Este primer programa
solo contempla recoger los tres primeros canales*/
Rx_State = RECEIVE_DATA;
}

}
break;

case RECEIVE_DATA:
/*Comprobamos si hay error de trama. Si nosotros recivimos un error de trama
esto puede ser el inicio de un nuevo paquete o un verdadero error de trama */
if (rcsta.bits.FERR)
{
/* Si es el inicio de un nuevo paquete el dato debe ser 0 sino es un error
en la trama */
if (!data)
Rx_State = WAIT_FOR_START;
else
Rx_State = WAIT_FOR_NEXT_BYTE;
}
else
{
/* ALmacenamos el dato recibido en el buffer de recepcion */
*ptr_Rx=data;
ptr_Rx++;
/*Comprobamos si hemos recibido todos nuestros datos */

11 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

if(ptr_Rx > &Rx_Buffer[MAX_PWMS-1] )


{
/* Hemos recibido todos los datos*/
Check_levels=1;
Rx_State= WAIT_FOR_BREAK;
}

}
break;

}
}
return;
}

/************************************************************************
* Programa Principal *
************************************************************************/

void main (void) {

int8 i;

//////////////////Configuramos los puertos ////////////////////////


set_tris_a(0x00);
set_tris_b(0x00);
set_tris_c(0b10000000);

setup_oscillator(OSC_INTRC|OSC_4MHZ); //pone el oscilador interno a 4Mhz

//un 1 es como entrada y 0 como salida


/////////////////////////////////////////

SPBRG=0x00; // SPBRG=0 implica que a 4Mhz el baudrate=250.000


BRGH=1; // BRGH=1 implica High speed.
SYNC=0; // enable aSYNChronous reception
SPEN=1; // serial port enabled - rc7/rx/dt , rc6/tx/ck pins as serial port pins

/////////////////////////////////////////

RX9=1; // 9 bit reception


CREN=1; // enable reception
ADDEN=0;
FERR=1;
OERR=1;
/////////////////////////////////////////
delay_ms(3000);
///////////////////////////////////////////////////////////////////
//// Configuramos los tres PWM ////
///////////////////////////////////////////////////////////////////

setup_ccp1(CCP_PWM); //Configure CCP1 as a PWM


//El tiempo de ciclo sera (1/clock)*4*t2div*(period+1)
//Si el clock es de 4Mhz y el periodo 255 (debajo)
// (1/4000000)*4*1*256=256us freq=3.9KHz
// (1/4000000)*4*4*256=1024us freq=975.56Hz
// (1/4000000)*4*16*256=4096us freq=244.14Hz
//Si el clock es de 16Mhz y el periodo 255 (debajo)
// (1/16000000)*4*1*256=64us freq=15.625Hz
// (1/16000000)*4*4*256=256us freq=3.906Hz
// (1/16000000)*4*16*256=1024us freq=976.5625Hz

setup_ccp2(CCP_PWM); //Configure CCP2 as a PWM


setup_ccp3(CCP_PWM); //Configure CCP2 as a PWM

setup_timer_2(T2_DIV_BY_16,255,1); //configuramos a 200Hz aprox

//// Inicializamos los tres pwm ////


set_pwm1_duty(127);
set_pwm2_duty(127);
set_pwm3_duty(127);
delay_ms(1000);
/////////////////////////////////////////

GIE=1; // enable all interrupts


PEIE=1; // enable peripheral interrupts
RCIE=1; // enable receive interrupt

while (1)
{
/*Despues de cada paquete, el receptor actualiza este flag para
permitirnos detectar un cambio.*/
if (Check_levels)
{

12 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

Check_levels=0;

DMX_Levels[0]=Rx_Buffer[0];
DMX_Levels[1]=Rx_Buffer[1];
DMX_Levels[2]=Rx_Buffer[2];
set_pwm1_duty(DMX_Levels[0]); //CANAL 1 ->CCP1 (PIN 13) RC2
set_pwm2_duty(DMX_Levels[1]); //CANAL 2 ->CCP2 (PIN 12) RC1
set_pwm3_duty(DMX_Levels[2]); //CANAL 3 ->CCP3 (PIN 26) RC3

thanks!!

marquez dmx512 pwm leds


Posted: Wed Mar 30, 2005 1:33 am

Joined: 05 Jan 2005 hello everybody,


Posts: 2
Location: spain 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:

Code:

/************************************************************************
* FUSES *
* NOPROTECT=Code not protected from reading *
* CCP2C1=CCP2 input/output multiplexed with RC1 *
* NODEBUG=No Debug mode for ICD *
* BORV20=Brownout reset at 2.0V *
* MCLR=Master Clear pin enabled *
* Habilitamos el pin de clear *
* NOWDT=No Watch Dog Timer *
* INTRC_IO=Internal RC Osc, no CLKOUT *
* NOIESO=Internal External Switch Over mode disabled *
* NOFCMEN=Fail-safe clock monitor disabled *
* Desabilitamos la opcion de deteccion de que cuando hay una perdida *
* de clock externo el clock interno proporciona los clock al sistema*
* NOBROWNOUT=Reset when brownout detected *
************************************************************************/
#fuses NOPROTECT,CCP2C1,NODEBUG,MCLR,NOWDT,INTRC_IO,NOBROWNOUT
#include <16F767.h>
#use delay(clock=4000000) //Indicamos al compilador que los retardos los calcule
//en funcion de una base de tiempos con un clock de 4Mhz
#include <string.h>
#include <stdio.h>
/************************************************************************
* Puertos I/O *
************************************************************************/

struct PA_pin_map {
boolean unusedRA0; //bit 0
boolean unusedRA1;
boolean unusedRA2;
boolean unusedRA3;
boolean unusedRA4;
boolean unusedRA5; //bit 4
} Puerto_A;
#byte Puerto_A = 5

struct PB_pin_map {
boolean unusedRB0; //bit 0
boolean unusedRB1;
boolean unusedRB2;
boolean unusedRB3;
boolean unusedRB4;
boolean unusedRB5;
boolean unusedRB6;
boolean unusedRB7; //bit8

13 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

} Puerto_B;
#byte Puerto_B = 6

struct PC_pin_map {
boolean unusedRC0; //bit 0
boolean unusedRC1;
boolean unusedRC2;
boolean unusedRC3;
boolean unusedRC4;
boolean test_osc;
boolean unusedRC6;
boolean rx; //bit8
} Puerto_C;
#byte Puerto_C = 7

#CASE

#byte porta=0x05
#byte portb=0x06
#byte portc=0x07

/************************************************************************
* Registros USART *
************************************************************************/

#byte SPBRG = 0x99


#byte RCSTA = 0x18 //Registro de recepcion de la usart
#byte TXSTA = 0x98
#byte RCREG = 0x1a
#byte PIR1 = 0x0c
#byte PIE1 = 0x8c
#byte INTCON = 0x0b

#bit SPEN = RCSTA.7 //Serial port enable bit


#bit RX9 = RCSTA.6 // 9-bit receive enable
#bit SREN = RCSTA.5 //En modo asyncrono no se tiene en cuenta
#bit CREN = RCSTA.4 // Continuos receive enable bit
#bit ADDEN = RCSTA.3
#bit FERR = RCSTA.2 //Frame error bit
#bit OERR = RCSTA.1 //Overrun error bit
#bit RX9D = RCSTA.0 //El noveno bit

#bit BRGH = TXSTA.2


#bit SYNC = TXSTA.4

#bit RCIF = PIR1.5


#bit RCIE = PIE1.5
#bit GIE = INTCON.7
#bit PEIE = INTCON.6

/************************************************************************
* Variables globales *
************************************************************************/

#define MAX_PWMS 3 //antes 24

/*Rx Buffer for dmx stream */


int8 Rx_Buffer[MAX_PWMS];
/*Current levels -0 to 255 */
int8 DMX_Levels[MAX_PWMS];

int1 Check_levels=0;

/************************************************************************
* Declaracion de funciones *
************************************************************************/

void Interrupt_USART_Rx(void);

/************************************************************************
* Rutina de atencion a la interrupcion *
************************************************************************/

#int_rda
void Interrupt_USART_Rx(void)
{
#define WAIT_FOR_NEXT_BYTE 0
#define WAIT_FOR_BREAK 1
#define WAIT_FOR_START 2
#define RECEIVE_DATA 3

/* Maquina de estados para determinar el inicio de la trama dmx*/


static int8 Rx_State = WAIT_FOR_BREAK;

14 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

int8 data; //El dato que estamos recibiendo

/*Definimos una union que es como una struct pero con la diferencia de
que sus componentes se almacenan en la misma posicion de memoria.
Esto significa que el byte rcsta.byte esta formado por 8 bits los cuales
hemos definido idénticos a los bits del registro de estado de la usart: RCSTA */
union
{
unsigned char byte;
struct {
unsigned char RX9D:1; //bit0
unsigned char OERR:1;
unsigned char FERR:1;
unsigned char ADDEN:1;
unsigned char CREN:1;
unsigned char SREN:1;
unsigned char RX9:1;
unsigned char SPEN:1; //bit7
} bits ;
}rcsta;

/* ÍNDICE AL BUFFER DE RECEPCION */


static int8 *ptr_Rx;

while (RCIF) //Nos quedamos leyendo el dato tanto tiempo como este presente
{
/*Leemos el registro de estado de la usart y se lo asignamos
al byte rcsta.byte. Leemos el dato */

rcsta.byte = RCSTA;
data = RCREG;

if (rcsta.bits.OERR) //Miramos si hay un buffer overrun


{
//Si hay Overrun entonces hay que resetear la lógica de recepcion
CREN = 0;
CREN = 1;
/* Como hemos recibido un overrun hemos de esperar un byte correcto
antes de buscar la señal de break */
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:
if (rcsta.bits.FERR) //Miramos si hay un error de trama
{
/*Si recibimos un error de trama, hay que asegurarse que el dato es 0.
Esto significa que hemos recibido una señal de break de como mínimo 44us.
Hay que acordarse que trabajamos a 250Kbits lo cual implica un tbit de 4us
SI enviamos 11 bits( start+8bit datos+2stop)esto son 44us*/
if (!data)
Rx_State = WAIT_FOR_START;
}
break;
case WAIT_FOR_START:
/*Comprobamos si hay error en la trama. Si recibimos un error
tenemos que esperar a recibir un byte correcto antes de que
empezemos a buscar nuestra señal de break */
if (rcsta.bits.FERR)
Rx_State = WAIT_FOR_NEXT_BYTE;
/* El byte de start de nuestro paquete siempre empieza por 0. */
else
{
if (!data)
{
/*Inicializamos nuestro índice a nuestro buffer de recepcion */
ptr_Rx = Rx_Buffer;
/*En este punto debermos determinar donde de la trama DMX queremos empezar
a recibir datos basandonos en una direccion de offset. Este primer programa
solo contempla recoger los tres primeros canales*/
Rx_State = RECEIVE_DATA;
}

}
break;

case RECEIVE_DATA:
/*Comprobamos si hay error de trama. Si nosotros recivimos un error de trama
esto puede ser el inicio de un nuevo paquete o un verdadero error de trama */

15 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

if (rcsta.bits.FERR)
{
/* Si es el inicio de un nuevo paquete el dato debe ser 0 sino es un error
en la trama */
if (!data)
Rx_State = WAIT_FOR_START;
else
Rx_State = WAIT_FOR_NEXT_BYTE;
}
else
{
/* ALmacenamos el dato recibido en el buffer de recepcion */
*ptr_Rx=data;
ptr_Rx++;
/*Comprobamos si hemos recibido todos nuestros datos */
if(ptr_Rx > &Rx_Buffer[MAX_PWMS-1] )
{
/* Hemos recibido todos los datos*/
Check_levels=1;
Rx_State= WAIT_FOR_BREAK;
}

}
break;

}
}
return;
}

/************************************************************************
* Programa Principal *
************************************************************************/

void main (void) {

int8 i;

//////////////////Configuramos los puertos ////////////////////////


set_tris_a(0x00);
set_tris_b(0x00);
set_tris_c(0b10000000);

setup_oscillator(OSC_INTRC|OSC_4MHZ); //pone el oscilador interno a 4Mhz

//un 1 es como entrada y 0 como salida


/////////////////////////////////////////

SPBRG=0x00; // SPBRG=0 implica que a 4Mhz el baudrate=250.000


BRGH=1; // BRGH=1 implica High speed.
SYNC=0; // enable aSYNChronous reception
SPEN=1; // serial port enabled - rc7/rx/dt , rc6/tx/ck pins as serial port pins

/////////////////////////////////////////

RX9=1; // 9 bit reception


CREN=1; // enable reception
ADDEN=0;
FERR=1;
OERR=1;
/////////////////////////////////////////
delay_ms(3000);
///////////////////////////////////////////////////////////////////
//// Configuramos los tres PWM ////
///////////////////////////////////////////////////////////////////

setup_ccp1(CCP_PWM); //Configure CCP1 as a PWM


//El tiempo de ciclo sera (1/clock)*4*t2div*(period+1)
//Si el clock es de 4Mhz y el periodo 255 (debajo)
// (1/4000000)*4*1*256=256us freq=3.9KHz
// (1/4000000)*4*4*256=1024us freq=975.56Hz
// (1/4000000)*4*16*256=4096us freq=244.14Hz
//Si el clock es de 16Mhz y el periodo 255 (debajo)
// (1/16000000)*4*1*256=64us freq=15.625Hz
// (1/16000000)*4*4*256=256us freq=3.906Hz
// (1/16000000)*4*16*256=1024us freq=976.5625Hz

setup_ccp2(CCP_PWM); //Configure CCP2 as a PWM


setup_ccp3(CCP_PWM); //Configure CCP2 as a PWM

setup_timer_2(T2_DIV_BY_16,255,1); //configuramos a 200Hz aprox

//// Inicializamos los tres pwm ////


set_pwm1_duty(127);
set_pwm2_duty(127);

16 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

set_pwm3_duty(127);
delay_ms(1000);
/////////////////////////////////////////

GIE=1; // enable all interrupts


PEIE=1; // enable peripheral interrupts
RCIE=1; // enable receive interrupt

while (1)
{
/*Despues de cada paquete, el receptor actualiza este flag para
permitirnos detectar un cambio.*/
if (Check_levels)
{
Check_levels=0;

DMX_Levels[0]=Rx_Buffer[0];
DMX_Levels[1]=Rx_Buffer[1];
DMX_Levels[2]=Rx_Buffer[2];
set_pwm1_duty(DMX_Levels[0]); //CANAL 1 ->CCP1 (PIN 13) RC2
set_pwm2_duty(DMX_Levels[1]); //CANAL 2 ->CCP2 (PIN 12) RC1
set_pwm3_duty(DMX_Levels[2]); //CANAL 3 ->CCP3 (PIN 26) RC3

thanks!!

Mark Posted: Wed Mar 30, 2005 7:14 am

Don't use the actual DMX value. Instead, have a lookup table of 256 entries (0-255). This will
Joined: 07 Sep 2003
Posts: 3511 allow you to adjust the curve. The PWM is a 10 bit value, you can use all ten bits but that alone
Location: Atlanta, GA 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
Code:
curve[256] = {0,4,8,12,16,20,...}
you can still use the values in between
Code:

current_value = curve[0];
new_value = curve[3];
............
while(1)
{
delaysometime();
if (new_value < current_value)
{
current_value--;
set_pwm(current_value);
}
else if (new_value > current_value)
{
current_value++;
set_pwm(current_value);
}
}

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

17 от 18 01.3.2007 г. 11:03
CCS :: View topic - DMX protocol http://ccsinfo.com/forum/viewtopic.php?t=17513&highlight=inte...

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!

Display posts from previous: All Posts Oldest First Go

All times are GMT - 6 Hours


CCS Forum Index -> General CCS C Discussion
Goto page 1, 2 Next
Page 1 of 2

Jump to: General CCS C Discussion Go

You can post new topics in this forum


You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2001, 2005 phpBB Group

18 от 18 01.3.2007 г. 11:03

You might also like