For those that like root canal work. I could probably spend a month explaining what I'm doing here and that is the reason why I did not attach all the code. But you are exactly right, the error was in code and not obvious at first. It was code left in before some changes in outputs were made. Please excuse the crappy coding, but it is my first attempt at C++ or anything to do with Arduino. This is being used as a remote satellite controller via RS485 to adjust radiant floor temperatures with a stepper mixing valve, controlling 3 zone valves and three pumps. It incorporates an offline mode in case the main controller wigs out. One or two suggestion on coding would be welcomed. I am a beginner. I left the bug for your entertainment. Let's see how you do with all the code. I can send the schematic for the piggy packed expansion PCB. I admit it was a bugger for me to find.
/*
NEMA 17 Bipolar Stepper with A4988/TCM2208 Driver
Set TCM2208 Current limit for TCM2208 is 1.2 Amp. Max I for motor is 1.5
https://wiki.fysetc.com/TMC2208/#pin-functions
Set Static Vref to 1.4 -1.5V less 10% = 1.35V
DS18B20 temperature sensor (https://arduino-tutorials.net)
// Define Constants
// Connections to A TCM2208
******* LCD CONTROL *******
http://www.arduino.cc/en/Tutorial/LiquidCrystal
The circuit:
LCD RS pin to digital pin 7
LCD Enable pin to digital pin 8
LCD D4 pin to digital pin 9
LCD D5 pin to digital pin 10
LCD D6 pin to digital pin 11
LCD D7 pin to digital pin 12
LCD R/W pin 5 to ground
LCD VSS pin 1 to ground
LCD VDD or VCC pin to 5V
10K resistor:
ends to +5V and ground
wiper to LCD VO pin (pin 3)
*/
// Include the LCD library code:
#include <Streaming.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Libraries for the 1-wire DS18B20 temperature sensor
#include <OneWire.h>
#include <DallasTemperature.h>
//URL: http://forum.arduino.cc/index.php?topic=356253
#include "CountDown.h"
CountDown CD;// Count Do
CountDown KACD;// Keep Alive
//https:///oreil.ly/PJWJR Page 128 Arduino Cookbook
#include <Streaming.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define sSerialTxControl 4 //RS485 Direction control
#define rS485Transmit HIGH
#define rs485Receive LOW
#define turnOnBacklight 6
#define Pin13LED 13 // To blink serial in data
#define zone1 22
#define zone2 23
#define zone3 24
#define floorPump 25
#define DHWPump 26
#define boilerRelay 27
#define convector 28
#define Spare 29
#define denThermostate 31
#define bedroomThermostate 32
#define kitchenThermostate 33
#define zoneSwitch 34
#define endSensor 35 // Limit Closed Stepper uses Pullup Resistor. Normally Grounded
#define limitOpen 36 // Limit Open Stepper
#define DHWSwitch 37
/*-----( Declare Variables )-----*/
// Motor steps per rotation and connected pins
const int STEPS_PER_REV = 200;
const int dirPin = A1; // Direction
const int stepPin = A0; // Step
int leadScrewRevolutions = 107;// Must move valve 4 1/8" or 25 revolutions per inch. Total steps 21400
int stepCount = (STEPS_PER_REV * leadScrewRevolutions);
short LF = 10; //ASCII Linefeed
int outputSelect = 0;
int keepAliveTime = 1;// Minutes
int displayBlankTime = 10;// Minutes
bool offLine = false;
const byte OPEN = HIGH;
const byte CLOSED = LOW;
// bool homePosition = false; //Not Used
String stepDirection = "";
float tempDelta = 0; // Initialize. May not need
float setTemp = 27; //Default Start Temp
float temperature = 0.0;
int oneWireBus = 5; // 1-wire pin// variable to store the measured temperaturevariabele (float = floating point number)
const int NUMBER_OF_FIELDS = 3;
float values[NUMBER_OF_FIELDS];
/*-----( Declare objects )-----*/
OneWire oneWire(oneWireBus); // 1-wire instance on the oneWireBus pin
DallasTemperature sensors(&oneWire); // give the OneWire instance as parameter to the DallasTemperature library.
// pass the address (Pointer) and not the contents of the variable itself, we use &.
// initialize the library with the numbers of the interface pins. Use when not employing Serial LCD control <LiquidCrystal_I2C.h>
// LiquidCrystal lcd(7, 8, 9, 10, 11, 12); //LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup()
{
// set up the LCD's number of columns and rows:
lcd.init();
lcd.backlight();
lcd.setCursor(2, 0);
lcd.print("Harmony Controls");
lcd.setCursor(1, 2);
lcd.print("Initiating Stepper");
// Countdown 10 minute for display backlight turn off
CD.start(0, 0, displayBlankTime, 0); //Days,Hours,Min,Sec Initial lcd on time
//Countdown for Uptairs Computer PWR Fail
KACD.start(0, 0, keepAliveTime, 0); //Initial lcd on time
// Setup the pins as Outputs
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
//pinMode(LED_BUILTIN, OUTPUT);
//Output config
pinMode(endSensor, INPUT_PULLUP); // May not need pullup if using mechanical Sw
pinMode(limitOpen, INPUT_PULLUP); // May not need pullup if using mechanical Sw
pinMode(zone1, OUTPUT);
pinMode(zone2, OUTPUT);
pinMode(zone3, OUTPUT);
pinMode(convector, OUTPUT);
pinMode(DHWPump, OUTPUT);
pinMode(boilerRelay, OUTPUT);
pinMode(floorPump, OUTPUT);
pinMode(DHWSwitch, INPUT_PULLUP);
pinMode(kitchenThermostate, INPUT_PULLUP);
pinMode(bedroomThermostate, INPUT_PULLUP);
pinMode(denThermostate, INPUT_PULLUP);
pinMode(turnOnBacklight, INPUT_PULLUP);
pinMode(zoneSwitch, INPUT_PULLUP);
DDRC = B11111111; // set PORTC (digital 7~0) to outputs
DDRA = B11111111; // set PORTA (digital 7~0) to outputs
// Configure Serial1
pinMode(Pin13LED, OUTPUT); //Shows input data received
pinMode(sSerialTxControl, OUTPUT); //Direction Control Pin for Max485
// Begin built in Serial communication at a baud rate of 9600:
Serial.begin(9600); // set the data rate
// Begin built in Serial1 communication at a baud rate of 9600:
Serial1.begin(9600); // set the data rate for Max 485
digitalWrite(sSerialTxControl, rs485Receive); // Init Transceiver direction to Receive (LOW)
// Serial.println("Bas on Tech - 1-wire temperature sensor"); // print message to serial monitor
// sensors.begin(); // start with reading the sensor
// Reset stepper to home position
findHome();
}
void loop() {
temperature = CallTemperature();
//if (homePosition) // Heating disabled or too low. Not used
// setTemp = 0;// not used
tempDelta = setTemp - temperature;
if (temperature > setTemp + .1)
{
digitalWrite(dirPin, HIGH); // Set Directing to in
closeValve();
}
if (temperature < setTemp - .1)
{
digitalWrite(dirPin, LOW); // Set to open direction to out
openValve();
}
serial1Check();
if (KACD.remaining() <= 0)// && offLine == false ) // Reached end of Keep Alive Time
{
PORTA = 0; // Clear all outputs once (PORTA = 0) before going into Offline Mode
PORTC = 0;
offLine = true;
}
if (offLine == true)
thermostateMode();
}
/******* OPEN VALVE (Out) *********/
void openValve() {
for (int i = 0; i <= int(tempDelta * 10); i++) // Number of loops decreases as temp get closer to desired
if (stepCount <= (STEPS_PER_REV * leadScrewRevolutions))
{
stepCount++;
digitalWrite(stepPin, HIGH);
delay(1);
digitalWrite(stepPin, LOW);
}
Serial.println("");
Serial.println("Opening ");
Serial.print("Temperature Delta = "); Serial.println(tempDelta); // Temperature differentual (Desired - Actual)
//printData(); //Sub to print all data
stepDirection = "Open";
int limitOpenSensor = digitalRead(limitOpen); // Look to see if end stop sensor reached
if (limitOpenSensor == HIGH) // Change to LOW if using pullup resister
{
stepCount = 21401; // Reset stepcount to 21401
Serial << "" << "Open End Sensor Reached" << endl;
}
}
/******* CLOSE VALVE (IN) *********/
void closeValve() {
for (int i = 0; i <= int((tempDelta * -1) * 10); i++) // Number of loops decreases as temp get closer to desired
if (stepCount >= 0)
{
stepCount--;
digitalWrite(stepPin, HIGH);
delay(1);
digitalWrite(stepPin, LOW);
}
Serial.println("");
Serial.println("Closing ");
Serial.print("Temperature Delta = "); Serial.println(tempDelta); // Temperature differentual (Desired - Actual)
//printData(); //Sub to print all data
stepDirection = "Close";
int endStopSensor = digitalRead(endSensor); // Look to see if end stop sensor reached
if (endStopSensor == HIGH) // Change to LOW if using pullup resister
{
stepCount = 0; // Reset stepcount to 0
Serial << "" << "End Stop Reached" << endl;
}
}
/******* CALCULATE TEMPERATURE & Check on LCD Off Timer *********/
float CallTemperature() {
sensors.requestTemperatures(); // read the temperature of all 1-wire sensors connected to the 1-wire bus
float temp = sensors.getTempCByIndex(0); // get the temperature of the first sensors in Celcius (lists start with 0 not 1)
// temp = sensors.getTempFByIndex(0); // get the temperature of the first sensors in Fahrenheit (lists start with 0 not 1)
Serial << "Temperature = " << temp << " \xC2\xB0" << "C" << endl;
Serial << "Step Count = " << stepCount << endl;
LCDControl();
return (temp);
}
void LCDControl() {
// Check if the (turnOnBacklight) pushbutton is pressed.
if (digitalRead(turnOnBacklight) == LOW)
CD.start(0, 0, displayBlankTime, 0); // Reset Backlight timer to 10 min
if (CD.remaining() > 0 && CD.isRunning() ) // Time on timer > 0 and Timer runing
{
lcd.backlight();//Turn on
}
else
{
lcd.noBacklight();//Turn off
outputSelect = 27; // skip Lcd output routine
}
outputSelect ++;
switch (outputSelect)
{
case 1:
lcd.clear();
lcd.print("Zone #1 = ");
lcd.print(digitalRead(zone1));// Zone Valve #1
lcd.setCursor(0, 1);//Zone Valve #2
lcd.print("Zone #2 = ");
lcd.print(digitalRead(zone2));// Zone Valve #2
lcd.setCursor(0, 2);
lcd.print("Zone #3 = ");
lcd.print(digitalRead(zone3));// Zone Valve #3
lcd.setCursor(0, 3);
lcd.print("Floor Pump = ");
lcd.print(digitalRead(floorPump));//Downstairs Floor Pump
break;
case 8:
lcd.clear();
lcd.print("DHW Pump = ");
lcd.print(digitalRead(DHWPump));//DHW Pump
lcd.setCursor(0, 1);
lcd.print("Boiler Relay = ");
lcd.print(digitalRead(boilerRelay)); //Boiler
lcd.setCursor(0, 2);
lcd.print("Register Pump = ");
lcd.print(digitalRead(convector));//Register Pump
lcd.setCursor(0, 3);
lcd.print("Spare 29 = ");
lcd.print(digitalRead(convector));// Spare
break;
case 15: //Required Temp & Actual Temperature
lcd.clear();
lcd.print("Req Temp = ");
lcd.print(setTemp);// Requested temp
lcd.setCursor(0, 1);
lcd.print("Curent Temp = ");
lcd.print(temperature);// Current Temp
lcd.setCursor(0, 2);
lcd.print("Step Count = ");
lcd.print(stepCount);// Step Count
lcd.setCursor(0, 3);// Stepper Direction
lcd.print("Direction = ");
lcd.print(stepDirection);
break;
case 23: //Required Temperature & Actual Temperature
lcd.clear();
lcd.print("Display CD = ");
lcd.print(CD.remaining()); lcd.print(" Sec");// Requested temp
lcd.setCursor(0, 1);
lcd.print("Keep Alive = ");
if (KACD.remaining() >> 0) // Keep Alive Timer time remaining
{
lcd.print(KACD.remaining()); lcd.print(" Sec"); // Keep Alive Countdown
}
else
{
lcd.setCursor(0, 1);
lcd.print("OFF Line ");
}
lcd.setCursor(0, 2);
lcd.print("Zone Switch = ");
if (digitalRead(zoneSwitch) == CLOSED)// Zone 1-3 (True = open)
lcd.print ("Closed");
else
lcd.print ("Open");
lcd.setCursor(0, 3);//
lcd.print("DHW Switch = ");
if (digitalRead(DHWSwitch) == CLOSED)// DHW Switch
lcd.print ("Closed");
else
lcd.print ("Open");
//lcd.print(stepDirection);
break;
case 31:
if (offLine == true)
{
lcd.clear();
lcd.print("Kitchen = ");
if (digitalRead(kitchenThermostate) == OPEN) // Kitchen Thermostate open
{
lcd.print ("Open");
Serial.println("Kitchen Thermostate = ");
Serial.println("Open");
Serial.println(kitchenThermostate);
}
else
{
lcd.print ("Closed");
Serial.println("Kitchen Thermostate = ");
Serial.println("Closed");
Serial.println(kitchenThermostate);
}
lcd.setCursor(0, 1);
lcd.print("Bedroom = ");
if (digitalRead(bedroomThermostate) == OPEN) // Bedroom Thermostate closed
lcd.print ("Open");
else
{
lcd.print ("Closed");
Serial.println("Bedroom Thermostate = ");
Serial.println("Closed");
}
lcd.setCursor(0, 2);
lcd.print("Den = ");
if (digitalRead(denThermostate) == OPEN) // Den Thermostate closed
lcd.print ("Open");
else
{
lcd.print ("Closed");
Serial.println("Den Thermostate = ");
Serial.println("Closed");
}
}
else
outputSelect = 0;
break;
case 39:
outputSelect = 0;
break;
}
}
/******* STEPPER TO HOME SUB *********/
void findHome() {
// ---- SET VALVE TO CLOSE -----
digitalWrite(dirPin, HIGH);
//Serial.println("Finding Home"); Serial.println("");
Serial << "" << "Finding Home" << endl;
Serial.println("");
// stepCount = 21400 // *******Un-rem this when finnished to allow home switch to be found on reset************
// Turn stepper one rotation (In)
for (; stepCount >= 0; stepCount--)
{
digitalWrite(stepPin, HIGH);
serial1Check(); // Check for serial1 data
delayMicroseconds(500);
digitalWrite(stepPin, LOW);
delayMicroseconds(500);
int endStopSensor = digitalRead(endSensor);
if (endStopSensor == HIGH)
{
stepCount = 0; // Clear step count
Serial << "" << "End Stop Reached" << endl;
Serial.println("");
}
}
loop();
}
/******* READ SERIAL PORT FOR DATA COMMAND FROM XOJO *********/
void serial1Check() {
if (Serial1.available())
{
if (Serial1.read() == 'H') {
digitalWrite(Pin13LED, HIGH); // Show activity on Pin 13 LED
/******* Set Read Values *********/
Serial.println("");
lcd.begin(20, 4);
for (int i = 0; i < NUMBER_OF_FIELDS; i++)
{
values[i] = Serial1.parseFloat();
}
//Display the values in comma-separated format
Serial.print(values[0]); // first value
//Print the rest of the values with leading comma
for (int i = 1; i < NUMBER_OF_FIELDS; i++)
{
Serial.print(","); Serial.print(values[i]);
}
// Set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
lcd.print(int(values[0])); lcd.print(" "); lcd.print(values[1] ); lcd.print(" "); lcd.print(int(values[2]));
/******* Set Outputs *********/
PORTA = values[0];
/******* Set Temperature *********/
setTemp = values[1];
setTemp = constrain (setTemp, 0, 46);// Max temp is 46 C or 115 F
Serial.println("");
Serial << "Constained Value = " << setTemp << " \xC2\xB0" << "C" << endl;
Serial.println("");
/******* Reset Valve *********/
if (values[2] == 1) //1 = Reset Valve
findHome(); //Do not need brackets if one liner
/******* Return Data *********/
if (values[2] == 2) //2 = Return data
ReturnDataToXOJO(); //Do not need brackets if one liner
/******* Keep Alive *********/
if (values[2] == 3) //3 = Keep Alive
{
KACD.start(0, 0, keepAliveTime, 0); // Keep alive signal from XOJO (10 Min)
offLine = false;
ReturnDataToXOJO(); //Do not need brackets if one liner
}
/******* Stepper Disabled ********* Not Used
if (values[2] == 4) //4 = Home position (Stepper Disabled)
homePosition = true;
/******* Stepper Enabled ********* Not Used
if (values[2] == 5) //5 = Stepper Enabled. Not used
homePosition = false;
*/
digitalWrite(Pin13LED, LOW); // Clear pin 13
}
}
}
/******* Retrun data to XOJO *********/
void ReturnDataToXOJO()
{
Serial1.readString();
// Send data out to XOJO through 485 serial
digitalWrite(sSerialTxControl, rS485Transmit); // Enable RS485 to Transmit
Serial1.print(setTemp);
Serial1.print(",");
Serial1.print(temperature);
Serial1.print(",");
Serial1.print(tempDelta);
Serial1.print(",");
Serial1.print(stepCount);
Serial1.print(",");
Serial1.print(digitalRead(zone1));// Zone Valve #1
Serial1.print(",");
Serial1.print(digitalRead(zone2));// Zone Valve #2
Serial1.print(",");
Serial1.print(digitalRead(zone3));// Zone Valve #3
Serial1.print(",");
Serial1.print(digitalRead(floorPump));// Downstairs Floor Pump
Serial1.print(",");
Serial1.print(digitalRead(DHWPump));// DHW Pump
Serial1.print(",");
Serial1.print(digitalRead(boilerRelay));// Boiler
Serial1.print(",");
Serial1.print(digitalRead(convector));// Upstairs register Pump (Convector)
Serial1.print(",");
Serial1.print((digitalRead(zone1) * 1) + (digitalRead(zone2) * 2) + (digitalRead(zone3) * 4) + (digitalRead(floorPump) * 8) + (digitalRead(DHWPump) * 16) + (digitalRead(boilerRelay) * 32) + (digitalRead(convector) * 64));
Serial1.print(",");
delay(100);
digitalWrite(sSerialTxControl, rs485Receive); // Disable RS485 Transmit. Set to Receive
delay(100);
}
/******* XOJO Fail Mode *********/
void thermostateMode() {
Serial.println ("Off Line");
if ((digitalRead(DHWSwitch) == LOW) || (digitalRead(zoneSwitch) == LOW)) // DHW switch (37) closed or any zone open switch (2)
digitalWrite(boilerRelay, 1); //Boiler Relay Turn On
else
digitalWrite(boilerRelay, 0); //Boiler Relay Turn Off
if (digitalRead(zoneSwitch) == LOW) // Any zone needs heat and is open which closes zone switch (Pin 2)
{
setTemp = 46; //Set Mixing Valve Temp to 46C or 115F
digitalWrite(floorPump, 1); // Floor Pump Turn On
}
else
{
Serial.print ("Zone Switch = ");
Serial.println(digitalRead(zoneSwitch));
}
setTemp = 25;// Set temp to 25C
digitalWrite(floorPump, 0); // Floor Pump Turn Off
if (digitalRead(denThermostate) == HIGH) //Den Thermostate Requirement (pulled to ground on closure)
digitalWrite(convector, 0); // Upstairs Floor Register Pump Turn off
else
digitalWrite(convector, 1); // Upstairs Floor Register Pump Turn On
if (digitalRead(bedroomThermostate) == HIGH) //Bedroom Thermostate Requirement (pulled to ground on closure)
{
digitalWrite(zone2, 0); //Zone Valve #2 Turn Off
digitalWrite(zone3, 0); //Zone Valve #3 Turn Off
}
else
{
digitalWrite(zone2, 1); //Zone Valve #2 Turn On
digitalWrite(zone3, 1); //Zone Valve # 3 Turn On
}
if (digitalRead(kitchenThermostate) == HIGH) //Kitchen Thermostate Requirement (pulled to ground on closure)
// digitalWrite(zone1, 0); //Zone Valve #1 Turn Off
//else
//digitalWrite(zone1, 1); //Zone Valve #2 Turn On
if (digitalRead(DHWSwitch) == HIGH) //DHW SW
digitalWrite(DHWPump, 0); //DHW Pump Turn Off
else
digitalWrite(DHWPump, 1); //DHW Pump Turn On
}