I think,... but have no evidence, other than my App almost fails,.. but no quite.
To explain,.. I am using a nano as a thermostatically PWM (4wire) controlled fan,.. to keep my router (Pfsense Box) cooled, albeit it with some BlueTooth coms to monitor activity and status.
In 'main loop' I create a 10 second loop doing different things at each second, so as not to overload things. Reading each sensor once per 10sec loop.
But reading, If bluetooth active connection the serial port to see if there is any data available,.. and likewise to update the Android App with current status, as well as return new Fan duty cycle to turn fan override on for 1hr if required.
I also try to measure fan RPM,.. if fast speed,.. using a MicroSecond timer,.. and if slow, ( less than 100rpm ) via a period counter...
Now the system can run for many hours if not days without issue,.. but will ultimately start getting corrupt Amb air temperature.
I have approx. 1050 bytes of free memory when compiled, and keep serial print to a minimum,.. but no matter what I try 'Amb air' sensor fails to read,...
'I assume',.. this is probably due to the array of sensor ID addresses being written over,... but I do not know by what?,.. or what mechanism is causing this,.. I have thought about using fixed addresses for the sensors,.. rather than using a 'search',.. and although this might fix / fudge the issue it is not addressing the route cause,.. IMHO.
Is anyone else able to shed any light on what I might need to address to resolve my memory corruptions.
I did wonder if the strings used during BlueTooth were messing things up until I removed the bluetooth not active flag was implemented to prevent unnecessary processing during normal running.
One thing I also wondered is do I need to establish the interrupt variables with more compiler directives,.. eg 'const',.. I just don't know.
I have included my source files ( all concatenated into a single text file ) for review.
Many tx for any feedback, corrections or criticisms...
// Init_Defines.hold
// -------------------------------------
#include <LiquidCrystal_I2C.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <SoftwareSerial.h>
SoftwareSerial MyBlue(12, 11); // RX to Ard | TX from Ard
LiquidCrystal_I2C lcd(0x27, 20, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
/* we always wait a bit between updates of the display */
unsigned long delaytime = 50;
byte Patt_Time[1];
byte HexByteSplit[4];
byte Time[1];
byte Patt[1];
byte FanTime, ticktime, Segmenttime, tenthsec = 0;
#define MaxTemp 60
#define MinTemp 30
#define dutydiv 10
// ----------------------------------
unsigned long currentMillis, PreviousMillis = millis();
// -----------------------------------
// Temperature stuff, connected to Digital PIN 3
#define ds18b20 3
OneWire oneWire(ds18b20);
DallasTemperature sensors(&oneWire);
// arrays to hold device addresses
DeviceAddress Ambient, Heatsink;
uint8_t index2arry;
// Assign address manually. The addresses below will need to be changed
// to valid device addresses on your bus. Device address can be retrieved
// by using either oneWire.search(deviceAddress) or individually via
// sensors.getAddress(deviceAddress, index)
// DeviceAddress Ambient =
// DeviceAddress Heatsink =
//#define LongPrint
#define NumberSensors 2
#define SensorArrySize 5
float temperatureArray[NumberSensors][SensorArrySize + 1] {
{21, 21, 21, 21, 21, 21 },
{31, 31, 31, 31, 31, 31 }
}; // 5 entries, with Postion [6] used as avaerage
byte temperatureIndex = -1; // Intialise Index to array next average to -1 as will be incremented on 1st use
byte id = 0;
char Display[10]; // 8 digit display
char fltbuff[10]; // buffer for float conversion
float AmbTemp, HeatSinkTemp, TempInc;
float minAmb = 25, maxAmb = 25, minhtsk = 25, maxhtsk = 25;
//int maxrpm = 0, Dcycle;
int LCDLEDTimer = 0;
int Dcycle = 0;
#define minmaxtimeout 120000
#define TimerLoadValue 3600 // default time-out 1hr
#define maxindatalen 20
//char inData[maxindatalen]; // Allocate some space for the string
char inChar = -1; // Where to store the character read
byte index = 0; // Index into array; where to store the character
//char outstring[50];
char preData[8];
char actData[5];
char postData[8];
int BTdutyCycle = 0;
int BTdutyTimer = 0;
unsigned long lastcount = 0;
unsigned long timediff = 0;
#define SWstate A6
int StatePin = A1;
int SwitchState = SWstate;
int StateBT = 0;
//int counter;
// -------------------------------------------------------------------
const byte interruptPin = 2; // Pin used to read fan rotational speed
// Fan Interupt Stuff
volatile unsigned long RotorPulseCount = 0;
//unsigned int FanSpeed = 0;
const unsigned int pulsesPerRev = 2;
//const unsigned long now;
//const unsigned long interval;
unsigned long lastPulseTime = 0;
unsigned long rpm = 0;
unsigned long RPMslowfinalcount, slowCountDiff = 0;
unsigned long slowRPMcountSTART = 0;
byte TimeoutRPMcount = 0; // used to check if rotor is actually rotating
//int fanVal;
byte DutyCycle = 1;
unsigned long FANlastmillis = 0;
//float FanCountPeriod, RAWFanRPM, FanCalcRPM, FanCalcTest; ;
const byte OC1A_PIN = 9;
const byte OC1B_PIN = 10;
const word PWM_FREQ_HZ = 25000; //Adjust this value to adjust the frequency
const word TCNT1_TOP = 16000000 / (2 * PWM_FREQ_HZ);
// --------------------------------------------------------------------
//#define Chk_Bit(var,pos) ((var) & (1<<(pos)))
//#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)
//https://stackoverflow.com/questions/523724/c-c-check-if-one-bit-is-set-in-i-e-int-variable
//#define bit_set(val, bit_no) (((val) >> (bit_no)) & 1)
#define Chk_Bit(val, bit_no) (((val) >> (bit_no)) & 1)
#define Set_Bit(var,pos) ((var) |= (1<<(pos)))
#define Clr_Bit(var,pos) ((var) &= ~(1<<(pos)))
#define Tog_Bit(var,pos) ((var) ^= (1<<(pos)))
#define DefaultFlags 0b00000000
// ----------------------------
byte Status_Flags = 0; // 8 Bit Register
#define ENfastRPM 0 // 1
#define ENslowRPM 1 // 2
#define BackLightStatus 2 // 4 1 if on, 0 if off
#define SensorError 3 // 8 1 if error 0 No-error
#define WriteTemp 4 // 16 1 ignore checks to start and write all values, 0 check for valid temperatures
#
#define CriticalBattVolt 5 // 32
#define Supp65volt 6 // 64
#define sample 7 // 128
// -----------------------------
#define LedFlash 6
byte activity = 0;
byte ErrorCount = 0; // count will roll round after 256
// ---------------------------------------
// Setup.ino
// *******************************************************************
void setup() {
Serial.begin(57600);
MyBlue.begin(9600);
Wire.begin();
lcd.init(); // initialize the lcd
lcd.backlight();
Set_Bit(Status_Flags, BackLightStatus);
lcd.home();
lcd.print("Fan Control");
lcd.setCursor(0, 1);
lcd.print("Start...");
Serial.println(F("display setup"));
FanCalcs();
delay(1000);
// Setup pin to flash LED in Switch
pinMode(LedFlash, OUTPUT);
Set_Bit(Status_Flags, WriteTemp); // Set Flag so all temperature data get written to array
// ------------------------------------
// Check if sensors present
if (!sensors.getAddress(Ambient, 0)) Serial.println(F("Unable to find address for Device 0"));
if (!sensors.getAddress(Heatsink, 1)) Serial.println(F("Unable to find address for Device 1"));
// --------------------------------------------------------
// fan setup
pinMode(interruptPin, INPUT); // Pin 2 is tacho input to which a fan is connected
EnableFastRPM();
// attachInterrupt(digitalPinToInterrupt(interruptPin), FANrpmISR, RISING); // attach and enable FastRPM interrupt 2
// attachInterrupt(digitalPinToInterrupt(interruptPin), SlowRPMCount, RISING); // attach and enable slowRPM interrupt 2
pinMode(OC1A_PIN, OUTPUT); // This sets the PWM pin output...
// Clear Timer1 control and count registers
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
TCCR1A |= (1 << COM1A1) | (1 << WGM11);
TCCR1B |= (1 << WGM13) | (1 << CS10);
ICR1 = TCNT1_TOP;
// fanVal = 25;
LCDLEDTimer = 300; // give an initial timeout value of 300 seconds
lcd.clear();
}
// ------------------------------------------------------------
void EnableFastRPM() {
detachInterrupt(digitalPinToInterrupt(interruptPin));
Clr_Bit(Status_Flags, ENslowRPM); // clear both flags just to be safe
Clr_Bit(Status_Flags, ENfastRPM); //
//
// timers and vraiables for fast checking using micro seconds are all set and sorted with ISR
attachInterrupt(digitalPinToInterrupt(interruptPin), FANrpmISR, RISING); // attach and enable FastRPM interrupt 2
// attachInterrupt(digitalPinToInterrupt(interruptPin), SlowRPMCount, RISING); // attach and enable slowRPM interrupt 2
Set_Bit(Status_Flags, ENfastRPM); // Set Bit zero to a 1 to show fast RPM enabled
Serial.println(F("Fast RPM Enabled"));
}
void EnableSlowRPM() {
detachInterrupt(digitalPinToInterrupt(interruptPin));
Clr_Bit(Status_Flags, ENslowRPM); //
Clr_Bit(Status_Flags, ENfastRPM); //
slowRPMcountSTART = micros();
TimeoutRPMcount = 0;
RotorPulseCount = 0;
// now we see how long to get 20 interupts whilst in slow mode count
// attachInterrupt(digitalPinToInterrupt(interruptPin), FANrpmISR, RISING); // attach and enable FastRPM interrupt 2
attachInterrupt(digitalPinToInterrupt(interruptPin), SlowRPMCount, RISING); // attach and enable slowRPM interrupt 2
Set_Bit(Status_Flags, ENslowRPM); // Set Bit zero to a 1 to show fast RPM enabled
Serial.println(F("Slow RPM Enabled"));
}
// FanCtrl7-8.ino
// **********************************************************************************************
#include "Init_Defines.h"
// Sketch uses 16156 bytes (52%) of program storage space. Maximum is 30720 bytes.
// Global variables use 873 bytes (42%) of dynamic memory, leaving 1175 bytes for local variables. Maximum is 2048 bytes.
void loop() {
do {
delay(10);
// Do Nothing
} while ( ( millis() - PreviousMillis ) < 100 );
// we land here every 0.1 of a second
// Read Blue Tooth every 1/10 second
readSerialBlu();
// Now see what we have to do
// processBlueRead();
tenthsec++;
if ( tenthsec > 9 ) { // count is zero to 9, so 10 increments
tenthsec = 0;
}
// We go past here every 1/10 of a second
// Turn fan off
if ( millis() > 2000 && millis() < 2200 ) { // after switch on between 2 and 2.2 second set duty cycle to zero
Dcycle = 0;
setPwmDuty((100 - Dcycle)); // This inverts the value sent to the PWM,.. as output transistor inverts output
}
// ----------------------
// Clear the Write data flag so data will now be checked before commiting to array
// One off timer that counts from reset time zero
if ( millis() > 180000 && millis() < 180200 ) { // after switch on between 3 and 3 minutes+1sec reset max rpm to zero
// this gives enough time to write to flag twice
Clr_Bit(Status_Flags, WriteTemp);
Serial.println(F("Temperatre write bad data flag cleared"));
}
// -----------------------------------
// So now we read BlueTooth connection status once every second
StateBT = analogRead(StatePin); // read the input pin to determine the BlueTooth connection status
// Serial.print("State Pin ->");
// Serial.println(StateBT); // debug value
SwitchState = analogRead(SWstate); // 138 closed or 73 open <> 100 can be the threshold
// Serial.print("Switch State Pin ->");
// Serial.println(SwitchState); // debug value
// Now check if we need to turn backlight on without doing it multiple times
if ( SwitchState > 100 ) {
SetBacklightON();
//
// // Serial.print("backlight status>");
// // Serial.println(Chk_Bit(Status_Flags, BackLightStatus));
//
// if ( Chk_Bit(Status_Flags, BackLightStatus) == 0 ) {
// lcd.backlight(); // Turn Backlight ON
// Set_Bit(Status_Flags, BackLightStatus);
// // Serial.println("Backlight ON");
// }
// LCDLEDTimer = 1800; // 1800; // 1/2 hr timer
}
// Serial.print("Switch state >");
// Serial.println(SwitchState);
// Toggle LED Light in switch
// digitalWrite(LedFlash, !digitalRead(LedFlash)); // toggle state
// **********************************************************************
/*
This creates a 1 second timer,...
so 1 miniute will have a total count of 60
*/
if ( tenthsec == 0 ) {
ticktime++;
if ( ticktime > 10) {
ticktime = 0;
// Serial.println("");
}
// Serial.print(ticktime);
// Serial.print(" ");
// timediff = millis() - lastcount;
// Serial.println(timediff);
// lastcount = millis();
EvalLCDLight();
if ( BTdutyTimer > 0 ) {
// this will allow timer to count down to Zero
BTdutyTimer--;
}
TimeoutRPMcount++; // this just increments a local counter to timeout if no rotor pulses
EvaluateSlowRPM();
ActivityIcons();
switch (ticktime)
{
case 0:
FanTime++;
if ( FanTime > 6 ) {
FanTime = 0;
SetFanCntl();
}
break;
case 1:
Inc_Temp_Store_indx(); // This increments the storage pointer for the next store
// of temperature value into array
SerialwriteBlu();
break;
case 2:
// Sensor reads take approx 750mS,.. and lock system, so stagger
// reads at 2 a 7 seconds of the 10second cycle
GetTemp(0, Ambient);
break;
case 3:
DisplayDutyCycleRPM(Dcycle); // Pass Float number for conversion and display
break;
case 4:
DisplayTempUpdate(); // Pass Float number for conversion and display
// DisplayTempUpdate(HeatSinkTemp); // Pass Float number for conversion and display
break;
case 5:
// determine which mode is running
if ( (Chk_Bit(Status_Flags, ENfastRPM) == 1 ) && ( rpm < 100 )) {
// Serial.println("Fastrpm is checked as enabled, and rpm less than 100");
EnableSlowRPM();
Serial.println(F("SLOWrpm is now enabled "));
} else if ( (Chk_Bit(Status_Flags, ENslowRPM) == 1 ) && ( rpm > 100 )) {
// Serial.println("Slowrpm is enabled but rpm is greater than 100");
EnableFastRPM();
Serial.println(F("FASTrpm is now enabled "));
}
break;
case 7:
DisplayDutyCycleRPM(Dcycle); // Pass Float number for conversion and display
break;
case 8:
GetTemp(1, Heatsink);
break;
case 9:
DisplayTempUpdate(); // Pass Float number for conversion and display
// DisplayTempUpdate(HeatSinkTemp); // Pass Float number for conversion and display
// Serial.println(ErrorCount);
break;
}
}
PreviousMillis = millis();
}
// Bluetooth.ino
// **************************************************************************************
/*
Send string formatted as follows
Data to send to Android App
p1=1230p2=2200p3=-06p4=24 25 chars
ss;1230;36;25;-06;24;34;24;34;32;150;ee;- 41 Char
p5=34p6=24p7=34p8=32 45 chars or one line
Updated 30 April2021 include set cycle
p1 > ss
p2 > current measured rpm
p3 > current set Duty Cycle
p4 > set RPM time-out
p5 > Current Amb temperature measured
p6 min Amb temperature measured
p7> max Amb temperature measured
p8> Current Heat sink temperature measured
p9> min Heat Sink temperature measured
p10 max Heat Sink temperature measured
p11 ErrorCount
p12> ee;-
*******************************************
Data to recieve
Dcycle;12;DCend
*/
void readSerialBlu() {
if ( StateBT > 500 ) {
char inData[maxindatalen];
index = 0;
inData[index] = '\0'; // Null terminate the string on zero length string
while (MyBlue.available() > 0) { // Don't read unless
// you know there is data
// Always read the data... so as to not block buffer
// but dont save as will get buffer overflow
inChar = MyBlue.read(); // Read a character
if (index < ( maxindatalen - 1) ) // One less than the size of the array
{
// inChar = MyBlue.read(); // Read a character
inData[index] = inChar; // Store it
index++; // Increment where to write next
inData[index] = '\0'; // Null terminate the string
}
}
// Serial data now has been read,.. now we must process it
//void processBlueRead() { no nonlger a subroutine
// char inData[maxindatalen];
if ( index > 0 ) { // variable 'index' indexes input string as it is read in from bluetooth device
// Serial.print("Data to process >");
// Serial.println(inData);
// -------------------------
char *pntr;
byte i = 0;
pntr = strtok(inData, ";"); // set pointer to 1st byte of the string.
while (pntr && i < 3)
{
// BTReadField[i] = pntr;
if ( i == 0 ) {
if ( strlen(pntr) < 7 ) {
strcpy(preData, pntr);
} else {
Serial.println(F("stringpre too long"));
}
} else if ( i == 1 ) {
if ( strlen(pntr) < 4 ) {
strcpy(actData, pntr);
} else {
Serial.println(F("stringdata too long"));
}
} else if ( i == 2 ) {
if ( strlen(pntr) < 6 ) {
strcpy(postData, pntr);
} else {
Serial.println(F("stringpost too long"));
}
}
pntr = strtok(NULL, ";");
++i;
}
// Serial.print("the Numeric data >");
BTdutyCycle = atoi(actData);
// Serial.println(BTdutyCycle);
// ----
Dcycle = BTdutyCycle;
// fanVal = Dcycle;
setPwmDuty((100 - Dcycle)); // This inverts the value sent to the PWM,.. as output transistor inverts output
// Serial.print("Fan Duty Cycle >");
// Serial.println(fanVal);
if ( Dcycle == 19 ) {
// ----
// Start Timer
BTdutyTimer = 65; // this just loads a short value that will timeout quickly
SetBacklightON();
Serial.println(F("Setting duty cycle timer to short timer"));
} else {
BTdutyTimer = TimerLoadValue; // Load default timeout nominally 1hr
// Now check if we need to turn backlight on without doing it multiple times
if ( Chk_Bit(Status_Flags, BackLightStatus) == 0 ) {
SetBacklightON();
}
Serial.println(F("Backlight on due to Btooth"));
Serial.print(F("Setting duty cycle to >"));
Serial.print(Dcycle);
Serial.println(F(", and timer to 60"));
}
// ----------------------------
// // clear index and buffer
// index = 0;
// inData[index] = '\0'; // Null terminate the string on zero length string
}
}
}
// ------------------------------------------------
void SerialwriteBlu() {
char outstring[20];
// eg
// ss;1230;100;60;24.0;25.0;25.0;24.3;24.3;25.0;200;ee;- 54 chars max length
// ss;1230;100;60; -- send up to timer 15 chars with each send
// 24.0;25.0;25.0; --
// 24.3;24.3;25.0;
// 200;ee;- 54 chars max length
// ss;0;0;0;24.1;24.1;25.0;24.5;24.5;25.0;0;ee;- 46 chars min number
//
char convertString[10];
// StateBT = analogRead(StatePin); // read the input pin to determine the BlueTooth connection status
// Serial.print("State Pin ->");
// Serial.println(StateBT); // debug value
if ( StateBT > 500 ) {
// Serial.println("\nData to write back");
// p2 > current rpm measured
// char asciCurrRPM[6];
itoa(rpm, convertString, 10); // 10 is the base
strcpy(outstring, "ss;");
strcat(outstring, convertString);
strcat(outstring, ";");
// Serial.print("ASC rpm ->");
// Serial.println(convertString);
// Serial.print("RAW rpm ->");
// Serial.println(rpm);
// ascDutyCylce added 30Apr2021
// p3 > Current Duty Cycle
char ascDutyCylce[4];
itoa(Dcycle, convertString, 10);
strcat(outstring, convertString);
strcat(outstring, ";");
// Serial.print("Duty cycle value to transmit>");
// Serial.println(convertString);
// p4 > Current Time-out counter value in minutes
// char ascTimer[6];
if ( BTdutyTimer != 0 ) { // Check first to see if timer is actually running
// / 60 to get from minutes timer,,, and +60 so display show less minutes correctly
// and times out when less than 1 minute as sums are not float numbers
itoa(((BTdutyTimer + 60) / 60), convertString, 10 ); // 10 is the base
} else {
itoa((BTdutyTimer / 60), convertString, 10 ); // no offsetting required
}
strcat(outstring, convertString);
strcat(outstring, ";");
// **************
MyBlue.print(outstring); // Write the character to Bluetooth
Serial.print(outstring);
// **************
// Serial.print("RAW BTdutyTimer ->");
// Serial.println(convertString);
// Serial.print("ASC Timer ->");
// Serial.println(convertString);
// -------------------------
// p5 > Current Amb temperature measured
// char asciiAmbTemp[6];
dtostrf(AmbTemp, 4, 1, convertString);
strcpy(outstring, convertString);
strcat(outstring, ";");
// Serial.println(convertString);
// p6
// char asciiAmbMinTemp[6];
dtostrf(minAmb, 4, 1, convertString);
strcat(outstring, convertString);
strcat(outstring, ";");
// Serial.println(convertString);
// p7
// char asciiAmbMaxTemp[6];
dtostrf(maxAmb, 4, 1, convertString);
strcat(outstring, convertString);
strcat(outstring, ";");
// Serial.println(convertString);
// **************
MyBlue.print(outstring); // Write the character to Bluetooth
Serial.print(outstring);
// **************
// -------------------------
// p8 > Current Heat sink temperature measured
// char asciiHeatSinkTemp[6];
dtostrf(HeatSinkTemp, 4, 1, convertString);
strcpy(outstring, convertString);
strcat(outstring, ";");
// Serial.println(convertString);
// p9
// char asciiHeatSinkMinTemp[6];
dtostrf(minhtsk, 4, 1, convertString);
strcat(outstring, convertString);
strcat(outstring, ";");
// Serial.println(convertString);
// p10
// char asciiHeatSinkMaxTemp[6];
dtostrf(maxhtsk, 4, 1, convertString);
strcat(outstring, convertString);
strcat(outstring, ";");
// Serial.println(convertString);
// **************
MyBlue.print(outstring); // Write the character to Bluetooth
Serial.print(outstring);
// **************
// p11
// char asciiErrorCount[4];
itoa(ErrorCount, convertString, 10);
strcpy(outstring, convertString);
strcat(outstring, ";ee;-");
// Serial.println(convertString);
// ******************
MyBlue.println(outstring); // Write the final character string to Bluetooth
Serial.println(outstring); // NOTE!! this has terminating <CR> LF at end if print
// ************************
// Serial.println("ss;870;3500;22;14;28;44;34;52;150;ee;-"); // 38 chars
}
}
// ------------------------------------------------
// Display.ino
// *************************************************************************
void ActivityIcons() {
activity++;
if ( activity > 7 ) {
activity = 0;
}
if ( activity == 0 ) {
lcd.setCursor(7, 0);
lcd.print(" ");
lcd.setCursor(7, 1);
lcd.print(" ");
} else if ( activity == 1 ) {
lcd.setCursor(7, 0);
lcd.print(".");
lcd.setCursor(7, 1);
lcd.print(" ");
} else if ( activity == 2 ) {
lcd.setCursor(7, 0);
lcd.print(":");
lcd.setCursor(7, 1);
lcd.print(" ");
} else if ( activity == 3 ) {
lcd.setCursor(7, 0);
lcd.print(":");
lcd.setCursor(7, 1);
lcd.print(".");
} else if ( activity == 4 ) {
lcd.setCursor(7, 0);
lcd.print(":");
lcd.setCursor(7, 1);
lcd.print(":");
} else if ( activity == 5 ) {
lcd.setCursor(7, 0);
lcd.print(".");
lcd.setCursor(7, 1);
lcd.print(":");
} else if ( activity == 6 ) {
lcd.setCursor(7, 0);
lcd.print(" ");
lcd.setCursor(7, 1);
lcd.print(":");
} else if ( activity == 7 ) {
lcd.setCursor(7, 0);
lcd.print(" ");
lcd.setCursor(7, 1);
lcd.print(".");
}
}
// ----------------------------------------
void EvalLCDLight() {
if (LCDLEDTimer != 0 ) {
LCDLEDTimer--;
} else if ( LCDLEDTimer == 0 && BTdutyTimer < 2000 ) {
if ( Chk_Bit(Status_Flags, BackLightStatus) == 1 ) {
Clr_Bit(Status_Flags, BackLightStatus);
lcd.noBacklight(); // this will turn the backlight off for both conditions being TRUE
Serial.println(F("Backlight Off"));
// Serial.print("backlight status>");
// Serial.println(Chk_Bit(Status_Flags, BackLightStatus));
}
}
}
// ----------------------------------------
void DisplayTempUpdate() {
char outstring[5];
if ( Chk_Bit(Status_Flags, SensorError) == 0 ) { // if sensor error do not update temperature
lcd.setCursor(8, 1);
strcpy(outstring, "Air"); // Start string for Ambient Air
lcd.print(outstring);
lcd.print(AmbTemp, 1); // Set output to 1 dp
lcd.print("C");
lcd.setCursor(8, 0);
strcpy(outstring, "Hsk"); // Start string for Heat Sink
lcd.print(outstring);
lcd.print(HeatSinkTemp, 1); // Set output to 1 dp
lcd.print("C");
// We will now display how much of the manual timer remains
// if less than minute left
if ( BTdutyTimer < 10 ) {
dtostrf((BTdutyTimer + 60 ) / 60, 2, 0, outstring);
strcpy(outstring, "<1");
} else {
dtostrf((BTdutyTimer + 60 ) / 60 , 2, 0, outstring);
}
strcat(outstring, "m");
// And if timer is at zero
if ( BTdutyTimer == 0 ) {
strcpy(outstring, "-- ");
}
// And finally just print it
lcd.setCursor(4, 0);
lcd.print(outstring);
}
}
// ---------------------------------------
void DisplayDutyCycleRPM(int duty) {
if ( Chk_Bit(Status_Flags, SensorError) == 0 ) { // if sensor error do not update temperature
itoa(duty, fltbuff, 10); // duty = value 0 -> 100
strcat(fltbuff, "%");
byte stringLen = strlen(fltbuff);
if ( stringLen == 2 ) {
strcat(fltbuff, " ");
} else if ( stringLen == 3 ) {
strcat(fltbuff, " ");
}
// Print duty cycle to Display
lcd.setCursor(0, 0);
lcd.print(fltbuff);
// ------------------------------------------------
// validateRPM();
// Print RPM to 2nd line of display
lcd.setCursor(0, 1);
itoa(rpm, fltbuff, 10);
strcat( fltbuff , "rpm" );
stringLen = strlen(fltbuff);
if ( strlen(fltbuff) == 4 ) {
strcat(fltbuff, " " ); // add 4 spaces
} else if ( strlen(fltbuff) == 5 ) {
strcat(fltbuff, " " ); // add 3 spaces
} else if ( strlen(fltbuff) == 6 ) {
strcat(fltbuff, " " ); // add 2 spaces
}
lcd.print(fltbuff);
// lcd.print("XXX");
}
}
// --------------------------------
void SetBacklightON() {
if ( Chk_Bit(Status_Flags, BackLightStatus) == 0 ) {
lcd.backlight(); // Turn Backlight ON as well
LCDLEDTimer = 1800; // 1800; // 1/2 hr timer
Set_Bit(Status_Flags, BackLightStatus);
Serial.println(F("Backlight ON"));
}
}
// FanCtrl.ino
// *************************************************************************************
void SetFanCntl() {
// if timer is running no need to process this automatic loop
if ( BTdutyTimer == 0 ) {
// Serial.println("\n-----------------In fan control");
// HeatSinkTemp
if (HeatSinkTemp > MinTemp) {
Dcycle = 10;
float TrackTemp = MinTemp;
while ( TrackTemp < HeatSinkTemp ) {
// Serial.print("Dcycle ->");
// Serial.println(Dcycle);
// Serial.print("TrackTemp ->");
// Serial.println(TrackTemp);
TrackTemp += TempInc;
Dcycle += 10;
}
} else {
Dcycle = 0;
}
// fanVal = Dcycle;
// fanVal = 15; // used to force a duty cycle and turn fan on or off
// fanVal = 1;
setPwmDuty((100 - Dcycle)); // This inverts the value sent to the PWM,.. as output transistor inverts output
// Serial.print("Fan Duty Cycle >");
// Serial.println(fanVal);
}
// Emergency error Check-----------------------
// This caters for situation where sensor is disconnected
if ( HeatSinkTemp < -100 || ErrorCount > 200 ) {
Dcycle = 60;
setPwmDuty((100 - Dcycle)); // This inverts the value sent to the PWM,.. as output transistor inverts output
if ( HeatSinkTemp < -100 ) {
lcd.setCursor(2, 0);
lcd.print("Sensor Error");
lcd.setCursor(2, 1);
lcd.print("Sensor Error");
Serial.println(F("Sensor Error"));
Set_Bit(Status_Flags, SensorError); // Set Sensor Error Flag
lcd.backlight(); // Turn Backlight ON
Set_Bit(Status_Flags, BackLightStatus);
LCDLEDTimer = 1800; // 1800; // 1/2 hr timer
} else if ( ErrorCount > 200 ) {
lcd.setCursor(3, 0);
lcd.print("Error Count");
lcd.setCursor(3, 1);
lcd.print("Error Count");
Serial.println(F("Error Count"));
Set_Bit(Status_Flags, SensorError); // Set Sensor Error Flag
lcd.backlight(); // Turn Backlight ON
Set_Bit(Status_Flags, BackLightStatus);
LCDLEDTimer = 1800; // 1800; // 1/2 hr timer
} else if ( HeatSinkTemp > -100 && Chk_Bit(Status_Flags, SensorError) == 1 ) {
Clr_Bit(Status_Flags, SensorError); // Clear Sensor Error Flag
lcd.clear(); // Clear LCD display
}
}
}
// ------------------------------------------------------------
//void validateRPM() {
// // Check that RPM values are sensible
//
// if ( rpm > 4000 ) {
// rpm = 2800;
//// Serial.println("RPM reset to 99rpm as rpm > 4000rpm");
// } else if ( rpm < 75 ) {
// rpm = 0;
//// Serial.println("RPM reset to 0rpm as rpm > 50rpm");
// }
//
// if ( rpm > maxrpm ) {
// maxrpm = rpm;
// }
//}
// ----------------------------------------------------------
void FanCalcs() {
// This calculates the Temp Increment eg. (60 - 30 ) / 10 = 3
TempInc = ( MaxTemp - MinTemp ) / dutydiv;
// And then prints it to the LCD
lcd.setCursor(0, 0);
lcd.print("Temp Inc. ->");
lcd.print(TempInc);
}
// ----------------------
void EvaluateSlowRPM() {
// ( TimeoutRPMcount > 20 && Chk_Bit(Status_Flags, ENslowRPM) == 1)
// ( RotorPulseCount > 20 && Chk_Bit(Status_Flags, ENslowRPM) == 1 )
// NB if rotor is slow/sationary count will never pass 20.. need to check for this
// so we have run for 10 seconds with someclocks from fan,.
// Serial.print("\nChk_Bit(Status_Flags, ENslowRPM) ");
// Serial.println(Chk_Bit(Status_Flags, ENslowRPM) );
//
// Serial.print("RotorPulseCount");
// Serial.println(RotorPulseCount);
//
// Serial.print("status flags >");
// Serial.println(Status_Flags, BIN);
//
// Serial.print("TimeoutRPMcount >");
// Serial.println(TimeoutRPMcount);
if ( RotorPulseCount > 0 && Chk_Bit(Status_Flags, ENslowRPM) == 1 ) { // check bit position value
// ie it has stopped
RPMslowfinalcount = micros(); // we now set and end point for the timer
slowCountDiff = RPMslowfinalcount - slowRPMcountSTART;
// Serial.print("Timerdiff =");
// Serial.println(slowCountDiff);
// Serial.print("RotorPulseCount =");
// Serial.println(RotorPulseCount);
// rpm = 60000000UL / (slowCountDiff * pulsesPerRev);
// timediff / 1000000 to get to seconds
// divide into number of pulses to get number of pulses per second ( /2 for no. pulses per rev) x60 to get to minutes
rpm = ( RotorPulseCount / pulsesPerRev / (slowCountDiff / 1000000)) * 60;
// Serial.print("Slow rpm Value");
// Serial.println(rpm);
TimeoutRPMcount = 0;
slowRPMcountSTART = micros();
RotorPulseCount = 0;
// -----------------------------
// --------elseif--------------- 8 second timeout
} else if ( TimeoutRPMcount > 8 && Chk_Bit(Status_Flags, ENslowRPM) == 1 ) { // ==2 BIN 10
// time caculations irrelavent as time-out has occured
// RPMslowfinalcount = micros(); // we now set and end point for the timer
// slowCountDiff = RPMslowfinalcount - slowRPMcountSTART;
// just check see that rotor count is zero
// Serial.print("RotorPulseCount =");
// Serial.println(RotorPulseCount);
// count timeout exceeded so rotor in NOT rotating,
// and we need to reset counters and rpm speed to zero
TimeoutRPMcount = 0;
slowRPMcountSTART = micros();
RotorPulseCount = 0;
rpm = 0; // still!!
}
// // this just prints the variables for test purposes
// TimeoutRPMcount++; // this just increments a local counter to timeout if no rotor pulses
// Serial.print("Print the state of the ENslowRPM flag>B");
// Serial.println(Chk_Bit(Status_Flags, ENslowRPM));
//
// if ( Chk_Bit(Status_Flags, ENslowRPM) == 1 ) { // is this 1 or 10 Binary ie 2
// Serial.print("\n---------------- runningRotorPulseCount =");
// Serial.println(TimeoutRPMcount);
// }
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
void setPwmDuty(byte duty) {
OCR1A = (word)(duty * TCNT1_TOP) / 100;
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
void FANrpmISR() {
/*
do not add additional stuff to this function as it is executed with the ISR
so additional serial.prints etc screws timing up else where
just keep it simple!!!!!!
*/
rpm = 0;
unsigned long now = micros();
unsigned long interval = now - lastPulseTime;
if ( interval > 2000 ) {
rpm = 60000000UL / (interval * pulsesPerRev); // 60seconds (unassigned Long,.. so no sign bit)
lastPulseTime = now;
}
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
void SlowRPMCount() { /* this code will be executed every time the interrupt 0 (pin2 Goes High.*/
// just keep it simple!!!!!!
RotorPulseCount++; // we want to count say 20 pulses and see how long it takes...
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ReadTemps.ino
// *************************************************
void Inc_Temp_Store_indx() {
// Setup temperatureIndex for next save within array
// This sets the next store location within the 2 x 5 array for ech temperature sensor.
// it starts at -1,.. so the first increment takes it to zero,..
// and then cycles around on a count of 5
// The last location of the array is used to store the average of the previous 5 reads
temperatureIndex++;
// Now check if out of array range
if ( temperatureIndex > SensorArrySize - 1 ) {
temperatureIndex = 0; // increment Storage location within Array
}
}
/*
GetTemp(0, Ambient);
GetTemp(1, Heatsink);
}
*/
// ----------------------------------------------------------------
void GetTemp(byte id, DeviceAddress addr) {
// First we turn the LED switch light on to show activity
digitalWrite(LedFlash, HIGH );
// Enable this section to print the sensor Ids..address
// Serial.println();
// printAddress(addr);
// Serial.print("ReadTemp ID ->");
// Serial.println(id);
sensors.requestTemperatures();
float TempValue = sensors.getTempC(addr); // Get Temperature Reading from Sensor
// Current Sensor value now read,..
// Serial.println(TempValue);
//------------------------------------------------------
if ( Chk_Bit(Status_Flags, WriteTemp) == 0 ) {
// so is it a good value
// Now we try some error checking to ensure no silly values get stored into array
if ( (TempValue < temperatureArray[id][SensorArrySize] + 10 ) && (TempValue > temperatureArray[id][SensorArrySize] - 10 ) ) {
// As long as new temperature is within a +- 10degree window it will get saved into array
// This assumes temperature is a slow changing paramater
temperatureArray[id][temperatureIndex] = TempValue; // Store New temperature reading in Array
// Serial.println("Good sensor value");
} else if ( TempValue < -100 ) {
temperatureArray[id][temperatureIndex] = TempValue; // this saves the value (-127C) for a disconnected Sensor
ErrorCount++;
lcd.setCursor(7, 0);
lcd.print("E");
// So that the disconnected error checking will trigger and turn the fan on
// Serial.println("Really bad sensor value, ie disconnected");
} else {
// and this just saves the average back in to the array, so as to not skew the average
temperatureArray[id][temperatureIndex] = temperatureArray[id][SensorArrySize];
ErrorCount++;
lcd.setCursor(7, 0);
lcd.print("e");
// Serial.println("Bad sensor value, saved average back into array");
}
} else {
temperatureArray[id][temperatureIndex] = TempValue; // Store New temperature reading in Array
// Serial.println("Good 1st sensor value");
}
// ------------------------------------------------------
// now Reset average number out counter location
for (byte idx = 0; idx < NumberSensors; ++idx) {
// Sum all values to last index
// But 1st reset value to zero
temperatureArray[id][SensorArrySize] = 0;
}
for (byte idx = 0; idx < SensorArrySize; ++idx) { // Note Less than SensorArrySize
// Now we Sum all the values into the last index
temperatureArray[id][SensorArrySize] += temperatureArray[id][idx];
}
// Create Average by simply dividing by 5
temperatureArray[id][SensorArrySize] = (temperatureArray[id][SensorArrySize]) / 5;
//
// Serial.print("Temp ID =>0x");
// Serial.println((addr[1]), HEX);
switch (addr[1]) {
// Sensor Ids
// Ambient = 10-5A-56-C6-00-08-00-55
// Heat Sink = 10-59-47-C6-00-08-00-BD
// New Test Sensors
// 28-73-81-D0-05-00-00-ED
// 28-7A-DB-45-92-08-02-AB
case 0x7A: // Ambient
AmbTemp = temperatureArray[id][SensorArrySize];
if ( millis() > minmaxtimeout ) { // Dont write initial temperatures into min/max value,.. allow timeout bafore saving
if ( AmbTemp < minAmb ) {
minAmb = AmbTemp;
}
if ( AmbTemp > maxAmb ) {
maxAmb = AmbTemp;
}
}
// Serial.print("Ambient Temp =>");
// Serial.println(AmbTemp);
break;
case 0x73: // Heat Sink
HeatSinkTemp = temperatureArray[id][SensorArrySize]; // SensorArrySize =5
if ( millis() > minmaxtimeout ) { // Dont write initial temperatures into min/max value,.. allow timeout bafore saving
if ( HeatSinkTemp < minhtsk ) {
minhtsk = HeatSinkTemp;
}
if ( HeatSinkTemp > maxhtsk ) {
maxhtsk = HeatSinkTemp;
}
}
// Serial.print("HeatSinkTemp Temp =>");
// Serial.println(HeatSinkTemp);
break;
}
// Serial.print("Average =>");
// Serial.println(temperatureArray[id][SensorArrySize]);
#ifdef LongPrint
// ----------------------------------
// Long printout
Serial.print("temperature Array ");
for (byte idx = 0; idx < SensorArrySize + 1; ++idx) {
if ( idx == 0 && id == 0 ) {
Serial.print("Ambient -0->");
} else if ( idx == 0 && id == 1 ) {
Serial.print("Heatsink -1->");
}
Serial.print(idx);
if ( idx == temperatureIndex ) {
Serial.print("-> Indx Pnt->");
} else {
Serial.print("-> ");
}
Serial.print(temperatureArray[id][idx]);
if ( idx < SensorArrySize ) {
Serial.print("<, ");
} else {
Serial.print("< ");
}
}
Serial.println(F("last Num is Average"));
// -----------------------------------
#endif
digitalWrite(LedFlash, LOW );
}
// ----------------------------------------------------------------
// function to print a device address
void printAddress(DeviceAddress deviceAddress) {
for (uint8_t i = 0; i < 8; i++) {
// zero pad the address if necessary
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
if ( i < 7 ) {
Serial.print("-");
}
}
Serial.println("");
}
// **********************************************************************
complete.ino (39.7 KB)