I just loaded this one successfully, but it should be the same one I already gave you. Im posting this as text, maybe it will make a differance.
// Note this program uses a watchdog timmer.
// It is required to reset the Arduino by two presses of the reset button and setting available com ports prior to upload.
// After upload the com port needs to be reset.
// Define Global Constants /////////////////////////////////////////////////////////////////
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 unsigned long WDT = 30; // Watch Dog Timer max time seconds This must be greater than the time requird to complete a cycle
const int frequency = 10.0; // Set fan frequency
const int NumberOfSamples = 20; // Sent number of data samples for averaging.
const int BlinkTimeOnTest = 2000; // Blink time on period for initial circuit test
const int BlinkTimeOn = 500; // Blink time on period
const int BlinkTimeOff = 500; // Blink time off 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 _PWM_LOGLEVEL_ 2
#define USING_MICROS_RESOLUTION true //false
#define HW_TIMER_INTERVAL_US 20L
#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
// Initialize Global Variables ///////////////////////////////////////////////////////////////////
int RadVals [NumberOfSamples + 1];
int CndVals [NumberOfSamples + 1];
int AuxVals [NumberOfSamples + 1];
int RadValAvg = 0;
int CndValAvg = 0;
int AuxValAvg = 0;
int RadSpeed = 10;
int CndSpeed = 10;
int AuxSpeed = 10;
int RadTemp;
int CndTemp;
int AuxTemp;
int FanSpeed = 10; // Set fan to 10% PWM = off
uint32_t startMicros = 0;
// 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;
//////////////////////////////////////////////////////
#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
// 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
#include <ArduinoBLE.h>
// 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;
///////////////////////////////////////////////////////////////////////// Define the Temperature Service for BLE
BLEService TempService("10187e9f-f0c6-496c-9003-64d40d8c4b3e"); //*** BLEService Class Any Hex Name 128-bit UUID in String format *********************************************************
// Define Temperature and Fan Speed Characteristics
BLEUnsignedIntCharacteristic RadLevelChar("694d181e-4421-47f3-9653-c4d6bb295a07", // standard 128-bit characteristic UUID *******************************
BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
BLEUnsignedIntCharacteristic CndLevelChar("bf9c5598-19ed-4dfb-b6fc-fe136b7210e4", // standard 128-bit characteristic UUID *******************************
BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
BLEUnsignedIntCharacteristic AuxLevelChar("3b310c7c-dacf-4a27-a297-6454dd561393", // standard 128-bit characteristic UUID *******************************
BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
BLEUnsignedIntCharacteristic FanSpeedChar("efb1fe61-7de4-40e6-891c-84b626081c11", // standard 128-bit characteristic UUID *******************************
BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
////////////////////////////////////////////////////////////////////////////////////
void TimerHandler()
{
ISR_PWM.run();
}
////////////////////////////////////////////////////////////////////////////////////
void printData(const int& index = 0) // Subroutine to print each pin value to the serial monitor
// Note this subroutine must be declared befor it is called?
{
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
// Not this subroutine must be declared befor it is called?
{
PWM_LOGWARN1("RadAvg = ", RadValAvg);
PWM_LOGWARN1("CndAvg = ", CndValAvg);
PWM_LOGWARN1("AuxAvg = ", AuxValAvg);
}
////////////////////////////////////////////////////////////////////////////////////
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);
//Configure WDT.
NRF_WDT->CONFIG = 0x01; // Configure WDT to run when CPU is asleep
NRF_WDT->CRV = WDT*32769; // CRV = WDT *(32768 + 1)
NRF_WDT->RREN = 0x01; // Enable the RR[0] reload register
NRF_WDT->TASKS_START = 1; // Start WDT
NRF_WDT->RR[0] = WDT_RR_RR_Reload; // Reset WDT
Serial.println("Watchdog iniialized and Set *************************************************************");
Serial.begin(115200);
// while (!Serial); // Comment this out prior to installation
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.
ReadAveragSensorsData(); // Read all the sensors and find the averages
CalcFanSpeed(); // Call the CalcFanSpeed routine
StartUpBlink(); // Call the blink sensor StartUpBlink subroutine to test all sensors
SetUpBLE(); // Call the SetUpBLE routine
Serial.println("Setup Complete *************************************************************"); Serial.println();
}
////////////////////////////////////////////////////////////////////////////////////
void loop(){
// wait for a Bluetooth® Low Energy central
BLEDevice central = BLE.central();
// if a central is connected to the peripheral:
static unsigned long update_timeout = 0;
static bool LED_status = HIGH;
// Take reading every update_timeout ms.
if ( (millis() > update_timeout) && (millis() > UPDATE_CHECK_INTERVAL_MS) )
{
printData(); // Print every update_timeout ms.
LED_status = !LED_status;
digitalWrite(LED_BUILTIN, LED_status);
ReadAveragSensorsData(); // Read all the sensors and find the averages
CalcFanSpeed(); // Call read sensors subroutine to calculate fan speed and print values to serial moniter
CalculateTemperatures(); // Calculate the thermister temperatures
//BlinkSpeed(); // Call blink test to blink out speeds
Serial.print("millis() = "); Serial.println(millis());
NRF_WDT->RR[0] = WDT_RR_RR_Reload; // Reset WDT
Serial.println("Watchdog Reset *************************************************************");
update_timeout = millis() + UPDATE_CHECK_INTERVAL_MS;
if (central) {
Serial.print("Connected to central: ");
// print the central's BT address:
Serial.println(central.address());
// turn on the LED to indicate the connection:
digitalWrite(LED_BUILTIN, HIGH);
updateTemperatures();
}
// when the central disconnects, turn off the LED:
digitalWrite(LED_BUILTIN, LOW);
Serial.print("Disconnected from central: ");
Serial.println(central.address());
}
}
////////////////////////////////////////////////////////////////////////////////////
void ReadAveragSensorsData() // Subroutine to read each pin and sum them
{
int index = 0;
RadValAvg = 0;
CndValAvg = 0;
AuxValAvg = 0;
do
{
// Read al data points
RadVals[index] = analogRead(RadPin);
CndVals[index] = analogRead(CndPin);
AuxVals[index] = analogRead(AuxPin);
// sum all data points
RadValAvg += RadVals [index];
CndValAvg += CndVals[index];
AuxValAvg += AuxVals [index];
printData(index); //Call the printData subroutine to print each reading to the serial monitor.
index = index + 1;
} while (index < NumberOfSamples);
// Find Average of all data points
RadValAvg = RadValAvg / NumberOfSamples;
CndValAvg = CndValAvg / NumberOfSamples;
AuxValAvg = AuxValAvg / NumberOfSamples;
printAvg(); //Call the printAvg function to print the average data to the serial monitor.
}
////////////////////////////////////////////////////////////////////////////////////
void CalcFanSpeed() // Subroutine to do 1 cycle of reading the temperature data
{
// 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"));
}
}
////////////////////////////////////////////////////////////////////////////////////
void StartUpBlink() // 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
}
if (analogRead(AuxPin) >= Aux0 && analogRead(RadPin) <= Rad100) {
digitalWrite(LED3Pin, HIGH); // turn the LED on
}
delay(BlinkTimeOnTest); // Time to leave LEDs on
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
{
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); // Find the total number of blinks required
do { // Do the blink loop until the max number of blinks has occured.
CountRadOn = CountRadOn + 1;
CountCndOn = CountCndOn + 1;
CountAuxOn = CountAuxOn + 1;
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
}
delay(BlinkTimeOn); // Time to leave LEDs on
digitalWrite(LED1Pin, LOW); // turn the LED off
digitalWrite(LED2Pin, LOW); // turn the LED off
digitalWrite(LED3Pin, LOW); // turn the LED off
delay(BlinkTimeOff); // Time to leave LEDs on
index = index + 1;
} while (index < MaxBlinks);
}
////////////////////////////////////////////////////////////////////////////////////
void SetUpBLE() {
// begin initialization
if (!BLE.begin()) {
Serial.println("starting BLE failed!");
while (1);
}
/* Set a local name for the Bluetooth® Low Energy device
This name will appear in advertising packets
and can be used by remote devices to identify this Bluetooth® Low Energy device
The name can be changed but maybe be truncated based on space left in advertisement packet
*/
BLE.setLocalName("Fan Control Monitor"); //******************************************************************************
BLE.setAdvertisedService(TempService); // add the service UUID
TempService.addCharacteristic(RadLevelChar); // add the radiator level characteristic
TempService.addCharacteristic(CndLevelChar); // add the condenser level characteristic
TempService.addCharacteristic(AuxLevelChar); // add the aux level characteristic
TempService.addCharacteristic(FanSpeedChar); // add the fan Speed characteristic
BLE.addService(TempService); // Add the Temperature service
RadLevelChar.writeValue(0); // set initial value for this characteristic
CndLevelChar.writeValue(0); // set initial value for this characteristic
AuxLevelChar.writeValue(0); // set initial value for this characteristic
FanSpeedChar.writeValue(0); // set initial value for this characteristic
// Start advertising Bluetooth® Low Energy. It will start continuously transmitting Bluetooth® Low Energy
// advertising packets and will be visible to remote Bluetooth® Low Energy central devices
// until it receives a new connection
BLE.advertise(); // start advertising
Serial.println("Bluetooth® device active, waiting for connections...");
}
////////////////////////////////////////////////////////////////////////////////////////
void updateTemperatures() {
// Read the current voltage level on each analog input pin.
// This is used here to simulate the charge level of temperaturs.
Serial.print("Rad Level % is now: "); Serial.println(RadTemp);
Serial.print("Cnd Level % is now: "); Serial.println(CndTemp);
Serial.print("Aux Level % is now: "); Serial.println(AuxTemp);
Serial.print("Fan Speed % is now: "); Serial.println(FanSpeed);
RadLevelChar.writeValue(RadTemp); // update the Radiator level characteristics
CndLevelChar.writeValue(CndTemp); // update the Condenser level characteristics
AuxLevelChar.writeValue(AuxTemp); // update the Aux level characteristics
FanSpeedChar.writeValue(FanSpeed); // update the Aux level characteristics
}
////////////////////////////////////////////////////////////////////////////////////////////////
void CalculateTemperatures() {
//// Defining 6th order polynomial coefficients
double RadCoeff0 = -3.191109E+01;
double RadCoeff1 = 1.333142E+00;
double RadCoeff2 = -9.388659E-03;
double RadCoeff3 = 3.502677E-05;
double RadCoeff4 = -6.643350E-08;
double RadCoeff5 = 6.164271E-11;
double RadCoeff6 = -2.214795E-14;
double CndCoeff0 = -4.330212E+01;
double CndCoeff1 = 7.697340E-01;
double CndCoeff2 = -4.329864E-03;
double CndCoeff3 = 1.423127E-05;
double CndCoeff4 = -2.456664E-08;
double CndCoeff5 = 2.111208E-11;
double CndCoeff6 = -7.068046E-15;
double AuxCoeff0 = -3.210410E+01;
double AuxCoeff1 = 1.316881E+00;
double AuxCoeff2 = 1.316881E+00;
double AuxCoeff3 = 3.414067E-05;
double AuxCoeff4 = -6.438080E-08;
double AuxCoeff5 = 5.940511E-11;
double AuxCoeff6 = -2.122449E-14;
//Calculate temperatures
RadTemp = RadCoeff0 + RadCoeff1*RadValAvg + RadCoeff2*RadValAvg*RadValAvg + RadCoeff3*RadValAvg*RadValAvg*RadValAvg + RadCoeff4*RadValAvg*RadValAvg*RadValAvg*RadValAvg + RadCoeff5*RadValAvg*RadValAvg*RadValAvg*RadValAvg*RadValAvg + RadCoeff6*RadValAvg*RadValAvg*RadValAvg*RadValAvg*RadValAvg*RadValAvg;
CndTemp = CndCoeff0 + CndCoeff1*CndValAvg + CndCoeff2*CndValAvg*CndValAvg + CndCoeff3*CndValAvg*CndValAvg*CndValAvg + CndCoeff4*CndValAvg*CndValAvg*CndValAvg*CndValAvg + CndCoeff5*CndValAvg*CndValAvg*CndValAvg*CndValAvg*CndValAvg + CndCoeff6*CndValAvg*CndValAvg*CndValAvg*CndValAvg*CndValAvg*CndValAvg;
AuxTemp = AuxCoeff0 + AuxCoeff1*AuxValAvg + AuxCoeff2*AuxValAvg*AuxValAvg + AuxCoeff3*AuxValAvg*AuxValAvg*AuxValAvg + AuxCoeff4*AuxValAvg*AuxValAvg*AuxValAvg*AuxValAvg + AuxCoeff5*AuxValAvg*AuxValAvg*AuxValAvg*AuxValAvg*AuxValAvg + AuxCoeff6*AuxValAvg*AuxValAvg*AuxValAvg*AuxValAvg*AuxValAvg*AuxValAvg;
}