/************************************************************************
* Receptor DMX con PIC 18F2550 *
* El emisor debe tener unos parámetros mínimos de: *
* - DMX Sending Rate 20ms *
* - Data Present 210 *
* - Start/clock 210 *
* *
* Mis agradecimientos a Mark por su código libre para recepción DMX *
* en el que se ha inspirado el núcleo de este programa. *
* *
* www.micropic.es Nocturno - 2007 *
************************************************************************/
/************************************************************************
* Configuración micro *
************************************************************************/
#include <18F2550.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
// #FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES BORV43 //Brownout reset at 4.3V
#FUSES PUT //Power Up Timer
#FUSES NOCPD //No EE protection
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //No Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES NOPBADEN //PORTB pins are configured as digital I/O input channels on RESET
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#FUSES NOCPB //No Boot Block code protection
#FUSES NOMCLR //Master Clear pin disabled
#FUSES LPT1OSC //Timer1 configured for low-power operation
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PLL1 //No PLL PreScaler
#use delay(clock=8000000, RESTART_WDT)
#byte PORTA= 0xF80
#byte PORTB= 0xF81
#byte PORTC= 0xF82
#byte PORTE= 0xF84
/************************************************************************
* Registros USART *
************************************************************************/
#byte SPBRG= 0xFAF // Registros para establecer la velocidad
#byte SPBRGH= 0xFB0 // de la USART
#byte RCSTA= 0xFAB // Registro de recepcion de la usart
#byte TXSTA= 0xFAC // Registro de emisión de la usart
#byte RCREG= 0xFAE // Aquí se recibe el dato de la usart
#byte PIR1= 0xF9E // Estado de interrupciones de periféricos
#byte PIE1= 0xF9D // Activación de interrupciones de periféricos
#byte BAUDCON= 0xFB8 // Control de la velocidad en baudios
#bit SPEN= RCSTA.7 // Bit activación puerto serie
#bit RX9= RCSTA.6 // Activación de recepción de 9 bits
#bit SREN= RCSTA.5 // Se activa para recibir un sólo byte
#bit CREN= RCSTA.4 // Se activa para recepción continua
#bit ADDEN= RCSTA.3 // Autodetección de dirección
#bit FERR= RCSTA.2 // Error de Frame
#bit OERR= RCSTA.1 // Error de Overrun
#bit RX9D= RCSTA.0 // El noveno bit
#bit BRGH= TXSTA.2 // Selección de alta velocidad
#bit BRG16= BAUDCON.3 // Uso de un valor baudrate de 16 bits
#bit SYNC= TXSTA.4 // Selección de modo síncrono o asíncrono
#bit RCIF= PIR1.5 // Señalizador de byte recibido en USART
#bit RCIE= PIE1.5 // Activación de la interrupción USART
/************************************************************************
* Pinout *
************************************************************************/
#bit Relay0= PORTB.0 // Salida a relés
#bit Relay1= PORTB.1
#bit Relay2= PORTB.2
#bit Relay3= PORTB.3
#bit Relay4= PORTB.4
#bit Relay5= PORTB.5
#bit Relay6= PORTB.6
#bit Relay7= PORTB.7
#byte Relays= PORTB
#bit Dip1= PORTA.6 //Entrada DIP
#bit Dip2= PORTA.5
#bit Dip4= PORTA.4
#bit Dip8= PORTA.3
#bit Dip16= PORTA.2
#bit Dip32= PORTA.1
#bit Dip64= PORTA.0
#bit Dip128= PORTC.1
#bit Dip256= PORTC.0
#bit DMXRX= PORTC.7 // Entrada RX desde el 75176
/************************************************************************
* Estados protocolo DMX *
************************************************************************/
#define DMX_ESPERA_BYTE 0
#define DMX_ESPERA_BREAK 1
#define DMX_ESPERA_START 2
#define DMX_ESPERA_DATO 3
#define DMX_RECEPCION_DATOS 4
/************************************************************************
* Variables globales y constantes *
************************************************************************/
char CONST SEGM[36]= { // Esta variable tiene la representación gráfica de cada dígito en 7-seg
// 0 1 2 3 4 5 6 7 8 9
/* Números */ 63,6,91,79,102,109,125,7,127,111,
// A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
/* LETRAS */ 119,124,57,94,121,113,125,118,6,30,118,56,84,84,63,115,103,80,109,120,62,28,28,119,110,91};
int16 direccion0;
int8 DMX_Estado = DMX_ESPERA_BREAK; // Estado de la máquina de estados
int8 DatoRX; // Dato genérico recibido en USART
int16 DMX_Indice = 0; // Apuntador a una posición de la trama DMX
#define TotalCanales 512 // Total canales a almacenar
#define NumeroCanales 8 // Canales a usar
int8 TramaDMX[TotalCanales]; // Trama completa de valores DMX
union // Estructura para hacer una copia del registro RCSTA
{
unsigned char registro;
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 ;
}Copia_RCSTA;
int LeeInt(){
int16 number;
number=0;
if(Dip1) number+=1;
if(Dip2) number+=2;
if(Dip4) number+=4;
if(Dip8) number+=8;
if(Dip16) number+=16;
if(Dip32) number+=32;
if(Dip64) number+=64;
if(Dip128) number+=128;
if(Dip256) number+=256;
return (number);
}
/************************************************************************
* Interrupción RDA: dato recibido por la USART *
* Esta interrupción se activa cada vez que se recibe un dato en la *
* USART. Mediante el control de una máquina de estados se determina *
* la validez y el significado del dato recibido, y se obra en *
* consecuencia. *
************************************************************************/
#int_rda
void Dato_Recibido_USART(void)
{
while (RCIF) // ejecutamos mientras haya un dato pendiente de procesar
{
// Hacemos una copia del registro RCSTA porque sus bits cambian de valor
// al leer RCREG y modificar CREN
Copia_RCSTA.registro = RCSTA;
// En RCREG está el dato que acaba de recibir la USART
DatoRX = RCREG;
// Si se reciben más de 3 bytes sin haberlos procesado, se produce un error
// de Overrun. En este caso, se borra el error reiniciando CREN y dejamos
// la interrupción preparada para procesar la siguiente trama DMX
if (Copia_RCSTA.bits.OERR)
{
CREN=0;
CREN=1;
DMX_Estado = DMX_ESPERA_BYTE;
return;
}
// Máquina de estados
switch (DMX_Estado)
{
case DMX_ESPERA_BYTE: // si estamos en este estado y hay error FRAME
// es que nos ha pillado en medio de un Byte. Hay que seguir esperando
// hasta que desaparezca el error.
if (!Copia_RCSTA.bits.FERR)
// Ha llegado un byte. Ahora esperaremos la señal Break
DMX_Estado = DMX_ESPERA_BREAK;
break;
case DMX_ESPERA_BREAK: // estamos esperando la señal Break
// Esta señal se identifica porque aparece el error de Frame
if (Copia_RCSTA.bits.FERR)
// Tras recibir el error de Break, hay que esperar un byte de valor 0
if (!DatoRX)
DMX_Estado = DMX_ESPERA_START;
break;
case DMX_ESPERA_START: // ya hemos recibido el Break y ahora hay que
// esperar un Byte con valor 0, que será la señal de Start
// Mientras tanto, si recibimos un error de Frame, hay que volver a
// empezar para recibir la señal de comienzo de trama.
if (Copia_RCSTA.bits.FERR)
DMX_Estado = DMX_ESPERA_BYTE;
else {
if (!DatoRX)
{
// Llegados a este punto, ya hemos recibido el Byte Start=0
// y comenzamos la trama de valores DMX.
DMX_Indice = 0;
DMX_Estado = DMX_RECEPCION_DATOS;
} else
// Si el dato recibido no es 0, volvemos a empezar
DMX_Estado = DMX_ESPERA_BREAK;
}
break;
case DMX_RECEPCION_DATOS:
// En este estado estamos recibiendo la trama de datos DMX
// Si se detecta un error de Frame es que ha habido un error y estamos
// al principio
if (Copia_RCSTA.bits.FERR)
if (!DatoRX)
DMX_Estado = DMX_ESPERA_START;
else
DMX_Estado = DMX_ESPERA_BYTE;
else
{
// Almacenamos el dato recibido en nuestro array
TramaDMX[DMX_Indice++] = DatoRX;
// Si ha llegado al final de la capacidad, cambiamos al estado de espera
// de nueva trama
if (DMX_Indice >= TotalCanales)
DMX_Estado = DMX_ESPERA_BREAK;
}
break;
}
}
return;
}
//No se usa
int16 pow(int16 base, int16 exp){
if(exp==0) return 1;
int16 index;
for(index=0; index<exp; index++){
base*=base;
}
return base;
}
void main()
{
int8 DMX_Subindice;
int8 RelesDMX[NumeroCanales]; // Canales a usar
// Configuración de Entradas / Salidas
// Puerto A: del 0 al 6 entradas de los DIP
set_tris_a(0b01111111);
// Puerto B: Todo salidas a los relés.
set_tris_b(0x0);
// Puerto C: Entradas 0 y 1 del DIP. Resto salida. El pin RX de la usart se pone
// como entrada al configurar la USART.
set_tris_c(3);
// Puerto E: solo tiene un pin (E3) y se usa como entrada de los DIP
set_tris_e(0x08);
// Configuración del micro:
// - oscilador interno a 8 MHz
// - entradas analógicas desactivadas y Vref desactivada
// - CCP1 activo para PWM
// - comparador desactivado
// - Timer0: interno, con prescaler 64 y a 8 bits
// - Timer1, 2 y 3: desactivados
// - Watchdog activado
// - Sin detección de bajo voltaje
setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_31250|OSC_PLL_OFF);
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
//setup_ccp1(CCP_PWM);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64|RTCC_8_bit);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,1,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
// setup_wdt(WDT_ON);
setup_low_volt_detect(FALSE);
// Configuración de la USART
BRGH=1; // Alta velocidad seleccionada.
BRG16=1; // Baudrate de 16 bits
SYNC=0; // Seleccionamos transmisión asíncrona
SPBRG=7; // A 8MHz representa Baudios = 250KHz
SPBRGH=0;
RX9=1; // Activada la recepción a 9 bits
SREN=0; // Desactivada la recepción de un sólo byte
ADDEN=0; // Desactivada la autodetección de dirección
FERR=0; // No hay error de frame
OERR=0; // No hay error de overrun
SPEN=1; // USART activada
CREN=1; // Recepción activada
// Activamos las interrupciones de recepción de la USART y del Timer0 (displays)
enable_interrupts(INT_RDA);
//enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
Relays=0x0;
while(1) {
direccion0=leeInt();
for(DMX_Subindice=0; DMX_Subindice<NumeroCanales; DMX_Subindice++){
if((direccion0+DMX_Subindice)<TotalCanales){
RelesDMX[DMX_Subindice]=TramaDMX[DMX_Subindice+direccion0];
}
else RelesDMX[DMX_Subindice]=0;
}
//////////////////////////////////////////////////////////
if(Dip16)
RelesDMX[3]=140;
else RelesDMX[3]=120;
////////////////////////////////////////////////////////////
/*
//0
if(RelesDMX[0]>=140){
Relay0=1;
}
if( RelesDMX[0]<=120){
Relay0=0;
}
//1
if(RelesDMX[1]>=140){
Relay1=1;
}
if( RelesDMX[1]<=120){
Relay1=0;
}
//2
if(RelesDMX[2]>=140){
Relay2=1;
}
if( RelesDMX[2]<=120){
Relay2=0;
}
//3
if(RelesDMX[3]>=140){
Relay3=1;
}
if( RelesDMX[3]<=120){
Relay3=0;
}
//4
if(RelesDMX[4]>=140){
Relay4=1;
}
if( RelesDMX[4]<=120){
Relay4=0;
}
//5
if( RelesDMX[5]>=140){
Relay5=1;
}
if( RelesDMX[5]<=120){
Relay5=0;
}
//6
if( RelesDMX[6]>=140){
Relay6=1;
}
if( RelesDMX[6]<=120){
Relay6=0;
}
//7
if( RelesDMX[7]>=140){
Relay7=1;
}
if( RelesDMX[7]<=120){
Relay7=0;
}*/
//También quiero desactivar un pin de pwm en todos los lados que haya que desactivarlo, de momento no quiero pwm...
for(DMX_Subindice=0; DMX_Subindice<NumeroCanales; DMX_Subindice++){
if(RelesDMX[DMX_Subindice]>=140){
bit_set(Relays, DMX_Subindice);
}
else if(RelesDMX[DMX_Subindice]<=120){
bit_clear(Relays, DMX_Subindice);
}
}
};
}