DMX hardware rec for Teensy 3.2?

Status
Not open for further replies.

jparisse

Active member
Hi,

I'm making a halloween show controller with a Teensy 3.2 at the heart. Currently the Teensy is mounted to a SparkFun board that adapts it to the Arduino hardware format because I needed it to fit a DMX Arduino Shield I had purcahsed. The shield and accompaining library don't work (perhaps looking for an Arduino Uno harware timer that isnt there ??? IDK). I'm scrapping the shield...

Question? Will someone please recommend a DMX hardware board (Arduino style shield or not) that is proven to work with Teensy 3.2 and DMXSimple which I understand is a PJRC creation that works.

Thanks in advance.

Jeff
 
TeensyDMX Lib & existing shield

I’m looking at TeensyDMX and it looks well used/supported so I’m going to concentrate on making that library work.

I’ll start with the mystery DMX shield and move on with known hardware solutions if any are suggested.

Thanks.
 

Attachments

  • 2BA4F09C-0C3A-4891-ACBA-7D13678C8516.jpeg
    2BA4F09C-0C3A-4891-ACBA-7D13678C8516.jpeg
    139.5 KB · Views: 45
Last edited:
Thanks Paul! The key seems to be the TeensyDMX library. I able to get the library to work the hardware. To my DMX instruments to work just required a change from hex to decimal in the “data” string. Thanks again for the referral.

Jeff
 
Thanks Shawn!

Do let me know how the library works for you. I’m very interested in making sure it works well and robustly. (I’m assuming you mean this one: https://github.com/ssilverman/TeensyDMX. It’s also accessible via PlatformIO and the Arduino IDE.)

I can’t wait to jump in… I’m using very inexpensive fixtures that may not be unit addressable. BUT, your library is the only one (of three) that will communicate with them. I will bring up the DMX ID setting issue with the manufacturer (wish me luck) and in the meantime explore the seven channels of data that the units will accept via TeensyDMX.

Thanks for your efforts. This is my first foray into DMX lighting and my goal is to entertain the folks that walk by the house on halloween. I’ll keep the thread alive and share my experience.

Jeff
 

Attachments

  • 2B55133E-51EC-4F44-9E34-28561565A920.jpeg
    2B55133E-51EC-4F44-9E34-28561565A920.jpeg
    142.1 KB · Views: 59
I’m glad you got it working! Thanks for sharing the picture. Now I’m curious, what do you think is different or special about those fixtures? I wonder why my library works and not the others? I love this stuff…
 
I believe the other libraries made calls to hardware timers that don’t exist on the Teensy (just conjecture). The fixtures have a provision to set the DMX ID but the values either don’t stick or work. I’m waiting for more instruction from the maker.

Here are some photos of the fixture and the DMX instructions that came with it. I included photos of the project so far and am I’m going to start on the DMX code later today. I will share code as I move along.

Thanks for being interested, I love this stuff too!

Jeff
 

Attachments

  • 4645530C-39F0-47BF-A172-B2694204B25B.jpeg
    4645530C-39F0-47BF-A172-B2694204B25B.jpeg
    94.5 KB · Views: 42
  • E2918CDE-DF6E-40EB-9FDB-1A7A2132E683.jpeg
    E2918CDE-DF6E-40EB-9FDB-1A7A2132E683.jpeg
    129.3 KB · Views: 58
  • AE39E8D1-9513-472E-994D-1A932904C90E.jpeg
    AE39E8D1-9513-472E-994D-1A932904C90E.jpeg
    107.1 KB · Views: 49
  • E44FBAF8-D50A-4FBE-81B6-7475E598EC0C.jpeg
    E44FBAF8-D50A-4FBE-81B6-7475E598EC0C.jpeg
    118.5 KB · Views: 40
  • 52278F87-9085-46A7-867A-91898DCC992B.jpeg
    52278F87-9085-46A7-867A-91898DCC992B.jpeg
    109.4 KB · Views: 48
  • A6FB5A03-EAFE-49CE-B6A2-728D7B6119D5.jpeg
    A6FB5A03-EAFE-49CE-B6A2-728D7B6119D5.jpeg
    131.7 KB · Views: 40
How to address individual instruments?

I'm able to send seven channels of information to the first instrument (ID 1) but not to any others. Perhaps this question is too basic for the TeensyDMX documentation; I am a complete DMX newbie. How does one send a dmxTx.set command to other IDs?

If I set the ID on all instruments to "ID 1" then all lights respond to TeensyDMX commands sent to ID 1 (default ID?).

I have four instruments (non-moving RGB LED lights) in total, each capable of receiving seven channels of data.

Thanks in advance.

Jeff




Code:
/*
   A basic toy send example.

   This example is part of the TeensyDMX library.
   (c) 2019-2020 Shawn Silverman
*/

#include <TeensyDMX.h>

namespace teensydmx = ::qindesign::teensydmx;

teensydmx::Sender dmxTx{Serial1};

constexpr uint8_t kTXPin = 2;
uint8_t bright = 255;
uint8_t red = 128;
uint8_t green = 128;
uint8_t blue = 128;
uint8_t strobe = 0;
uint8_t mode = 0;
uint8_t modeModifier = 0;
uint8_t data[7] {bright, red, green, blue, strobe, mode, modeModifier};

void setup() {
  // Serial.begin(11520);
  pinMode(kTXPin, OUTPUT);
  digitalWrite(kTXPin, HIGH);

  // Set channels 1-7 to the 7 values in 'data'
  dmxTx.set(1, data, 7);

  dmxTx.begin();
}

void loop() {
  // Do something, maybe alter channel values.
}
 
Some questions and comments:
1. Change "11520" to "115200" in that commented-out Serial.begin(). (For posterity.)
2. One DMX universe consists of essentially one serial port and 513 slots. (The first slot, slot 0, is the "start code" and there are 512 channels.) The packets are sent approximately 44 times a second.
3. There's no such thing as "ID" in DMX. I can think of a few possibilities of what they might mean. First, do they mean different universes? (i.e. They all expect channels 1-7, where each device needs different values.) If so, just create more DMX transmitters on more serial ports and connect those separately. Each "universe", however, is still composed of 513 8-bit slots with no further meaning (other than the start code (slot 0) needing to be zero for raw DMX). It's also possible that "ID" means "Starting multiple of 7." For example, ID 1 means channels 1-7, ID 2 means channels 8-14, etc.
4. Do you need to be setting pin 2 high? It's meant for circuits that require some pin to be set (high or low) to enable or disable TX/RX. For example, the Sparkfun RS-485 breakout boards use such a line. How are you interfacing the serial port to the RS-485 lines? On the other hand, this may be entirely intended. (I’ve received questions about it because I set the pin in the examples and sometimes people just copy it. I believe you know what you’re doing.)
5. Do you have device docs you can share?
 
Last edited:
shawn,

Re:
#1 - burp, how funny that I set that here for debugging.
#2 - Thanks for that... I understand the universe now! I reason now that the ID is for different universes. I should therefore set all instruments to ID1 (Universe 0).
#3 - The second possibliity you suggested seems to be correct.
#4 - Hardware (shown in pic on second post in thread) is poorly documented. Pin #2 is set HIGH to enable transmitting as I am reasoning at this point. I really dont know for sure.
#5 - I just found this on the web; it pretty much spells out what I reason you're about to tell me. Still a mystery until I start trying out code but I think I get it; I have to send four sets of seven channels to my four instruments (that all live in the same universe).

I'm laughing only because I thought it was only science fiction superhero movies that employed multiple universes. Thanks for your help and interest in the project. My wife and I hung rigging all day for the animatronic skeletions... I cant wait to add DMX and Im very happy for your help.

From the web:
Table 2 – Example channel ranges for 7-channel fixtures in a DMX universe

Fixture DMX Channel Base Channels Used
1 1 1-7
2 8 8-14
3 15 15-21
4 22 22-28
5 29 29-35
6 36 36-42
7 43 43-49
8 50 50-56
9 57 57-63
10 64 64-70

73 505 505-512


Technical details

The following tables show the technical specifications of the fixtures, as tested by the Finale support team.



Table 3 – DMX channels for 7CH personality

DMX Channel Meaning
Channel 1 (DMX Channel Base + 0) Dimmer
Channel 2 (DMX Channel Base + 1) Red
Channel 3 (DMX Channel Base + 2) Green
Channel 4 (DMX Channel Base + 3) Blue
Channel 5 (DMX Channel Base + 4) Strobe (0-7 = no strobe; 8-255 = slow to fast)
Channel 6 (DMX Channel Base + 5) Set to zero
Channel 7 (DMX Channel Base + 6) Set to zero
 
Glad you figured it out. Sounds like “ID” is really just “DMX Channel Base”. Side note: that last line, #73, should end in 511.

This also means you can use the same universe and just set all the fixtures to consecutive numbers and then physically chain them. Then, when addressing each one, just add “(base*7)-6”, assuming the first base is set to “1”.

How many fixtures in total do you have?

I’d love to see videos when you have it all working.
 
Last edited:
Here's some code I whipped up. There's lots and lots of ways to tackle this. Hope this is useful.

Code:
// C++ includes
#include <vector>

#include <TeensyDMX.h>

namespace teensydmx = qindesign::teensydmx;

// --------------------------------------------------------------------------
//  Configuration
// --------------------------------------------------------------------------

// Enables TX on the connected fixtures.
constexpr uint8_t kTXPin = 2;

// Number of fixtures.
constexpr int kFixtureCount = 6;

// --------------------------------------------------------------------------
//  Fixture interface
// --------------------------------------------------------------------------

// Provides an easier interface to a fixture.
class Fixture {
 public:
  Fixture(int id, teensydmx::Sender &dmxTx)
      : base_((id - 1)*7 + 1),
        dmxTx_(dmxTx) {
    // Initialize everything to zero
    dmxTx_.fill(base_, 7, 0);
  }

  ~Fixture() = default;

  void setDim(uint8_t value) {
    dim_ = value;
    dmxTx_.set(base_ + kDim, value);
  }
  uint8_t getDim() const { return dim_; }

  void setRed(uint8_t value) {
    red_ = value;
    dmxTx_.set(base_ + kRed, value);
  }
  uint8_t getRed() const { return red_; }
  
  void setGreen(uint8_t value) {
    green_ = value;
    dmxTx_.set(base_ + kGreen, value);
  }
  uint8_t getGreen() const { return green_; }

  void setBlue(uint8_t value) {
    blue_ = value;
    dmxTx_.set(base_ + kBlue, value);
  }
  uint8_t getBlue() const { return blue_; }

  // Sets the strobe. 0-7 means "No strobe" and
  // 8-255 means "Slow to fast".
  void setStrobe(uint8_t value) {
    strobe_ = value;
    dmxTx_.set(base_ + kStrobe, value);
  }
  uint8_t getStrobe() const { return strobe_; }

 private:
  // Channels
  static constexpr int kDim = 0;
  static constexpr int kRed = 1;
  static constexpr int kGreen = 2;
  static constexpr int kBlue = 3;
  static constexpr int kStrobe = 4;

  const int base_;  // Base DMX address
  teensydmx::Sender &dmxTx_;

  // Since Sender doesn't currently let you read what's being output,
  // capture the current states here
  uint8_t dim_ = 0;
  uint8_t red_ = 0;
  uint8_t green_ = 0;
  uint8_t blue_ = 0;
  uint8_t strobe_ = 0;
};

// -------------------------------------------------------------------
//  Main program
// -------------------------------------------------------------------

teensydmx::Sender dmxTx{Serial1};  // DMX on Serial1

// All the fixtures, set up in setup().
std::vector<Fixture> fixtures;

// For "change every second demo"
elapsedMillis timer;

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 4000) {
    // Wait for Serial to initialize for at most 4 seconds
  }
  Serial.println("Starting...");

  // Enable DMX output (check if this is needed)
  pinMode(kTXPin, OUTPUT);
  digitalWrite(kTXPin, HIGH);

  // Set up all the fixtures
  // Note: There's ways around it, but index 0 has fixture 1,
  //       index 1 has fixture 2, etc.
  for (int i = 0; i < kFixtureCount; i++) {
    fixtures.emplace_back(i + 1, dmxTx);  // Start ID at 1
  }

  // I believe the system initializes the sender to be all zero,
  // but clear just in case
  dmxTx.clear();

  // Initialize all the fixtures
  Serial.println("Initializing fixtures...");
  for (auto &fixture : fixtures) {
    fixture.setDim(255);
    fixture.setRed(128);
    fixture.setGreen(128);
    fixture.setBlue(128);
    fixture.setStrobe(0);
  }

  Serial.println("Starting DMX TX...");
  dmxTx.begin();
}

void loop() {
  // For demo purposes, change the dimming of all fixtures
  // once every second
  // There's a gazillion other effects you could do here

  if (timer < 1000) {
    return;
  }
  timer = 0;

  for (auto &fixture : fixtures) {
    fixture.setDim(fixture.getDim() + 128);
  }
}
 
Wow Shawn! Tremendously useful! It may take more time than I have for this Halloween to understand fully but I will look at it very soon.

I wrote something very simple (luckily for me it is a Roaring Twenties light show so it doesn't need to be sophisticated (like my programming skills). I'd figure that I'd write a bunch of light setting functions and pick them at random as my show progresses.


/*
TeensyDMX library (c) 2019-2020 Shawn Silverman
*/

#include <TeensyDMX.h>

namespace teensydmx = ::qindesign::teensydmx;

constexpr uint8_t dmxPin = 2;

teensydmx::Sender dmxTx{Serial1};

/*
Data
1 [0]brightness 0-255
2 [1]red 0-255
3 (2]green 0-255
4 [3]blue 0-255
5 [4]strobe 0-255
6 [5]mode
0-10 Manual control CH1-CH5
11-60 Color Selection (controlled by CH7)
61-110 Color Shade (controlled bt CH7)
111-160 Color Pulse Transform (speed controlled by CH7)
161-210 Color Transform (speed controlled by CH7)
211-255 Sound Control
7 [6]modifier 0-255
*/

// Default - All instruments BLUE 50% Brightness
uint8_t bright = 128;
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 255;
uint8_t strobe = 0;
uint8_t mode = 0;
uint8_t modifier = 0;
uint8_t data[7] {bright, red, green, blue, strobe, mode, modifier}; // All instruments BLUE

void setup() {
// Serial.begin(115200);
pinMode(dmxPin, OUTPUT);
digitalWriteFast(dmxPin, HIGH);
dmxTx.set(1, data, 7); // Instrument #1
dmxTx.set(8, data, 7); // Instrument #2
dmxTx.set(15, data, 7); // Instrument #3
dmxTx.set(22, data, 7); // Instrument #4
dmxTx.begin();
delay(3000);
}

void loop() {
dmx_allRed();
dmxTx.begin();
delay(3000);
dmx_allGreen();
dmxTx.begin();
delay(3000);
}

void dmx_allRed() {
data[0] = 255; // Brightness
data[1] = 255; // Red
data[2] = 0; // Green
data[3] = 0; // Blue
data[4] = 0; // Strobe
data[5] = 0; // Mode (see Table)
data[6] = 0; // Modifier (see Table)
dmxTx.set(1, data, 7); // Instrument #1
dmxTx.set(8, data, 7); // Instrument #2
dmxTx.set(15, data, 7); // Instrument #3
dmxTx.set(22, data, 7); // Instrument #4
}

void dmx_allGreen() {
data[0] = 255; // Brightness
data[1] = 0; // Red
data[2] = 255; // Green
data[3] = 0; // Blue
data[4] = 0; // Strobe
data[5] = 0; // Mode (see Table)
data[6] = 0; // Modifier (see Table)
dmxTx.set(1, data, 7); // Instrument #1
dmxTx.set(8, data, 7); // Instrument #2
dmxTx.set(15, data, 7); // Instrument #3
dmxTx.set(22, data, 7); // Instrument #4
}
 
Do you think in future you could enclose your code between [C ODE] tags. These are the ones produced by pressing the # button above.
Doing so keeps the format of the code and makes it more readable, so others are more able to help you.
I am glad you are making progress with your project.
Code:
/*
TeensyDMX library (c) 2019-2020 Shawn Silverman
*/

#include <TeensyDMX.h>

namespace teensydmx = ::qindesign::teensydmx;

constexpr uint8_t dmxPin = 2;

teensydmx::Sender dmxTx{ Serial1 };

/*
Data
1 [0]brightness 0-255
2 [1]red 0-255
3 (2]green 0-255
4 [3]blue 0-255
5 [4]strobe 0-255
6 [5]mode
0-10 Manual control CH1-CH5
11-60 Color Selection (controlled by CH7)
61-110 Color Shade (controlled bt CH7)
111-160 Color Pulse Transform (speed controlled by CH7)
161-210 Color Transform (speed controlled by CH7)
211-255 Sound Control
7 [6]modifier 0-255
*/

// Default - All instruments BLUE 50% Brightness
uint8_t bright = 128;
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 255;
uint8_t strobe = 0;
uint8_t mode = 0;
uint8_t modifier = 0;
uint8_t data[7]{ bright, red, green, blue, strobe, mode, modifier }; // All instruments BLUE

void setup() {
	// Serial.begin(115200);
	pinMode(dmxPin, OUTPUT);
	digitalWriteFast(dmxPin, HIGH);
	dmxTx.set(1, data, 7); // Instrument #1
	dmxTx.set(8, data, 7); // Instrument #2
	dmxTx.set(15, data, 7); // Instrument #3
	dmxTx.set(22, data, 7); // Instrument #4
	dmxTx.begin();
	delay(3000);
}

void loop() {
	dmx_allRed();
	dmxTx.begin();
	delay(3000);
	dmx_allGreen();
	dmxTx.begin();
	delay(3000);
}

void dmx_allRed() {
	data[0] = 255; // Brightness
	data[1] = 255; // Red
	data[2] = 0; // Green
	data[3] = 0; // Blue
	data[4] = 0; // Strobe
	data[5] = 0; // Mode (see Table)
	data[6] = 0; // Modifier (see Table)
	dmxTx.set(1, data, 7); // Instrument #1
	dmxTx.set(8, data, 7); // Instrument #2
	dmxTx.set(15, data, 7); // Instrument #3
	dmxTx.set(22, data, 7); // Instrument #4
}

void dmx_allGreen() {
	data[0] = 255; // Brightness
	data[1] = 0; // Red
	data[2] = 255; // Green
	data[3] = 0; // Blue
	data[4] = 0; // Strobe
	data[5] = 0; // Mode (see Table)
	data[6] = 0; // Modifier (see Table)
	dmxTx.set(1, data, 7); // Instrument #1
	dmxTx.set(8, data, 7); // Instrument #2
	dmxTx.set(15, data, 7); // Instrument #3
	dmxTx.set(22, data, 7); // Instrument #4
}
 
@Jeff
You better delete dmxTx.begin(); from loop().
You already started the service in your setup(), so no need to (re)start that in loop() again and again. Just apply new values using dmxTx.set(). Like so:
Code:
void loop() {
  dmx_allRed();
  delay(3000);
  dmx_allGreen();
  delay(3000);
}
Paul
 
Do you think in future you could enclose your code between [C ODE] tags. These are the ones produced by pressing the # button above.
Doing so keeps the format of the code and makes it more readable, so others are more able to help you.
I am glad you are making progress with your project.
Code:
/*
TeensyDMX library (c) 2019-2020 Shawn Silverman
*/

#include <TeensyDMX.h>

namespace teensydmx = ::qindesign::teensydmx;

constexpr uint8_t dmxPin = 2;

teensydmx::Sender dmxTx{ Serial1 };

/*
Data
1 [0]brightness 0-255
2 [1]red 0-255
3 (2]green 0-255
4 [3]blue 0-255
5 [4]strobe 0-255
6 [5]mode
0-10 Manual control CH1-CH5
11-60 Color Selection (controlled by CH7)
61-110 Color Shade (controlled bt CH7)
111-160 Color Pulse Transform (speed controlled by CH7)
161-210 Color Transform (speed controlled by CH7)
211-255 Sound Control
7 [6]modifier 0-255
*/

// Default - All instruments BLUE 50% Brightness
uint8_t bright = 128;
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 255;
uint8_t strobe = 0;
uint8_t mode = 0;
uint8_t modifier = 0;
uint8_t data[7]{ bright, red, green, blue, strobe, mode, modifier }; // All instruments BLUE

void setup() {
	// Serial.begin(115200);
	pinMode(dmxPin, OUTPUT);
	digitalWriteFast(dmxPin, HIGH);
	dmxTx.set(1, data, 7); // Instrument #1
	dmxTx.set(8, data, 7); // Instrument #2
	dmxTx.set(15, data, 7); // Instrument #3
	dmxTx.set(22, data, 7); // Instrument #4
	dmxTx.begin();
	delay(3000);
}

void loop() {
	dmx_allRed();
	dmxTx.begin();
	delay(3000);
	dmx_allGreen();
	dmxTx.begin();
	delay(3000);
}

void dmx_allRed() {
	data[0] = 255; // Brightness
	data[1] = 255; // Red
	data[2] = 0; // Green
	data[3] = 0; // Blue
	data[4] = 0; // Strobe
	data[5] = 0; // Mode (see Table)
	data[6] = 0; // Modifier (see Table)
	dmxTx.set(1, data, 7); // Instrument #1
	dmxTx.set(8, data, 7); // Instrument #2
	dmxTx.set(15, data, 7); // Instrument #3
	dmxTx.set(22, data, 7); // Instrument #4
}

void dmx_allGreen() {
	data[0] = 255; // Brightness
	data[1] = 0; // Red
	data[2] = 255; // Green
	data[3] = 0; // Blue
	data[4] = 0; // Strobe
	data[5] = 0; // Mode (see Table)
	data[6] = 0; // Modifier (see Table)
	dmxTx.set(1, data, 7); // Instrument #1
	dmxTx.set(8, data, 7); // Instrument #2
	dmxTx.set(15, data, 7); // Instrument #3
	dmxTx.set(22, data, 7); // Instrument #4
}


Thanks BriComp! I believe I did exactly that and one can reason my intentions from the “encapsulated code” I did publish. I will look more closely at the tiny buttons; none of which say “code”. Thanks for the style tip. I’ll be more careful in my subsequent replies and uses the # button next time.

Jeff
 
Paul,

Thanks so much for the catch. I’m getting to frantic part of the project and am mired in mechanics and spray paint while attempting to up my coding skills. I bit off more than I can chew this Halloween and I am very grateful for all the help I have been getting in this thread. Teensy rocks and so does the community!

Jeff

D0C4D7A4-6C56-41CD-BB38-BD235A100A4B.jpeg9A1BA3A3-1BB1-45F3-8C17-741D3A392549.jpeg
 

Attachments

  • A671F6EF-09D3-4E46-B493-6DE445BAC5EC.jpeg
    A671F6EF-09D3-4E46-B493-6DE445BAC5EC.jpeg
    125.6 KB · Views: 36
Thanks BriComp! I believe I did exactly that and one can reason my intentions from the “encapsulated code” I did publish. I will look more closely at the tiny buttons; none of which say “code”. Thanks for the style tip. I’ll be more careful in my subsequent replies and uses the # button next time.

Jeff
Yea I couldn't find out how people were encapsulating the code when I first started. Eventually found out how!!
I have since found that if you hover over the buttons an explanation of it's use pops up.
 
Opening Night Friday!

Here is the basis of what is working for me so far. In the final program, the various light functions will be called at a set time to match the music but a random choice (spot light on dancer #1, all blue, fade to black. etc.). I did something similar with the skeleton dance moves using "switch case" and a random number generator.


Code:
/*
   TeensyDMX library (c) 2019-2020 Shawn Silverman
*/

#include <TeensyDMX.h>
namespace teensydmx = ::qindesign::teensydmx;
constexpr uint8_t dmxPin = 2;
teensydmx::Sender dmxTx{Serial1};

/*
   Data
   1 [0]brightness 0-255
   2 [1]red 0-255
   3 (2]green 0-255
   4 [3]blue 0-255
   5 [4]strobe 0-255
   6 [5]mode
          0-10 Manual control CH1-CH5
          11-60 Color Selection (controlled by CH7)
          61-110 Color Shade (controlled bt CH7)
          111-160 Color Pulse Transform (speed controlled by CH7)
          161-210 Color Transform (speed controlled by CH7)
          211-255 Sound Control
   7 [6]modifier 0-255
*/

uint8_t data[7] {128, 0, 0, 255, 0, 0, 0};    // Default: All instruments BLUE @ 50%

void setup() {
  // Serial.begin(115200);
  pinMode(dmxPin, OUTPUT);
  digitalWrite(dmxPin, HIGH);
  for (int x = 1; x <= 23; x = x + 7) {
    dmxTx.set(x, data, 7);
  }
  dmxTx.begin();
  delay(3000);
}

void loop() {
  dmx_allRed();
  delay(3000);
  for (int fade=255; fade>=0; --fade) {
    dmxTx.set(1, fade);
    delay(10);
  }
  dmx_allGreen();
  delay(3000);
  dmx_allBlue();
  delay(3000);
}

void dmx_allRed() {
  uint8_t data[7] = {255, 255, 0, 0, 0, 0, 0};
  for (int x = 1; x <= 23; x = x + 7) {
    dmxTx.set(x, data, 7);
  }
}

void dmx_allGreen() {
  uint8_t data[7] = {255, 0, 255, 0, 0, 0, 0};
  for (int x = 1; x <= 23; x = x + 7) {
    dmxTx.set(x, data, 7);
  }
}

void dmx_allBlue() {
  uint8_t data[7] = {255, 0, 0, 255, 0, 0, 0};
  for (int x = 1; x <= 23; x = x + 7) {
    dmxTx.set(x, data, 7);
  }
}
 
Stuck for the night.....

OK... It is 12AM and I have to go to sleep....
For some reason I can't figure out how an array assignment that works standalone does not work as a function.
I am getting a error that reads:

Holiday_Show_Controller: In function 'void playDmx()':

Holiday_Show_Controller:306: error: cannot convert '<brace-enclosed initializer list>' to 'uint8_t {aka unsigned char}' in assignment

data[7] = {255, 255, 0, 0, 0, 0, 0}; // Red

^
What am I doing wrong? Thanks in advance....

Jeff



Code:
/***************************************************
  Holiday Show Control - v1.1 10/09/21
  by Jeff W. Parisse - 09/09/2021
  jparisse@me.com
  TeensyDMX library (c) 2019-2020 Shawn Silverman

  This program acts as a show controller for holiday show projects. It runs on a Teesy 3.2 and controls servos via
  an Adafruit I2C servo controller, addressable LEDs via a Adafruit M4 Express processor board, sound via an Adafruit
  16Mb Sound F/C Controller and DMX via a CTC-DRA-10-R2 Arduino Shield.

  Processor: Teensy 3.2
  PIR Sensor: 5V In, 3.3V Logic HIGH on Detect
  DMX Shield: Generic using TeensyDMX Library
  NEO Processor; Adafruit Itsy Bitsy M4 Express, LOW to trigger
  Sound F/X Board: LOW to trigger
  Servo Driver: I2C Address A1 (despite hardware A0 selected)
  AC Relays: HIGH to turn ON

  Pin Outs:
    Pin 0   RX    Serial In
    Pin 1   TX    Serial Out
    Pin 2   DMX   DOUT
    Pin 3   PIR   DIN
    Pin 4   AUX   DIN
    Pin 5   NEO   DOUT
    Pin 6   AC1   DOUT
    Pin 7   AC2   DOUT
    Pin 8   SFX0  DOUT
    Pin 9   SFX1  DOUT
    Pin 10  SFX2  DOUT
    Pin 11  SFX3  DOUT
    Pin 12  SFX4  DOUT
    Pin 13  LED   DOUT
    Pin 14  SFX5  DOUT
    Pin 15  SFX6  DOUT
    Pin 16  SFX7  DOUT
    Pin 17  SFX8  DOUT
    Pin 18  SDA   I2C
    Pin 19  SCL   I2C
    Pin 22  VOL+  DOUT (v1.1 not used)
    Pin 23  VOL-  DOUT (v1.1 not used)
 ****************************************************/

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include <TeensyDMX.h>

#define dmxPin 2
#define pirPin 3
#define auxPin 4
#define neoPin 5
#define ac1Pin 6
#define ac2Pin 7
#define sfx0Pin 8
#define sfx1Pin 9
#define sfx2Pin 10
#define sfx3Pin 11
#define sfx4Pin 12
#define ledPin 13
#define sfx5Pin 14
#define sfx6Pin 15
#define sfx7Pin 16
#define sfx8Pin 17
#define volupPin 22
#define voldnPin 23
#define servoFreq 50                 // ~50 Hz servo updates

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
namespace teensydmx = ::qindesign::teensydmx;
teensydmx::Sender dmxTx{Serial1};

// DMX Variables
uint8_t data[7] = {0, 128, 128, 128, 0, 0, 0};          // Default: 50% White OFF

// Servo Variables
uint8_t servo1 = 0;
uint8_t servo2 = 1;
uint8_t servo3 = 2;
uint8_t servo4 = 3;
uint8_t servo5 = 4;
uint8_t servo6 = 5;
uint8_t servo7 = 6;
uint8_t servo8 = 7;
uint8_t servo9 = 8;
uint8_t servo10 = 9;
uint8_t servo11 = 10;
uint8_t servo12 = 11;
uint8_t servo13 = 12;
uint8_t servo14 = 13;
uint8_t servo15 = 14;
uint8_t servo16 = 15;

// Servo Timer
boolean servoDirection = LOW;
uint16_t servoMin = 167;                       // 900ms This is the 'minimum' pulse length count (out of 4096)
uint16_t servoCenter = 279;                    // 900ms This is the 'minimum' pulse length count (out of 4096)
uint16_t servoMax = 390;                       // 2100ms This is the 'maximum' pulse length count (out of 4096)
unsigned long servoInterval = 500;             // Default
unsigned long previousServoMillis = 0;

// Moon Timer
boolean moonState = LOW;
uint16_t moonMin = 167;                       // 900ms This is the 'minimum' pulse length count (out of 4096)
uint16_t moonMax = 390;                       // 2100ms This is the 'maximum' pulse length count (out of 4096)
unsigned long moonInterval = 10;              // Default Servo Delay
unsigned long previousMoonMillis = 0;

// Show Timer
boolean showState = LOW;
int showMin = 120000;                         // 120,000 ms = 00:02:00 (two minutes)
int showMax = 180000;                         // 180,000 ms = 00:03:00 (three minutes)
unsigned long showInterval = 120000;          // 120,000 ms = 00:02:00
unsigned long previousShowMillis = 0;

// Delay Timer
boolean delayState = HIGH;
int delayMin = 30000;                        // 30,000 ms = 00:00:30 (thirty seconds)
int delayMax = 60000;                        // 60,000 ms = 00:01:00 (one minute)
unsigned long delayInterval = 15000;         // 15,000 ms = 00:00:15
unsigned long previousDelayMillis = 0;

int songPick = 6;                            // Start with Song #6
int dmxPick = 1;                             // Default
int intervalPick = 2;                        // Default
int danceStep = 250;                         // Default

void setup() {
  // Serial.begin(115200);
  pwm.begin();
  pwm.setOscillatorFrequency(27000000);
  pwm.setPWMFreq(servoFreq);                 // Analog servos run at ~50 Hz updates
  pinMode(pirPin, INPUT);
  pinMode(auxPin, INPUT_PULLUP);
  pinMode(dmxPin, OUTPUT);
  pinMode(neoPin, OUTPUT);
  pinMode(ac1Pin, OUTPUT);
  pinMode(ac2Pin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(sfx0Pin, OUTPUT);
  pinMode(sfx1Pin, OUTPUT);
  pinMode(sfx2Pin, OUTPUT);
  pinMode(sfx3Pin, OUTPUT);
  pinMode(sfx4Pin, OUTPUT);
  pinMode(sfx5Pin, OUTPUT);
  pinMode(sfx6Pin, OUTPUT);
  pinMode(sfx7Pin, OUTPUT);
  pinMode(sfx8Pin, OUTPUT);
  pinMode(volupPin, OUTPUT);
  pinMode(voldnPin, OUTPUT);

  // Turn everything OFF
  pwm.setPWM(servo9, 0, moonMin);
  digitalWrite(dmxPin, HIGH);
  for (int x = 1; x <= 23; x = x + 7) {
    dmxTx.set(x, data, 7);
  }
  dmxTx.begin();
  digitalWrite(neoPin, LOW);
  digitalWrite(ac1Pin, LOW);
  digitalWrite(ac2Pin, LOW);
  digitalWrite(ledPin, LOW);
  soundOff();
  delay(4000);                                          // Wait 4 seconds for PIR Module to go LOW
  digitalWrite(sfx0Pin, LOW);                           // Ambient Sound ON
}

void loop() {
  unsigned long currentMillis = millis();              // Check Time
  boolean pirState = digitalRead(pirPin);              // Check PIR Trigger
  if (pirState == HIGH) {                              // If PIR triggered, change showState to HIGH
    showState = HIGH;
    digitalWrite(ledPin, HIGH);
  }
  else {
    digitalWrite(ledPin, LOW);
  }
  if (showState == HIGH && delayState == HIGH) {
    digitalWrite(sfx0Pin, HIGH);                       // Ambient Sound OFF
    digitalWrite(sfx1Pin, LOW);                        // Play Paper Moon
    digitalWrite(ac1Pin, HIGH);                        // Black Lights ON
    if (moonState == LOW) {
      for (uint16_t moonPos = moonMin; moonPos <= moonMax; ++moonPos) {
        pwm.setPWM(servo9, 0, moonPos); // Test Servo
        delay(10);
      }

      // wait for song to end
      delay(5000); //test

      digitalWrite(ac1Pin, LOW);                        // Black Lights ON
      for (uint16_t moonPos = moonMax; moonPos <= moonMin; --moonPos) {
        pwm.setPWM(servo9, 0, moonPos); // Test Servo
        delay(10);
      }
      moonState = HIGH;
      digitalWrite(sfx1Pin, HIGH);                     // Paper Moon OFF
    }

    // Dance Show Starts Here
    digitalWrite(ac2Pin, HIGH);                       // Mirror Ball ON
    digitalWrite(neoPin, HIGH);                       // Neopixels ON
    playSong();                                       // Start Music
    if (currentMillis - previousServoMillis >= servoInterval) {
      previousServoMillis = currentMillis;
      playDmx();
      for (int x = 1; x <= 23; x = x + 7) {
        dmxTx.set(x, data, 7);
      }
      if (servoDirection == LOW) {
        uint16_t pulseLengthLow1 = random(servoMin, servoCenter);
        uint16_t pulseLengthLow2 = random(servoMin, servoCenter);
        pwm.setPWM(servo1, 0, pulseLengthLow1);
        pwm.setPWM(servo2, 0, pulseLengthLow2);
        pwm.setPWM(servo9, 0, pulseLengthLow2); // Test Servo
        servoInterval = getDanceStep();
        servoDirection = HIGH;
      }
      else {
        uint16_t pulseLengthHigh1 = random(servoCenter, servoMax);
        uint16_t pulseLengthHigh2 = random(servoCenter, servoMax);
        pwm.setPWM(servo1, 0, pulseLengthHigh1);
        pwm.setPWM(servo2, 0, pulseLengthHigh2);
        pwm.setPWM(servo9, 0, pulseLengthHigh2); // Test Servo
        servoInterval = getDanceStep();
        servoDirection = LOW;
      }
    }

    // Check for End of Show
    if (currentMillis - previousShowMillis >= showInterval) {
      previousShowMillis = currentMillis;
      previousDelayMillis = currentMillis;
      showState = LOW;                                              // Change STATE to Delay
      delayState = LOW;
      moonState = LOW;
      pwm.setPWM(servo1, 0, servoCenter);
      pwm.setPWM(servo2, 0, servoCenter);
      pwm.setPWM(servo9, 0, servoCenter);                           // Test Servo
      digitalWrite(neoPin, LOW);                                    // NeoPixels Off
      digitalWrite(ac2Pin, LOW);                                    // AC 2 OFF
      soundOff();                                                   // Turn off sound
      digitalWrite(sfx0Pin, LOW);                                   // Sound #0 ON - Scene 0
      ++songPick;                                                   // Advance Song List by 1
      if (songPick >= 9) {                                          // If >8, Rollover Song List
        songPick = 1;
      }
      showInterval = random(showMin, showMax);                      // Pick new show interval.
      delayInterval = random(delayMin, delayMax);                   // Pick new delay interval.
    }
  }

  if (currentMillis - previousDelayMillis >= delayInterval) {
    previousDelayMillis = currentMillis;
    delayState = HIGH;
  }
}

// Functions
void soundOff() {
  digitalWrite(sfx0Pin, HIGH);
  digitalWrite(sfx1Pin, HIGH);
  digitalWrite(sfx2Pin, HIGH);
  digitalWrite(sfx3Pin, HIGH);
  digitalWrite(sfx4Pin, HIGH);
  digitalWrite(sfx5Pin, HIGH);
  digitalWrite(sfx6Pin, HIGH);
  digitalWrite(sfx7Pin, HIGH);
  digitalWrite(sfx8Pin, HIGH);
  digitalWrite(volupPin, HIGH);
  digitalWrite(voldnPin, HIGH);
}

void playSong() {
  switch (songPick) {
    case 1:
      digitalWrite(sfx1Pin, LOW);
      break;
    case 2:
      digitalWrite(sfx2Pin, LOW);
      break;
    case 3:
      digitalWrite(sfx3Pin, LOW);
      break;
    case 4:
      digitalWrite(sfx4Pin, LOW);
      break;
    case 5:
      digitalWrite(sfx5Pin, LOW);
      break;
    case 6:
      digitalWrite(sfx6Pin, LOW);
      break;
    case 7:
      digitalWrite(sfx7Pin, LOW);
      break;
    case 8:
      digitalWrite(sfx8Pin, LOW);
      break;
  }
}

void playDmx() {
  dmxPick = random(1, 11);
  switch (dmxPick) {
    case 1:
      data[7] = {255, 255, 0, 0, 0, 0, 0}; // Red
      break;
    case 2:
      data[7] = {255, 0, 255, 0, 0, 0, 0}; // Green
      break;
    case 3:
      data[7] = {255, 0, 0, 255, 0, 0, 0}; // Blue
      break;
    case 4:
      data[7] = {255, 255, 255, 255, 0, 0, 0}; // White
      break;
    case 5:
      data[7] = {255, 255, 255, 0, 0, 0, 0}; // Yellow
      break;
    case 6:
      data[7] = {255, 255, 0, 255, 0, 0, 0}; // Purple
      break;
    case 7:
      data[7] = {255, 0, 255, 255, 0, 0, 0}; // Cyan
      break;
    case 8:
      uint8_t data[7] = {255, 255, 255, 255, 0, 0, 0};
      break;
    case 9:
      uint8_t data[7] = {255, 255, 255, 255, 0, 0, 0};
      break;
    case 10:
      uint8_t data[7] = {255, 255, 255, 255, 0, 0, 0};
      break;
  }
//  return data[7];
}

int getDanceStep() {
  intervalPick = random(1, 5);
  switch (intervalPick) {
    case 1:
      danceStep = 125;
      break;
    case 2:
      danceStep = 250;
      break;
    case 3:
      danceStep = 375;
      break;
    case 4:
      danceStep = 500;
      break;
  }
  return danceStep;
}
 
OK... It is 12AM and I have to go to sleep....
For some reason I can't figure out how an array assignment that works standalone does not work as a function.
I am getting a error that reads:

Holiday_Show_Controller: In function 'void playDmx()':

Holiday_Show_Controller:306: error: cannot convert '<brace-enclosed initializer list>' to 'uint8_t {aka unsigned char}' in assignment

data[7] = {255, 255, 0, 0, 0, 0, 0}; // Red

You're trying to assign all the values to one single element data[7]
 
Last edited:
Thanks Frank.
The same statement works in the setup section:
Code:
// DMX Variables
uint8_t data[7] = {0, 128, 128, 128, 0, 0, 0}; 
[CODE]
Any suggestions on how to fix?
 
One way is:
Code:
 const uint8_t xyz[7] = {0, 128, 128, 128, 0, 0, 0};
 memcpy(data, xyz, sizeof(data));

Or, you can make data a pointer to an array and let it point to the new array (is faster, but i'd not recommend it for beginners) - everything should be const and global, then.
 
If your really want to use a pointer (which is better but more difficult)

Code:
typedef uint8_t  arr7[7] ;

arr7 white = {0, 128, 128, 128, 0, 0, 0};
arr7 green = {255, 0, 255, 0, 0, 0, 0};

arr7 *data = &white;

and later just 

data = &green;
 
Status
Not open for further replies.
Back
Top