I have been working towards getting a TX/RX solution for sending DMX data short distances cheaply using nRF24L01 radio modules with the RF24 library. Initially I just sent 4 bytes to see if I could control a DMX fixture remotely, and it worked, so I then tweaked the code to ensure to stream was smooth and error free at best. So now I am working towards sending larger and larger amounts of 32 byte packets..
Transmitter:
The first Node receives DMX using Matt Hertels DMX library, I use a ATMega328 for this, the DMX is stored in an array and is received in the background automatically
Using a simple timer routine, I send the current DMX data out over radio every 25ms.
I send each 32 byte packet as [packet number] [timestamp] [30 bytes of data]
At present I am only using 8 packets of 30 DMX data bytes (240 bytes) so still not the full DMX512
The timestamp is just a sequential number so the receiver can see if there are any dropped packets and show reception quality with an LED
There will be an allowance for selecting Radio channel number via DIP Switches (matched with receiver)
Receiver:
For the receiver I use a ATMega8-16 for cheapness
I receive all the packets and check for dropped packets
Then recompile all the DMX data back into its own slots using the packet number*30 as an offset into the array
Once the data is compiled I manually blatt out the DMX data using some special timed code I saw on the internet
I am remaking the PCBs for TX and RX and will try out the FULL software very soon
Once I have got it working as best as I can I will submit it on here
I am also dealing with sending DMX data over nRF24L01 wireless transceivers. Have you faced with data receiving? Anything you can share (code or circuit shematic ) would be very appriciated here.
mail address*************
CODE TO TRANSMIT DMX USING nRF24L01:
This code will take in 512 channels of DMX and transmit it in 30 byte packets over RF every 40ms
// FOR ATMEGA328 16mhz ONLY //
// connection information...
// http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
// use ATMEGA RXD pin to receive DMX data from pin 1 of SN75176 chip
// SN75176: pins 2, 3 & 5 to 0v | pin 8 to 5v | pin 6 to DMX+ | pin7 to DMX-
// Ensure 3.3v is used to supply NRF24L01 board !!
#include <SPI.h>
#include "nRF24L01.h" // library: https://github.com/maniacbug/RF24
#include "RF24.h"
#include <Wire.h>
#include <DMXSerial.h> // library: http://www.mathertel.de/Arduino/DMXSerial.aspx //
#define MAXGROUPS 17 // 17 groups of 30 channels = 510 channels
#define MAXPAYLOAD 32 // max payload size for nrf24l01
#define BURSTTIMER 40 // 40ms between blasts of radio data
#define DMX_LED 8 // DMX monitor : LED from digital pin 8 to 0V via 470R resistor
RF24 radio(9,10);
const uint64_t pipe = 0xF0F0F0F0E1LL; //0xE8E8F0F0E1LL;
uint8_t payload[MAXPAYLOAD];
unsigned long timeslot, flashTimer;
uint8_t timeStamp, channel=0; // ensure TX & RX channels are the same
void setup(void)
{
pinMode(DMX_LED, OUTPUT);
digitalWrite(DMX_LED, LOW);
DMXSerial.init(DMXReceiver);
radio.begin();
radio.setAutoAck(false);
radio.setPayloadSize(MAXPAYLOAD);
radio.setPALevel(RF24_PA_HIGH);
radio.setDataRate(RF24_250KBPS);
radio.openWritingPipe(pipe);
radio.stopListening();
radio.setChannel(channel);
flashTimer = millis();
}
void loop(void)
{
if (millis() - timeslot > BURSTTIMER) {
timeslot = millis();
for (uint8_t group = 0; group<=MAXGROUPS; group++) {
payload[0] = group; // set first byte to point to group (groups of 30 bytes)
payload[1] = timeStamp++; // second byte helps us monitor consistency of reception at receiver
for (uint8_t chan = 1; chan<31; chan++) {
payload[1+chan] = DMXSerial.read((group*30)+chan); // fill payload with DMX data
}
radio.write( payload, sizeof(payload) ); // dump payload to radio
delayMicroseconds(20); // short delay between packets to ensure radio not overloaded
}
}
unsigned long lastPacket = DMXSerial.noDataSince();
unsigned long lastFlash = millis() - flashTimer;
if (lastPacket < 5000) { // if continuous DMX data is received then flash LED
if (lastFlash < 500) { digitalWrite(DMX_LED,1); } // flash on 0.5sec
else if (lastFlash < 1000) { digitalWrite(DMX_LED,0); } // flash off 0.5sec
else if (lastFlash > 1000) { flashTimer = millis(); } // reset timer after 1 second
}
}
CODE TO RECEIVE DMX USING nRF24L01:
This code will take in receive 30 byte packets of data via RF and recompile it into a 512 byte DMX stream
The code will work for ATmega 328 and ATMega8 processors, I chose to adapt for ATmega8 to keep receiver cost down
// DMX RECEIVE USES ATMEGA328 or ATMEGA8-16PU
// connection information...
// http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
// use ATMEGA DigitalPin 1 to send DMX data to pin 4 of SN75176 chip
// SN75176: pins 2 & 5 to 0v | pin 3 & 8 to 5v | pin 6 to DMX+ | pin7 to DMX-
// Ensure 3.3v is used to supply NRF24L01 board !!
//
#include <SPI.h>
#include "nRF24L01.h" // library: https://github.com/maniacbug/RF24
#include "RF24.h"
#include <Wire.h>
#include "pins_arduino.h";
RF24 radio(9,10);
const uint64_t pipe = 0xF0F0F0F0E1LL;
#define MAXPAYLOAD 32 // max payload size for nrf24l01
#define DMXout 1 // DMX signal output pin (same as TX pin)
#define ERRout 8 // LED to show signal strength : digitalpin 8 to LED via 470 resistor to 0v
#define MAXGROUPS 17 // 17 groups of 30 channels = 510 channels
unsigned long time;
uint8_t payload[MAXPAYLOAD], DMXData[30*MAXGROUPS];
uint8_t lastStamp, channel=0, i;
unsigned long timer;
void setup(void)
{
pinMode(DMXout, OUTPUT);
digitalWrite(DMXout, HIGH);
pinMode(ERRout, OUTPUT);
digitalWrite(ERRout, LOW);
radio.begin();
radio.setAutoAck(false);
radio.setPayloadSize(MAXPAYLOAD); // 9 for 6 byte packet, 12 for 6 byte data + SSD, needs to be 14 to stop failing !!
radio.setPALevel(RF24_PA_HIGH); // try and set PA to max !
radio.setDataRate(RF24_250KBPS); // 250kbps for best tx/rx
radio.openReadingPipe(1,pipe);
radio.startListening();
radio.setChannel(channel);
}
void loop(void)
{
if ( radio.available() ) {
radio.read( payload, sizeof(payload) ); // get data packet from radio if available
}
if ( payload[1] == (lastStamp+1) ) { digitalWrite(ERRout,1); } // check for incontinuous timestamps, LED HI if good
else { digitalWrite(ERRout,0); } // if time stamp error set LED low
lastStamp = payload[1]; // reset last time stamp
for (i = 0; i <30; i++) {
DMXData[(30*payload[0])+i] = payload[i+2]; // recompile DMX data from RF data
}
if (payload[0] == MAXGROUPS-1) { // send DMX once last packet has been received
digitalWrite(DMXout, LOW);
delay(10); // send the break
shiftDmxOut(DMXout, 0); // send the start byte
for (int count = 0; count <= 30*MAXGROUPS; count++){
shiftDmxOut(DMXout, DMXData[count]);
}
}
}
void shiftDmxOut(int pin, int theByte){
int port_to_output[] = { NOT_A_PORT, NOT_A_PORT, _SFR_IO_ADDR(PORTB), _SFR_IO_ADDR(PORTC), _SFR_IO_ADDR(PORTD) };
int portNumber = port_to_output[digitalPinToPort(pin)];
int pinMask = digitalPinToBitMask(pin);
_SFR_BYTE(_SFR_IO8(portNumber)) |= pinMask;
cli();
_SFR_BYTE(_SFR_IO8(portNumber)) &= ~pinMask;
fourUSdelay();
for (int i = 0; i < 8; i++){
if (theByte & 01){ _SFR_BYTE(_SFR_IO8(portNumber)) |= pinMask; }
else { _SFR_BYTE(_SFR_IO8(portNumber)) &= ~pinMask; }
fourUSdelay();
theByte >>= 1;
}
_SFR_BYTE(_SFR_IO8(portNumber)) |= pinMask;
sei();
}
void fourUSdelay(void) {
asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");
asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");
asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");
}
Alot of the above code has been nicked/nobbled/adapted from stuff I have researched online, it was just the stitching together I did really, and many hours scoping to get the speed/reliability/throughput as good as I can get it
I have successfully transmitted and received 512 channels over 25ft through 2 solid brick walls at 25hz to give a very smooth result at my collection of DMX fixtures, there was little or no noticable loss of data packets as there is always a good one following up 40ms later !
The nRF24L01 boards I used were the ones with the antenna ON etched as part of the PCB at a cost of under 1GBP a go !
I have done some further BITRATE testing on this, I can definately vouch for using the lower Bitrate of 250kbps over 2mbps, you get a much better distance (over twice) and far far fewer dropouts at the lower speed
For this application as I have written it, it would not be noticable at the lower speed as the full cycle for the refresh rate would allow everything to happen within the time period of 40ms I have allowed. You cant see any jitter when watching DMX fixtures move so I am happy
I'm trying to implement your code on my arduino uno
I would like to know which version you are using IDE
I use to 1.05 when compiling command appear several errors ... could you help me?
RF24_v2.cpp.o: In function __static_initialization_and_destruction_0': F:\Programas\Arduino/RF24_v2.ino:19: undefined reference to RF24::RF24(unsigned char, unsigned char)'
RF24_v2.cpp.o: In function loop': F:\Programas\Arduino/RF24_v2.ino:52: undefined reference to RF24::write(void const*, unsigned char)'
RF24_v2.cpp.o: In function setup': F:\Programas\Arduino/RF24_v2.ino:31: undefined reference to RF24::begin()'
F:\Programas\Arduino/RF24_v2.ino:32: undefined reference to RF24::setAutoAck(bool)' F:\Programas\Arduino/RF24_v2.ino:33: undefined reference to RF24::setPayloadSize(unsigned char)'
F:\Programas\Arduino/RF24_v2.ino:34: undefined reference to RF24::setPALevel(rf24_pa_dbm_e)' F:\Programas\Arduino/RF24_v2.ino:35: undefined reference to RF24::setDataRate(rf24_datarate_e)'
F:\Programas\Arduino/RF24_v2.ino:36: undefined reference to RF24::openWritingPipe(unsigned long long)' F:\Programas\Arduino/RF24_v2.ino:37: undefined reference to RF24::stopListening()'
F:\Programas\Arduino/RF24_v2.ino:38: undefined reference to `RF24::setChannel(unsigned char)'
Do not mind remakes my hardware for using external clock and the matter will be solved I would still ask if you have any new update of finished because I noticed that in this version are some channels not working