Webcampista.com

mucho más que un foro

Dmx

:scratch: El ciclo de red ya lo sabes... creo que no lo he entendido, a ver cuando vea el código, pero si esto no es importante, dedícate a estudiar, que sin darte cuenta, se te pasa el tiempo, como me ha pasado a mi "recopilando" instrucciones... :(


Creo que no piensas usar instrucciones ¿puede ser? este es un caso típico para usarlas, por que además son cada mucho, bueno, ahora que lo pienso, si vas a recibir DMX las necesitas ¿no?

¡oye! He puesto instrucciones y quería decir interrupciones. Es un caso en el que las interrupciones vendrían bien.


Mucha suerte con los exámenes
 
Ya dije yo que no era muy coherente :scratch:

Ya, lo mas seguro es que se haga así.
 
Esto es lo que tengo de momento y que estoy a la espera de probar, partiendo del código que encontré en Micropic.

Es el del relé DMX. Lo de la USART es del autor del código y el main modificado por mi. Tenía que haberlo pasado antes.


Código:
            /************************************************************************
             *                    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);
                     }
         
            
                  }
            
         
            
               };
            }

Desde luego he de limpiarlo si funciona.
 
Sin mirarlo a fondo, parece que puede funcionar. Y no lo parece, pero la interrupción serie hace lo mismo que la otra de ensamblador, aunque muchísimo más claro, eso sí, pues "llama a las cosas por su nombre", me refiero a los estados. Observa que en cuanto algo va mal, desecha la trama entera, lo que hablábamos de que la velocidad de refresco del DMX no es crítica, ya vendrá otra trama.

¿Está hecho con CCS C? me suena lo de poner #int_rda al principio de la rutina.
 
Sí, CCS C, que me costó lo suyo encontrar el compilador.
 
En el tema de los relés tienes código ineficiente.

Por ejemplo
PHP:
                  if( RelesDMX[7]>=140){
                     Relay7=1;
                  }
            
                  if( RelesDMX[7]<=120){
                     Relay7=0;
                  }

Eso se puede mejorar así.
PHP:
                  if( RelesDMX[7]>=140){
                     Relay7=1;
                  } 
            
                  else
                  
                  if( RelesDMX[7]<=120)  {   
                  Relay7=0;   
                  }

de esta manera, si RelesDMX[7] es >= de 140, ya no hace ninguna comparación más. En estos casos estaría bien saber cual de las dos se da con más frecuencia, si es que se puede saber y si es que hay una que predomine más que la otra, en ese caso, es mejor ponerla primero, así solo se ejecuta una comparación la mayoría de las veces y el código resultante es más rápido en general.
 
Me gusta esa. Lo hice así por mi odio a los else if, que no me aclaro con ellos (o al menos no me compilaba en navidades una cosa de VHDL y lo dejé por eso). Desde luego no está limpiado a expensas de que funcione (y el programador no llega, putos chinos. Ebay está tardando ahora 4 semanas en que las cosas lleguen :triste:).

Aunque esa parte está comentada y la que uso es un bucle for, ya que no sabia como hacer referencia con el indice del for al puerto en cuestion a encender apagar. Sí, es menos eficiente (o no, no lo sé realmente), pero como aqui no me es clave lo quise hacer con un for por gusto:

PHP:
                  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);
                     }
         
            
                  }

Ahora que lo veo, aquí si que tengo puesto el else if. Y ahora que lo pienso, como on y off son equiprobables, si tuviese que poner una delante pondría el apagado, por eso de la seguridad del sistema (si estoy manejando un telon, ante un error a mitad del if prefiero que se pare a que se siga moviendo). Es un poco chorra el criterio, pero alguno ha de haber.
Una pregunta, este código actualiza el estado del canal en cada pasada, ¿esto ocasionaría un parpadeo en cada iteracion (microencendido o microapagado por la actualizacion)?
 
Me gusta esa. Lo hice así por mi odio a los else if, que no me aclaro con ellos (o al menos no me compilaba en navidades una cosa de VHDL y lo dejé por eso). Desde luego no está limpiado a expensas de que funcione (y el programador no llega, putos chinos. Ebay está tardando ahora 4 semanas en que las cosas lleguen :triste:).

Aunque esa parte está comentada y la que uso es un bucle for, ya que no sabia como hacer referencia con el indice del for al puerto en cuestion a encender apagar. Sí, es menos eficiente (o no, no lo sé realmente), pero como aqui no me es clave lo quise hacer con un for por gusto:

PHP:
                  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);
                     }
         
            
                  }

Ahora que lo veo, aquí si que tengo puesto el else if. Y ahora que lo pienso, como on y off son equiprobables, si tuviese que poner una delante pondría el apagado, por eso de la seguridad del sistema (si estoy manejando un telon, ante un error a mitad del if prefiero que se pare a que se siga moviendo). Es un poco chorra el criterio, pero alguno ha de haber.
Una pregunta, este código actualiza el estado del canal en cada pasada, ¿esto ocasionaría un parpadeo en cada iteracion (microencendido o microapagado por la actualizacion)?

No creo que genere parpadeo, si el dato no cambia.

Lo de los else if, depende del compilador, cuando tengas problemas: pon llaves, el MCC18 de Microchip tiene ese problema. Además, ten en cuenta que en todos los compiladores, si pones else if, ese else solo tiene una instrucción: el if, y ninguna más, esto puede hacer que pongas alguna instrucción detrás pensando que está dentro, y no está dentro.


PHP:
if (loquesea) then
	{
		tarari;
	}
	else {   // Atención a este corchete
		if (otra cosa) then
		{ 
			niananiana;
		}

		else {	 // y este otro.
			if (la tercera) then
			{
				la ultima; 
			} // acaba este if
		} // acaba el segundo else
	} // acaba el tercer else



// Atención a este caso, 

	if (condicion) then
		haz algo  // una sola instrucción, no hace falta corchetes y NO se pone punto y coma
	else if (otra condicion) then
		haz otra cosa // una instrucción, no hace falta corchetes y NO se pone punto y coma
	else if (la ultima) then
		ultima instruccion; // está SÍ que lleva punto y coma, aunque no pongas corchetes

// la última instrucción cierra todo el if, 


// Otro caso
	if (condicion) then
		haz algo  // una sola instrucción, no hace falta corchetes y NO se pone punto y coma
	else { // pongo corchete
		if (otra condicion) then
			haz otra cosa // una instrucción, no hace falta corchetes y NO se pone punto y coma
	else if (la ultima) then
		ultima instruccion; // está SÍ que lleva punto y coma aunque no pongas corchetes
	} //este corchete cierra el anterior, pero no lo parece,
 
Traigo buenas noticias de la mano de la electrónica analógica. He conseguido diseñar e implementar un filtro pasobajo con frecuencia de corte a 3 dB de 25 Hz y de 51 dB a 200 Hz, cumpliendo mis espectativas del PWM para obtener mi señal analógica. El filtro es un filtro de Butterworth de orden 3 implementado con un pasobajo RC en cascada con una celda activa de Sallen-Key. Con esto cumplo mis especificaciones y la respuesta del dimmer es buena.
Me he tirado toda la tarde montandolo en un PCB universal y este es el resultado. Queda probarlo.
photo_2015-06-07_00-19-17.jpg
 
No has escrito para que te lo digamos pero... ¿has estudiado para los exámenes?... :rolleyes: :D que uno se pone con esto y se olvida del mundo...
 
Tenia unas horitas ayer (y la muela del juicio dando por saco).
 
¿Dos semanas ya de la última respuesta? Madre mía... Pues eso, que examenes--, aprobados+=2 y DMX++.
En primer lugar me he hecho una interfaz DMX casera para el FreeStyler, con un FTDI, un 75176 y una caja de aluminio. Queda DPM. Luego he montado el PWM en otra caja y también DPM, con conectores DIN y XLR. Finalmente estuvo mi amigo por los madriles, se trajo el pickit y hemos grabado en un 2550 el código este del relé DMX. Tenía un bug gordo, y es que no leía las direcciones 256-512. Era porque la funcion de leer Dip tenía el retorno forzado a int[8] y claro, el 9º bit nada de nada. Ahora va dpm. Y cuando examenes=0 lo montaré en una caja y lo acabaré. También me dejó grabado el sw de un Pickit2, porque el que compré no llega y acabaré haciéndome uno.
 
https://youtu.be/7812dngARbk

Pues eso, que álgebra done. Puedo aprobar o suspender, ahí está. Y hasta septiembre nada.

Tema DMX. Nos hemos metido en el fregado de hacer un dimmer DMX. La idea de código: basicamente una interrupción debido al cruce por cero tal que pone los triacs a cero y reinicia el temporizador. Luego está la USART que lee el DMX y finalmente el main que coge los canales DMX asignados por los DIP y para esos canales lee en una tabla (array) si el tiempo calculado para el valor DMX presente en el canal es mayor que el temporizador. Si lo es activa la salida hasta el siguiente cruce por cero.

No se si así valdría, teniendo en cuenta todo lo que hay que tener.
 
He tardado en responder por que quería enterarme con calma. Ahora el wifi hace cosas raras y me toca hacerlo desde el movil...

¿El dimmer es de un canal o de tres?
A priori la idea es buena, si la he entendido bien. Vas a hacer que el temporizador interrumpa 256 veces entre dos pasos por cero, y cada vez compararás los valores y actuarás en consecuencia ¿es eso? Si tienes tiempo de computación para hacerlo, perfecto. Para evitar parpadeos tendrás que dar a ese temporizador más prioridad que a la interrupción serie. Si la interrupción serie interrumpe justo cuando estás poniendo a uno o cero la salida, ese uno o cero durará más de lo que tenía que durar.
Además no puedes cambiar el valor del dato hasta el siguiente paso por cero, aunque lo recibas, si lo haces, puede pasar que el valor anterior sea 100, al llegar a 101 apagas, pero antes de llegar al 0 de nuevo recibes el 200, y lo vuelves a encender, generando parpadeos. Esto me hace pensar que necesitas o bien dos arrays uno para recibir y el otro para procesar o no hacer caso a lo que recibas hasta el siguiente paso por cero. En las rutinas que puse antes se utiliza el último modo, así no hay tanto que tratar. Es el bit "Entratamiento, "tratando" o algo así, si estuviera en el PC lo buscaba :(

Si no te aclarad con lo que digo, dímelo y lo intento explicar de otro modo.
 
Por cierto, pon optoacopladores que incluyan lo del paso por cero, cuestan lo mismo y te ahorra muchos problemas, incluso disimula algunos fallos de programación.
 
El problema es que tiramos a lo grande: 12 Canales (yo no pago) y una fase. Sé las limitaciones de potencia pero ese no es el propósito.
Respecto al código no es exactamente así como lo has dicho. Tu planteas 3 tipos de interrupciones: USART, cruce por cero y temporizador, y que el temporizador interrumpa un número determinado de veces (256, que no han de ser por los 256 niveles, o incluso más) y que en cada instante compruebe para cada canal DMX el valor DMX presente y si es mayor o menor que el seteado para cada instante de tiempo en la tabla encienda o apague el opto, aparte de la subrutina de copiado del array. Yo lo planteaba de otra forma: en vez de ser el temporizador el que interrumpa, que sea el main quien vaya pooleando todos los canales DMX ya copiados y filtrados según la dirección (la USART recibe todo, pero sólo se copian los 12 canales posteriores a la dirección fijada por el DIPSW) y para cada uno de ellos que consulte el temporizador global (acceda a su cuenta), y según el valor dmx del canal acceda a una tabla de tiempos y active o no la salida if(cuenta>=tabla_mapping[canales_DMX[1]]) triac1=1; Luego sería la interrupción de cruce por cero la que apagaría todas las salidas y reiniciaría el temporizador, así como veo conveniente que también se encarge de la subrutina de copiar del array de la USART los canales a usar según la dirección. No se si esto sería factible o no como lo planteo (he investigado y acceder a la cuenta del contador requiere de structs y cosas así, sobre todo porque necesitaría 16 bits), si no siempre quedará la opción inversa, que sea el temporizador quien compruebe los valores. En cualquier caso me has dejado claras 2 cosas que me eran importantes y dudaba: la prioridad de la interrupción de cruce por cero debe ser mayor que la de la USART y que han de copiarse los valores de los canales del array de la USART para evitar parpadeos.

Y una cosa, si pongo optos de cruce por cero me quedo sin dimmer (solo encienden en los pasos por cero y lo que quiero es controlar ese punto de disparo).
 
Eso es lo que yo dudaba, que a 4Mhz tuvieras tiempo de hacerlo todo.
Pero algunos detalles. No me extiendo que me están esperando.
Para un foco 256 niveles son hasta demasiados, pero es que, suponiendo que necesites más niveles, necesitas otro byte DMX, eso convierte los 12 canales en 24, salvo apaños raros de compartir un byte para dos de 12 bits.

La interrupción menos importante es la de recepción DMX, por que no importa que te saltes datos, llegarán nuevos. Es más importante que el valor "108" tenga siempre la misma distancia para evitar parpadeos, además de empezar y acabar en el mismo momento del ciclo para que la tensión eficaz sea la misma, por eso temporizador (o bucle) y paso por cero deben ir sincronizados y a eso ayudan los optos, pero eso lo puedes comprobar fácilmente cambiando uno por otro. Para evitar ruidos en la red, incluso hacer que la lámpara dure más, la conmutación debería hacerse cuando la tensión sea cero, eso solo lo asegura el opto que lo tenga, pero ya digo que es fácil de comprobar.

Que haya tres interrupciones no es tan complicado, lo importante es decidir la prioridad, y cuando acabe una se tratará la otra o la prioritaria interrumpirá a la que no lo es. Hacer estas cosas con bucles en main es delicado precisamente por que cualquier interrupción puede hacer que un bit dure más de lo que tocaba, o eso, o inhibes todas las interrupciones dentro del bucle, que se puede hacer. Creo que es lo que hago en el anterior.
 
¿Exactamente que hace un opto con cruce por cero? Yo entiendo que si la tensión de la red pasa por cero en pi y 2*pi y vas y tu atacas el optotriac en pi/2, por ejemplo, de tal modo que el optotriac y el triac se enciendan desde pi/2 hasta que el triac corte en pi. Si usas un optotriac con cruce por cero te retrasa el disparo hasta que la tensión llegue a 0, o sea te lo retrasa el encendido desde pi/2 a pi. De este modo activas la carga siempre en multiplos de k*pi, encenderías siempre en k*pi hasta (k+1)*pi. Sin embargo con esto te cargas la regulación, ya que al encender siempre en k*pi hasta (k+1)*pi no eres capaz de controlar la fase, y por ende el valor rms, que es en lo que se basa el control del dimmer. Por eso yo tenía entendido que opto de cruce por cero sólo para conmutación on-off (luego pudes hacer dimmerización controlando el número de semiciclos ENTEROS que enciendes, pero ya no es tan habitual). A lo mejor me equivoco pero es lo que creo.
 
Piénsalo de esta manera. Tu quieres activar el triac durante 3ms, si lo activas justo en el paso por cero, la lámpara (si eso lo que estás controlando) se encenderá muy poco, pero si los activas justo en medio, cuando la tensión está más alta, se encenderá mucho más, aunque sigan siendo 3ms. Es importante que la activación sean siempre en el mismo momento. Por eso se sincroniza con lo más fácil, el paso por cero.
También es por el ruido eléctrico generado, si activas el foco justo en cero, no metes tanto ruido, el de desactivación lo vas a tener siempre, hagas como lo hagas. Solo el triac de paso por cero te lo asegura, por que si lo haces a través de la interrupción, cuando quieras activarlo la tensión ya no está en cero, será poco, pero no cero.

Lo mejor es que lo compruebes tú mismo, cuestan lo mismo y si la programación está bien hecha, desde fuera, no se va a notar la diferencia.




Esto ya son recuerdos y puedo estar equivocado, pero me suena algún control "analógico", un "seguidor de ritmo" las luces que se encienden al ritmo de la música, sin sincronización ni leches, que funcionaba bien, gracias a esos optos.
 
El problema es que el triac es un tiristor y solo se apaga cuando la corriente a través de el es cero, tension cero para cargas resistivas, de tal modo que solo puedes controlar el instante de encendido, el de apagado te lo marca el triac, por eso no te vale el de cruce por cero, porque tu aunque quites la tension de puerta no se apaga el triac hasta que la tension llegue a cero, por eso si disparas en cero, hasta que la tension no vuelva a cero el triac no se apaga.
 
Tirando otra vez de recuerdos. Ya sé por qué funcionaba sin sincronización. El circuito funciona rectificando y filtrando la señal de audio, esto nos da una tensión continua que depende del nivel de esa señal. Y ya está. Si aplicas esta señal continua directamente al led del optoacoplador (adaptando niveles máximos, claro) ya tienes una lámpara que se enciende al ritmo de la música, los pasajes más altos, con más luz, música bajita, menos luz. Pero solo funciona bien si es con un opto de paso por cero, por que por muy grande que sea la señal, empieza a conducir en 0, y se corta cuando la señal (la continua sacada del filtro) no es suficiente para activar el led.

Seguro que hay algún esquema por la red.
 
Te colaste mientras escribía y buscaba el esquema, que no he encontrado.

Si no ten convenzo, no pasa nada deja eso para el final, a lo mejor no es tan crítico.
 
Ya tenemos el codigo funcionando para 12 ch. El sistema va a 48 Mhz y regula de maravilla. Al final hemos hecho la idea que planteas de dividir los 10 ms en 256 ranuras y con un temporizador contar 39 uS (10 ms/256) y al interrumpirse comprobar que canales hay que disparar porque ya toque y ranuras++. Por otro lado está el cruce por cero, que reinicia el contador de ranuras y apaga los triacs, así como copia la trama de la usart y la pasa por el mapping lineal (hemos conseguido que la potencia media sea lineal al DMX gracias a Matlab®). Además creo que le pondremos analógico con el ADC (6 entradas sólo con mapping doble) Cuando esté debuggeado te lo paso. Además convertirlo en un pwm para DAC sería fácil (apagar salidas en ranura 255 quitando el cruce por cero y subir la frecuencia de pwm todo lo que se pueda)
 
Arriba
© 2004-2024 Webcampista.com