DMX sans fil

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

  • 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

Emetteur.png 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-485MAX 485 1
Transmetteur sans fil XBee 1
Connecteur XLR 5 broches mâle1

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èmeCommentaire
+++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


//-----------------------------------------------------------------------------
// 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++;
            }
        }
    }
}
//-----------------------------------------------------------------------------
// 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
# 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
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++;
}

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

  • dmx_sans_fil.txt
  • Dernière modification: 2018/07/04 18:55
  • par Mushussu