// https://wokwi.com/projects/449543217676856321
// https://forum.arduino.cc/t/help-with-relay-code/1417761
// Arduino Forum member GoForSmoke 12/4/25 free to use code, it compiles, 95% done, 95% to go!
// AVRduino: never use 16 bits to do what 8 bits can do. Uno total RAM = 2048 bytes.
// AVR Code: avoid doing math with mixed variable types... so bytes for pins and most indexes
// now with an alternate integer EMA filter
const byte pots = 2;
byte potIdx = 0; // which pot to read next
const unsigned int averageOver = 10;
unsigned int runningTotal[ pots ] = { 0, 0 };
unsigned int avgRead[ pots ] = { 0, 0 };
// globals for alternate EMA function xReadADCupdateStatus
uint16_t xAvgRead[pots]; // alternate resluts
int32_t xRunningTotal[pots]; // alternate accumulator
int xReading[pots]; // store adc reading for reuse in the alternate
unsigned int microsReadLast = 0;
unsigned int microsTweenPotReads = 1024; // can be less than 1000, should be >= 200
const byte potPin[ pots ] = { A0, A1 }; // Potentiometer analog pins
const int midpoint = 511; // Midpoint of 10-bit ADC
const int tolerance = 20; // Acceptable range around midpoint
const byte relays = 2;
const byte relayPin[ relays ] = { 8, 7 }; // Relay pin 8 to A0, Relay pin 7 to A1
byte relayLimits[ relays ][ 2 ] = { 150, 850, 450, 550 };
void setMUX( byte pin ) // change the ADC channel to allow settle time before the next read
{
byte mux = ADMUX;
ADMUX = ( mux & 0xF0 ) | ( pin & 0xF );
}
void setup()
{ // start setup()
for ( byte i = 0; i < relays; i++ )
{
pinMode( relayPin[ i ], OUTPUT); // default start is LOW
}
setMUX( potIdx ); // init
delayMicroseconds( 60 ); // IIRC actual datasheet settle time is ~55 usecs
Serial.begin(115200); // set your Serial Monitor to clear the serial buffer faster than 9600
} // end setup()
// here the working one
void readADCupdateStatus()
{
int adcRead = analogRead(potPin[potIdx]);
runningTotal[potIdx] += adcRead - runningTotal[potIdx] / averageOver;
avgRead[potIdx] = runningTotal[potIdx] / averageOver;
if ( ++potIdx == pots ) potIdx = 0; // next channel
} // end readADCupdateStatus()
//
void xReadADCupdateStatus()
{
byte idx = potIdx; // mirror the index
int adcRead = xReading[idx]; // same sample
xRunningTotal[idx] += (int32_t) adcRead - xRunningTotal[idx] / averageOver;
xAvgRead[idx] = 0;
//; xRunningTotal[idx] / averageOver;
}
void runRelays()
{
for ( byte i = 0; i < relays; i++ )
{
// Check if within midpoint range pin 8
if (avgRead[ 0 ] >= (relayLimits[ i ][ 0 ]) && avgRead[ 0 ] <= (relayLimits[ i ][ 1 ]))
{
digitalWrite(relayPin[ i ], HIGH); // Turn relay ON
}
else
{
digitalWrite(relayPin[ i ], LOW); // Turn relay OFF
}
}
}
unsigned int debugLast;
const unsigned int debugWait = 250; // millis
unsigned long startTime;
void loop()
{ // start loop()
unsigned int now = micros(); // reads the low 16 bits, 65.535 ms max
readADCupdateStatus();
// xReadADCupdateStatus(); // feed the same data to the alternate
if ( now - debugLast >= debugWait )
{ // start Debug output
debugLast += debugWait;
for ( byte i = 0; i < pots; i++ )
{
Serial.print( "A" );
Serial.print( i );
Serial.print( ": " );
// fill spaces to right-justify ADC print data in columns
if ( avgRead[ i ] < 10 )
{
Serial.print( " " );
}
else
{
if ( avgRead[ i ] < 100 )
{
Serial.print( " " );
}
else
{
if ( avgRead[ i ] < 1000 )
{
Serial.print( " " );
}
else
{
if ( avgRead[ i ] < 10000 )
{
Serial.print( " " );
}
}
}
}
Serial.print( avgRead[ i ] );
Serial.print(" or " );
Serial.print(xAvgRead[i]);
Serial.print(" ");
}
Serial.println();
} // end Debug output
runRelays(); // this has no act-interval to add latency and Nooooo Delay!
} // end loop()