Hello All
I am having difficulty subtracting two unsigned long numbers. The results are coming out unexpectedly.
The attached sketch is a program for running a PWM fan. The fan part works good but I am trying to create a subroutine to tell me what speed is being called for by each of the sensors. The subroutine in question is BlinkSpeed.
The problem can be seen in the serial output. Where CurrentMillis - NextBlinkOff should = -500 but instead = 4294966796.
02:26:23.366 -> CurrentMillis = 30065
02:26:23.366 -> NextBlinkOff = 30565
02:26:23.366 -> CurrentMillis - NextBlinkOff = 4294966796
I actually have a similar code to this working but needed to do a total restructure of the program to drive the fan using a PWM library. So something went wrong here and I really have no understanding of why and when to work with unsigned longs.
[code]
#if !( ARDUINO_ARCH_NRF52840 && TARGET_NAME == ARDUINO_NANO33BLE )
#error This code is designed to run on nRF52-based Nano-33-BLE boards using mbed-RTOS platform! Please check your Tools->Board setting.
#endif
#define _PWM_LOGLEVEL_ 2
#define USING_MICROS_RESOLUTION true //false
// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
#include "nRF52_MBED_Slow_PWM.h" // https://github.com/khoih-prog/nRF52_MBED_Slow_PWM
#define HW_TIMER_INTERVAL_US 20L
uint32_t startMicros = 0;
// For mbed nRF52, you can only select NRF52 Hardware Timer NRF_TIMER_3-NRF_TIMER_4 (3 to 4)
// If you select the already-used NRF_TIMER_0-2, it'll be auto modified to use NRF_TIMER_3
// Init NRF52 timer NRF_TIMER3
NRF52_MBED_Timer ITimer(NRF_TIMER_3);
// Init nRF52_Slow_PWM, each can service 16 different ISR-based PWM channels
NRF52_MBED_Slow_PWM ISR_PWM;
///////////////////////////////////////////////////////////////////
const int RadPin = A0; // Radiator Input Thermister
const int CndPin = A1; // Condenser Input Thermister
const int AuxPin = A2; // Auxilary Input Not used at this time
const int FanPin = 9; // Set Fan pin
const int LED1Pin = 7; // Set Cooling Fan LED
const int LED2Pin = 6; // Set Condenser Fan LED
const int LED3Pin = 5; // Set Aux Fan FED
const int frequency = 10.0; // Set fan frequency
const int NUMBER_OF_SAMPLES = 20; // Sent number of averages for data samples.
const unsigned long BlinkInterval = 1000; // Blink period
// 10 bit temperature equivolents for radiator sensor Delphi 12146312
const int Rad0 = 8; // - 20°C equivolent Sensor assumed open.
const int Rad20 = 444; //85C
const int Rad30 = 466; //88C
const int Rad40 = 489; //91C
const int Rad50 = 512; //94C
const int Rad60 = 536; //97C
const int Rad70 = 560; //100C
const int Rad80 = 584; //103C
const int Rad90 = 608; //106C
const int Rad100 = 668; //115C This is an emergency mode either coolant is too hot or senser is shorted. Set duty cycle to 0 to activate emergency mode
// 10 bit temperature equivolents for condenser sensor Litlefuse USP7766
const int Cnd0 = 19; //-30C Sensor Test point
const int Cnd20 = 391; //40C
const int Cnd30 = 440; //45C
const int Cnd40 = 489; //50C
const int Cnd50 = 537; //55C
const int Cnd60 = 583; //60C
const int Cnd70 = 627; //65C
const int Cnd80 = 668; //70C
const int Cnd90 = 706; //75C
const int Cnd100 = 849; //100C Sensor Test Point
// 10 bit temperature equivolents for temp sensor Delphi 25036751
const int Aux0 = 8; //-20C Sensor Test Point
const int Aux20 = 452; //85C
const int Aux30 = 474; //88C
const int Aux40 = 496; //91C
const int Aux50 = 519; //94C
const int Aux60 = 543; //97C
const int Aux70 = 567; //100C
const int Aux80 = 591; //103C
const int Aux90 = 614; //106C
const int Aux100 = 733; //125C Sensor Test Point
//#define NUMBER_OF_SAMPLES
int RadVals [NUMBER_OF_SAMPLES + 1];
int CndVals [NUMBER_OF_SAMPLES + 1];
int AuxVals [NUMBER_OF_SAMPLES + 1];
int RadValAvg = 0;
int CndValAvg = 0;
int AuxValAvg = 0;
int RadSpeed = 10;
int CndSpeed = 10;
int AuxSpeed = 10;
int FanSpeed = 10; // Set fan to 10% PWM = off
//////////////////////////////////////////////////////
void TimerHandler()
{
ISR_PWM.run();
}
//////////////////////////////////////////////////////
// You can assign pins here. Be careful to select good pin to use or crash
uint32_t PWM_Pin = FanPin;
// Channel number used to identify associated channel
int channelNum;
////////////////////////////////////////////////
//////////////////////////////////////////////////////
//float frequency = 10.0f;
void BlinkTest() // Blink LEDs at startup to test sensors are in range
{
// Sensor one time test on startup test, Blink lights for each sensor in range.
if (analogRead(RadPin) >= Rad0 && analogRead(RadPin) <= Rad100) {
digitalWrite(LED1Pin, HIGH); // turn the LED on
}
if (analogRead(CndPin) >= Cnd0 && analogRead(CndPin) <= Cnd100) {
digitalWrite(LED2Pin, HIGH); // turn the LED on
delay(500); // wait for a 1/2 second
}
if (analogRead(AuxPin) >= Aux0 && analogRead(RadPin) <= Rad100) {
digitalWrite(LED3Pin, HIGH); // turn the LED on
delay(500); // wait for a 1/2 second
}
delay(500); // wait for a 1/2 second
digitalWrite(LED1Pin, LOW); // turn the LED off
digitalWrite(LED2Pin, LOW); // turn the LED off
digitalWrite(LED3Pin, LOW); // turn the LED off
}
void BlinkSpeed() // Blink LEDs to indicate speed called by each sensor
{
unsigned long CurrentMillis; // This sets the initial time the fan PWM cycle is started
unsigned long NextBlinkOn; // this sets the next time the LEDs blink on
unsigned long NextBlinkOff; // this sets the next time the LEDs blink off
int CountRadOn = 0; // Counter for number of radiator blinks on
int CountCndOn = 0; // Counter for number of condenser blinks on
int CountAuxOn = 0; // Counter for number of Aux blinks on
int CountRadOff = 0; // Counter for number of radiator blinks off
int CountCndOff = 0; // Counter for number of condenser blinks off
int CountAuxOff = 0; // Counter for number of Aux blinks off
int RadBlinks = 0; // Initialise number of blinks based on radiator temp
int CndBlinks = 0; // Initialise number of blinks based on Condenser temp
int AuxBlinks = 0; // Initialise number of blinks based on Aux temp
int MaxBlinks = 0; // Maximum number of blinks for all channels
int index = 0;
RadBlinks = RadSpeed/10; // Number of Blinks Based on Rad Temp
CndBlinks = CndSpeed/10; // Number of Blinks Based on Cnd Temp
AuxBlinks = AuxSpeed/10; // Number of Blinks Based on Aux Temp
MaxBlinks = max(RadBlinks, CndBlinks);
MaxBlinks = max(MaxBlinks, AuxBlinks);
do {
CurrentMillis = millis();
NextBlinkOn = CurrentMillis;
NextBlinkOff = NextBlinkOn + BlinkInterval/2;
Serial.println();
Serial.print("CurrentMillis = "); Serial.print(CurrentMillis); Serial.println();
Serial.print("NextBlinkOn = "); Serial.print(NextBlinkOn); Serial.println();
Serial.print("CurrentMillis - NextBlinkOn = "); Serial.print(CurrentMillis - NextBlinkOn); Serial.println(); Serial.println();
if ((signed long)(CurrentMillis - NextBlinkOn) >=0) {
CountRadOn = CountRadOn + 1;
CountCndOn = CountCndOn + 1;
CountAuxOn = CountAuxOn + 1;
Serial.print("CountRadOn = "); Serial.print(CountRadOn); Serial.println();
if (CountRadOn <= RadBlinks) {
digitalWrite(LED1Pin, HIGH); // turn the LED on
}
if (CountCndOn <= CndBlinks) {
digitalWrite(LED2Pin, HIGH); // turn the LED on
}
if (CountAuxOn <= AuxBlinks) {
digitalWrite(LED3Pin, HIGH); // turn the LED on
}
NextBlinkOn += BlinkInterval;
}
Serial.println();
Serial.print("CurrentMillis = "); Serial.print(CurrentMillis); Serial.println();
Serial.print("NextBlinkOff = "); Serial.print(NextBlinkOff); Serial.println();
Serial.print("CurrentMillis - NextBlinkOff = "); Serial.print(CurrentMillis - NextBlinkOff); Serial.println(); Serial.println();
if ((signed long)(CurrentMillis - NextBlinkOff) >=0) {
CountRadOff = CountRadOff + 1;
CountCndOff = CountCndOff + 1;
CountAuxOff = CountAuxOff + 1;
Serial.print("CountRadff = "); Serial.print(CountRadOff); Serial.println();
if (CountRadOff <= RadBlinks) {
digitalWrite(LED1Pin, LOW); // turn the LED off
}
if (CountCndOff <= CndBlinks) {
digitalWrite(LED2Pin, LOW); // turn the LED off
}
if (CountAuxOff <= AuxBlinks) {
digitalWrite(LED3Pin, LOW); // turn the LED off
}
NextBlinkOff += BlinkInterval;
}
index = index + 1;
} while (index < MaxBlinks);
}
void printData(const int& index = 0) // Subroutine to print each pin value to the serial monitor
{
PWM_LOGINFO3("Rad(", index, ") input = ", RadVals[index]);
PWM_LOGINFO3("Cnd(", index, ") input = ", CndVals[index]);
PWM_LOGINFO3("Aux(", index, ") input = ", AuxVals[index]);
}
void printAvg() // Subroutine to print the average values to the serial monitor
{
PWM_LOGWARN1("RadAvg = ", RadValAvg);
PWM_LOGWARN1("CndAvg = ", CndValAvg);
PWM_LOGWARN1("AuxAvg = ", AuxValAvg);
}
void readAnalogData(const int& index) // Subroutine to read each pin and sum them
{
RadVals[index] = analogRead(RadPin);
CndVals[index] = analogRead(CndPin);
AuxVals[index] = analogRead(AuxPin);
// sum all 5 data points
RadValAvg += RadVals [index];
CndValAvg+= CndVals[index];
AuxValAvg += AuxVals [index];
}
void updateCheck() // Subroutine to do 1 cycle of reading the temperature data
{
int index = 0;
RadValAvg = 0;
CndValAvg = 0;
AuxValAvg = 0;
do
{
// Read 5 data points
readAnalogData(index); // Call the read AnalogData subroutine
printData(index); //Call the printData subroutine to print each reading to the serial monitor.
index = index + 1;
} while (index < NUMBER_OF_SAMPLES);
// Find Average of all data points
RadValAvg = RadValAvg / NUMBER_OF_SAMPLES;
CndValAvg = CndValAvg / NUMBER_OF_SAMPLES;
AuxValAvg = AuxValAvg / NUMBER_OF_SAMPLES;
printAvg(); //Call the printAvg function to print the average data to the serial monitor.
// Find the speed levels required by each sensor Not only rad temperature can initiate emergency mode.
if (RadValAvg < Rad0) RadSpeed = 0; // Open sensor assumed fan will run in emergency mode at 100%
if (RadValAvg < Rad20 and RadValAvg >= Rad0) RadSpeed = 10; // 10% duty cycle = fan off
if (RadValAvg < Rad30 and RadValAvg >= Rad20) RadSpeed = 20;
if (RadValAvg < Rad40 and RadValAvg >= Rad30) RadSpeed = 30;
if (RadValAvg < Rad50 and RadValAvg >= Rad40) RadSpeed = 40;
if (RadValAvg < Rad60 and RadValAvg >= Rad50) RadSpeed = 50;
if (RadValAvg < Rad70 and RadValAvg >= Rad60) RadSpeed = 60;
if (RadValAvg < Rad80 and RadValAvg >= Rad70) RadSpeed = 70;
if (RadValAvg < Rad90 and RadValAvg >= Rad80) RadSpeed = 80;
if (RadValAvg < Rad100 and RadValAvg >= Rad90) RadSpeed = 90;
if (RadValAvg >= Rad100) RadSpeed = 100; // Set PWM duty cycle to 0 for emergency mode
if (CndValAvg < Cnd20) CndSpeed = 10; // 10% duty cycle = fan off
if (CndValAvg < Cnd30 and CndValAvg >= Cnd20) CndSpeed = 20;
if (CndValAvg < Cnd40 and CndValAvg >= Cnd30) CndSpeed = 30;
if (CndValAvg < Cnd50 and CndValAvg >= Cnd40) CndSpeed = 40;
if (CndValAvg < Cnd60 and CndValAvg >= Cnd50) CndSpeed = 50;
if (CndValAvg >= Cnd60) CndSpeed = 60; // Condensor is limited to 60%
if (AuxValAvg < Aux20) AuxSpeed = 10; // 10% duty cycle = fan off
if (AuxValAvg < Aux30 and AuxValAvg >= Aux20) AuxSpeed = 20;
if (AuxValAvg < Aux40 and AuxValAvg >= Aux30) AuxSpeed = 30;
if (AuxValAvg < Aux50 and AuxValAvg >= Aux40) AuxSpeed = 40;
if (AuxValAvg < Aux60 and AuxValAvg >= Aux50) AuxSpeed = 50;
if (AuxValAvg < Aux70 and AuxValAvg >= Aux60) AuxSpeed = 60;
if (AuxValAvg < Aux80 and AuxValAvg >= Aux70) AuxSpeed = 70;
if (AuxValAvg < Aux90 and AuxValAvg >= Aux80) AuxSpeed = 80;
if (AuxValAvg >= Aux90) AuxSpeed = 90;
// find the sensor with the highest speed requirment or set emergency mode
if (RadSpeed == 100|| RadSpeed == 0){
FanSpeed = 0; // Emergency mode rad too hot or shorted sensor = 100, sensor open = 0
}
else {
FanSpeed = max(RadSpeed, CndSpeed); // find the highest
FanSpeed = max(FanSpeed, AuxSpeed); // This is the duty Cycle
}
PWM_LOGWARN1("Fan Speed = ", FanSpeed);
//write the PWM value to the pwm output pin
PWM_LOGWARN5("Freq = ", frequency, ", FanSpeed % = ", FanSpeed, ", Pin = ", FanPin);
if (!ISR_PWM.modifyPWMChannel(channelNum, PWM_Pin, frequency, FanSpeed))
{
Serial.print(F("modifyPWMChannel error"));
}
//RadBlinks = RadSpeed/10;
//CndBlinks = CndSpeed/10;
//AuxBlinks = AuxSpeed/10;
}
#define PRINT_INTERVAL 15000L // Interval of time ms for printing to the serial moniter
#define UPDATE_CHECK_INTERVAL_MS 15000L // Interval of time for fan to run befor checking sensors and re adjusting fan speed
void check_status() // Printd data to Serial Moniter
{
static unsigned long print_timeout = 0;
static unsigned long update_timeout = 0;
static bool LED_status = HIGH;
// Print every PRINT_INTERVAL (15) seconds.
if ((millis() > print_timeout) || (print_timeout == 0))
{
printData();
print_timeout = millis() + PRINT_INTERVAL;
}
if ( (millis() > update_timeout) && (millis() > UPDATE_CHECK_INTERVAL_MS) )
{
// Blink LED
LED_status = !LED_status;
digitalWrite(LED_BUILTIN, LED_status);
updateCheck(); // Call update check to print values to serial moniter
BlinkSpeed(); // Call blink test to blink out speeds
update_timeout = millis() + UPDATE_CHECK_INTERVAL_MS;
}
}
void setup()
{
// put your setup code here, to run once:
pinMode(RadPin, INPUT);
pinMode(LED1Pin, OUTPUT);
pinMode(LED2Pin, OUTPUT);
pinMode(LED3Pin, OUTPUT);
pinMode(FanPin, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
//while (!Serial); // comment this out prior to installation in vehical
delay(200);
Serial.print(F("\nStarting Car_Fan_Control using ")); Serial.println(BOARD_NAME);
Serial.println(NRF52_MBED_SLOW_PWM_VERSION);
digitalWrite(LED_BUILTIN, HIGH);
// Interval in microsecs
if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_US, TimerHandler))
{
startMicros = micros();
Serial.print(F("Starting ITimer OK, micros() = ")); Serial.println(startMicros);
}
else
Serial.println(F("Can't set ITimer. Select another freq. or timer"));
channelNum = ISR_PWM.setPWM(PWM_Pin, frequency, FanSpeed); // During setup FanSpeed will be set to initialized value of 10 = off.
readAnalogData(0); // Call the read AnalogData subroutine
BlinkTest(); // Call the blink sensor BlinkTest subroutine
}
void loop()
{
check_status();
}
[/code]
Serial Output sample
02:26:23.366 -> CurrentMillis - NextBlinkOn = 0
02:26:23.366 ->
02:26:23.366 -> CountRadOn = 2
02:26:23.366 ->
02:26:23.366 -> CurrentMillis = 30065
02:26:23.366 -> NextBlinkOff = 30565
02:26:23.366 -> CurrentMillis - NextBlinkOff = 4294966796
02:26:23.366 ->
02:26:23.366 ->
02:26:23.366 -> CurrentMillis = 30090
02:26:23.366 -> NextBlinkOn = 30090
02:26:23.366 -> CurrentMillis - NextBlinkOn = 0
02:26:23.366 ->
02:26:23.366 -> CountRadOn = 3
02:26:23.366 ->
02:26:23.366 -> CurrentMillis = 30090
02:26:23.366 -> NextBlinkOff = 30590
02:26:23.420 -> CurrentMillis - NextBlinkOff = 4294966796
02:26:23.420 ->
02:26:23.420 ->
02:26:23.420 -> CurrentMillis = 30115
02:26:23.420 -> NextBlinkOn = 30115
02:26:23.420 -> CurrentMillis - NextBlinkOn = 0
02:26:23.420 ->
02:26:23.420 -> CountRadOn = 4
02:26:23.420 ->
02:26:23.420 -> CurrentMillis = 30115
02:26:23.420 -> NextBlinkOff = 30615
02:26:23.420 -> CurrentMillis - NextBlinkOff = 4294966796
02:26:23.420 ->