user78180: I'm building a small project to maintain a copper plating tank's temperature and filter pump duty cycle. I'm using the Adafruit Feather platform to hold an 8 segment matrix coupled with a Teensy 3.2 (on a Feather shield) to calculate and display temp. There is a 10K Pot on A0 and an 8 segment NeoPixel Strip to set and display pump duty cycle from 1 to 8 corresponding to .125*hour and 100% on. There is also a push and hold set switch to operate temperature target point setting using the same pot.
Things that work: Almost Everything!
Thing that doesn't work:
Changing the Duty Cycle knob (which changes the duty cycle global variable) after turning the unit on doesn't seem to change the on/off times other than to successfully change the NeoPixel display. If the unit is turned on at a particular duty cycle, the program will run that duty cycle successfully. While running, if I change the duty Cycle to 8, I don't get a "100% On". In other words the change in the duty cycle variable doesn't seem to change the on time and off time variables in the code while running.
Q: What do I need to do to make the duty cycle setting work on the fly?
Oh... That Volatile Float declaration was my last desperate attempt, Please ignore / forgive. ;-)
Hopefully the fix is as simple as the code. ;-) I just don't see it and my (perhaps flawed) understanding of global variables is hit a wall.
Any help will be much appreciated. Thanks.
Jeff
Code:

/***************************************************
  Copper Plating Tank Control - v1.1
  by Jeff W. Parisse - July 7st, 2021
  www.coppercholla.com

  This program runs a programmable interval timer for chemical pump
  duty cycle and a programmable temperature setting and heating control
  for maintaining plating solution temperature.

  Processor: PJRC Teensy 3.2
  Additional Libraries: Adafruit Industries LLC
  Temperature Sensor: Adafruit MAX31865 w/P1000 Platinum Wire Probe
  Pin Outs:
    Setting Knob: Pin A0
    Matrix Display: Feather Matrix I2C 0x70
    Neopixels: Pin 5
    MAX31865: CLK Blue
    MAX31865: SDO Yellow
    MAX31865: SDI White
    MAX31865: CS Pin 6 Green
    Temp Set Switch: Pin 8
    Chemical Pump: Pin 9
    Tank Heater: Pin 10

 ****************************************************/

#include <Adafruit_MAX31865.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
#include <Adafruit_NeoPixel.h>

#define knobPin A0
#define ledPin 5
#define csPin 6
#define switchPin 8
#define pumpPin 9
#define heaterPin 10
#define ledCount 8
#define sampleNum 4
#define RREF      4296.0
#define RNOMINAL  1000.0

Adafruit_MAX31865 thermo = Adafruit_MAX31865(csPin);
Adafruit_7segment matrix = Adafruit_7segment();
Adafruit_NeoPixel strip(ledCount, ledPin, NEO_GRB + NEO_KHZ800);

float targetTemp = 77.0;                // Starting Value
float readTemp = 0;
float toleranceTemp = 0.25;
float tempSum = 0;
float cTemp = 0;
float fTemp = 0;
volatile float dutyCycle = 4;
unsigned long previousTime = 0;
unsigned long oneHour = 3600000;       // 1 Hour in Milliseconds
unsigned long timeOn = 450000;         // 7.5 Minutes in Milliseconds
unsigned long pumpInterval = timeOn;
boolean pumpState = true;

void setup() {
  thermo.begin(MAX31865_3WIRE);;
  matrix.begin(0x70);
  strip.begin();
  strip.show();
  pinMode(csPin, OUTPUT);
  pinMode(heaterPin, OUTPUT);
  pinMode(pumpPin, OUTPUT);
  pinMode(switchPin, INPUT_PULLUP);
  digitalWrite(csPin, LOW);
  digitalWrite(heaterPin, LOW);
  digitalWrite(pumpPin, LOW);
}

void loop() {
  // Read Set Switch
  int setSwitch = (digitalRead(switchPin));
  while (setSwitch == LOW) {
    int readKnob = analogRead(knobPin);
    targetTemp = map(readKnob, 1, 1023, 67, 87);
    matrix.print(targetTemp, 1);
    matrix.writeDisplay();
    setSwitch = (digitalRead(switchPin));
  }

  // Read, Convert, and Display Temp
  tempSum = 0;
  for (int i = 1; i <= sampleNum; i++) {
    readTemp = thermo.temperature(RNOMINAL, RREF);
    tempSum = tempSum + readTemp;
  }
  cTemp = tempSum / sampleNum;
  fTemp = (cTemp * 1.8) + 32;
  matrix.print(fTemp, 1);
  matrix.writeDisplay();

  // Heater Logic
  if (fTemp < targetTemp - toleranceTemp) {
    digitalWrite(heaterPin, HIGH);
  }
  else if (fTemp > targetTemp + toleranceTemp) {
    digitalWrite(heaterPin, LOW);
  }

  // Read and Display Duty Cycle
  int readKnob = analogRead(knobPin);
  dutyCycle = map(readKnob, 1, 1023, 1, 8);
  for (int i = 0; i <= ledCount; i++) {
    strip.setPixelColor(i, 0, 0, 0);
  }
  strip.show();
  for (int i = 0; i <= dutyCycle - 1; i++) {
    strip.setPixelColor(i, 0, 0, 20);
  }
  strip.show();

  // Pump Timer
  digitalWrite(pumpPin, pumpState);
  unsigned long timeOn = ((dutyCycle / 8UL) * oneHour);
  unsigned long timeOff = (oneHour - timeOn);
  unsigned long currentTime = millis();
  if (currentTime - previousTime >= pumpInterval) {
    if (pumpState) {
      pumpInterval = timeOff;
    }
    else {
      pumpInterval = timeOn;
    }
    pumpState = !(pumpState);
    previousTime = currentTime;
  }
}



user7508: I do not really understand what may be the cause of your problem, but I
have identified two issues that could potentially be related.
You have:

dutyCycle = map(readKnob, 1, 1023, 1, 8);


Because of some rounding issues in the Arduino map() function, this
may not work as you expect: the output will be 8 only if the input
reaches 1023. If readKnob is 1022, dutyCycle will be 7. This may
explain why you never see the pump being constantly on.
The way map() works makes most sense if you think in terms of
half-open intervals, open on the right. If you write:
dutyCycle = map(readKnob, 0, 1024, 1, 9);

you will get a perfect mapping from [0, 1024) to [1, 9). Perfect in the
sense that there will be exactly 128 input values mapped to each output
value:
[  0, 128) → 1
[128, 256) → 2
[256, 384) → 3
...

And later:

for (int i = 0; i <= ledCount; i++) {
    strip.setPixelColor(i, 0, 0, 0);
}


The strip has ledCount pixels, numbered 0 to ledCount-1. This loop
will set the color of pixels 0 through ledCount inclusive. The last
iteration goes beyond the end of the strip, and it is most likely
corrupting memory, i.e. overwriting whatever data happens to sit right
after the memory area used for the strip. If this is overwriting some
variable related to the duty cycle, that may explain the weird behavior
you experience.

78180: <p>I'm building a small project to maintain a copper plating tank's temperature and filter pump duty cycle. I'm using the Adafruit Feather platform to hold an 8 segment matrix coupled with a Teensy 3.2 (on a Feather shield) to calculate and display temp. There is a 10K Pot on A0 and an 8 segment NeoPixel Strip to set and display pump duty cycle from 1 to 8 corresponding to .125*hour and 100% on. There is also a push and hold set switch to operate temperature target point setting using the same pot.</p>
<p>Things that work: Almost Everything!
Thing that doesn't work:</p>
<p>Changing the Duty Cycle knob (which changes the duty cycle global variable) after turning the unit on doesn't seem to change the on/off times other than to successfully change the NeoPixel display. If the unit is turned on at a particular duty cycle, the program will run that duty cycle successfully. While running, if I change the duty Cycle to 8, I don't get a &quot;100% On&quot;. In other words the change in the duty cycle variable doesn't seem to change the on time and off time variables in the code while running.</p>
<p>Q: What do I need to do to make the duty cycle setting work on the fly?</p>
<p>Oh... That Volatile Float declaration was my last desperate attempt, Please ignore / forgive. ;-)</p>
<p>Hopefully the fix is as simple as the code. ;-) I just don't see it and my (perhaps flawed) understanding of global variables is hit a wall.</p>
<p>Any help will be much appreciated. Thanks.</p>
<p>Jeff</p>
<p>Code:</p>
<pre><code>
/***************************************************
  Copper Plating Tank Control - v1.1
  by Jeff W. Parisse - July 7st, 2021
  www.coppercholla.com

  This program runs a programmable interval timer for chemical pump
  duty cycle and a programmable temperature setting and heating control
  for maintaining plating solution temperature.

  Processor: PJRC Teensy 3.2
  Additional Libraries: Adafruit Industries LLC
  Temperature Sensor: Adafruit MAX31865 w/P1000 Platinum Wire Probe
  Pin Outs:
    Setting Knob: Pin A0
    Matrix Display: Feather Matrix I2C 0x70
    Neopixels: Pin 5
    MAX31865: CLK Blue
    MAX31865: SDO Yellow
    MAX31865: SDI White
    MAX31865: CS Pin 6 Green
    Temp Set Switch: Pin 8
    Chemical Pump: Pin 9
    Tank Heater: Pin 10

 ****************************************************/

#include &lt;Adafruit_MAX31865.h&gt;
#include &lt;Adafruit_GFX.h&gt;
#include &quot;Adafruit_LEDBackpack.h&quot;
#include &lt;Adafruit_NeoPixel.h&gt;

#define knobPin A0
#define ledPin 5
#define csPin 6
#define switchPin 8
#define pumpPin 9
#define heaterPin 10
#define ledCount 8
#define sampleNum 4
#define RREF      4296.0
#define RNOMINAL  1000.0

Adafruit_MAX31865 thermo = Adafruit_MAX31865(csPin);
Adafruit_7segment matrix = Adafruit_7segment();
Adafruit_NeoPixel strip(ledCount, ledPin, NEO_GRB + NEO_KHZ800);

float targetTemp = 77.0;                // Starting Value
float readTemp = 0;
float toleranceTemp = 0.25;
float tempSum = 0;
float cTemp = 0;
float fTemp = 0;
volatile float dutyCycle = 4;
unsigned long previousTime = 0;
unsigned long oneHour = 3600000;       // 1 Hour in Milliseconds
unsigned long timeOn = 450000;         // 7.5 Minutes in Milliseconds
unsigned long pumpInterval = timeOn;
boolean pumpState = true;

void setup() {
  thermo.begin(MAX31865_3WIRE);;
  matrix.begin(0x70);
  strip.begin();
  strip.show();
  pinMode(csPin, OUTPUT);
  pinMode(heaterPin, OUTPUT);
  pinMode(pumpPin, OUTPUT);
  pinMode(switchPin, INPUT_PULLUP);
  digitalWrite(csPin, LOW);
  digitalWrite(heaterPin, LOW);
  digitalWrite(pumpPin, LOW);
}

void loop() {
  // Read Set Switch
  int setSwitch = (digitalRead(switchPin));
  while (setSwitch == LOW) {
    int readKnob = analogRead(knobPin);
    targetTemp = map(readKnob, 1, 1023, 67, 87);
    matrix.print(targetTemp, 1);
    matrix.writeDisplay();
    setSwitch = (digitalRead(switchPin));
  }

  // Read, Convert, and Display Temp
  tempSum = 0;
  for (int i = 1; i &lt;= sampleNum; i++) {
    readTemp = thermo.temperature(RNOMINAL, RREF);
    tempSum = tempSum + readTemp;
  }
  cTemp = tempSum / sampleNum;
  fTemp = (cTemp * 1.8) + 32;
  matrix.print(fTemp, 1);
  matrix.writeDisplay();

  // Heater Logic
  if (fTemp &lt; targetTemp - toleranceTemp) {
    digitalWrite(heaterPin, HIGH);
  }
  else if (fTemp &gt; targetTemp + toleranceTemp) {
    digitalWrite(heaterPin, LOW);
  }

  // Read and Display Duty Cycle
  int readKnob = analogRead(knobPin);
  dutyCycle = map(readKnob, 1, 1023, 1, 8);
  for (int i = 0; i &lt;= ledCount; i++) {
    strip.setPixelColor(i, 0, 0, 0);
  }
  strip.show();
  for (int i = 0; i &lt;= dutyCycle - 1; i++) {
    strip.setPixelColor(i, 0, 0, 20);
  }
  strip.show();

  // Pump Timer
  digitalWrite(pumpPin, pumpState);
  unsigned long timeOn = ((dutyCycle / 8UL) * oneHour);
  unsigned long timeOff = (oneHour - timeOn);
  unsigned long currentTime = millis();
  if (currentTime - previousTime &gt;= pumpInterval) {
    if (pumpState) {
      pumpInterval = timeOff;
    }
    else {
      pumpInterval = timeOn;
    }
    pumpState = !(pumpState);
    previousTime = currentTime;
  }
}

</code></pre>
 7508: <p>I do not really understand what may be the cause of your problem, but I
have identified two issues that could potentially be related.</p>
<p>You have:</p>
<blockquote>
<pre class="lang-cpp prettyprint-override"><code>dutyCycle = map(readKnob, 1, 1023, 1, 8);
</code></pre>
</blockquote>
<p>Because of some rounding issues in the Arduino <code>map()</code> function, this
may not work as you expect: the output will be 8 only if the input
reaches 1023. If <code>readKnob</code> is 1022, <code>dutyCycle</code> will be 7. This may
explain why you never see the pump being constantly on.</p>
<p>The way <code>map()</code> works makes most sense if you think in terms of
<em>half-open</em> intervals, open on the right. If you write:</p>
<pre class="lang-cpp prettyprint-override"><code>dutyCycle = map(readKnob, 0, 1024, 1, 9);
</code></pre>
<p>you will get a perfect mapping from [0, 1024) to [1, 9). Perfect in the
sense that there will be exactly 128 input values mapped to each output
value:</p>
<pre><code>[  0, 128) → 1
[128, 256) → 2
[256, 384) → 3
...
</code></pre>
<p>And later:</p>
<blockquote>
<pre class="lang-cpp prettyprint-override"><code>for (int i = 0; i &lt;= ledCount; i++) {
    strip.setPixelColor(i, 0, 0, 0);
}
</code></pre>
</blockquote>
<p>The strip has <code>ledCount</code> pixels, numbered 0 to <code>ledCount-1</code>. This loop
will set the color of pixels 0 through <code>ledCount</code> inclusive. The last
iteration goes beyond the end of the strip, and it is most likely
corrupting memory, i.e. overwriting whatever data happens to sit right
after the memory area used for the strip. If this is overwriting some
variable related to the duty cycle, that may explain the weird behavior
you experience.</p>
