DMX sans fil

De Centre de Ressources Numériques - Labomedia
Aller à : navigation, rechercher

Description du projet

Réaliser un réseau de récepteurs sans fil d'un signal DMX.

Matériel utilisé

  • Ordinateur avec CrossPack, DLight, Processing et un éditeur de texte installé
  • 2 modules XBee
  • Câbles USB
  • Câble DMX 5 broches
  • Platine de conversion USB/Série
  • Montage réalisé
  • Boitier Enttec Pro
  • Programmateur de micro-contrôleur AVR (mySmartUSB ou autre)

Le projet a été construit avec un MAC il est aisé de trouver un équivalent des programmes pour Windows ou Linux

Montage électronique

Emetteur.png
Liste des pièces
Nom Référence Quantité

Résistance

120 1/4W

2

Résistance

220 1/4W

1

Résistance

10K 1/4W

1

Condensateur céramique

22pF

2

Quartz

16 MHz

1

Micro contrôleur

Atmega 168 20PU

1

Émetteur/Récepteur RS-485

MAX 485

1

Transmetteur sans fil

XBee

1

Connecteur

XLR 5 broches mâle

1

Configuration des modules XBee

Pour configurer correctement les modules, j'utilise le script Terminal de Tom Igoe. Une fois le script lancé entrer les séquences suivantes:


Commande Réponse du système Commentaire
+++ OK <CR> Entre dans le mode Commande
ATRE <Enter> OK <CR> Restore les paramètres par défaut
ATID1234 <Enter> OK <CR> Définit l'adresse du réseau
ATMY1111 <Enter> OK <CR> Définit l'adresse du module dans le réseau
ATBD7 <Enter> OK <CR> Définit le taux de transfert des donnée à 115200 Bauds par seconde
ATAP1 <Enter> OK <CR> Permet de faire fonctionner le module en mode API
ATWR <Enter> OK <CR> Écrit la nouvelle configuration dans la mémoire flash du module
ATCN <Enter> OK <CR> Sort du mode configuration


Pour le module récepteur :

Commande Réponse du système Commentaire
+++ OK<CR> Entre dans le mode Commande
ATRE <Enter> OK <CR> Restore les paramètres par défaut
ATID1234 <Enter> OK <CR> Définit l'adresse du réseau
ATMY0 <Enter> OK <CR> Définit l'adresse du module dans le réseau
ATBD7 <Enter> OK <CR> Définit le taux de transfert des donnée à 115200 Bauds par seconde
ATAP1 <Enter> OK <CR> Permet de faire fonctionner le module en mode API
ATWR <Enter> OK <CR> Écrit la nouvelle configuration dans la mémoire flash du module
ATCN <Enter> OK <CR> Sort du mode configuration


Script C

//-----------------------------------------------------------------------------
// Projet		: Transmission XBee 1 emetteur / X récepteurs
// Programme	: Emetteur
// Auteur		: Sylvain Blocquaux
// Date			: 26 septembre 2010 
// Version		: 4
//-----------------------------------------------------------------------------
#include <util/delay.h>
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>

#define nombreXbee 2
#define nombreMaxCanaux 5
#define tailleBuffer 8							// Nombre de canaux différents
#define FCPU 16000000							// Fréquence de l'oscillateur en Hz
#define BAUD 250000
#define MYUBBR ((FCPU/16)/BAUD-1)

extern void transmission(uint8_t *adresse, uint8_t taille);

volatile uint8_t message[] = {0x7E, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
volatile uint8_t taille[nombreXbee] = {5, 3};		// La somme des indices doit être égale à tailleBuffer
volatile uint8_t tableau[nombreXbee][nombreMaxCanaux];
volatile uint16_t adresseDMX, compteurDMX;
volatile uint16_t iter;
volatile uint8_t buffer[tailleBuffer];


//-----------------------------------------------------------------------------
// Fonction d'envoi des données à travers le XBee
//-----------------------------------------------------------------------------	
void envoie(void) {
	uint8_t i, addr;
	uint16_t checksum;
	
	for (addr = 0; addr < nombreXbee; addr++) {
		checksum = 0;
		message[2] = taille[addr] + 5;
		message[6] = addr;
		for (i = 0; i < taille[addr]; i++) {
			message[i + 8] = tableau[addr][i];
		}
		for (i = 3; i < (taille[addr] + 8); i++) {
			checksum += message[i];
		}
		checksum %= 256;
		message[taille[addr] + 8] = 255 - checksum;
		transmission(&message, (taille[addr] + 9));
	}
}

//-----------------------------------------------------------------------------
// Routine d'intérruption de l'USART 0
//-----------------------------------------------------------------------------	
ISR(USART_RX_vect) { 
	uint8_t status, data;
	status=UCSR0A;
	data=UDR0;

	if(status & 0x10){ // Frame Error
		compteurDMX = 0;
		iter = 0;
		UCSR0A &= ~(1<<FE0);
		return;
	} 
	if (compteurDMX == adresseDMX) {iter = 1;};
	if (iter > 0) {
		buffer[iter - 1] = data;
		if (iter == tailleBuffer) {
			iter = 0;
			envoie();
		} else {
			iter++;
		}
	}
	compteurDMX++;
}

//-----------------------------------------------------------------------------
// Fonction d'initialisation de l'USART
//-----------------------------------------------------------------------------	
void initUART(void) {   
	UCSR0B = (1<<RXEN0) | (1<<RXCIE0); // permet la réception et l'interruption de donées
	UBRR0H = (MYUBBR>>8);  // The high byte, UBRR0H
	UBRR0L = MYUBBR;       // The low byte, UBRR0L
	UCSR0C = (1<<UCSZ01) | (1<<UCSZ00) | (1<<USBS0); // Données sur 8 bits, 2 stop bits, pas de parité
	return;
}

//-----------------------------------------------------------------------------
// Corps du programme
//-----------------------------------------------------------------------------	
int main(void) {
	adresseDMX = 22;
	uint8_t compteur, xBeeCourant, indice;
	DDRC |= (1<<DDC0);
	PORTC |= (1<<PORTC0);
	initUART();
	sei();
	
	while(1) {
		compteur = 0;
		for (xBeeCourant = 0; xBeeCourant < nombreXbee; xBeeCourant++) {
			for (indice = 0; indice < taille[xBeeCourant]; indice++) {
				tableau[xBeeCourant][indice] = buffer[compteur];
				compteur++;
			}
		}
	}
}

Script Assembleur

//-----------------------------------------------------------------------------
// Projet		: Transmission XBee 1 emetteur / X récepteurs
// Programme	: extension.S
// Auteur		: Sylvain Blocquaux
// Date			: 26 septembre 2010 
// Version		: 4
// Fréquence	: 16 MHz
// Baud			: 115200
// Série		        : 141 coups d horloge
//-----------------------------------------------------------------------------

#ifndef __AVR_ATmega168__
#define __AVR_ATmega168__
#endif

#include <avr/io.h> 

.global transmission
transmission:
	push r16								; Sauvegarde dans la pile les registre de travail
	push r17
	push r18
	push r19
	cli
	movw r30, r24							; r24 récupère le premier arguments de la fonction comme c'est une adresse sur 2 octet utilisation de movw r30:r31 sont les registres que l'on peut utiliser avec ld
	clr r18									; Mise à zéro du compteur de la taille du tableau
	1:	ld r17, Z+							; 2 Charge dans r17 le contenu de la mémoire stoocké dans Z (r30:r31)
		cbi _SFR_IO_ADDR(PORTC), 0			; Start bit
		ldi r19, 0							; 1
		11:	inc r19							; 1
			cpi r19, 33						; 1
			brlo 11b						; 1 faux, 2 vrai ; boucle 4 x argument => 132
		nop
		nop
		nop									; 135
		ldi r16, 0							; 1
	2:	sbrs r17, 0							; 1 faux / 2 vrai(saut)
		rjmp 3f								; 2
		nop
		sbi _SFR_IO_ADDR(PORTC), 0			; 2
		rjmp 4f								; 2
		3:	cbi _SFR_IO_ADDR(PORTC), 0		; 2
			nop
			nop
		4:	ldi r19, 0						; 1
			41:	inc r19						; 1
				cpi r19, 32					; 1
				brlo 41b					; 1 faux, 2 vrai ; boucle 4 x argument => 128
			nop								; 131
			lsr r17							; 1
			inc r16							; 1
			sbrs r16, 3						; 1 faux / 2 vrai (saut)
			rjmp 2b							; 2
			nop
			nop
			nop
			nop
			sbi _SFR_IO_ADDR(PORTC), 0		; Stop bit
			ldi r19, 0						; 1
			42:	inc r19						; 1
				cpi r19, 32					; 1
				brlo 42b					; 1 faux, 2 vrai ; boucle 4 x argument => 128
			nop
			nop
			nop
			nop
			inc r18							; 1 Incrémente le compteur de caractère
		cp r18, r22							; 1 Teste si la valeur de la taille du tableau est atteinte
		brge 5f								; 1 Sort de la boucle si c'est égal ou supérieur
		rjmp 1b								; 2
		5:
			
	sei
	pop r19
	pop r18
	pop r17
	pop r16
	ret

Makefile

# Name: Makefile
# Author: Sylvain Blocquaux
# Copyright: <insert your copyright message here>
# License: <insert your license reference here>

# This is a prototype Makefile. Modify it according to your needs.
# You should at least check the settings for
# DEVICE ....... The AVR device you compile for
# CLOCK ........ Target AVR clock rate in Hertz
# OBJECTS ...... The object files created from your source files. This list is
#                usually the same as the list of source files with suffix ".o".
# PROGRAMMER ... Options to avrdude which define the hardware you use for
#                uploading to the AVR and the interface where this hardware
#                is connected.
# FUSES ........ Parameters for avrdude to flash the fuses appropriately.

DEVICE     = atmega168
CLOCK      = 16000000
PROGRAMMER = -c avr910 -P /dev/cu.SLAB_USBtoUART
OBJECTS    = main.o extension.o
FUSES      = -U lfuse:w:0xE6:m


AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE)
COMPILE = avr-gcc -Wall -g -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE)

# symbolic targets:
all:	main.hex

.c.o:
	$(COMPILE) -c $< -o $@

.S.o:
	$(COMPILE) -x assembler-with-cpp -c $< -o $@
# "-x assembler-with-cpp" should not be necessary since this is the default
# file type for the .S (with capital S) extension. However, upper case
# characters are not always preserved on Windows. To ensure WinAVR
# compatibility define the file type manually.

.c.s:
	$(COMPILE) -S $< -o $@

flash:	all
	$(AVRDUDE) -U flash:w:main.hex:i

fuse:
	$(AVRDUDE) $(FUSES)

# Xcode uses the Makefile targets "", "clean" and "install"
install: flash fuse

# if you use a bootloader, change the command below appropriately:
load: all
	bootloadHID main.hex

clean:
	rm -f main.hex main.elf $(OBJECTS)

# file targets:
main.elf: $(OBJECTS)
	$(COMPILE) -o main.elf $(OBJECTS)

main.hex: main.elf
	rm -f main.hex
	avr-objcopy -j .text -j .data -O ihex main.elf main.hex
# If you have an EEPROM section, you must also create a hex file for the
# EEPROM and add it to the "flash" target.

# Targets for code debugging and analysis:
disasm:	main.elf
	avr-objdump -d main.elf

cpp:
	$(COMPILE) -E main.c
	
# Permet le debuggage rapide
e: clean all flash

Script Processing

import processing.serial.*;

Serial myPort;  // Crée un objet de classe Serial
int rate, flag, compteur;   
int checksum = 0;
int tailleBuffer = 5; // Taille du tableau reçu il doit égal à la valeur du tableau taille du programme main.c pour le XBee concerné
int adresseEmetteur = 0x1111;
char val;
char[] buffer = new char[tailleBuffer]; // Tableau des valeurs recues
char[] valeur = new char[tailleBuffer];

void setup() {
  size(600, 140);
  frameRate(60);
  PFont myFont = createFont(PFont.list()[2], 30);
  textFont(myFont);
  textAlign(RIGHT);
  compteur = 0;
  flag = 0;
  checksum = 0;
  println(Serial.list());
  String portName = Serial.list()[0];
  rate = 115200;
  myPort = new Serial(this, portName, rate,'N',8,1.0); // Configuration de la liaison série
}

void draw() {
  background(0);             // Set background to white
  text("Récepteur : 1", 250, 50);
  for (char i = 0; i < tailleBuffer; i++) {
    text(int(valeur[i]), 80 + i*80, 100);
  }
}

void serialEvent(Serial myPort) {
  val = myPort.readChar();
  if (flag == 2) {flag = 0; return;}
  if ((val == 0x7E) && (flag == 0)) {flag = 1; compteur = 0; checksum = 0; return;}
  if (((flag == 1) && (compteur == 2)) && (val != 0x81)) { flag = 0;println("erreur 1"); return;}
  if (((flag == 1) && (compteur == 3)) && (val != adresseEmetteur >> 8)) { flag = 0;println("erreur 2"); return;}
  if (((flag == 1) && (compteur == 4)) && (val != ((adresseEmetteur << 24) >>24))) { flag = 0;println("erreur 3"); return;}
  if ((flag == 1) && (compteur == (tailleBuffer + 7))) {
    if ((val + (checksum % 256)) != 255) {
      flag = 2;
    } else {
      for (char iter = 0; iter < tailleBuffer; iter++) {
        valeur[iter] = buffer[iter];
      }
      flag = 0;
    }
    return;
  }
  if ((flag == 1) && (compteur >= 2)) {
    checksum += val;
  }
  if ((flag == 1) && (compteur >= 7)) {
    buffer[compteur - 7] = val;
  }
  compteur++;
}

Liens externes

CrossPack (en) : Site officiel

DLight (fr) : Site officiel

Processing (en) : Site officiel

Script Processing de Tom Igoe (fr) : Script Terminal

Tutoriel de mise en route d'un Atmega (en) : Sparkfun

Archive du projet