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;
}
}
-
1Had you tried to print and test to output of map function?fabianoriccardi– fabianoriccardi2021年07月09日 18:48:37 +00:00Commented Jul 9, 2021 at 18:48
-
And why is it a float if its value can only be an integer from 1-8?Dave Newton– Dave Newton2021年07月09日 19:06:08 +00:00Commented Jul 9, 2021 at 19:06
1 Answer 1
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.
-
Thanks Edgar... I will rewrite this after lunch and feedback...Jeff Parisse– Jeff Parisse2021年07月09日 19:58:28 +00:00Commented Jul 9, 2021 at 19:58
-
Fabian... at first I did when I was getting the led routing working. Then I stopped monitoring that function... probably why I may have missed it.Jeff Parisse– Jeff Parisse2021年07月09日 20:01:02 +00:00Commented Jul 9, 2021 at 20:01
-
Dave, because I was grasping at straws rather doing what I doing now, asking for help, which is way more rational... I’ll fix that code asap. :-)Jeff Parisse– Jeff Parisse2021年07月09日 20:02:32 +00:00Commented Jul 9, 2021 at 20:02