CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

DMX protocol
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
davt



Joined: 07 Oct 2003
Posts: 66
Location: England

View user's profile Send private message

DMX protocol
PostPosted: Fri Nov 07, 2003 8:34 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Fri Nov 07, 2003 9:42 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Nov 07, 2003 9:59 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Nov 07, 2003 2:34 pm     Reply with quote

You will get such info at:
http://www.usitt.org/DMX/DMX512.htm
Best wishes
Humberto
Mark



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

View user's profile Send private message Send e-mail

PostPosted: Fri Nov 07, 2003 2:36 pm     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Nov 10, 2003 7:15 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Nov 10, 2003 8:19 am     Reply with quote

Thanks Mark for the code for DMX512. Very Happy
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

View user's profile Send private message Send e-mail

PostPosted: Mon Nov 10, 2003 8:39 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Dec 27, 2004 1:34 pm     Reply with quote

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







PostPosted: Mon Dec 27, 2004 3:25 pm     Reply with quote

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

View user's profile Send private message

dmx512 pwm leds
PostPosted: Wed Mar 30, 2005 1:33 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Wed Mar 30, 2005 7:14 am     Reply with quote

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








PostPosted: Wed Mar 30, 2005 7:27 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Wed Mar 30, 2005 7:36 am     Reply with quote

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

View user's profile Send private message

select channel in dmx
PostPosted: Thu Apr 14, 2005 8:14 am     Reply with quote

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!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot 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