DMX sans fil
Sommaire
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
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