View previous topic :: View next topic |
Author |
Message |
davt
Joined: 07 Oct 2003 Posts: 66 Location: England
|
DMX protocol |
Posted: Fri Nov 07, 2003 8:34 am |
|
|
Hi all
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 2003 Posts: 2838 Location: 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 2003 Posts: 66 Location: 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 |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
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 software from it. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: 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.
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)
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;
}
break;
// default:
/* Unknown start code */
}
}
return;
}
|
|
|
|
davt
Joined: 07 Oct 2003 Posts: 66 Location: England
|
|
Posted: Mon Nov 10, 2003 8:19 am |
|
|
Thanks Mark for the code for DMX512.
Do you have a copy of the DMX512 protocol that I could use, so I can progress further.
My e-mail address is:
i.d.teece@hull.ac.uk
Many thanks for your kind attention! |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
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 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. |
|
|
jmann
Joined: 27 Dec 2004 Posts: 21
|
|
Posted: Mon Dec 27, 2004 1:34 pm |
|
|
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 inefficient, there must be a better way. |
|
|
Ttelmah Guest
|
|
Posted: Mon Dec 27, 2004 3:25 pm |
|
|
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
Joined: 05 Jan 2005 Posts: 0 Location: 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:
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
#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;
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 *
************************************************************************/
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
}
}
} |
thanks!! |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
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 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
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 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 2003 Posts: 2838 Location: 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 2005 Posts: 0 Location: 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)
Here is the actual 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 *
************************************************************************/
#include <16F767.h>
#fuses NOPROTECT,CCP2C1,NODEBUG,MCLR,NOWDT,HS,NOBROWNOUT
//#use delay(clock=4000000) #use delay(clock=16000000)
#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; //canal pwm
boolean unusedRB6;
boolean unusedRB7; //bit8
} Puerto_B;
#byte Puerto_B = 6
struct PC_pin_map {
boolean unusedRC0; //bit 0
boolean unusedRC1; //canal pwm
boolean PWM1; //canal pwm
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 32 //Queremos almacenar 3 valores (RGB)
unsigned int DMX_512_Offset = 5;
/*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);
int16 calcul_duty1(int8 level1, int16 current_value1);
int16 calcul_duty2(int8 level2, int16 current_value2);
int16 calcul_duty3(int8 level3, int16 current_value3);
/************************************************************************
* 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_INT 3
#define RECEIVE_DATA 4
/* 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
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; //de 1 a 64
static unsigned int DMX_512_Count = 0;
while (RCIF) {
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;
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
{
if (!data)
Rx_State = WAIT_FOR_START;
}
break;
case WAIT_FOR_START:
if (rcsta.bits.FERR)
Rx_State = WAIT_FOR_NEXT_BYTE;
else
{
if (!data)
{
if(DMX_512_Offset==1)
{
ptr_Rx=Rx_Buffer;
Rx_State = RECEIVE_DATA;
}
else
{
Rx_State = RECEIVE_DATA_INT;
DMX_512_Count=1;
}
}
}
break;
case RECEIVE_DATA_INT:
if (rcsta.bits.FERR)
{
if (!data)
Rx_State = WAIT_FOR_START;
else
Rx_State = WAIT_FOR_NEXT_BYTE;
}
else
{
DMX_512_Count++;
if( DMX_512_Count == DMX_512_Offset)
{
ptr_Rx=Rx_Buffer;
Rx_State = RECEIVE_DATA;
}
}
break;
case RECEIVE_DATA:
if (rcsta.bits.FERR)
{
if (!data)
Rx_State = WAIT_FOR_START;
else
Rx_State = WAIT_FOR_NEXT_BYTE;
}
else
{
*ptr_Rx=data;
ptr_Rx++;
if( ptr_Rx > &Rx_Buffer[MAX_PWMS-1] )
{
Rx_State= WAIT_FOR_BREAK;
Check_levels=1;
}
}
break;
}
}
return;
}
/************************************************************************
* Programa Principal *
************************************************************************/
void main (void) {
int8 i;
int1 exit; //var used para salir de bucles
//////////////////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 para 4Mhz
SYNC=0; // enable aSYNChronous reception
SPEN=1; // serial port enabled - rc7/rx/dt , rc6/tx/ck pins as serial port pins
*/
SPBRG=0x00; // SPBRG=0 implica que a 16Mhz el baudrate=250.000
BRGH=0; // BRGH=0 implica Low 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);
setup_ccp2(CCP_PWM);
setup_ccp3(CCP_PWM);
setup_timer_2(T2_DIV_BY_16,255,1); //1khz a 16Mhz
//// Inicializamos los tres pwm ////
//PONEMOS LA ANCHURA DE PULSO A LA MITAD
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
current_value1=valorpwm1[0] ;
current_value2=valorpwm1[0] ;
current_value3=valorpwm1[0] ;//Inicializamos con un valor de duty de 0 -> leds off
exit=0;
while (1)
{
if (Check_levels)
{
Check_levels=0;
level1=Rx_Buffer[DMX_512_Offset-1];
level2=Rx_Buffer[DMX_512_Offset];
level3=Rx_Buffer[DMX_512_Offset];
calcul_duty1(level1,current_value1);
calcul_duty2(level2,current_value2);
calcul_duty3(level3,current_value3);
} //cierra check levels
current_value1=new_value1;
current_value2=new_value2;
current_value3=new_value3;
}//cierra while(1)
}//cierra main
|
thanks! |
|
|
|