Pots do not control relay times

So defining 4 IO-pins for the relays as outputs
and initialising the 4 timers looks like this

void setup () {
  for (byte Index = 0; Index < 4; Index++) {
    pinMode (relayPin[Index], OUTPUT);
    RelayTimer[Index] = millis();
  }
}  // end of setup

reading in the potentiometers looks like this

void readPotentiometers() {
  
  // count variable Idxx from 0 to 3   (3 < 4) 
  for (byte Idx = 0; Idx < 4; Idx++) {
    RELAYinterval[Idx] = analogRead(potPin[Idx]);
  }
}

checking if it is time to toggle a relay looks like this with a helper-function for the non-blocking timing

void checkRelayTimers_and_toggle() {
  // count variable Index from 0 to 3   (3 < 4) 
  for (byte Index = 0; Index < 4; Index++) {
    if ( TimePeriodIsOver(RelayTimer[Index],RELAYinterval[Index]) ) {
      digitalWrite(relayPin[Index], !digitalRead(relayPin[Index]) );
      // the attentionmark!   is the NOT-operator:    not HIGH = LOW   not LOW = HIGH
      // the not-operator inverts the state              !HIGH = LOW      !LOW = HIGH
    }
  }
/* same as if you would code

    if ( TimePeriodIsOver(RelayTimer[0],RELAYinterval[0]) ) {
      digitalWrite(relayPin[0], !digitalRead(relayPin[0]) );

    if ( TimePeriodIsOver(RelayTimer[1],RELAYinterval[1]) ) {
      digitalWrite(relayPin[0], !digitalRead(relayPin[1]) );

    if ( TimePeriodIsOver(RelayTimer[2],RELAYinterval[2]) ) {
      digitalWrite(relayPin[2], !digitalRead(relayPin[2]) );

    if ( TimePeriodIsOver(RelayTimer[3],RELAYinterval[3]) ) {
      digitalWrite(relayPin[3], !digitalRead(relayPin[3]) );

only difference is the number in the brackets "[]"
*/
}
1 Like

Agreed. Which is why I replied as follows

1 Like

Here is the complete sketch

// Which pins are connected to which RELAY
/*
const byte RELAY01 = 2;
const byte RELAY02 = 3;
const byte RELAY03 = 4;
const byte RELAY04 = 5;
*/
// replaced with an array
const byte relayPin[4] = {2, 3, 4, 5};
// relayPin[0] contains value 2
// relayPin[1] contains value 3
// relayPin[2] contains value 4
// relayPin[3] contains value 5


const byte potPin[4] = {A0,A1,A2,A3};


// Time periods of blinks in milliseconds.
/*
const unsigned long RELAY01interval = analogRead(A0);
const unsigned long RELAY02interval = analogRead(A1);
const unsigned long RELAY03interval = analogRead(A2);
const unsigned long RELAY04interval = analogRead(A3);
*/

// replaced by an array
unsigned long RELAYinterval[4];


// Variable holding the timer value so far. One for each "Timer"
/*
unsigned long RELAY01timer;
unsigned long RELAY02timer;
unsigned long RELAY03timer;
unsigned long RELAY04timer;
*/
// replaced by an array
unsigned long RelayTimer[4];
// RelayTimer[0] contains value for timer 1
// RelayTimer[1] contains value for timer 2
// RelayTimer[2] contains value for timer 3
// RelayTimer[3] contains value for timer 4


void setup () {
  for (byte Index = 0; Index < 4; Index++) {
    pinMode (relayPin[Index], OUTPUT);
    RelayTimer[Index] = millis();
  }
}  // end of setup


void readPotentiometers() {
  
  // count variable Idxx from 0 to 3   (3 < 4) 
  for (byte Idx = 0; Idx < 4; Idx++) {
    RELAYinterval[Idx] = analogRead(potPin[Idx]);
  }
}


void checkRelayTimers_and_toggle() {
  // count variable Index from 0 to 3   (3 < 4) 
  for (byte Index = 0; Index < 4; Index++) {
    // check if more milliseconds have passed by as value in variable RELAYinterval[Index]
    if ( TimePeriodIsOver(RelayTimer[Index],RELAYinterval[Index]) ) {
      // if REALLY more milliseconds HAVE passed by       
      digitalWrite(relayPin[Index], !digitalRead(relayPin[Index]) );
      // the attentionmark!   is the NOT-operator:    not HIGH = LOW   not LOW = HIGH
      // the not-operator inverts the state              !HIGH = LOW      !LOW = HIGH
    }
  }
/* same as if you would code

    if ( TimePeriodIsOver(RelayTimer[0],RELAYinterval[0]) ) {
      digitalWrite(relayPin[0], !digitalRead(relayPin[0]);

    if ( TimePeriodIsOver(RelayTimer[1],RELAYinterval[1]) ) {
      digitalWrite(relayPin[0], !digitalRead(relayPin[1]);

    if ( TimePeriodIsOver(RelayTimer[2],RELAYinterval[2]) ) {
      digitalWrite(relayPin[2], !digitalRead(relayPin[2]);

    if ( TimePeriodIsOver(RelayTimer[3],RELAYinterval[3]) ) {
      digitalWrite(relayPin[3], !digitalRead(relayPin[3]);

only difference is the number in the brackets "[]"
*/

}

void loop (){
  readPotentiometers();

  checkRelayTimers_and_toggle();
}  // end of loop

// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

The same sketch but without your outcommented code

const byte relayPin[4] = {2, 3, 4, 5};
const byte potPin[4]   = {A0,A1,A2,A3};

unsigned long RELAYinterval[4];
unsigned long RelayTimer[4];


void setup () {
  for (byte Index = 0; Index < 4; Index++) {
    pinMode (relayPin[Index], OUTPUT);
    RelayTimer[Index] = millis();
  }
}  // end of setup


void readPotentiometers() {  
  // count variable Idx from 0 to 3   (3 < 4) 
  for (byte Idx = 0; Idx < 4; Idx++) {
    RELAYinterval[Idx] = analogRead(potPin[Idx]);
  }
}


void checkRelayTimers_and_toggle() {
  // count variable Index from 0 to 3   (3 < 4) 
  for (byte Index = 0; Index < 4; Index++) {
    // check if more milliseconds have passed by as value in variable RELAYinterval[Index]
    if ( TimePeriodIsOver(RelayTimer[Index],RELAYinterval[Index]) ) {
      // if REALLY more milliseconds HAVE passed by       
      digitalWrite(relayPin[Index], !digitalRead(relayPin[Index]) );
      // the attentionmark!   is the NOT-operator:    not HIGH = LOW   not LOW = HIGH
      // the not-operator inverts the state              !HIGH = LOW      !LOW = HIGH
    }
  }
}


void loop (){
  readPotentiometers();

  checkRelayTimers_and_toggle();
}  // end of loop


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

best regards Stefan

2 Likes

both are good usable. The difference is:
higher resistance = more sensitive to electromagnetic noise.
But both values 20 k and 100k are in a range that - as long as you don't do plasma-cutting with HF-ignition - it will work good.
The value could go down to 1 kOhm. Which means current would be 5V / 1000 Ohm = 5 mA

1 Like

For this you can use the map()-function.

The map-function works like a linear function y = mx + b
But not with parameters "m" and "b" the parameters are
lowest "x", highest "x"
and
lowest "y" highest "y"

with generalised words

myY = map (myX, fromLow, fromHigh, toLow, toHigh);

To make it more clear I define another array

unsigned int PotiValue[4];

Potentiometer-values vary from 0 to 1023
and this shall be transformed into values 300 to 3000
So the code with the map-function looks like this

    RELAYinterval[Idx] = map(PotiValue[Idx],0,1023,300,3000);

complete code

const byte relayPin[4] = {2, 3, 4, 5};
const byte potPin[4]   = {A0,A1,A2,A3};

unsigned int PotiValue[4];

unsigned long RELAYinterval[4];
unsigned long RelayTimer[4];


void setup () {
  for (byte Index = 0; Index < 4; Index++) {
    pinMode (relayPin[Index], OUTPUT);
    RelayTimer[Index] = millis();
  }
}  // end of setup


void readPotentiometers() {  
  // count variable Idx from 0 to 3   (3 < 4) 
  for (byte Idx = 0; Idx < 4; Idx++) {
    PotiValue[Idx]= analogRead(potPin[Idx]);
    RELAYinterval[Idx] = map(PotiValue[Idx],0,1023,300,3000);
  }
}


void checkRelayTimers_and_toggle() {
  // count variable Index from 0 to 3   (3 < 4) 
  for (byte Index = 0; Index < 4; Index++) {
    // check if more milliseconds have passed by as value in variable RELAYinterval[Index]
    if ( TimePeriodIsOver(RelayTimer[Index],RELAYinterval[Index]) ) {
      // if REALLY more milliseconds HAVE passed by       
      digitalWrite(relayPin[Index], !digitalRead(relayPin[Index]) );
      // the attentionmark!   is the NOT-operator:    not HIGH = LOW   not LOW = HIGH
      // the not-operator inverts the state              !HIGH = LOW      !LOW = HIGH
    }
  }
}


void loop (){
  readPotentiometers();

  checkRelayTimers_and_toggle();
}  // end of loop


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

best regards Stefan

1 Like

excellent, I am trying to figure out now how to make the the potentiometer only controlling the OFF state. While I am controlling 4 solenoids with the relays, and the ON state is fixed to as in a hammer fashion
These are the solenoids in question

toggling on/off with the same interval is different than different times for on and off
you can't just toggle anymore for having that functionality.
post a timing-diagramm that gives an example how the different on/off-times look like

And then you should write your own attempt how to code this.
This attempt can have bugs or even not compile. But you should start learning programming.

And this is not by presenting ready to use code but by own attempts and asking specific questions
best regards Stefan

2 Likes

Hello piralemu

Do you are going to design and code a controller for a glockenspiel?

1 Like

Hi @paulpaulson
I am designing something like this but not exactly.
It is something simple ...to have 4 solenoids drumming at different rates and controlling these rates in real time with the potentiometer knobs

thanks for the advise and your time Stefan, sadly I have been attempting to learn to code without effort for years now. This doesn't discourage me from continuing to come up with new DIY gadgets to make sound. Unfortunately I have to continue asking specialists about technical programming issues and such :blush: .

Regarding the code for the 4 solenoids, I have the code that I use on another system that only uses one solenoid and it looks like this: (the thing get complicated when there are 4 solenoids at the same time)

int mosfetPin = 2;  // the Arduino pin, which connects to the IN pin of mosfet
int potPin = A0;  // Analog pin connects to knob
int potVal = 0;  


void setup() {
  // initialize digital pin as an output.
  Serial.begin(9600);
  pinMode(mosfetPin, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {

  potVal = analogRead(potPin);
  Serial.println(potVal);
  digitalWrite(mosfetPin, HIGH);
  delay(100);
  digitalWrite(mosfetPin, LOW);
  delay(potVal);
}```

Hello piralemu

In general - Arrays and structs are your friends.
Don't duplicate code in your sketch. Write code once - use it multiple times.
You should not use magic numbers. The I/O pins love to have a functional name.

Do you have experience with programming in C++?

The task can easily be realised with an object.
A structured array contains all information, such as pin addresses for the I/O devices, as well as the information for the timing.
A single service takes care of this information and initiates the intended action.
The structured array makes the sketch scalable until all I/O pins are used up without having to adapt the code for the service.
It is cool stuff, isn´t it?

Have a nice day and enjoy coding in C++.

1 Like

The code that you have posted in post #31 uses blocking timing based on delay().

If more than one thing shall happen in parallel you need non-blocking timing.
Sadly there is this always the same not explaining much too short hint to a hard to understand example-code blink-without understand ehm sorry blink without delay

So I want to encourage you to make another attempt to understand non-blocking timing
where the explanation is based on a everyday-example of pizza-baking
and uses easy to follow specific numbers like
13:05 - 13:06 = 1 minute etc.

please give it a try.

best regards Stefan

I thought it had been clear that the concepts of blocking and not blocking were understood both since my original post (and by the way, if it's true, there are many examples on the internet that use culinary metaphors. I'm already getting hungry). The example of the system using delay was presented to generate a picture of how the solenoids are required to behave (the fact that the ON time is fixed, and only the OFF time is controlled with the pots).

So what is the difficulty to write an attempt of a code that does

??
Is the reason just lazyness trying to get other users to post another working code
or
something different?

This could be the difficulty.

1 Like

I have been trying to learn to program for years without success (instead of effort, I made a translation error). It must be something at my cognitive limits. I posted my problem with faith that someone who has a better understanding of the Arduino programming language and some time to help will help me with the code. Thanks to everyone who enthusiastically responds on this forum.

Sometimes, because it looks like the boat will float, and then...
Seriously, though, I backed away from this thread not because you didn't deserve help, but because we have a habit on this forum of help-swarming posters; by that I mean, instead of letting 1, 2, or 3 helpers try and move the OP forward, we get a dozen or more all pulling in different directions, and no one tries to think about this from the OP's viewpoint. This thread is a classic, with several approaches and several solutions from some excellent helpers, stomping all over each other. Hilarious, if you just sit back and watch, but it must have been frustrating for you.

If you attempt to learn

with

effort
I might answer questions again
maybe microbit with code-blocks is the right toy for you

thank you, this helps to read

1 Like