# Desarrollo de cargador de direcciones DMX



## locodelafonola (Feb 9, 2014)

Hola gente... basicamente esto nació como una colaboracion de DJ WASH... y como saben me gusta compartir.. el hecho es que tengo una serie de archivos base.... y otros no tan base.... sobre el funcionamiento de estos equipos.. y ya saben que yo me construyo y desarrollo mis propios equipos de luces y maquinas afines. Lo aclaro......no trabajo de dj....y no fabrico equipos en forma comercial.....solo los hago por que me gustan.... y me ayudan a salir de una fuertísima depresión que tenía.....ocupando la cabeza en algo que me encanta y que puede ser util a otros...

Para juntar esa funciones...(todos absolutamente todos ) usan el atmega8515-16pu...estos codigos base..me los paso un amigo ruso..que baso su tesis en dmx....y aparte..... todo sus esquemas fueron comprados por una empresa alemana...... para la cual trabaja hoy... 

En si doy la razones para lo cual quiero desarrollar esto...varios saben que ando con los laser..bueno para que funcione bien.tengo que colocar un microprocesador.....ejemplo : el que yo diseñe..tiene dos laser uno rojo y otro verde.. los laser solo se pueden conmutar....no se pueden dinmerizar....

Tengo que controlar un motor pap.que mueve un vidrio..bueno esto tiene que ser muy lento....probe con un motor sincronico ...y un inversor de frecuencia variable... pero el motor tiene un punto que vibra y no gira... tiene su limite . y ademas tiene un led de 10w ultravioleta....que genera un fondo de luz negra sobre donde trabajan los laser..bueno... ese diodo led....se tiene que dimerizar... 

Otro ejemplo de lo que hago es la maquina de humo..era y digo era.... manual. le fabrique con la ayuda del foro un control remoto..y tambien la hice andar por dmx con un atmega..... ahora quiero cambiar su control de temperatura lo hacia por un termostato o bi-metalico de esos de plancha.... porque los chispazos consumen los contactos...... 4 resistencias de planchas puestas en serie paralelo....

Y el atmega que uso me da posibilidad de regular eso.. y aclaro que los codigos base son separados o sea motores por un lado.. servos por otro.. dimmer por otro... servos por otro matrix en uno aparte.. comutadores separado.. y para combinar las funciones ....es este artilugio.....entienden.. para realizar este diseño fabrique esto :


 





 

 

 


Para fabricarlo me guie por este esquema :


Tenia este otro : 

 

Pero sigue conservando las mini llaves aparte de tener tres botones. Y no cuatro.....y con respecto a esto quiero aclarar algo que veo mucho en internet....todos los desarrollos a nivel amateur....no tiene la reglas basicas de uso....y que quiero decir con eso....que son normas no escritas pero estan estandarizadas por el uso cotidiano..... 

Ejemplo : los digitos de carga..si queremos mostrar la direccion 255 ..tendria que mostrar D255..si le ponen tres digitos no sabes que estas leyendo..y lo demas no entienden nada...como he visto montajes con arduino....en equipos caseros funciona con la libreria para arduino DMX .....pero solo no... ni en forma manual..... otros sin direccionamiento dmx.....sin las llaves minidip....y el freestyler.....pero si pones otro equipo no anda .. asi infinidad de equipos...

Con respecto a lo que yo quiero desarrollar....ya me encuento con el primer "tapon"..los codigos base que me enviaron son para una pantalla 1x16....y el que yo consegui (no encontre el especificado ) es 2x16..o sea la libreria no es igual... adjunto los ejemplos de desarrollo de los dos esquemas ....estan en los .RAR......no se como ponerlos para que se vean... si son tan amables de decirme como lo hare....espero sus comentarios...o si necesitan algo mas que yo tenga...

Juan


----------



## locodelafonola (May 31, 2014)

El LCD y el micro los conecte así:​

Se está conectando el cristal de 8MHz con los capacitores, en la imagen tenéis como los conecté.
Lo dejé igual al montaje del dibujo pero no logro que funcione la pantalla.
Juan.​


----------



## cosmefulanito04 (Jun 1, 2014)

Te dejo mi librería para manejar el LCD, esta sé como funciona y no vas a tener problemas, lo único a tener en cuenta es que usa el timer0 de manera esporádica, pero en caso de ser necesario eso se puede modificar. Tenés que mandar el hex y ver si funciona, la conexión se mantiene.


----------



## locodelafonola (Jun 3, 2014)

hola cosme ... bueno ...... se me ocurrio hacer algo ..... una prueba que talvez te sirva el dato ... y te lo pongo en la imagen  ....te aclaro que es el mismo archivo que me pasaste sin cambios ........  me es mas facil explicartelo graficamente (perdona el dibujo ...... pero me lleve jardin de infantes a marzo ) ..... lo probe tanto con la alimentacion sola ... 5v y gnd ...como en la placa con el cristal .... los puntos rojos son los que destella el led ..... los puntos amarillos son los puertos que no destellan .... los grices ... son donde se prende permanentemete los negros no se prenden .... el led lo conecte asi .....  A (anodo) a 5v .... K (katodo) mas resistencia de 390Ω ...... al pin de prueba ...... el led (rojo opaco) visualmente seve que parpadea ..... trate de grabar un video pero en la imagen del video no se nota ....... pero el destello es menor a 5 segundos ....... tambien menor a 1 segundo .... es rapido tipo flahs ... bueno tambien te muestro una captura de los fuses de un atmega virgen  ....... no quise grabarlo ......  hasta mostrartelo bueno espero que sirva de algo ...... juan


----------



## locodelafonola (Jun 3, 2014)

bueno amigaso ... destilde la casilla del fuse..y los grabe con la configuracion nueva ... probe la librerias de puertos ...y ahora es mas lento ... y el ensendido del led es mas fuerte ..... probe con la alimentacion sola (5v y GND )...y tambien con la placa ..... probe primero la primer libreria.la que hiciste a partir de dmx ....esa no funciono.... se veian los caracteres de la primer hilera igual a la foto .... y probe tu libreia ... !!!!! yyyyy bbbbbuuuuualaaaaa ¡¡¡¡¡¡ funciono aca esta el video 



 ...bueno despues de eso hice otras pruebas .... volvi a cargar el .HEX  del servo-led .... no funciono daba error el led de señal DMX ....... cambie los fuses de nuevo (el que desmarque ) ........ lo volvi a poner y alli si funciono ........ yyy te aclaro que las llaves mini-dip .... si funcionaron ....... le cambie varias direcciones de inicio  ej: 1 .... 65.... 127... 248  y funcionan ...... porque si no le asignaba esa direccion programada (ej ) en las llaves .......  en el freestyler ...... no lo reconocia como tal ........ bueno espero que te sirva estos datos .... gracias amigo ....  juan


----------



## locodelafonola (Jun 4, 2014)

mira te soy sincero ..... eso me salio de suertudo que soy ..... por que te juro que si lo quiero hacer de nuevo no me sale ..... no sep...sera que estoy angelado.o que cuando construyo algo..trato de ser prolijo..y reviso las cosas 1.000.000.000 de veces ...... pero mis montajes salen andando a la primera ... (exepcion del fusebit doctor ) que crei que era el micro  y eran los trancistores con el patillaje mal (nuevos ) en el post #20  tenes lo que seria un proyecto de led"S completo (SIN DRM) para no complicarnos la vida ... aparte la consola que tengo no puede trabajar con DRM (dinoelectro ) ..... vendria siendo como esto Ver el archivo adjunto 104195 Ver el archivo adjunto 104196 ...  son led solamente y el programa ya lo probe funciona ....no tiene esenas guardadas ni tampoco funciona con sonido ........ aca te pongo un video del efecto que tiene los digitos y los cuatro botones .......  para que veas como funciona con un cargador de direcciones 



 sip .. ... (ya se esta en ruso)  .......  pero lo importante es que veas lo que hace  .... igual a este que no explica tanto pero muestra que hace ....  



 pero nos vallamos tan lejos .... lo primero seria unir el primer archivo y el del lcd  y tratar de cambiar con los botones ....... la direccion de inicio ( el set del universo ) que va de  o a 511  ( de 1 a 512 en la practica )  el cero no existe ( es inicio o beak) ...... y poder guardarlo en la memoria (no se bien cual seria el lugar para guardarlo ) solamente eso y nada mas  ..... si tiene led o no .........  no importa eso lo vemos luego .... o sea la  libreria que esta aqui Ver el archivo adjunto 111070 y el LCD (el tuyo o el del ruso ) en la del ruso estan las sentecias ya fijadas para hacer eso  .......  y que ademas va alli (esta colocado donde irian las llaves mini-dip)..... fijate las senteccias de la libreria ... de entrada da eso (esta explicado en el PDF)..y algo para tomar en cuenta..fijate que con la llaves toma 10 puertos del uC .... 8 del puerto C y dos del puerto E .el restante puerto E0 .... se usa como indicador o tester de señal (DMX y eslave) que seria el port D7 esos puertos esta configurados en la libreria de inicio como asi los tienpos de funcionamiento .... esas van si o si.. si no entendes algo otenes dudas preguntame .... asi veo como te aclaro la cosa ....... empezemos por alli ... y solo eso encuanto a las librerias que usa fijate  te subo el txt ........ de lo que se leee en la carpeta DEP pues alli puede ser que veamos que mas hace falta .... juan


----------



## locodelafonola (Jun 11, 2014)

bien cosme ...... esa era mi duda ...... justamente...pero no te lo sabia explicar.... la otra que tengo es que estube pensando ... si te fijas en el pdf de la libreria de recepcion ..hay un anagrama de funcionamiento .... y por lo que desducis vos ..... ( y si lle sumas lo poco que se )jajajajajajajaja esas rutinas que ejemplifican para el inicio.... ¿¿¿¿¿ ninguna llama al watch dog ???? ... .o sea a mi entender si una sentencia no se cumple .....por un error de lectura o medicion .. ¿¿¿¿ no dice en voz alta ........ pichicho...... pichicho .... y  viene el bobi ???? de alli mi duda ..... pero bueno vos sabes ...yo ni idea !!!!!!  bueno aca te subo las librerias que encontre ........ tal vez alla alguna por alli despelotada ...


----------



## cosmefulanito04 (Jun 12, 2014)

Antes de seguir con las pruebas, vamos a dejar claro esto, el protocolo DMX es el siguiente:







Cada canal es una dirección distinta y yo puedo fijar la dirección que quiera al equipo y por lo tanto tomara los 8 canales que le siguen (incluyendo la propia dirección asignada). 

Así que por ej. si se me ocurre fijar la dirección 0x08 en el equipo, los canales tendrán la siguiente dirección: 

- Canal 0 = 0x08
- Canal 1 = 0x09
...
- Canal 7 = 0x0F

Y en esas direcciones el equipo leera los datos enviados por la consola, que luego esos datos manejarán elementos distintos, leds, motores, etc. 

La lectura que hace la rutina DMX es básicamente esa, por lo tanto debiera funcionar, lo único que falta probar con el soft es ver que pasa con el:

- Watch dog.
- La dirección de la rutina de interrupción que tal vez no le gusta como está definida.

En cuanto al hard, verificar que toooodo esté bien conectado.


----------



## cosmefulanito04 (Jun 14, 2014)

Te paso el DMX original que me pasaste compilado con el AVR Studio 6. Tenés la versión sin minidip, donde la dirección es 1; después tenés la versión con minidip. En ambos casos se maneja el puerto D7 como ya te comenté antes.


----------



## dinoelectro (Jun 24, 2014)

Hola, locodelafonola, cosmefulanito y demás usuarios, he revisado el proyecto de cargador de direcciones DMX, me parece bastante interesante, y ya mismo me animo a construirlo.. 

Estuve investigando en la pagina de microchip y encontré un KIT de desarrollo de MICROCHIP para iluminación LED con DMX que contiene muchas herramientas y software interesantes para experimentar con esta tecnología nos dan toda la información de como construirlo.  mas información aqui: 

(http://www.microchip.com/DevelopmentTools/ProductDetails.aspx?PartNO=DM330014)


comparto con vosotros esta información para ver que de bueno puede resultar de todo esto  saludos! y suerte con vuestro cargador de direcciones DMX


----------



## cosmefulanito04 (Jul 14, 2014)

Si ven que las respuestas del tópico son un tanto inconexas, eso se debe a que fue limpiado, gracias *D@rkbytes* por el trabajo. 

Recapitulando un poco, hasta este punto *locodelafonola* había conseguido hacer funcionar el LCD y su principal meta era que el receptor pueda modificar la dirección del equipo mediante el uso de un menú usando botones y presentarlo en pantalla, para lo cual era necesario que el programa que subí en el mensaje #9 (el receptor) pueda combinarse con el resto de las librerías.

*- Librería receptor DMX:*

Esta librería la subió *locodelafonola*, que a su vez la consiguió de la siguiente página. Dicha librería pertenece a  *Hendrik Hölscher*.

*lib_dmx_in.h (versión que modifiqué)*


```
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

//#define  USE_DIP
#define  F_OSC			(8000)		  		//oscillator freq. in kHz (typical 8MHz or 16MHz)
#define  CANT_CANALES   8

volatile uint8_t	 DmxRxField[CANT_CANALES]; 		//array of DMX vals (raw)
volatile uint16_t	 DmxAddress;			//start address

extern void    init_DMX_RX(void);
extern void    get_dips(void);
```

*lib_dmx_in.c (versión que modifiqué)*


```
/**** A P P L I C A T I O N   N O T E   ************************************
*
* Title			: DMX512 reception library
* Version		: v1.3
* Last updated	: 13.04.09
* Target		: Transceiver Rev.3.01 [ATmega8515]
* Clock			: 8MHz, 16MHz
*
* written by hendrik hoelscher, www.hoelscher-hi.de
***************************************************************************
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version2 of
 the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 General Public License for more details.

 If you have no copy of the GNU General Public License, write to the
 Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 For other license models, please contact the author.

;***************************************************************************/

#include "lib_dmx_in.h"

// ********************* local definitions *********************

enum {IDLE, BREAK, STARTB, STARTADR};			//DMX states

volatile uint8_t 	 gDmxState;


// *************** DMX Reception Initialisation ****************
void init_DMX_RX(void)
{
#ifdef USE_DIP
DDRC   = 0;										//set up DIPs
PORTC  = 0xFF;
DDRE  &= ~((1<<PE2)|(1<<PE1));
PORTE |=   (1<<PE2)|(1<<PE1);
#endif

DDRD  |= (1<<2);
PORTD &= ~(1<<2);
UBRRH  = 0;										//enable reception
UBRRL  = ((F_OSC/4000)-1);						//250kbaud, 8N2
UCSRC  = (1<<URSEL)|(3<<UCSZ0)|(1<<USBS);
UCSRB  = (1<<RXEN)|(1<<RXCIE);
gDmxState= IDLE;
}



// ************* get DMX start address **************
void get_dips(void)
{
#ifdef USE_DIP
uint16_t Temp= (0xFF-PINC);						//invert DIP state
if (!(PINE &(1<<2)))
	{
	Temp += 256;								//9th bit
	}
if (Temp != 0)
	{
	DmxAddress= Temp;
	if (!(UCSRB &(1<<RXCIE)))					//if receiver was disabled -> enable and wait for break
		{
		gDmxState= IDLE;
		UCSRB |= (1<<RXCIE);
		}
	}
else
	{
	UCSRB &= ~(1<<RXCIE);						//disable Receiver if start address = 0
	uint8_t i;
	for (i=0; i<sizeof(DmxRxField); i++)
		{
		DmxRxField[i]= 0;
		}
	}
#endif
}



// *************** DMX Reception ISR ****************
ISR (USART_RX_vect)
{
static  uint16_t DmxCount;
		uint8_t  USARTstate= UCSRA;				//get state before data!
		uint8_t  DmxByte   = UDR;				//get data
		uint8_t  DmxState  = gDmxState;			//just load once from SRAM to increase speed

if (USARTstate &(1<<FE))						//check for break
	{
	UCSRA &= ~(1<<FE);							//reset flag (necessary for simulation in AVR Studio)
	DmxCount =  DmxAddress;						//reset channel counter (count channels before start address)
	gDmxState= BREAK;
	}

else if (DmxState == BREAK)
	{
	if (DmxByte == 0) gDmxState= STARTB;		//normal start code detected
	else			  gDmxState= IDLE;
	}

else if (DmxState == STARTB)
	{
	if (--DmxCount == 0)						//start address reached?
		{
		DmxCount= 1;							//set up counter for required channels
		DmxRxField[0]= DmxByte;					//get 1st DMX channel of device
		gDmxState= STARTADR;
		}
	}

else if (DmxState == STARTADR)
	{
	DmxRxField[DmxCount++]= DmxByte;			//get channel
	if (DmxCount >= CANT_CANALES) 		//all ch received?
		{
		gDmxState= IDLE;						//wait for next break
		}
	}
}
```

La única modificación que le agregué fue la definición de la cantidad de canales:


```
#define  CANT_CANALES   8
```

Y en el .c:


```
if (DmxCount >= CANT_CANALES) 		//all ch received?
```

La única ventaja con el original es que no usa la función "sizeof()" sobre el vector "DmxRxField", esto ahorra tiempo en el llamado de la función y por otro lado se evita una posible diferencia entre el tamaño real del vector (tipo de variable) con la cantidad de elementos. En GCC realizar un "sizeof()" sobre un vector del tipo "unsigned char" implica que la cantidad de elementos es igual a su tamaño final, sin embargo en AVR-GCC no llegué a comprobar si la función arroja un tamaño igual a la cantidad de elementos, por lo tanto para evitar problemas decidí modificar eso.

Con estas modificaciones el usuario *locodelafonola* comprobó que la recepción funciona sin problemas usando un cristal de 8MHz.

Resumiendo las funciones de la librería:

*- init_DMX_RX():* se encarga de inicializar la UART en 8bits de datos, con 2 bits de stop y una velocidad de 250kbps. Por otro lado usando un transreceptor SN75176A para convertir RS232-TTL en RS485 y viceversa, la librería se encarga de habilitar la recepción del integrado y deshabilitar la tranmisión mediante el uso del puerto PD2.

*- get_dips():* en nuestro caso esta función no nos resulta de utilidad, ya que la idea es reemplazar el uso del minidip por un menu manejado con pulsadores y el LCD.

*- ISR (USART_RX_vect):* será la rutina de interrupción de la UART que se manejará mediante una máquina de estados. Dichos estados serán IDLE (reposo, en espera del inicio de una trama), BREAK (quiebre, a la espera de la confirmación de inicio mediante un byte=0x00 => START CODE), STARTB (comienzo de trama, a la espera de la direcciones del equipo), STARTADR (comienzo de la dirección del equipo, se empieza a tomar los 8 canales del equipo). Se puede ver que sigue fielmente la trama DMX que subí en el mensaje #8.

Esto sería la parte central del proyecto, es decir la recepción de las tramas DMX. El resto es un agregado para darle mayor funcionalidad (LCD, Menus, Botones) que no valen la pena explicar, pero que el código será subido y en caso de que haya algún interesado se puede explicar más detalladamente.

Sin ir más lejos, la parte principal del código (el main) es el siguiente:


```
//-------------- Definiciones de tipos de variables
typedef unsigned char			u8;
typedef unsigned int			u16;
//-------------- Definiciones de tipos de variables

//-------------- Variables globales de interrupciones
volatile u8 flag_timer0=0;
//-------------- Variables globales de interrupciones

#include "lib_dmx_in.h"
#include "rutinas_de_interrupcion.h"
#include "funciones_perifericos.h"
#include "funciones_LCD.h"
#include "funciones_utiles.h"
#include "menu.h"

int main(void)
{
	u8 estado_antireb=ANTI_REB_IDLE;
    u8 cont_canales;

	cli();
	DDRA=0xff;

	init_DMX_RX();
	sei();

	configurar_botones();
	inicia_lcd_4bits();
	leer_e_imprimir_dir_dmx();

	for(;;)
	{
		wdt_reset();
		get_dips();						//get start address

		for(cont_canales=0;cont_canales<CANT_CANALES;cont_canales++)
            {
                if (DmxRxField[cont_canales] >= 127)		//enable LED if 1st DMX val is >127
                    {
                        PORTA &= ~(1<<cont_canales);			//LED ON
                    }
                else
                    {
                        PORTA |= (1<<cont_canales);			//LED OFF
                    }
            }



		if(anti_rebote(BOTON_MENU,&estado_antireb)>0)
			{
				UCSRB  &= ~((1<<RXEN)|(1<<RXCIE));
				menu();
				leer_e_imprimir_dir_dmx();
				UCSRB  = (1<<RXEN)|(1<<RXCIE);  //Habilita la recepción
			}
	}
}
```

Las funciones que se llaman son:

*- configurar_botones():* configura los puertos a donde irán conectados los pulsadores como entradas. Estos puertos serán PE2=Menu, PE1=UP, PC7=DOWN, PC6=ENTER.

*- inicia_lcd_4bits():* inicializa el display en modo de 4 bits según la conexión que mostró *locodelafonola* arriba.

*- leer_e_imprimir_dir_dmx():* se encarga de leer en los bytes 510 y 511 de la memoria EEPROM, la última dirección DMX almacenada por el usuario para que tome el equipo y luego la imprima en el LCD.

*- wdt_reset():* resetea el contador del watch dog, evitando que el uC se resetee en normal funcionamiento. En caso de alguna falla, el watch dog reseteará el uC.

*- anti_rebote(...,....):* se encarga de preguntar si un cierto pulsador fue presionado o si se trató de un rebote. Para ello utiliza un máquina de estado.

*- menu():* genera un menú en el LCD (en este caso de una sola opción, el ingreso de una nueva dirección DMX), con posibilidad de agregar nuevas opciones al equipo.

El programa simplemente lee los 8 canales recibidos y en base a eso enciende o apaga los 8 leds del puerto A (un led por c/canal). La condición de encendido será que el dato recibido en un cierto canal sea mayor a 127 y viceversa. 

Con este programa bastante simple, se busca verificar que el equipo recibe tramas DMX, pueda visualizarse la dirección DMX actual por medio del LCD y permita modificar dicha dirección DMX mediante el uso de los botones.

Subo el proyecto completo, en este caso usé el IDE Code::Blocks, pero tranquilamente se puede armar en el AVR Studio sea 4, 5 o 6.

Próximamente subiré un programa que previamente subió el usuario *locodelafonola* que utiliza indicadores para verificar la presencia de la consola y si las tramas DMX fueron recibidas correctamente.


----------



## cosmefulanito04 (Jul 15, 2014)

Agrego un programa que permite ver por medio de leds el estado de la conexión DMX, más adelante el usuario *locodelafonola* explicará mejor lo que hace.

El programa consta de las librerías de:

- Recepción DMX (las vistas), con algunas modificaciones.
- LCD (las mencionadas).
- Botones y menú (las mencionadas).
- Indicadores de estado DMX (nuevas).

La idea es la misma que antes, que el equipo permita modificar su dirección DMX mediante un menú, mostrar dicha dirección DMX, pero ahora en vez de manejar 8 leds en función de los 8 canales, simplemente se indicarán el estado de conexión de la consola y de dichos canales.

*Modificaciones realizadas en la librería de recepción:*

Cambian el nombre de los archivos fuente y se agregan variables, estados que requiere la librería de los indicadores.

*lib_dmx_in.h*


```
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

//#define DIPSWITCH							//use DIPs?
#define DMX_CHANNELS    (8)					//use at least 2ch
#define F_OSC		(8000)		  			//oscillator freq. in kHz (typical 8MHz or 16MHz)

volatile uint8_t 	 Flags;					//Flags
volatile uint8_t	 DmxField[DMX_CHANNELS];	//array of DMX vals (raw)
volatile uint16_t	 DmxAddress;			//start address

extern void init_DMX(void);
extern void get_dips(void);
```

Permite configurar la cantidad de canales definiendo DMX_CHANNELS, la frecuencia del oscilador y por último anula el uso de los dipswitch.

*lib_dmx_in.c*


```
#include "lib_dmx_in.h"
#include "lib_indicator.h"

// ********************* local definitions *********************

enum {IDLE, BREAK, STARTB, STARTADR};			//DMX states

		 uint8_t 	 gDmxState;
		 uint8_t 	*gDmxPnt;
		 uint16_t	 DmxCount;

enum {EVAL_DMX, IND};						//main flags
// *************** DMX Reception Initialisation ****************
void init_DMX(void)
{
#ifdef DIPSWITCH
DDRC= 0;							//set up DIPs
PORTC= 0xFF;
DDRE &= ~((1<<2)|(1<<1));
PORTE |= (1<<2)|(1<<1);
#endif

DDRD |= (1<<2);
PORTD &= ~(1<<2);					//enable reception
UBRRH  = 0;
UBRRL  = ((F_OSC/4000)-1);			//250kbaud, 8N2
UCSRC |= (1<<URSEL)|(3<<UCSZ0)|(1<<USBS);
UCSRB |= (1<<RXEN)|(1<<RXCIE);
gDmxState= IDLE;

uint8_t i;
for (i=0; i<DMX_CHANNELS; i++)
	{
	DmxField[i]= 0;
	}

}


// ************* get DMX start address **************
void get_dips(void)
{
#ifdef DIPSWITCH
uint16_t Temp= (255-PINC);			//invert DIP state
if (!(PINE &(1<<2)))
	{
	Temp= Temp +256;				//9th bit
	}
if (Temp != 0)
	{
	DmxAddress= Temp;
	if (!(UCSRB &(1<<RXCIE)))		//if receiver was disabled -> enable and wait for break
		{
		gDmxState= IDLE;
		UCSRB |= (1<<RXCIE);
		}
	}
else
	{
	UCSRB &= ~(1<<RXCIE);			//disable Receiver if start address = 0
	for (Temp=0; Temp<DMX_CHANNELS; Temp++)
		{
		DmxField[Temp]= 0;
		}
	Flags |= (1<<EVAL_DMX);		//data set ready -> eval in main
	}
#endif
}


// *************** DMX Reception ISR ****************
ISR (USART_RX_vect)
{
uint8_t USARTstate= UCSRA;			//get state
uint8_t DmxByte= UDR;				//get data
uint8_t DmxState= gDmxState;		//just get once from SRAM!!!

IndFlags |= (1<<SIGNAL_COMING);		//receiving some data

if (DmxState == BREAK)
	{
	UCSRA &= ~(1<<FE);				//reset possible FE because of MAB
	if (DmxByte == 0)
		{
		gDmxState= STARTB;			//normal start code detected
		gDmxPnt= ((uint8_t*)DmxField +1);
		}
	else
		{
		gDmxState= IDLE;
		}
	}

else if (USARTstate &(1<<FE))		//check for break
	{
	UCSRA &= ~(1<<FE);				//reset flag
	if (DmxByte == 0)				//data in break must be 0
		{
		gDmxState= BREAK;
		DmxCount= DmxAddress;		//reset frame counter
		}
	else
		{
		gDmxState= IDLE;			//real FE -> wait for break
		}
	}

else if (DmxState == STARTB)
	{
	if (--DmxCount == 0)			//start address reached?
		{
		gDmxState= STARTADR;
		DmxField[0]= DmxByte;
		}
	}

else if (DmxState == STARTADR)
	{
	uint8_t *DmxPnt;
	DmxPnt= gDmxPnt;
	*DmxPnt= DmxByte;
	if (++DmxPnt >= (DmxField +DMX_CHANNELS)) //all ch received?
		{
		Flags |= (1<<EVAL_DMX);		//data set ready -> eval in main
		gDmxState= IDLE;
		}
	else
		{
		gDmxPnt= DmxPnt;
		}
	}
}
```

*Librería de indicadores:*

*lib_indicator.h*


```
#include <avr/io.h>
#include <stdint.h>

volatile uint8_t IndFlags;

enum {SIGNAL_COMING, VALID_DMX, DMX_ERR, DATA_REFRESHED, OVERHEAT, ZC_OK};

extern void indicate(void);
extern void init_ind(void);
```

*lib_indicator.c*


```
#include "lib_indicator.h"

#define NO_SIG_PAT 	(0b10000010)
#define NO_DMX_PAT	(0b10001010)
//#define NO_ZC_PAT	(0b10101010)
//#define HOT_PAT		(0b11111111)

		uint8_t Blink;

// ******************** initialize indicator *****************************
void init_ind(void)
{
DDRD  |= (1<<PD7);									//LED1
PORTD |= (1<<PD7); 
DDRE  |= (1<<PE0);									//LED2
PORTE |= (1<<PE0);
Blink=    0xFF;
IndFlags= 0;
}


// ******************** LED indicator *****************************
void indicate(void)
{
if (IndFlags &(1<<DATA_REFRESHED))
	{
	IndFlags &= ~(1<<DATA_REFRESHED);
	PORTE ^= (1<<PE0);								//change green LED state
	}
else PORTE |= (1<<PE0);								//disable LED if nothing's changed

if (Blink &(1<<0)) PORTD &= ~(1<<PD7);				//enable red LED if 1st bit is set
else PORTD |= (1<<PD7);

Blink= (Blink>>1);									//shift pattern

if (Blink == 1)
	{
	Blink= 0b10000000;
//	if (!(IndFlags &(1<<ZC_OK)))      Blink= NO_ZC_PAT; //load new pattern
//	else if (IndFlags &(1<<OVERHEAT)) Blink= HOT_PAT;
	if  (!(IndFlags &(1<<SIGNAL_COMING))) Blink= NO_SIG_PAT;
	else if (!(IndFlags &(1<<VALID_DMX))) Blink= NO_DMX_PAT;
	
	IndFlags &= ~((1<<VALID_DMX)|(1<<SIGNAL_COMING));	//clear IndFlags
	}
}
```

Esta nueva librería requiere usar un timer, originalmente usa el Timer0 (8 bits), pero como ese timer también lo utilizaba la librería de los botones, decidí usar el Timer1 (16 bits), para lo cual es necesario fijar el byte alto en 0xff para que trabaje como si fuera de 8 bits (¿podría haber optimizado el código? si, pero no lo hice, traté de dejarlo lo más parecido posible).

*Función principal:*

*main.c*


```
//-------------- Definiciones de tipos de variables
typedef unsigned char			u8;
typedef unsigned int			u16;
//-------------- Definiciones de tipos de variables

//-------------- Variables globales de interrupciones
volatile u8 flag_timer0=0;
//-------------- Variables globales de interrupciones

enum {EVAL_DMX, IND};						//main flags

#include "lib_dmx_in.h"
#include "lib_indicator.h"
#include "rutinas_de_interrupcion.h"
#include "funciones_perifericos.h"
#include "funciones_LCD.h"
#include "funciones_utiles.h"
#include "menu.h"

uint8_t count= 1;					//counter für soft
uint8_t IndCnt= 1;					//counter für LED indicator
uint8_t DmxBuf[DMX_CHANNELS];

void init_system(void)
{
    //Ports
    DDRA=  0xFF;						//low outputs
    PORTA= 0;
    DDRB=  0xFF;
    PORTB= 0;
    DDRD=  0b10000110;					//DMX, spare, LED1
    PORTD= 0b01111010;

    //Timer1
    TCCR1B= (1<<CS10);
    TIMSK= (1<<TOIE1);
    TCNT1L=0;
    TCNT1H=0xff;

    init_DMX();							//initialisiere DMX-Empfang
    init_ind();							//initialisiere LED Indikator
}

int main(void)
{
	u8 estado_antireb=ANTI_REB_IDLE;
    uint8_t i;

	cli();
	DDRA=0xff;

	init_system();
	sei();

	configurar_botones();
	inicia_lcd_4bits();
	leer_e_imprimir_dir_dmx();

	for(;;)
	{
		if (Flags &(1<<EVAL_DMX))		//DMX universe wurde refreshed
            {
                Flags &= ~(1<<EVAL_DMX);
                IndFlags |= (1<<VALID_DMX); //gültiges DMX-Signal angekommen
			}

		for (i=0; i<DMX_CHANNELS; i++)
			{
                if (DmxField[i] != DmxBuf[i])	//hat sich ein DMX-Wert geändert?
                    {
                        DmxBuf[i]= DmxField[i];
                        IndFlags |= (1<<DATA_REFRESHED); // ja -> blinken!
                    }
			}

        if (Flags &(1<<IND))			//LED Indikator,
            {
                Flags &= ~(1<<IND);
                wdt_reset();				//reset watchdog
                get_dips();
                if (--IndCnt == 0)
                    {
                        IndCnt= 8;
                        indicate();
                    }
            }

		if(anti_rebote(BOTON_MENU,&estado_antireb)>0)
			{
				UCSRB  &= ~((1<<RXEN)|(1<<RXCIE));
				menu();
				leer_e_imprimir_dir_dmx();
				UCSRB  = (1<<RXEN)|(1<<RXCIE);  //Habilita la recepción
			}
	}
}

// *************** DMX Reception ISR ****************
ISR (TIMER1_OVF_vect)
{

TCNT1L=0;
TCNT1H=0xff;

if (count == 0xFF)
	{													//wird mit 122Hz aufgerufen
	count= 1;
	Flags |= (1<<IND);
	}
else count++;
}
```

Subo el proyecto completo, en este caso usé el IDE Code::Blocks, pero tranquilamente se puede armar en el AVR Studio sea 4, 5 o 6.

La idea es que en el próximo mensaje el usuario *locodelafonola* suba un video que muestre como funciona este programa y el anterior, dando una breve explicación de lo que ocurre en c/u.


----------



## locodelafonola (Jul 17, 2014)

bueno como lo dijo el compañero .... cosmefulanito04 aca aporto el  video ...... comenzamos con la libreria del mensaje  #11 ....bueno esta libreria probamos con tester (voltaje ) .........  pero yo le puse unos led .... ( para que sea visual el cambio y se pueda ver junto con el programa de manejo ) ...... pero hay que aclarar....¡¡¡¡ que no es un dimer.... ni un swich !!!!! ...... solo lo usamos para corroborar .... que hubiera mando ..... y tambien que no hubiera desplazamiento de canales (ensimados o fuera de direcion DMX asignada )..... bueno sigue "enganchada" la libreria del mensaje #12 ... y hay una funcion mas de los indicadores cosme ¡¡¡¡¡¡ ... .. que la descubri recien (el video lo hice ayer ) ...y es que detecta la invercion de D+ y D- ...... pd7 destella a una frecuencia mas rapida ..... que la de error de trama ..... y destella junto con pe0 cada vez que habilita y desabilita la recepcion ..... o sea hace un ciclo ..... si no se cambia el estado de D+ y D- ... prometo mostrarlo en el siguiente video ...bueno los de los indicadores puede parecer tonto pero ..... en el campo de uso ...es muy apreciado ..sobre todo si son equipos que se trasportan .. y van de un lado para el otro .... .. hoy es muy comun colocar los equipos en altura.... o bastidores ... y con estos led tenemos al menos ..... una indicacion basica ...... del funcionamiento del equipo ... a cuantos les paso que una vez colocado el equipo no funciona ..y talvez sea por una rotura de cable o las señales invertidas... mucho mas comun de lo que se cree ... y esto es muy util ...... tambien prestenle atencion al cambio de direccion ..... de la manera facil ...segura y sobre todo rapida... muy simple ..y queda alojada en la memoria del micro ...por mas que se apague esta fija alli ... otra genialidad de don cosmefulanito04   ...... haciendo algo de recuento ...... me faltaron cosas por mostrar ...como el patch para la direccion en equipos caseros ..... el programa ayuda mucho en ese sentido ... si tienen preguntas o algien este intresado en algo del funcionamiento en particular ..... avisen ....y veo la manera de mostrarlo ....yyyyy pido mil perdones  por la calidad del video... pero mi camara "berreta" no me tomaba bien el lcd ....... esto es lo mejor que pude ..... porque queria mostrarlo junto con el programa ....   juan


----------



## cosmefulanito04 (Jul 18, 2014)

Agrego la librería para controlar el brillo de c/canal. Se siguen usando las librerías anteriores:

- Recepción DMX
- Indicadores DMX
- LCD
- Botones
- Menu

Sin embargo la librería para controlar el antirrebote y la de los indicadores tuvo que ser modificada para que ambas utilicen el mismo timer (antes c/librería usaba un timer distinto) debido a que la nueva librería requiere también usar un timer. Entonces esta combinación de las librerías anteriores fue necesaria por el hard que se dispone (Atmega8515 => solo dos timers), si bien no es la mejor solución, ya que el timer ahora interrumpe durante mayor tiempo y puede molestar a la recepción, funciona según el usuario *locodelafonola*.

*Librería nueva:*

*lib_pam.h*


```
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

volatile uint16_t	 PamField[8];	//array of pam vals

#define  PAM_WIDTH	(8)				//bit resolution of modulation (max 16)

extern void init_pam(void);
```

*lib_pam.c*


```
/* pam Library (8ch pulse angle modulation lib, C version)
   version:      0.9
   release date: 31.07.06
   author(s):    
   Target:       Transceiver Rev.3.01 
   

   
   This library was published in the hope that it will be useful, but without any warranty.
   You can use it if your work does not cause problems for the authors.      
*/

#include "lib_pam.h"

// ********************* local definitions *********************
		uint16_t 	PamBitMask =1;		//Bitmask for pam modulation
		uint8_t     PamCurBit  =1;
		uint16_t	PamFieldBuffer[8];  //buffer of vals during conversion


// *************** PAM Initialisation ****************
void init_pam(void)
{
uint8_t i;

//Output
DDRA= 0xFF;
PORTA= 0;

//Timer1
TCCR1B= (1<<CS10)|(1<<CS11);		//set T1 @clk/64
TIMSK |= (1<<TOIE1);				//enable overflow irq

//data
for (i=0; i<8; i++)
	{
	PamFieldBuffer[i]= PamField[i];	//get ch
	}
PamFieldBuffer[8]=0;
}


// ****************** PAM compare ISR ********************
ISR (TIMER1_OVF_vect)
{
uint8_t PamState= 0;

if (PamCurBit == (PAM_WIDTH -1))
	{
	PamFieldBuffer[0]= PamField[0];		//refresh ch
	PamFieldBuffer[1]= PamField[1];
	PamFieldBuffer[2]= PamField[2];
	PamFieldBuffer[3]= PamField[3];
	PamFieldBuffer[4]= PamField[4];
	PamFieldBuffer[5]= PamField[5];
	PamFieldBuffer[6]= PamField[6];
	PamFieldBuffer[7]= PamField[7];		//verbose code for speed
		
	PamCurBit=0;
	PamBitMask=1;						//reset bit mask
	}
else
	{
	PamBitMask= (PamBitMask <<1);		//isolate bit
	PamCurBit++;						//increment bit counter
	}

if (PamFieldBuffer[0]&PamBitMask)		//compare bits
	{
	PamState|= (1<<0);
	}
if (PamFieldBuffer[1]&PamBitMask)
	{
	PamState|= (1<<1);
	}
if (PamFieldBuffer[2]&PamBitMask)
	{
	PamState|= (1<<2);
	}
if (PamFieldBuffer[3]&PamBitMask)
	{
	PamState|= (1<<3);
	}
if (PamFieldBuffer[4]&PamBitMask)
	{
	PamState|= (1<<4);
	}
if (PamFieldBuffer[5]&PamBitMask)
	{
	PamState|= (1<<5);
	}
if (PamFieldBuffer[6]&PamBitMask)
	{
	PamState|= (1<<6);
	}
if (PamFieldBuffer[7]&PamBitMask)
	{
	PamState|= (1<<7);
	}
PORTA= PamState;
TCNT1= ~(PamBitMask);					//set bit length
}
```

Ahora la parte principal del código (el main) es el siguiente:


```
//-------------- Definiciones de tipos de variables
typedef unsigned char			u8;
typedef unsigned int			u16;
//-------------- Definiciones de tipos de variables

//-------------- Variables globales de interrupciones
volatile u8 flag_timer0=0;

volatile u8 count= 1;					//counter für soft
volatile u8   Flags;					//Flags
//-------------- Variables globales de interrupciones

enum {EVAL_DMX, IND};						//main flags

#include "lib_dmx_in.h"
#include "lib_indicator.h"
#include "lib_pam.h"
#include "rutinas_de_interrupcion.h"
#include "funciones_perifericos.h"
#include "funciones_LCD.h"
#include "funciones_utiles.h"
#include "menu.h"

uint8_t IndCnt= 1;					//counter für LED indicator
uint8_t DmxBuf[DMX_CHANNELS];

void init_system(void)
{
    //Ports
    DDRA=  0xFF;						//low outputs
    PORTA= 0;
    DDRB=  0xFF;
    PORTB= 0;
    DDRD=  0b10000110;					//DMX, spare, LED1
    PORTD= 0b01111010;

    configura_timer0(224,TIMER0_PREESCALER_256);	//1mSeg: Xtal 8MHz => 1 clk = 125nS => 1mS/125nS=8000 cuentas => Preescaler=256 y cuenta inicial 224 => Cuentas=(256-224)*256= 8192 cuentas un poco mas de 1mSeg.

    init_DMX();							//initialisiere DMX-Empfang
    init_ind();							//initialisiere LED Indikator
    init_pam();
}

int main(void)
{
	u8 estado_antireb=ANTI_REB_IDLE;
    u8 cont_canales;
    uint8_t i;

	cli();
	init_system();
	sei();

	configurar_botones();
	inicia_lcd_4bits();
	leer_e_imprimir_dir_dmx();

	for(;;)
	{
		wdt_reset();
		get_dips();						//get start address

		for(cont_canales=0;cont_canales<DMX_CHANNELS;cont_canales++)
            {
                PamField[cont_canales]= 0xff-DmxField[cont_canales];   //Control de fase angular mediante el receptor DMX
            }

        if (Flags &(1<<EVAL_DMX))		//DMX universe wurde refreshed
            {
                Flags &= ~(1<<EVAL_DMX);
                IndFlags |= (1<<VALID_DMX); //gültiges DMX-Signal angekommen
			}

		for (i=0; i<DMX_CHANNELS; i++)
			{
                if (DmxField[i] != DmxBuf[i])	//hat sich ein DMX-Wert geändert?
                    {
                        DmxBuf[i]= DmxField[i];
                        IndFlags |= (1<<DATA_REFRESHED); // ja -> blinken!
                    }
			}

        if (Flags &(1<<IND))			//LED Indikator,
            {
                Flags &= ~(1<<IND);
                wdt_reset();				//reset watchdog
                get_dips();
                if (--IndCnt == 0)
                    {
                        IndCnt= 8;
                        indicate();
                    }
            }

		if(anti_rebote(BOTON_MENU,&estado_antireb)>0)
			{
				UCSRB  &= ~((1<<RXEN)|(1<<RXCIE));
				menu();
				leer_e_imprimir_dir_dmx();
				UCSRB  = (1<<RXEN)|(1<<RXCIE);  //Habilita la recepción
			}
	}
}
```

Recién ahora se obtuvo una aplicación real usando DMX, donde el usuario tiene 8 puertos (PA0-PA7) para controlar 8 leds/lámparas distintas modificando su brillo. Obviamente será necesario agregar el hard necesario para manejar esos leds/lámparas.

Subo los archivos fuentes necesario para crear el proyecto y agrego el ejecutable.


----------

