Y el código es el siguiente:
#include <Dimmer v3.0 8CHDMX.h>
/***********************************************************************/
/***************DECLARACIONES PARA DMX512*******************************/
#define WAIT_FOR_NEXT_BYTE 0
#define WAIT_FOR_BREAK 1
#define WAIT_FOR_START 2 //MAQUINA DE ESTADOS
#define RECEIVE_DATA 3
#byte SPBRG = 0x99
#byte RCSTA = 0x18 //Registros de recepcion de la usart
#byte TXSTA = 0x98
#byte RCREG = 0x1a
#byte PIR1 = 0x0c
#byte PIE1 = 0x8c
#byte INTCON = 0x0b
#byte T1CON = 0X10
#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 //Addres detected enable bit
#bit FERR = RCSTA.2 //Frame error bit
#bit OERR = RCSTA.1 //Overrun error bit
#bit RX9D = RCSTA.0 //El noveno bit
#bit TMR1ON = T1CON.0 // empleo TMR1ON en vez de enable/disable_interrupt(TIMER1) porque el compilador
// no le da la gana de trabajar esta sentencia (no modifica TMR1ON????)
#bit BRGH = TXSTA.2
#bit SYNC = TXSTA.4
#bit RCIF = PIR1.5
#bit RCIE = PIE1.5
#bit GIE = INTCON.7
#bit PEIE = INTCON.6
#bit INTEDG = 0x81.6
/******************************************************************************/
/***************DECLARACIONES PARA DIMMERIZACION*******************************/
const int8 CH_DMX=8; //cantidad de canales a almacenar
int8 OFFSET=3; // direccion base del receptor al tener solo 8 interruptores solo se puede direccionar hasta el canal 255
#define DMX_LED PIN_E2 // led de indicacion de Rx DMX
int8 Rx_Buffer[CH_DMX]={255,255,255,255,255,255,255,255}; // en este arreglo se almacenan los datos DMX captados por el receptor
//tiene inicialmente la menor intensidad
int8 Ch_Rx=0; // contador del Canal que se esta recibiendo
int8 Id_Buffer=0; // contador del canal que se esta almacenando en el buffer de RX
// si se almacenan mas de 250 ch debe de ser de 16
#define TIMER0 229 // son 255 tramos de 32.7 us cada uno
#define TIMER1 55550 // valor medio 55600, debe ser calibrado en tiempo real //**********PARAMETRO A AJUSTAR**************************************
// debido a que la sensiblidad del detector de cruce por cero puede variar de un modelo a otro.
// por tanto hay que evitar el disparo continue al proximo semiciclo, lo cual provocar'ia que el triac
// conduciera TODO el semicilo...
int8 HEAT=220; // Este valor permite que la intensidad NUNCA SEA CERO. (DEFECTO: 240) //**********PARAMETRO A AJUSTAR**************************************
#define PREHEAT 250 // TIEMPO DE PRECALENTAMIENTO, este par'ametro tiene //**********PARAMETRO A AJUSTAR**************************************
//que ser ajustado en tiempo real porque aunque el delay
// en el main es de 200ms demora mucho mas debido
//a las frecuentes interrupciones, lo que alarga
// notablemente el tiempo. Se debe poner un valor mas
// alto para aumentar el tiempo de precalentamento.
int8 contador=0;
/*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
para hacer una copia despues de leer el buffer de recepcion, no antes segun mi programa,
antes segun datasheeat y el programa de marcos*/
union
{
unsigned char _byte; // Al parecer en ccs 5 no puede ser llamado 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 ;
}rcsta2; // en ccs 5 no puede ser llamado rcsta pues ya hay una var con ese nombre
/*********************PARA DIMMERIZACION**********************************************/
/**************************************************************************************/
#int_TIMER0
void TIMER0_isr(void){
set_timer0(TIMER0);
if (Rx_Buffer[0]==contador) output_high(PIN_D0);
if (Rx_Buffer[1]==contador) output_high(PIN_D1);
if (Rx_Buffer[2]==contador) output_high(PIN_D2);
if (Rx_Buffer[3]==contador) output_high(PIN_D3);
if (Rx_Buffer[4]==contador) output_high(PIN_D4);
if (Rx_Buffer[5]==contador) output_high(PIN_D5);
if (Rx_Buffer[6]==contador) output_high(PIN_D6);
if (Rx_Buffer[7]==contador) output_high(PIN_D7);
contador++;
if (contador>=HEAT) output_d(0xff); //VER EXPLICACI'ON EN LA DECLARACION DE HEAT
}
#int_TIMER1
void TIMER1_isr(void){
disable_interrupts(INT_TIMER0); // LOS DESHABILITO exepcto el de EXT_INT
// disable_interrupts(INT_TIMER1);
TMR1ON=0;
output_d(0x00);
}
#INT_EXT
void EXT_isr(void)
{
set_timer0(TIMER0);// este timer se mantendra activo hasta que se cumpla el timer 1
enable_interrupts(INT_TIMER0);
set_timer1(TIMER1); // timer para garantizar que no pase de 8.33 ms O SEA AL OTRO SEMICICLO
enable_interrupts(INT_TIMER1);
TMR1ON=1;
contador=0;
INTEDG=!INTEDG; /*CAMBIO EL FLANCO PARA EL PROXIMO SEMICICLO*/
}
void main()
{
int8 temp;
set_tris_a(0xff); //completo de entrada;
set_tris_b(0xff);
set_tris_c(0xff);
set_tris_d(0x00);
set_tris_e(0x00);
setup_adc_ports(AN0_AN1_AN3); //tres canales, solo empleo AN0
setup_adc(ADC_CLOCK_DIV_32);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);
disable_interrupts(INT_TIMER0); // LOS DESHABILITO, NO LOS NECESITO AHORA
// disable_interrupts(INT_TIMER1);
TMR1ON=0;
output_D(0);
/* CHEQUEANDO DIRECCION BASE*/
temp= input_b();
temp= temp&0x3E; //3e mascara pues solo necesito del bit 1 al 5 (ver esquema)
temp= temp>>1; // corro hacia la DER 1 lugar para ubicarlo en la parte BAJA
OFFSET= input_c();
OFFSET=OFFSET&0x07; // solo me interesan los 3 Lsb
OFFSET=OFFSET<<5; //LO SUBO A LA PARTE ALTA
OFFSET=OFFSET|temp; // tengo ya la direcci'on
/* */
INTEDG=1;
RCIE=0; // deshabilito receive interrupt(CERO) no se utiliza, estoy por encuesta
enable_interrupts(INT_EXT); // Habilito la interrupcion externa
GIE=1; // enable all interrupts
PEIE=1; // enable peripheral interrupts
HEAT=200;
for (int i=0;i<=PREHEAT;i++){ // Estamos en precalentamiento
output_high(DMX_LED); // LED parpadeando
delay_ms(100);
output_low(DMX_LED);
delay_ms(100);
}
HEAT=220;
if (OFFSET==0){ /*La dimmerizaci'on es por el potenciometro*/
output_high(DMX_LED); // se mantendr'a siempre activo, indicando que la fuente es el potenciometro.
while(1){
set_adc_channel(0);
delay_ms(50);
RX_Buffer[0]=255-read_adc();
for (int i=1;i<=7;i++){
RX_Buffer[i]=RX_Buffer[0]; //igualo todos los canales al valor dado por el POT
}
}
}
ELSE
{
SPBRG=0x04; // SPBRG=0 implica que a 20Mhz el baudrate=250.000 baud
BRGH=1; // BRGH=1 implica High speed.
SYNC=0; // enable aSYNChronous reception
SPEN=1; // serial port enabled
RX9=1; // 9 bit reception
CREN=1; // enable reception
ADDEN=0;
FERR=1;
OERR=1;
output_low(DMX_LED);
/* 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 se almacena temporalmente aqui
while (1){
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 */
data = RCREG;
rcsta2._byte = RCSTA;
if (rcsta2.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;
}
switch (Rx_State)
{
case WAIT_FOR_BREAK:
if (rcsta2.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 (rcsta2.bits.FERR)
Rx_State = WAIT_FOR_NEXT_BYTE;
/* El byte de start de nuestro paquete siempre empieza por 0. */
else
{
if (!data)
{
// ESTAMOS EN EL BYTE DE START, EL CANAL ES 0
/*En este punto debermos determinar donde de la trama DMX queremos empezar
a recibir datos basandonos en una direccion de offset. */
Ch_Rx=0;
Id_buffer=0;
Rx_State = RECEIVE_DATA;
output_high(DMX_LED);
}
}
break;
case WAIT_FOR_NEXT_BYTE:
if (!rcsta2.bits.FERR){
Rx_State = WAIT_FOR_BREAK;
}
break;
case RECEIVE_DATA:
/*Comprobamos si hay error de trama. Si nosotros recibimos un error de trama
esto puede ser el inicio de un nuevo paquete o un verdadero error de trama */
if (rcsta2.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
{
Ch_Rx++;
/* ALmacenamos el dato recibido en el buffer de recepcion si esta en el rango especificado */
if (Ch_Rx>=OFFSET) {
Rx_Buffer[Id_Buffer]=255-data;
Id_Buffer++;
}
/*Comprobamos si hemos recibido todos nuestros datos */
if(Id_Buffer>=CH_DMX)
{
/* Hemos recibido todos los datos*/
Rx_State= WAIT_FOR_BREAK;
}
output_low(DMX_LED);
}
break;
}
}
} // CIERRE DEL WHILE(1)
} // cierre del else
}
Espero les sirva, saludos desde Cuba....