Jumping/bouncing digital outputs

Hi all,

I’ve got a project in which I read data from a DMX signal using a MAX485 ic.
The data gets translated/calculated and based upon that two digital ports will be set to high/low and 1 PWM output will be controlled.
At the digital outputs, a double channel relais is installed.

Now, i’ve got this working, only to find that the relais are jumping/bouncing when the DMX value stays the same (or at least, the DMX value is not changed on the DMX controller. It may be that some small disruptions occur).

What I’d like to do is to smooth/debounce the DMXvalue, so that the ports will not jump/bounce anymore.

Does any of you have a small/neat idea to create for example an external function which can handle the smoothing?
Ultimately, the ‘DMXVAL001’ should only be updated if it is stable for X ms (i.e. 50ms).
I cannot afford to use delay(), due to the principle of the DMX readings.

Right now, the DMX value is retrieved in this line:

DMXVAL001 = DMXSerial.read(1);

Would it be possible to add some kind of function to it, so that this will look like this:

DMXVAL001 = Smoothed(DMXSerial.read(1));

Thanks in advance!

See the full code below:

// - - - - -
// DmxSerial - A hardware supported interface to DMX.
// DmxSerialRecv.ino: Sample DMX application for retrieving 3 DMX values:
// address 1 (red) -> PWM Port 9
// address 2 (green) -> PWM Port 6
// address 3 (blue) -> PWM Port 5
// 
// Copyright (c) 2011-2015 by Matthias Hertel, http://www.mathertel.de
// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
// 
// Documentation and samples are available at http://www.mathertel.de/Arduino
// 25.07.2011 creation of the DmxSerial library.
// 10.09.2011 fully control the serial hardware register
//            without using the Arduino Serial (HardwareSerial) class to avoid ISR implementation conflicts.
// 01.12.2011 include file and extension changed to work with the Arduino 1.0 environment
// 28.12.2011 changed to channels 1..3 (RGB) for compatibility with the DmxSerialSend sample.
// 10.05.2012 added some lines to loop to show how to fall back to a default color when no data was received since some time.
// - - - - -

#include <DMXSerial.h>

// Constants for demo program

int DMXPin = A0;        // select the input pin for the potentiometer
int SpeedPin = 9;       // Pin used to send speed to VFD  (SP1, P58=0, P10=2)
int ONPin = 12;         // Pin used to turn VFD on (X3, P52=1)  (Boolean) (also enables led on arduino when vfd is on)
int ReversePin  = 6;        // Pin used to set VFD to counterclockwise mode (X6, P55=9, P11=2)  CCW if pin is HIGH

int LEDPin = 13;

int DMXVAL001 = 0; //variable used for dmx value
bool error = false; //variable used if no dmx is coming in. 
int SpeedValue = 0; //variable used to write calculated speed value to. 


#define LEDNormalLevel 20
#define LEDErrorLevel 255

void setup () {
  DMXSerial.init(DMXReceiver);
  
  // set some default values
  DMXSerial.write(1, 0);
  DMXSerial.write(2, 0);
  DMXSerial.write(3, 0);
  
  // setup pins
    pinMode(SpeedPin, OUTPUT);
  digitalWrite(SpeedPin, 0);
  
  pinMode(ONPin, OUTPUT);
  analogWrite(ONPin, LOW);
  
  pinMode(ReversePin, OUTPUT);
  digitalWrite(ReversePin, LOW);
}


void loop() {

ReadDMX();
WriteValues();
  

}

void ReadDMX() {
  // Calculate how long no data backet was received
  unsigned long lastPacket = DMXSerial.noDataSince();
  
  if (lastPacket < 5000) {
    // read recent DMX values and set pwm levels 
    DMXVAL001 = DMXSerial.read(1);
    error = false; 
  } else {
    // Show pure red color, when no data was received since 5 seconds or more.
    error=true; 
    analogWrite(LEDPin,   LEDErrorLevel); 
  } // end if
}


void WriteValues() {
  if(error==false){
analogWrite(LEDPin,   LEDNormalLevel); 
if(DMXVAL001<=133){
    SpeedValue=map(DMXVAL001,10,133,0,255);
    
  }
  else{
    SpeedValue=map(DMXVAL001,134,255,0,255);
  }

    
if(DMXVAL001<=25){
  //Turn off and speed to 0
//  Serial.println("DMX<=10");
  digitalWrite(ONPin, LOW);
  analogWrite(SpeedPin, 0);
  SpeedValue = 0;
    
}
else if(DMXVAL001<=133){
  //Turn on, map speed, set rotation to clockwise
//  Serial.println("10<DMX<=133");
  digitalWrite(ONPin, HIGH);
  analogWrite(SpeedPin, SpeedValue);
  digitalWrite(ReversePin, LOW);
}
else{
  //Turn on, map speed, set rotation to COUNTERclockwise
//  Serial.println("DMX>133");
  digitalWrite(ONPin, HIGH);
  analogWrite(SpeedPin, SpeedValue);
  digitalWrite(ReversePin, HIGH);
}
  }
}

// End.

I’m going to suggest a window compare.

if( (lowLimit < DMXVAL001) and (DMXVAL001 < highLimit)){
//do something
}

This will give you a little leeway on either side of a center value to allow for input fluctuations.

Well,

Wouldn't this give the result that when the DMX value is currently set to i.e. 127, and after that is set (on purpose) to i.e. 128, that it will never ever go to this value? This would not be correct.

My first idea was some code which would i.e. monitor the last few readed values, and if they all are the same thén change the variable 'DMXVAL001' to this value.

Any ideas how this could be done neately?

So, after some thinking I’ve came up with the code below:
(Helped by this source)

int SmoothDMXVal(int DMXAddress){
  int i;
  int value = 0;
  int numReadings = 10;

  for (i = 0; i < numReadings; i++){
    
    // Read DMX value
    value = value + DMXSerial.read(DMXStartAddress -1 + DMXAddress);

    // 1ms pause adds more stability between reads.
    delay(1);
  }

  // Take an average of all the readings.
  value = value / numReadings;

  // Scale to 8 bits (0 - 255).
  value = value / 4;

  return value;
}

When reading my DMX signal, i’m using the following line in my main code now:

DMXVAL001 = SmoothDMXVal(1); //Read the DMX value (smoothed, through the 'SmoothDMXVal' function), with the address between brackets

Are there any improvements on this code?
I’m gonna to test it tonight, curious for your replies in advance!