Solved: Convert automotive temp & pressure sensor output to control PWM fan

I misinterpreted the pwmOut as stated, my error.

I've tried to be respectful here but clearly I have offended you in some manner. I began a job about 40 years ago as the new guy, and saw how new guys were treated by those that had worked the job for a few years & knew how to do it, especially when they made stupid mistakes. I made a note to myself not to treat future new guys in that manner so as not to run them off.

Translation, I'm trying to learn, but this is like learning to speak another language. It's not something I can pick up in just a couple of days, especially given other responsibilities in life. If you do not wish to provide further guidance, that is OK, and again I thank you for the help you've provided thus far.

If you want to learn about microcontrollers then I suggest an Arduino Starter Kit for self-study. Your project requires knowledge and skills in several areas, nothing simple for a newbie. Also coding is different from playing Lego, it's not obvious why something does not work as expected. A simulator can not even reveal many problems with the attached hardware.

If you only want a working solution for your project then ask in the Gigs And Collaborations forum section for somebody doing the job for you.

Below is a tested working code for the pressure sensor side. I tested it connected to the truck's fan PWM input using a 12V-9V DC converter to power the generic Uno and a pot to simulate the 0-5V input. It operated as desired.

I'm also working with fellow automotive enthusiasts on another forum to come up with a solution. We're making some progress when we are not playing with our Legos. :stuck_out_tongue:

/* Sketch to take inputs from two automotive sensors and operate a PWM cooling fan. 
This sketch only covers the AC pressure sensor, which is a native 0-5V sensor. 
The pressure sensor is equivalent to GM part #9131721 or Dorman 904-617. 
It has a maximum readable pressure of 508 PSI.
Added register code in setup to reduce Nano PWM frequency from 490 Hz to 122.55. 
Some Bosch fans will not operate beyond around 310 Hz.
At some point there will be added code to cover the coolant temperature sensor.
*/ 

//Portion for ACP
int acp = A0; // AC pressure sensor on pin A0
int pwmPin = 11; // Output pin for PWM to use 122.55 Hz
int acpvolts = 0; // Variable to store output
int pwmOut = 0; // Variable to store sensor output to run fan at different speeds and conditions

void setup() {
  // open the serial port at 9600 bps for serial printing if desired:
  Serial.begin(9600);

/*The below lines change the native 490 Hz PWM output of the Arduino to 122.55 Hz since 
most automotive fans operate in this range. Directions are available online if you need a different frequency.*/
  pinMode(11,OUTPUT);
  TCCR2B = TCCR2B & B11111000 | B00000110; // for PWM frequency of 122.55 Hz

}
void loop() {

  // Read the value on the AC pressure sensor, math added to convert to steps
  acpvolts = analogRead(acp); // Reads the value on acp pin and returns it as 0-1023 value

 
analogWrite(pwmPin, pwmOut); //Outputs to PWM pin

/* AC pressure fan activation and PWM duty cycles:
To determine pressure values, use a spreadsheet with 1024 rows to calibrate sensor 
volts (0-5) to a range of 0-1023, and then a column with the pressure values (a lookup table). 
Decide where you want the fan to operate and use the three-digit number for the applicable range(s). 
This setup uses 4 speeds, you can use as many speeds as you want following the below example.
Similarly, PWM is calibrated in a similar manner so the 0-100% duty cycles equate to the Arduino’s scale of 0-255 PWM output. 
This remains constant regardless of the sensor, so
PWM 64 is 25%, 127 is 50%, etc. 
Note that most automotive PWM fans shut off at 90 to 100% duty cycle, so the maximum PWM value here is 229 vs 255.*/

if (acpvolts <= 320) 
pwmOut = 0; // Fan off below 158 PSI
if ((acpvolts >= 321) && (acpvolts <= 394)) 
pwmOut = 64; // Fan at 25% at about 159-199 PSI
if ((acpvolts >= 395) && (acpvolts <= 465)) 
pwmOut = 127; // Fan at 50% at about 200-229 PSI
if ((acpvolts >= 466) && (acpvolts <= 505)) 
pwmOut = 190; // Fan at 75% at about 230-249 PSI
if (acpvolts >= 506) 
pwmOut = 229; // Fan at 100% over 250 PSI
// read the analog input on pin 0:

  // print it out in many formats:
   Serial.print("PWM = ");
  Serial.println(pwmOut);       // print as an ASCII-encoded decimal
  delay(1000);                                  //delay between readings
}

Congratulations, It happens to work :slight_smile:

It would look more professional if you move the analogWrite() to the end of loop(), after the calculation of the new pwmOut used in analogWrite().

The below sketch now operates the fan independently based upon both inputs. I field tested it on my truck and it was able to start, speed up, slow down, and stop the fan using both inputs. The file has been updated to add averaging of input readings for more stable operation. I found if reading the original GM coolant sensor no resistor was needed for the Arduino. Using a voltage divider resistor caused a coolant sensor fault on my truck. I spliced into the OEM sensor signal wire (5V from PCM) and wired this signal output to pin A1. If using a standalone sensor, then you'll need the resistor.

The initial text is lengthy as this is aimed at automotive users like me with only basic knowledge. The sketch is relatively simple since it does not do the sensor math needed to display temperature or pressure.

To properly use this file, you need to read the ADC values via the Arduino program and serial monitor while the vehicle is idling and then match them using an OBD2 scanner program that can read AC pressure and coolant temperature. Make a document with table and record the ADC values for a given temp / pressure in your normal operation range, and then input those values into the sketch. The values below worked well for a commonly-used GM sensors, but your settings may vary.

To solve this, I did some more reading about the various operators and have incorporated the logic "OR" function in a couple of places along with "IF" coding to operate the fan when needed.

Code:

/*
This coding is to operate an automotive PWM cooling fan based upon input from two sensors-
AC pressure and engine coolant temperature. It was tested succesfully on a vehicle using a potentiometer
to simulate the range for each sensor.

In this case, the sensors used were GM PN 9131721 or Dorman 904-617 for the AC pressure. 
It has a range of 0-508 PSI. GM PN 19236568 or Delco PN 2134514 was used for the coolant temp. 
It has a resisance value of 105,553 ohms at -40 C, 9,420 ohms at 0 deg C, 392 ohms at 75 deg C, 
and 47 ohms at 150 deg C.
If other sensors are used, the ADC values (0-1,023) will need to be obtained for them. 
For simplicity, no output values such as coolant temp or AC pressure are shown, only an ADC value 
to validate the inputs. 

The sensor inputs were obtained using a spreadhsheet for both sensors to obtain the 
needed ADC value for each input pin. The Steinhart-Hart equation was used for
coolant temp since the sensor employs a voltage divider. It is too complex to describe here.

The AC pressure value comes from a GM 0-5V linear sensor with a max read value of 508 PSI. Here is how 
to make your own sheet so long as you know the max pressure value (Dorman's site listed this for mine).
On a spreadsheet, label Column A "ADC #". Beginning on row 2, number from 0-1,023 by dragging down to 1,023.

Column B is "Volts". Divide the range of the sensor (4.5V since it is 0 @ .5V) by 1,024 rows 
and you get .004395V per row. Row 2 begins at 0.
Starting with row 3, add this value to each successive row until row 1,023.

Column C is "Pressure PSI". Same formula, divide the PSI range of the sensor (508) by 1,024 (.4961). 
Starting with 0 in row 2, add this value to each successive row beginning with row 3.

Column A is "ADC #", with .5V= 0 PSI and 5.0V= 508 PSI.

You then need to determine at what temperatures and pressures you want the fan to run and at what speed.

Some factors to keep in mind:
Don't run the fan below your thermostat value, otherwise it will likely run all the time. 
Likewise, don't set the AC pressure so low the fan is running when you are going down the road.
Modern high-output PWM fans are to aide cooling at idle and low speeds.
You'll need to fine-tune the settings by monitoring the coolant temp and AC pressure.
Various scan tools allow you to do so on later model vehicles.

The PWM frequency of the Arduino (Nano in this case) was reduced from 490 Hz on pin 11
to 122.55 Hz to make it more compatible with different automotive fans. The register code there 
cannot be used with most simulators.
Serial print functions are limted to the ADC value for each input and the PWM output.
This setup uses 4x speeds for the fan, more could be added via extra lines of code.

It was updated to average the sensor values for more stable operation.

This project is discused on LS1tech.com in the Forced Induction section under the title of 
Variable Speed PWM Fan Control under $25 or less DIY
*/

const int numACPReadings = 10;
const int numECTReadings = 10;

int acpPin = 0; // AC pressure sensor input pin A0
int ectPin = 1; // Coolant temp sensor input pin A1
int pwmPin = 11; // PWM output pin
int pwmOut; // Output value to fan

int readingsACP[numACPReadings];      // the readings from the ACP input
int readACPIndex = 0;              // the index of the current reading
int totalACP = 0;                  // the running total
int averageACP = 0;                // the average for ACP sensor

int readingsECT[numECTReadings];      // the readings from the ECT input
int readECTIndex = 0;              // the index of the current reading
int totalECT = 0;                  // the running total
int averageECT = 0;                // the average for ECT sensor

// Fan speeds
#define Fan0 pwmOut = 0
#define Fan25 pwmOut = 64
#define Fan50 pwmOut = 127
#define Fan75 pwmOut = 190
#define Fan100 pwmOut = 229

void setup() {
  // initialize serial communication with computer:
  Serial.begin(9600);
  // initialize both readings to 0:
  for (int thisReading = 0; thisReading < numACPReadings; thisReading++) {
    readingsACP[thisReading] = 0;
  }
  for (int thisReading = 0; thisReading < numECTReadings; thisReading++) {
    readingsECT[thisReading] = 0;
  }
/*The below lines change the native 490 Hz PWM output of the Arduino to 122.55 Hz since 
most automotive fans operate in this range. Directions are available online if you need a different frequency.*/
  pinMode(11,OUTPUT);
  TCCR2B = TCCR2B & B11111000 | B00000110; // for PWM frequency of 122.55 Hz
}

void loop() {
//This section averages the ACP sensor values
  // subtract the last reading:
  totalACP = totalACP - readingsACP[readACPIndex];
  // read from the sensor:
  readingsACP[readACPIndex] = analogRead(acpPin);
  // add the reading to the total:
  totalACP = totalACP + readingsACP[readACPIndex];
  // advance to the next position in the array:
  readACPIndex = readACPIndex + 1;

  // if we're at the end of the array...
  if (readACPIndex >= numACPReadings) {
    // ...wrap around to the beginning:
    readACPIndex = 0;
  }

  // calculate the average:
  averageACP = totalACP / numACPReadings; //This is the ACP value to be evaluated for fan operation


//This section averages the ECT sensor readings
  // subtract the last reading:
  totalECT = totalECT - readingsECT[readECTIndex];
  // read from the sensor:
  readingsECT[readECTIndex] = analogRead(ectPin);
  // add the reading to the total:
  totalECT = totalECT + readingsECT[readECTIndex];
  // advance to the next position in the array:
  readECTIndex = readECTIndex + 1;

  // if we're at the end of the array...
  if (readECTIndex >= numECTReadings) {
    // ...wrap around to the beginning:
    readECTIndex = 0;
  }

  // calculate the average:
  averageECT = totalECT / numECTReadings; //This is the value to be evaluated for fan operation
  // send it to the computer as ASCII digits
  
  // IF coding used for various fan speeds based on temp & pressure averages
  if ((averageACP <= 300) || (averageECT >=450))
    Fan0; // Fan off below 187 degrees OR  110 PSI

  if ((averageACP >= 301) && (averageACP <= 400))
    Fan25; // Fan 25% from 111-170 PSI
  if ((averageECT <= 449) && (averageECT >= 415))
    Fan25; // Fan 25% from 188-195 degrees
   if ((averageACP >= 401) && (averageACP <= 515))
     Fan50; // Fan 50% from 171-230 PSI
  if ((averageECT <= 414) && (averageECT >= 350))
     Fan50; // Fan 50% from 221-229 degrees
 if ((averageACP >= 516) && (averageACP <= 620))
    Fan75; // Fan 75% from 231-275 PSI
  if ((averageECT <= 349) && (averageECT >= 300))
    Fan75; // Fan 75% from 230-239 degrees

  if ((averageACP >= 621) || (averageECT <=299))
    Fan100; // Fan 100% over 226 degrees OR  276 PSI


 analogWrite(pwmPin, pwmOut); //Outputs value to PWM pin

  //Serial display sections
  //AC pressure ADC value
  Serial.print("AC Pressure ADC "); 
  Serial.println(averageACP);
  delay(1000);

  //Coolant temp ADC value
  Serial.print("Coolant ADC "); 
  Serial.println(averageECT);
  delay(1000);

  // PWM output
  Serial.print("PWM Output ");
  Serial.println(pwmOut);
  delay(1000);
}