Различия
Показаны различия между двумя версиями страницы.
| Предыдущая версия справа и слева Предыдущая версия Следующая версия | Предыдущая версия | ||
| zheleznaja_chast:besprovodnoj_dmx512_svoimi_rukami [2016/10/16 19:43] – 46.28.89.178 | zheleznaja_chast:besprovodnoj_dmx512_svoimi_rukami [2025/12/21 19:49] (текущий) – удалено 216.73.216.10 | ||
|---|---|---|---|
| Строка 1: | Строка 1: | ||
| - | ====== Беспроводной DMX512 приемник/ | ||
| - | {{: | ||
| - | ===== Общая информация ===== | ||
| - | В данной статье я расскажу вам как создать передатчик и приемник DMX512 сигнала. Выложена принципиальная схема, схема платы, и вся разводка. | ||
| - | | ||
| - | Приемник и передатчик могут передавать все 512 каналов управления. Без антенны базовая конфигурация работает до 100 метров в прямой видимости// | ||
| - | |||
| - | ---- | ||
| - | ===== Элементы используемые в схеме ===== | ||
| - | Сборка состоит из микроконтролера | ||
| - | * [[http:// | ||
| - | * 12v Вход (5v и 3.3v регулятор напряжения) | ||
| - | * 2 x [[: | ||
| - | * 2 x Светодиода(для индикации) | ||
| - | * [[http:// | ||
| - | * 3 x 100ом резисторы. | ||
| - | * 1 x 10кОМ резистор. | ||
| - | * 3 x 10uF конденсаторы. | ||
| - | * переключатель каналов, | ||
| - | * [[http:// | ||
| - | {{youtube> | ||
| - | |||
| - | |||
| - | ===== Схема подключения ===== | ||
| - | {{: | ||
| - | ==== Беспроводной модуль в сборе ==== | ||
| - | | ||
| - | |||
| - | {{: | ||
| - | {{: | ||
| - | ==== Готовая плата ==== | ||
| - | {{: | ||
| - | {{: | ||
| - | \\ | ||
| - | Существуют ситуации, | ||
| - | ==== Протокол передачи ==== | ||
| - | Прием и передача по протоколу [[: | ||
| - | 2,4 Радиомодуль подключен к плате Arduino или микроконтроллеру ATmega с помощью интерфейса SPI. Библиотека для использования чипа находится здесь https:// | ||
| - | После инициализации библиотеки можно передавать и принимать данные, | ||
| - | ===== Скетч для микроконтроллера ===== | ||
| - | <note warning> | ||
| - | <code cpp DMX512device.uno> | ||
| - | // FOR ATMEGA328 16mhz ONLY // | ||
| - | // connection information... | ||
| - | // http:// | ||
| - | // SN75176 configuration : | ||
| - | // DMXrx NRFtx : pin 2 = 0v | pin 3 = 0v | ||
| - | // NRFrx DMXtx : pin 2 = 0v | pin 3 = 5v | ||
| - | // pin 6 = DMX+ | pin7 = DMX- | ||
| - | // Ensure 3.3v is used to supply NRF24L01 board !! | ||
| - | // | ||
| - | // the Nrf24L01 board can only transmit from channel 0 to 83 in the USA, therefore we shall limit it to 0-80 in steps of 5 | ||
| - | |||
| - | #include < | ||
| - | #include < | ||
| - | #include < | ||
| - | #include < | ||
| - | #include < | ||
| - | #include < | ||
| - | |||
| - | #define MAX_DMX_CHANNELS 512 // full [[: | ||
| - | #define BYTES_PER_PACKET 16 // usable bytes per packet | ||
| - | #define PACKET_OVERHEAD 2 // group and time stamp | ||
| - | #define MAXPAYLOAD (BYTES_PER_PACKET+PACKET_OVERHEAD) // max payload size for nrf24l01 | ||
| - | #define MAXGROUPS (MAX_DMX_CHANNELS/ | ||
| - | |||
| - | // 16way hex channel selector - hex switch mounted with zero at top (see PCB layout) | ||
| - | #define HEX_0 A4 | ||
| - | #define HEX_1 A1 | ||
| - | #define HEX_2 A2 | ||
| - | #define HEX_3 A5 | ||
| - | // nRF24L01 control | ||
| - | #define nRF_CE 9 // Chip enable | ||
| - | #define nRF_CSN 10 // Chip select not | ||
| - | // LEDs | ||
| - | #define LED_BLUE 6 // BLUE PWM | ||
| - | #define LED_RED 5 // RED PWM | ||
| - | // sn76175 control | ||
| - | #define DMX_NOT_EN 2 | ||
| - | #define DMX_MODE 3 | ||
| - | // other | ||
| - | #define ROLE A0 // if low (jumper on) then RX otherwise TX | ||
| - | |||
| - | RF24 radio(nRF_CE, | ||
| - | |||
| - | unsigned long RXtimer, flashTimer, taskTimer, lastFlash, refreshTimer, | ||
| - | uint64_t RXTXaddress, | ||
| - | uint16_t rfQuality; | ||
| - | uint8_t payload[MAXPAYLOAD], | ||
| - | uint8_t timeStamp, lastStamp, bestChannel; | ||
| - | uint8_t HEXchannel, _HEXchannel, | ||
| - | boolean role, _role, group_send; | ||
| - | |||
| - | void setup(void) | ||
| - | { | ||
| - | // set DMX/rs485 interface | ||
| - | pinMode(DMX_NOT_EN, | ||
| - | digitalWrite(DMX_NOT_EN, | ||
| - | pinMode(DMX_MODE, | ||
| - | // set bicolour LED | ||
| - | pinMode(LED_BLUE, | ||
| - | digitalWrite(LED_BLUE, | ||
| - | pinMode(LED_RED, | ||
| - | digitalWrite(LED_RED, | ||
| - | // set up ROLE switch | ||
| - | pinMode(ROLE, | ||
| - | // set up HEX channel select switch | ||
| - | pinMode(HEX_0, | ||
| - | pinMode(HEX_1, | ||
| - | pinMode(HEX_2, | ||
| - | pinMode(HEX_3, | ||
| - | if ( digitalRead(ROLE) ) { // jumper off : transmitter : initialise & read EEPROM | ||
| - | init_EEPROM(); | ||
| - | } | ||
| - | radio.begin(); | ||
| - | |||
| - | // test nRF board, if it doesnt reply then flash LED indefinately, | ||
| - | while (!radio.isPVariant() ) { // check if board connected | ||
| - | if (digitalRead(ROLE)) { blue(); delay(500); off(); delay(500); } // Wireless TX : if no rf comms then flash BLUE 50% | ||
| - | else { red(); delay(500); off(); delay(500); } // Wireless RX : if no rf comms then flash RED 50% | ||
| - | } | ||
| - | |||
| - | // generic radio stuff | ||
| - | radio.setAutoAck(false); | ||
| - | radio.setPayloadSize(MAXPAYLOAD); | ||
| - | radio.setPALevel(RF24_PA_HIGH); | ||
| - | radio.setDataRate(RF24_250KBPS); | ||
| - | radio.setRetries(0, | ||
| - | // | ||
| - | // | ||
| - | |||
| - | HEXchannel = HEXread(); | ||
| - | |||
| - | // if this is a transmitter, | ||
| - | // only send clean channel data if channel selector is set to zero (send 0xFF if channel other than zero : manualPair) | ||
| - | if ( digitalRead(ROLE) ) { // jumper off : transmitter | ||
| - | bestChannelScan(); | ||
| - | if (HEXchannel) { // | ||
| - | bestChannelDisplay(); | ||
| - | } | ||
| - | } | ||
| - | // if this is a receiver, go into pairing mode and wait (indefinately) for pairing & channel data | ||
| - | // only use received (clean) channel data if channel selector is set to zero | ||
| - | else { | ||
| - | receivePairingAddress(); | ||
| - | } | ||
| - | rePairTimer = flashTimer = taskTimer = millis(); // TXtimer = | ||
| - | DMXSerial.maxChannel(MAX_DMX_CHANNELS); | ||
| - | rfQuality = 0; | ||
| - | // read and initialise HEX switch and Role jumper | ||
| - | readPins(true); | ||
| - | } // end of init | ||
| - | |||
| - | |||
| - | void loop(void) { | ||
| - | // once per second, test for changes in HEX Switch and Role jumper (rx/tx) | ||
| - | if (millis() - taskTimer > 1000) { | ||
| - | taskTimer = millis(); | ||
| - | readPins(false); | ||
| - | } | ||
| - | |||
| - | // JUMPER OFF : [[: | ||
| - | // LED Wireless TX : Solid BLUE, broken with very short flash of RED only if [[: | ||
| - | if (digitalRead(ROLE)) { // if a wireless transmitter | ||
| - | // SEND OUT BURSTS OF RADIO DATA EVERY 30ms.... | ||
| - | for (uint8_t group = 0; group < MAXGROUPS; group++) { // scan through the groups of DMX data, 30 bytes at a time | ||
| - | uint16_t group_ptr = group*BYTES_PER_PACKET; | ||
| - | if (millis() - refreshTimer > 1000) { // allow ALL radio data (full [[: | ||
| - | group_send = true; // force ALL send | ||
| - | refreshTimer = millis(); | ||
| - | } //if refresh timer | ||
| - | else { | ||
| - | group_send = false; // preset flag to false, only set it if there has been a data change since last time | ||
| - | } // not refresh timer | ||
| - | for (uint8_t chan = 1; chan < BYTES_PER_PACKET+1; | ||
| - | if ( DMXSerial.read(group_ptr+chan-1) != shadow_DMX[group_ptr+chan-1] ) { // compare test : current DMX against old DMX | ||
| - | shadow_DMX[group_ptr+chan-1] = DMXSerial.read(group_ptr+chan-1); | ||
| - | group_send = true; // set flag so that THIS group packet gets sent | ||
| - | } // if data compare | ||
| - | payload[chan+1] = DMXSerial.read(group_ptr+chan-1); | ||
| - | } // for chan | ||
| - | if (group_send) { // only send the data that has changed, any data change in a group will result in whole group send | ||
| - | payload[0] = group; // set first byte to point to group number (groups of 30 bytes) | ||
| - | payload[1] = timeStamp++; | ||
| - | radio.write( payload, sizeof(payload) ); // dump payload to radio | ||
| - | } // if group_send | ||
| - | } // for group | ||
| - | if ( (DMXSerial.noDataSince() < 2000) && (millis() > 1000) ) { // if [[: | ||
| - | if (!(millis() & 0b1111000000)) { | ||
| - | red(); | ||
| - | } | ||
| - | else { // SIMPLE [[: | ||
| - | digitalWrite(LED_RED, | ||
| - | analogWrite(LED_BLUE, | ||
| - | } | ||
| - | } | ||
| - | else { // no [[: | ||
| - | digitalWrite(LED_RED, | ||
| - | analogWrite(LED_BLUE, | ||
| - | } | ||
| - | // trigger rePair information send, just once every 2 seconds | ||
| - | if (millis() - rePairTimer > 2000) { | ||
| - | rePairTimer = millis(); | ||
| - | rePairTX(); // single burst of pairing information on pairing channel using pairing network address | ||
| - | } | ||
| - | } // if role | ||
| - | |||
| - | // JUMPER ON | ||
| - | // WIRELESS --> DMX | ||
| - | // LED Wireless RX : Solid RED, broken with flash of BLUE if wireless is being received (channel match) | ||
| - | // the gaps between the BLUE flashes are dependant on consistency of consecutive packets, relating to timeStamp | ||
| - | else { | ||
| - | if (millis() - RXtimer > 20000) { // after 20 seconds without receving any radio data, try and rePair | ||
| - | receivePairingAddress(); | ||
| - | } | ||
| - | else if (millis() - RXtimer > 2000) { // after 2 seconds of no radio data, stop blinking | ||
| - | rfQuality = 0; | ||
| - | } | ||
| - | if ( radio.available() ) { | ||
| - | if (!rfQuality) { | ||
| - | rfQuality = 50; // just to show that channel and address are locked on ! | ||
| - | } | ||
| - | RXtimer = millis(); | ||
| - | radio.read( payload, sizeof(payload) ); // get data packet from radio | ||
| - | if ( payload[1] == (lastStamp+1) ) { // check for continuous timestamps, increase quality indicator if good | ||
| - | if (rfQuality < 255) { rfQuality++; | ||
| - | } | ||
| - | else { // if incontinuous, | ||
| - | if (rfQuality > 50) { rfQuality--; | ||
| - | } | ||
| - | lastStamp = payload[1]; // reset last time stamp to current for checking next time | ||
| - | for (uint8_t i = 0; i < | ||
| - | DMXSerial.write((BYTES_PER_PACKET*payload[0])+i, | ||
| - | } | ||
| - | } // if radio avail | ||
| - | lastFlash = millis() - flashTimer; | ||
| - | if (lastFlash < 64) { | ||
| - | digitalWrite(LED_RED, | ||
| - | analogWrite(LED_BLUE, | ||
| - | } | ||
| - | else if (lastFlash >= 64) { | ||
| - | digitalWrite(LED_BLUE, | ||
| - | analogWrite(LED_RED, | ||
| - | } | ||
| - | if (lastFlash > 1024) { | ||
| - | flashTimer = millis(); // reset timer after 1 second(ish) | ||
| - | } | ||
| - | } // else | ||
| - | } // loop | ||
| - | |||
| - | // read HEX switch and Role jumper, if there has been a change in settings then an update can be made | ||
| - | void readPins(boolean initialise) { | ||
| - | _HEXchannel = HEXread(); // get temp HEXchannel | ||
| - | _role = digitalRead(ROLE); | ||
| - | if (_role != role || initialise) { // has the ROLE changed ?? - initialise will override any change in settings | ||
| - | role = _role; | ||
| - | if (role) { // JUMPER OFF : this is a wireless transmitter | ||
| - | digitalWrite(DMX_MODE, | ||
| - | DMXSerial.init(DMXReceiver); | ||
| - | radio.openWritingPipe(RXTXaddress); | ||
| - | radio.stopListening(); | ||
| - | digitalWrite(LED_RED, | ||
| - | analogWrite(LED_BLUE, | ||
| - | } | ||
| - | else { // JUMPER ON : this is a wireless receiver | ||
| - | digitalWrite(DMX_MODE, | ||
| - | DMXSerial.init(DMXController); | ||
| - | radio.openReadingPipe(1, | ||
| - | radio.startListening(); | ||
| - | digitalWrite(LED_BLUE, | ||
| - | analogWrite(LED_RED, | ||
| - | } | ||
| - | } | ||
| - | if (_HEXchannel != HEXchannel || initialise) { // has the CHANNEL changed ? - ' | ||
| - | HEXchannel = _HEXchannel; | ||
| - | rfQuality = 0; // reset this so that led stops flashing | ||
| - | if (!role) { | ||
| - | radio.stopListening(); | ||
| - | } | ||
| - | if (HEXchannel) { | ||
| - | RXTXchannel = HEXchannel*5; | ||
| - | } | ||
| - | radio.setChannel(RXTXchannel); | ||
| - | if (!role) { | ||
| - | radio.startListening(); | ||
| - | } | ||
| - | } | ||
| - | } | ||
| - | |||
| - | void red(void) { | ||
| - | digitalWrite(LED_BLUE, | ||
| - | digitalWrite(LED_RED, | ||
| - | } | ||
| - | void blue(void) { | ||
| - | digitalWrite(LED_BLUE, | ||
| - | digitalWrite(LED_RED, | ||
| - | } | ||
| - | void off(void) { | ||
| - | digitalWrite(LED_BLUE, | ||
| - | digitalWrite(LED_RED, | ||
| - | } | ||
| - | |||
| - | // manualPair & autoPair information | ||
| - | // selecting HEXchannel 0 instigates " | ||
| - | // The transmitter and receivers MUST be set to either ALL autoPair(0) or ALL manualPair(1-15) to work correctly | ||
| - | // manualPair mode can only select RXTXchannels 5 to 75 (via hex switch positions 1-15) | ||
| - | // manualPair & autoPair (on the Transmitter) has a ' | ||
| - | // autoPair : The best(quietest)channel will be transmitted with the network address on pairing | ||
| - | // manualPair : The best(quietest)channel is shown by number of blinks (shown as 3 groups of blinks) (bestChannelDisplay) | ||
| - | // The RXTXchannel number is 5 times that indicated - example 5 blinks = channel 60 | ||
| - | // In manualPair, the transmitter and all receivers must be manually set to that channel via the hex switch | ||
| - | |||
| - | // Transmitter : every 2 seconds, the transmitter sends its network address/ | ||
| - | // Receivers : on power up, receiver(s) are in pairing mode, receiver goes to channel 80 and listens on the pairing address/ | ||
| - | // | ||
| - | |||
| - | void bestChannelScan(void) { | ||
| - | | ||
| - | for (reps=0; reps< | ||
| - | for (i=1; i<16; i++) { | ||
| - | radio.setChannel(i*5); | ||
| - | radio.startListening(); | ||
| - | delayMicroseconds(128); | ||
| - | radio.stopListening(); | ||
| - | if ( radio.testCarrier() ) | ||
| - | ++carriers[i]; | ||
| - | } // i | ||
| - | } // reps | ||
| - | for (i=15; i>0; i--) { // find quietest channel, starting from highest channel | ||
| - | if (carriers[i] < best) { | ||
| - | best = carriers[i]; | ||
| - | RXTXchannel = i*5; //and save corresponding channel number | ||
| - | } | ||
| - | } | ||
| - | } | ||
| - | |||
| - | // BestChannel will only display if transmitter is not on HEX SWITCH 0 | ||
| - | void bestChannelDisplay(void) { | ||
| - | uint8_t i, x; | ||
| - | for (x=0; x<3; x++) { | ||
| - | for (i=0; i< | ||
| - | blue(); | ||
| - | delay(25); | ||
| - | off(); | ||
| - | delay(375); | ||
| - | } | ||
| - | delay(1000); | ||
| - | } | ||
| - | } | ||
| - | |||
| - | // read the value of the Hex Switch | ||
| - | uint8_t HEXread(void) { | ||
| - | return (!digitalRead(HEX_0)) | (!digitalRead(HEX_1) << 1) | (!digitalRead(HEX_2) << 2) | (!digitalRead(HEX_3) << 3); | ||
| - | } | ||
| - | |||
| - | // reguarily, the transmitter sends out a short burst of the config data on the pairing channel and using the pairing address | ||
| - | void rePairTX(void) { | ||
| - | radio.openWritingPipe(pairingAddress); | ||
| - | radio.setChannel(pairingChannel); | ||
| - | radio.stopListening(); | ||
| - | payload[0] = (uint8_t) (RXTXaddress); | ||
| - | payload[1] = (uint8_t) (RXTXaddress >> 8); | ||
| - | payload[2] = (uint8_t) (RXTXaddress >> 16); | ||
| - | payload[3] = (uint8_t) (RXTXaddress >> 24); | ||
| - | payload[4] = (uint8_t) (RXTXaddress >> 32); | ||
| - | if (HEXread()) { payload[5] = 0xFF; } | ||
| - | else { payload[5] = RXTXchannel; | ||
| - | radio.write( payload, sizeof(payload) ); // dump pairing data to radio | ||
| - | radio.openWritingPipe(RXTXaddress); | ||
| - | radio.setChannel(RXTXchannel); | ||
| - | radio.stopListening(); | ||
| - | } | ||
| - | |||
| - | void receivePairingAddress(void) { | ||
| - | uint8_t p, q; | ||
| - | radio.stopListening(); | ||
| - | radio.openReadingPipe(1, | ||
| - | radio.setChannel(pairingChannel); | ||
| - | radio.startListening(); | ||
| - | digitalWrite(LED_BLUE, | ||
| - | while ( !radio.available() ) { | ||
| - | analogWrite(LED_RED, | ||
| - | } | ||
| - | radio.read( payload, sizeof(payload) ); // get data packet from radio if available | ||
| - | RXTXaddress = (uint64_t)(payload[0]) | (uint64_t)(payload[1] << 8) | (uint64_t)(payload[2] << 16); | ||
| - | RXTXaddress |= (uint64_t)(payload[3] << 24) | (uint64_t)(payload[4] << 32); // get RXTX address from payload | ||
| - | if ( payload[5] == 0xFF ) { | ||
| - | RXTXchannel = HEXread()*5; | ||
| - | } | ||
| - | else { | ||
| - | RXTXchannel = payload[5]; // use best channel from scan | ||
| - | } | ||
| - | radio.stopListening(); | ||
| - | radio.openReadingPipe(1, | ||
| - | radio.setChannel(RXTXchannel); | ||
| - | radio.startListening(); | ||
| - | RXtimer = millis(); | ||
| - | } | ||
| - | |||
| - | void init_EEPROM(void) { | ||
| - | // do this only if a transmitter | ||
| - | // if the EEPROM hasnt already been set (all bytes at 0xFF) then set an address using 2 random numbers to make up unique 40bit address | ||
| - | // the address will be used in pairing. Once it has been set the first time it wont need to be set again | ||
| - | if ( digitalRead(ROLE) ) { // jumper off : transmitter | ||
| - | if ( (EEPROM.read(0) == 0xff) && (EEPROM.read(1) == 0xff) ) {// check for uninitialised/ | ||
| - | randomSeed(analogRead(A3)); | ||
| - | EEPROM.write(0, | ||
| - | EEPROM.write(1, | ||
| - | } | ||
| - | RXTXaddress = (uint64_t) (EEPROM.read(0)) | (uint64_t)(EEPROM.read(1) << 8) | (uint64_t)(EEPROM.read(1) << 16); | ||
| - | RXTXaddress |= (uint64_t)(EEPROM.read(1) << 24) | (uint64_t)(EEPROM.read(1) << 32); // reconstruct RXTXaddress from eeprom, byte 0 is unique, bytes 1-4 are the same | ||
| - | } | ||
| - | } | ||
| - | |||
| - | |||
| - | </ | ||
| - | **#define ROLE A0** - Эта строка отвечает за прием и ли передачу. Если нужен приемник то A0, передатчик A1 | ||
| - | |||
| - | <note important> | ||
| - | {(rater> | ||
| - | |||
| - | --- // | ||