vvvv arduino dmx

Hi guys ¡

I have been trying to modify some code to control the arduino dmx dongle from vvvv , I got it to work , but probably not the best way , it is buggy . for testing , i set to control just the first 3 channels . I,m sending the values as an ascii string , it sends the values ok but sometimes interfear in the other 3 channels for a little time and the last dmx channels about the 500 to end are also bothered .

I test the setup with an enttet dongle getting the output from arduino .

possible reasons i humbly think :

the thing is that i dont know how to tell arduino to get the part of the array after a comma , space or any character ?

, so i send the values without logical separation value1value2value3 , the magic is that it mostly work arduino sort of guess where to cut ;D

the other posibility is that arduino is not getting the full data , is there a way of making a tokenizer in arduino ?

or maybe it is better to send a char and convert to int but dont know how to do it i tried some staff without luck .

I need your help , how would you do that ?

// 

This is the part i modified

int value[]={0, 1, 2};



// I,m just testing with the first 3 dmx channels 

if (Serial.available() > 0){

  for ( int count = 0; count<=2; count++) {
     
      value[count] = Serial.read();
      shiftDmxOut( sig, value[count]);
      } 
   
   
   
   
    //--------------------- 
 //   Those channels are set to 255 
     
   for (int count = 3; count<=512; count++){
     shiftDmxOut( sig, 255);
   }

Full code :

/*
 * DMX fade for arduino 008
 * based on the code of Tomek Ness and D. Cuartielles
 *
 * adapted to arduino 008 by Peter Szakal and Gabor Papp
 * http://nextlab.hu
 */

#include "pins_arduino.h"

int sig = 11; // signal
int value[]={0, 1, 2};


/* Sends a DMX byte out on a pin.  Assumes a 16 MHz clock.
 * Disables interrupts, which will disrupt the millis() function if used
 * too frequently. */
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);

  // the first thing we do is to write te pin to high
  // it will be the mark between bytes. It may be also
  // high from before
  _SFR_BYTE(_SFR_IO8(portNumber)) |= pinMask;
  delayMicroseconds(10);

  // disable interrupts, otherwise the timer 0 overflow interrupt that
  // tracks milliseconds will make us delay longer than we want.
  cli();

  // DMX starts with a start-bit that must always be zero
  _SFR_BYTE(_SFR_IO8(portNumber)) &= ~pinMask;

  // we need a delay of 4us (then one bit is transfered)
  // this seems more stable then using delayMicroseconds
  asm("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");

  asm("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");

  asm("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");

  for (int i = 0; i < 8; i++)
  {
    if (theByte & 01)
    {
      _SFR_BYTE(_SFR_IO8(portNumber)) |= pinMask;
    }
    else
    {
      _SFR_BYTE(_SFR_IO8(portNumber)) &= ~pinMask;
    }

    asm("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");

    asm("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");

    asm("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");

    theByte >>= 1;
  }

  // the last thing we do is to write the pin to high
  // it will be the mark between bytes. (this break is have to be between 8 us and 1 sec)
  _SFR_BYTE(_SFR_IO8(portNumber)) |= pinMask;

  // reenable interrupts.
  sei();
}


void setup()
{
  Serial.begin(115200);
  pinMode(sig, OUTPUT);
}

void loop()
{
  /***** sending the dmx signal *****/

  // sending the break (the break can be between 88us and 1sec)
  digitalWrite(sig, LOW);

  delay(10);

  // sending the start byte
  shiftDmxOut(sig, 0);
//------------------



// This is the part i,m modifying 

// I,m just testing with the first 3 dmx channels 

if (Serial.available() > 0){

  for ( int count = 0; count<=2; count++) {
     
      value[count] = Serial.read();
      shiftDmxOut( sig, value[count]);
      } 
   
   
   
   
    //--------------------- 
 //   Those channels are set to 255 
     
   for (int count = 3; count<=512; count++){
     shiftDmxOut( sig, 255);
   }
    
   
 

}

}

thanks in advance , i would upload the patch but dont see where to upload ?.

Regards :wink:

the code you posted is trying to read 3 values from the serial port but there may be only one or two available.

try replacing: if (Serial.available() > 0){ with: if (Serial.available() >= 3){

Hi , thanks for your reply ,i did the change and

i may have got a little imrpove in the signal but still the 22 last dmx channels and the channels 407-408-409 are bothered instead of being in 255 , the 407-408-409 are at 0 and when serial changes they get to 0 255 repetidly and when serial stop get to 0 , the rest last 22 have ramdom values and get the same effect .

In the testing 3 they seem to bother each other a bit less but still a little bit and they change positions , for example i send changing values to the part 0 and 2 and part 0 and 1 are modifying and then may get the order again . it looks that the swap the channal every certain time . the values are sent like this _ÿj so that would be 95255106 95 first channel 255 second 106 third . any ideas ?

are you trying to send or receive DMX512 data? your first post says you want to control a DMX dongle but your code is a receiver.

if you want to receive DMX data then a next step is to study and implement the DMX protocol. I have no experience with it so may not be able to help you very much. However, a quick look on google indicates a DMX512 packet consists of a start code followed by 512 data bytes.

So your implementation would want to wait on 513 bytes (rather then the 3 bytes in your test sketch) and check that a valid start byte has been received.

I also note that the start of packet is signified by a break of at least 88us. This may not be easy to detect using the hardware serial uart, but perhaps someone that is familiar with the DMX512 protocol can help you further.

Thanks mem , i think the hard part of dmx protocol is made in the top part of code by smart guys ¡ ,I thought just changing the bottom part will work (you have the break and the start byte too) as i saw in other dmx sketch example , they just changed the bottom part .

anyway i would love to know how to tell Serial.read to interpret the string separated by any character instead of sending 2123445 being value1 212 value 234 and value3 45 , woul be better to send 212 344 45 and that arduino knows that in this case space tell where to cut the string , anyone willing to show me how to do that ;D so i can test please.

cheers

the traditional way to handle strings separated by tokens in C is the function strtok. There is a reference here: http://www.cppreference.com/stdstring/strtok.html

Another method you could use if all DMX values are a byte is to pad the numeric strings with leading zeros so they are always three characters long.

thanks mem , i,m trying to implement the token but cannot see the way to do it , i,ll keep trying :)

Was the strtok example not clear or are you trying to do something else? Perhaps if you post and example of a string you would like to parse and show how you want to use the result, someone can provide more guidance.

Hi :slight_smile:
Yes the problem is that i did not get to make strtok to work .an example in arduino would be apreaciated .

i would like to send a string like that 234,22,121,567,CR ( this would be received from Serial.read)
being 234 the first value of the array in input[4] the values should be splited every “,”

if (Serial.available() > 0){

for ( int i = 0; i<=4; i++) {

input = Serial.read();
_ shiftDmxOut( sig, input*);_
_
}*_
thanks

Here is an example of strtok tailored for your app. Your code needs to wait until you have received a full line of data, perhaps check for a trailing cr. It then needs to remove anything in the string that is not an integer or a comma (such as the trailing cr) and call the function getValues to put the integers into the values arrray.

#define MAX_DATA_ELEMENTS 4    // the maximum number of integers in one received string
int input[MAX_DATA_ELEMENTS];  // array that will hold the received integers

void setup()                    // run once, when the sketch starts
{
}

void loop()                     // run over and over again
{
  char str[] = "234,22,121,567/r";   // replace this with code to receive a complete line of data
  str[strlen(str)] = '/0';  // remove the trailing CR !!
  getValues(str, input, MAX_DATA_ELEMENTS );
  for ( int i = 0; i < MAX_DATA_ELEMENTS; i++) { 
      shiftDmxOut( sig, input[i]); 
   }  
}


void getValues(char * str,int * values, int maxelements) {
 // function to parse the given string and populate the values integer array
 // maxelements is the number of elements in the given values array 
 // Note: this version assumes that the string is properly formed (i.e. contains only integers seperated by commas)

 char *result = NULL;
 int index = 0;
 result = strtok( str, "," );
 while( (result != NULL) && (index < maxelements) ) {
      values[index++] = atoi(result);
      result = strtok( NULL, "," );
 }
}

Hello again mem , i honestly apreaciate your help , I was testing your code and trying to adapt , but i can compile i get error that i can solve , i thoungt of trying with a simpler code instead of the dmx , until we get it to work , in the code above i send a string without commas to 3 pwm pins
it works a bit buggy so if you feel like and get the chance , i think is a good example to apply the strtok to it , take into account that i can send any string with the desired character separation with or without CR , but probably with CR better for telling finish of packet , probably you can suggest best way .

int pins[] = {11,10,9};
int input[3]; // it gets a string like that 234123146 for now  

void setup () {
 
 Serial.begin(9600);//starts serial at 9600
 
  }

void loop () {
  
  if (Serial.available() > 0) 
  
  {
        for (int i=0; i<3; i++) {
  input[i] = Serial.read();
  
analogWrite(pins[i],input[i]);  // we write the value from input  


delay(10); // wait 10 milliseconds
}
}
}

cheers

I think we are confusing each other.

The code you posted is mixing up integers with strings.

Perhaps you should start by clarifying the incoming data format and then writing some code that reads one line of serial data into a string.

Are you sure the data is of the following format: “234,22,121,567,CR”

If you are not sure, then check the specs or echo the data back out to a serial terminal if you can.

Once you know what format the serial data is in, you can write your code that waits until an entire line of data is received.

Post the format after you have verified what it is if you need some help writing the code.

hi , i can send any string to arduino if a send in ascci code then i use ints in arduino if i send a normal string i use char in arduino , so the incoming string can be as the best way to do , other side is no problem ,so far in last code i,m sending this 23422121567 in ascii , and use ints , as i do not know how to convert char to ints or viceversa .

So basicly i think sending this “234,22,121,CR” for 3 values is good then how can arduino understand this as separate values

value0 : 234 value1 : 22 value2 : 121 with the method of strtok i think it is the good directions ,

sorry for trouble did you understand me ?

OK, if you can send what you want to the arduino then lets work with strings that are a fixed length.

Will your integer values always be a number between 0 and 999?

If so then pad each integer value so that it is 3 digits long. Here is an example:
char stringtosend = “234,022,121,567”; // this represents the integers: 234,22,121,567

will you always send the same number of integers?
how many will that be?

assuming your will always send four integers then all strings will have exactly 15 characters before the terminating null (four sequences of three characters separated by commas with no cr)

Modify the loop function in the code I posted earlier as follows:

void loop()                     // run over and over again
{
  char str[] = "234,022,121,567";   // note there is no /r 
  getValues(str, input, MAX_DATA_ELEMENTS );
  for ( int i = 0; i < MAX_DATA_ELEMENTS; i++) { 
      shiftDmxOut( sig, input[i]); 
   }  
}

Run this code and see if you get the expected response from shiftDmxOut. If not then you need to debug this before working on the serial code.

sorry mate but can seem to implement the other code i get all sort of error messages again that is why i tried with eaisier code ,


Will your integer values always be a number between 0 and 999?

yes they will be from 0-255

so then pad each integer value so that it is 3 digits long

ok i will send from vvvv 234,22,121, ( so all of this channels can have a value from 0 to 255 )

will you always send the same number of integers?

yes i think so

how many will that be?

for now let,s send just 3 until it works please , // but for the dmx will be 512 a big string ,


assuming your will always send four integers then all strings will have exactly 15 characters before the terminating null (four sequences of three characters separated by commas with no cr)

ok so 3 integers will have 12 ?


could you check this code for the errors :

i get In function ‘void getValues(char*, int*, int)’:
error: ‘strtok’ was not declared in this scope

#include <stdio.h>   // i add this without knowing if it is needed 
#include <string.h> // i add this without knowing if it is needed 
#define MAX_DATA_ELEMENTS 3    // the maximum number of integers in one received string
int input[MAX_DATA_ELEMENTS];  // array that will hold the received integers
int pins[] = {11,10,9};


void setup () {
 
 Serial.begin(9600);//starts serial at 9600
 
  }

void loop () {
  
  if (Serial.available() > 0)  {
   char str[] = "000,000,000,"; // dont know if this is needed 
   
   getValues(str, input, MAX_DATA_ELEMENTS );
  
   for ( int i = 0; i < MAX_DATA_ELEMENTS; i++) {
      
   input[MAX_DATA_ELEMENTS] = Serial.read(); // i,m sending from vvvv value,value,value, 
      
   analogWrite(pins[i],input[MAX_DATA_ELEMENTS]);      // probably we need here the result instead of maxdataelement 
    
   delay(10);  }
  }
}


void getValues(char * str,int * values, int maxelements) {
 // function to parse the given string and populate the values integer array
 // maxelements is the number of elements in the given values array 
 // Note: this version assumes that the string is properly formed (i.e. contains only integers seperated by commas)

 char *result = NULL;
 int index = 0;
 result = strtok( str, "," );
 while( (result != NULL) && (index < maxelements) ) {
      values[index++] = atoi(result);
      result = strtok( NULL, "," );


Serial.print(result);


 }
}

thx :stuck_out_tongue:

If your values are always between 0 and 255 why not send them as binary data bytes

The sending side would do something like:

serialWrite(234);
serialWrite(22);
serialWrite(121);

note that these are bytes, not strings

the receiving side would be:

if (Serial.available() >= 3) {
for ( int i = 0; i < 3; i++)
shiftDmxOut( sig, SerialRead() );
}

uhmm i just found that it is strtok_r() regarding to this link avr-libc: <string.h>: Strings

but still errors any clue ?

#include <stdlib.h> 
#include <stdio.h>   
#include <string.h> 

#define MAX_DATA_ELEMENTS 3    // the maximum number of integers in one received string
int input[MAX_DATA_ELEMENTS];  // array that will hold the received integers
int pins[] = {11,10,9};


void setup () {
 
 Serial.begin(9600);//starts serial at 9600
 
  }

void loop () {
  
  if (Serial.available() > 0)  {
   char str[] = "000,000,000,"; // dont know if this is needed 
   
   getValues(str, input, MAX_DATA_ELEMENTS );
  
   for ( int i = 0; i < MAX_DATA_ELEMENTS; i++) {
      
   input[MAX_DATA_ELEMENTS] = Serial.read(); // i,m sending from vvvv value,value,value, 
      
   analogWrite(pins[i],input[MAX_DATA_ELEMENTS]);      
    
   delay(10);  }
  }
}


void getValues(char * str,int * values, int maxelements) {
 // function to parse the given string and populate the values integer array
 // maxelements is the number of elements in the given values array 
 // Note: this version assumes that the string is properly formed (i.e. contains only integers seperated by commas)

 char *result = NULL;
 int index = 0;
 result = strtok_r(str, "," );
 while( (result != NULL) && (index < maxelements) ) {
      values[index++] = atoi(result);
      result = strtok_r( NULL, "," );


Serial.print(result);


 }
}

the clue was in the compiler error message. strtok_r is a recursive version of strtok and requires a third argument which we don't use, but it is necessary to compile successfully

char * ptr; // add this variable result = strtok_r(str, ",", &ptr ); // strtok_r needs the third argument

But did you consider my previous suggestion to send binary data. Its simpler faster and more efficient.