Variable Speed PWM Fan Control under $25 or less DIY
#461
Ok now I'm really pissed. Aknovaman, now you also removed the comments that I spent hours looking over and replying to. I spent hours comparing the chatGTP code you posted and the code I originated for V8-Cowboy to see if your comments had merit. Obviously they had no merit because you went and pulled them. What a total waste of my time.
#462
I'm not sure how I could have the power to edit your posts or control how you spend your time. I post only my views, and if people choose to look at them or move along, I see that as their choice. I hope you have a nice day.
#464
So yeah, you DO have the power and ability to add/remove content to any post once quoted by you. And so you did....
#465
Hey guys, I have a gen 3 5.3 truck motor in my 2007 jeep jku. I have a Jeep Pentastar PWM fan in my Jeep. I have been using the Novak controller to control this, but I have now been through 3 of them, and they don't seem to last long at all. I have talked with the guy who designed them, and he isn't sure what is going on.
This led me to trying to attempt to come up with a controller that I can make short of buying an RPM extreme pwm controller at almost $500.
I do have a spare audrino board, the fan has positive, negative, and the pulse wire....I am not opposed to buying something other than an audrino board if theres a good controller out there. I am looking to use a positive 12v trigger to control a low speed and a high speed setting OR the ideal solution would be for it to be controlled from a factory GM temp sensor. Does any of you guys happen to have an idea as to how about I could tackle this?
I am looking for ideas, and there seems to be a ton of information in this thread, but not all are quite applicable to my scenario.
This led me to trying to attempt to come up with a controller that I can make short of buying an RPM extreme pwm controller at almost $500.
I do have a spare audrino board, the fan has positive, negative, and the pulse wire....I am not opposed to buying something other than an audrino board if theres a good controller out there. I am looking to use a positive 12v trigger to control a low speed and a high speed setting OR the ideal solution would be for it to be controlled from a factory GM temp sensor. Does any of you guys happen to have an idea as to how about I could tackle this?
I am looking for ideas, and there seems to be a ton of information in this thread, but not all are quite applicable to my scenario.
Last edited by matholland618; 07-06-2023 at 07:51 PM.
#466
Ran into a time crunch last weekend and couldn't get this data... Here's the test apparatus:
1. Spare ECT
2. Multimeter
3. Heat gun
4. Torque Pro connected to an OBDLink MX (not shown )
I did verify voltage at the ECT connector is the 5v reference voltage expected, here's some test points:
62F = 3.47v
111F = 2.24v
140F = 1.61v
185F = .93v
200F = .77v
210F = .68v
I tested these as heat was added, then verified as the sensor cooled down.
The last two are noteworthy, as that's probably the range where the fan will operate. The one thing I haven't rationalized yet is the aux electric pusher fan up front - it runs when the AC is on, but ostensibly also runs when the ECT hits 205F. I don't want the fans competing with each other (obvs) ... an interesting experiment to run might be to ditch the aux fan, use only the main fan, and see how the AC does. Or, maybe disable the high speed mode on the aux fan. Or, maybe engage the main fan at something closer to 195F? Details... For whatever it's worth, the thermostat open temp is either 176F or 180F - I've found mixed literature. Driving around over the past week with NO fan* and I've not once seen the ECT over 181F. Granted, ambient is 50F, but still, it does a good job of sticking right around 180F with no help.
* Here's my solution for running the fan during this test phase:
Not pretty, but it works! Or would work, if there'd been a reason to turn it on yet...
1. Spare ECT
2. Multimeter
3. Heat gun
4. Torque Pro connected to an OBDLink MX (not shown )
I did verify voltage at the ECT connector is the 5v reference voltage expected, here's some test points:
62F = 3.47v
111F = 2.24v
140F = 1.61v
185F = .93v
200F = .77v
210F = .68v
I tested these as heat was added, then verified as the sensor cooled down.
The last two are noteworthy, as that's probably the range where the fan will operate. The one thing I haven't rationalized yet is the aux electric pusher fan up front - it runs when the AC is on, but ostensibly also runs when the ECT hits 205F. I don't want the fans competing with each other (obvs) ... an interesting experiment to run might be to ditch the aux fan, use only the main fan, and see how the AC does. Or, maybe disable the high speed mode on the aux fan. Or, maybe engage the main fan at something closer to 195F? Details... For whatever it's worth, the thermostat open temp is either 176F or 180F - I've found mixed literature. Driving around over the past week with NO fan* and I've not once seen the ECT over 181F. Granted, ambient is 50F, but still, it does a good job of sticking right around 180F with no help.
* Here's my solution for running the fan during this test phase:
Not pretty, but it works! Or would work, if there'd been a reason to turn it on yet...
#467
You want a low speed trigger using 12V. (sounds like A/C clutch)
You want to use the factory GM temp sensor to adjust the speed.
You are OK with an arduino solution.
Your fan already has a PWM control of some sort.
All this is very doable and not hard. We just need to understand what the PWM signal is like for this fan. Is it a 12V signal, a ground signal, a 5V signal? What frequency an what duty cycles make is off, slow and full.
Last edited by LSswap; 07-08-2023 at 08:22 PM.
#468
Let me recap.
You want a low speed trigger using 12V. (sounds like A/C clutch)
You want to use the factory GM temp sensor to adjust the speed.
You are OK with an arduino solution.
Your fan already has a PWM control of some sort.
All this is very doable and not hard. We just need to understand what the PWM signal is like for this fan. Is it a 12V signal, a ground signal, a 5V signal? What frequency an what duty cycles make is off, slow and full.
You want a low speed trigger using 12V. (sounds like A/C clutch)
You want to use the factory GM temp sensor to adjust the speed.
You are OK with an arduino solution.
Your fan already has a PWM control of some sort.
All this is very doable and not hard. We just need to understand what the PWM signal is like for this fan. Is it a 12V signal, a ground signal, a 5V signal? What frequency an what duty cycles make is off, slow and full.
correct. I bought 2 of these to try. I don’t think this will allow aromatic temp on and off but will give me a solution for the time being.
The pwm is built into the fan. I am not sure if it’s 5v or 12v but from what I understand they are very similar to the Camaro fan they just bolt up in a early model jeep jku. Chrysler started using them in the later model jkus. After talking with the guy who makes them for Novak he said that it’s 10hz and I believe he said anything past about 90% will turn it off. It looks like I should have these tomorrow to give them a whirl.
I have the low speed and high speed toggles on one of those fancy digital switch panels. I had plans to tie it into the ac as well so that it gets turned on when the ac is switched on as well so it’s automatic. I just had not done that yet.
if I can use these controllers and do what I’m looking to accomplish cool, I’m not opposed to going the audrino route for that if needed be. I have one laying around that I did a speed hack with for an electric scooter I have and it hasn’t been touched since.
https://www.ebay.com/itm/11338146708...mis&media=COPY
#469
- If there is 5V or 12V, then it has an internal pullup and it only requires a ground signal for a PWM input. If it's a 5V pullup, only supply 5V to your PWM generator.
- If there is 0 volts, then it needs a square wave PWM input. I would first try it with 5V supplied to your PWM generator. If that gets no results, then try with 12V supplied to the PWM generator.
Yes, I also saw on some other page that these fans like 10hz.
Let us know what the specs you find and I'll put together the wiring and test program.
The following 2 users liked this post by LSswap:
matholland618 (07-10-2023), V8 Cowboy (07-10-2023)
#470
Holley Racepack CANBUS DIY for controlling fans (or anything else)
Holley has a large selection of displays and CAN BUS add ons, but some users want custom stuff or want to build it themselves. Let's say you have a trans cooler fan and a oil cooler fan and you want to PWM them. You could buy some Holley add on that reads the CAN BUS or you might try building your own add on.
The Holley CAN protocol is proprietary, but they do provide an additional canbus that is fully published and can be accessed by anyone. This is what Racepak devices use.
This Holley CAN BUS protocol, aka HEFI 3rd Party CAN Communications Protocol, is public and published here starting on page 92. There are 48 inputs and outputs like, RPM, boost, map, injector puleswidth, etc that are available through this interface and the data is updated about 100 times per second. I would guess that any Holley ECM that supports Racepak can output these messages.
I used an arduino nano and an MCP2515 CAN BUS transceiver. For this type of higher power requirement application, I suggest not connecting the arduino to 12 volts directly, but rather using some other 5V power converter from 12V. The built in nano power converter has limited power capabilities, especially as the voltage gets higher, like 12V and should not be relied on to power other devices.
There are lots of uses for this information. The sky is the limit. You might want to drive pwm fans, a gauge cluster, an huge alarm light, big gear display, relays, PWM devices, a very simple 4 digit LED display or even a custom DIY touchscreen like in my Vette. I used this to create a custom gasoline consumption gauge for an endurance road race car application.
Here is some sample code to read data from the Holley 3rd party CAN BUS protocol.
The Holley CAN protocol is proprietary, but they do provide an additional canbus that is fully published and can be accessed by anyone. This is what Racepak devices use.
This Holley CAN BUS protocol, aka HEFI 3rd Party CAN Communications Protocol, is public and published here starting on page 92. There are 48 inputs and outputs like, RPM, boost, map, injector puleswidth, etc that are available through this interface and the data is updated about 100 times per second. I would guess that any Holley ECM that supports Racepak can output these messages.
I used an arduino nano and an MCP2515 CAN BUS transceiver. For this type of higher power requirement application, I suggest not connecting the arduino to 12 volts directly, but rather using some other 5V power converter from 12V. The built in nano power converter has limited power capabilities, especially as the voltage gets higher, like 12V and should not be relied on to power other devices.
There are lots of uses for this information. The sky is the limit. You might want to drive pwm fans, a gauge cluster, an huge alarm light, big gear display, relays, PWM devices, a very simple 4 digit LED display or even a custom DIY touchscreen like in my Vette. I used this to create a custom gasoline consumption gauge for an endurance road race car application.
Here is some sample code to read data from the Holley 3rd party CAN BUS protocol.
Code:
// test program, no license, open source, no warranty given // reads canbus from Holley HEFI 3rd Party CAN Communications Protocol (RacePAK) // about 100 times per second using an MCP2515 canbus module. // libraries used to simplify using the can bus interface, display and EEprom memory #include <Arduino.h> #include <mcp_can.h> #include <SPI.h> const float versionNumber = 1.1; // so you can tell which version is burnt into the chip // *********************** CAN related variables ***************** unsigned char CANLen = 0; unsigned char buf[8]; #define CAN0_INT 2 // define CANbus interrupt pin const int spiChipSelectPin = 10; MCP_CAN CAN0(spiChipSelectPin); // Set CS pin unsigned long lastTimeCANgotMsg; // to check for CANBUS timeouts long unsigned int rxId; // pins for MCP2515 CAN bus board to arduino nano // Int D2 // SCK D13 // SI D11 // SO D12 // CS D10 // GND // VCC union Data { // overlay CAN payload with Long intgeger unsigned char payloadArray[4]; // 8 byte payload area to the CAN BUS unsigned long int payload; }; int currRpm; // RPM xx,xxx float currInjPulsewidth; // in milliseconds xx.x float currTiming; // in degrees xx.x int currMap; // in kPa xxx.x float currBattery; // in volts xx.x int currCoolant; // in F xxx int lbsPerHourFromHolley; // in lbs/hour x,xxx /* ++++++++++++++++++++++++++++++++++++++++++++++++++++*/ void setup() { // runs once when device is powered up Serial.begin(115200); Serial.print(F("Holley CANbus Ver: ")); Serial.println(versionNumber); Serial.println(F("Starting CANbus")); // CANbus setup while (CAN0.begin(MCP_ANY, CAN_1000KBPS, MCP_8MHZ) != CAN_OK) { // init CAN bus : baudrate = 1000k Serial.println(F("CAN BUS Shield init fail")); delay(500); } Serial.println(F("CAN BUS Shield init ok!")); pinMode(CAN0_INT, INPUT); CAN0.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP2515 sends acks to received data. } // end of setup /* ++++++++++++++++++++++++++++++++++++++++++++++++++++*/ void loop(){ // runs and loops forever check_for_CAN_message(); // checks for next CAN message from Holley check_for_CAN_timeout(); // checks for timeout in CAN messages // do something with the data you read from the Holley CANBUS } // end of loop /* ++++++++++++++++++++++++++++++++++++++++++++++++++++*/ void check_for_CAN_message() { if(!digitalRead(CAN0_INT)) { // If CAN0_INT pin is low, read receive buffer CAN0.readMsgBuf(&rxId, &CANLen, buf); // Read data: len = data length, buf = data byte(s) union Data data; // overlay 4 char buffer for conversion to unsigned long int rxId = rxId & 0x7FFFF000; // filter out serial number . switch ( rxId ) { case 0x1E005000: // 0x1E005000 fuel packet data.payloadArray[0] = buf[7]; // shift the data from CAN buffer to unsigned long data.payloadArray[1] = buf[6]; data.payloadArray[2] = buf[5]; data.payloadArray[3] = buf[4]; lbsPerHourFromHolley = (int)(data.payload / 256); // remove Holley 256 multiplier data.payloadArray[0] = buf[3]; // shift the data from CAN buffer to unsigned long data.payloadArray[1] = buf[2]; data.payloadArray[2] = buf[1]; data.payloadArray[3] = buf[0]; currInjPulsewidth = (float)data.payload / 256.0; break; case 0x1E001000: //rpm packet data.payloadArray[0] = buf[7]; // shift the data from CAN buffer to unsigned long data.payloadArray[1] = buf[6]; data.payloadArray[2] = buf[5]; data.payloadArray[3] = buf[4]; currRpm = (int)(data.payload / 256); break; case 0x1E015000: //Timing packet data.payloadArray[0] = buf[3]; // shift the data from CAN buffer to unsigned long data.payloadArray[1] = buf[2]; data.payloadArray[2] = buf[1]; data.payloadArray[3] = buf[0]; currTiming = (float)data.payload / 256.0; break; case 0x1E019000: //MAP packet data.payloadArray[0] = buf[3]; // shift the data from CAN buffer to unsigned long data.payloadArray[1] = buf[2]; data.payloadArray[2] = buf[1]; data.payloadArray[3] = buf[0]; currMap = (int)(data.payload / 256); break; case 0x1E021000: //coolant packet data.payloadArray[0] = buf[7]; // shift the data from CAN buffer to unsigned long data.payloadArray[1] = buf[6]; data.payloadArray[2] = buf[5]; data.payloadArray[3] = buf[4]; currCoolant = (int)(data.payload / 256); break; case 0x1E025000: //Battery data.payloadArray[0] = buf[7]; // shift the data from CAN buffer to unsigned long data.payloadArray[1] = buf[6]; data.payloadArray[2] = buf[5]; data.payloadArray[3] = buf[4]; currBattery = (float)data.payload / 256.0; break; default: // debug printing to serial return; break; lastTimeCANgotMsg = millis(); }// end switch }// end CAN msg avail } // end check_for_CAN_message /* ++++++++++++++++++++++++++++++++++++++++++++++++++++*/ void check_for_CAN_timeout() { // if a CAN failure occurs if ( millis() - lastTimeCANgotMsg > 500 ) { Serial.println(F("Canbus Timeout")); lastTimeCANgotMsg = millis(); // zero out values because the CAN timed out } } // end check_for_CAN_timeout
Last edited by LSswap; 07-10-2023 at 10:21 AM.
The following users liked this post:
V8 Cowboy (07-10-2023)
#471
Before you give it a whirl with the Ebay PWM generator, connect the Plus and minus to the battery. Then, with a voltmeter, measure the signal wire to ground.
- If there is 5V or 12V, then it has an internal pullup and it only requires a ground signal for a PWM input. If it's a 5V pullup, only supply 5V to your PWM generator.
- If there is 0 volts, then it needs a square wave PWM input. I would first try it with 5V supplied to your PWM generator. If that gets no results, then try with 12V supplied to the PWM generator.
Yes, I also saw on some other page that these fans like 10hz.
Let us know what the specs you find and I'll put together the wiring and test program.
- If there is 5V or 12V, then it has an internal pullup and it only requires a ground signal for a PWM input. If it's a 5V pullup, only supply 5V to your PWM generator.
- If there is 0 volts, then it needs a square wave PWM input. I would first try it with 5V supplied to your PWM generator. If that gets no results, then try with 12V supplied to the PWM generator.
Yes, I also saw on some other page that these fans like 10hz.
Let us know what the specs you find and I'll put together the wiring and test program.
Got the eBay fan controller plugged in loosely just to test and here is what I found
12hz @ 11% is low, and 12hz & 97% is high
I have a 180* thermostat, with the novak controller with it on "low" assuming it was about a 70* day, it would stay at 180. Ideally anything over 190-195 should be max fan speed.This is a trail rig, and in the woods and such, I like it to stay cool.
Last edited by matholland618; 07-10-2023 at 12:31 PM.
#472
Jeep Pentastar Brushless fan and stock GM coolant sensor
Here is an untested wiring and code for driving the Jeep Pentastar PWM fan using the stock GM temp sensor connected to GM ECM with an internal 2.5k pullup resistor to 5V.
A/C clutch signal runs the fan at a minimum preset PWM duty.
Assumption is that fan signal is 12hz, low speed = 11 percent duty, high speed is 95% duty. fan signal is 12V PWM.
The OHMS table for the GM temp sensor is used rather than a beta calculation in this example. For fan control, we roughly only care about the part in yellow, so a linear translation works fine.
Tweak the parameters to get the desired operation.
A/C clutch signal runs the fan at a minimum preset PWM duty.
Assumption is that fan signal is 12hz, low speed = 11 percent duty, high speed is 95% duty. fan signal is 12V PWM.
The OHMS table for the GM temp sensor is used rather than a beta calculation in this example. For fan control, we roughly only care about the part in yellow, so a linear translation works fine.
Tweak the parameters to get the desired operation.
Code:
// This a test program, no warranties are implied or given. Pentastar brushless fan, GM temp sensor V1 // Use, copy any modify this test program any way you want, at your own risk. Then test, test, test // It reads a stock GM LS temp sensor connected to and ECM. Assumed ECM has 2.5k ohm pullup to 5V // Pentastar fan: Freq = 12Hz, 95% duty = full, 11% = min, no PWM = off PWM signal is 12 volt, Temp in F. #include <PWM.h> /*----------------------- User adjustable variables and preferences section ---------------------------------*/ // FYI a PWM duty ranges from 0 to 255 which is equivalent to 0% to 100%. // OHM for temp sensor from 2005 silverado sensor table. yes it's a curve but the range is so small, a straight line interpolation will work fine. const float tempSensorOhmsAtForLowSpeed = 350.0; // above this ohmage, fan should be off (less than roughly 170F) const float tempSensorOhmsForHighSpeed = 230.0; // below this ohm reading, the fan should be on full (greater than roughly 195F) const float seriesECMresistorOhms = 2500.0; // The ohms of the series reistor in the ECM (to 5V) const int acOnMinPwmPct = 25; // If the A/C is on, this is the minumum PWM duty percentage // adjust these for PWN to for fan start and fan full on const int slowSpeedFanDuty = 26; // Duty Cycle for 11% ( Off Fan Speed ( 11% of 255 ) const int fanOnFullDuty = 230; // Duty Cycle for 90% ( Full Fan Speed ( 90% of 255 ) 90% instead of 95% to be on the safe side so fan wont shut off when hot /*----------------------- end of User adjustable variables and preferences -----------------------------------*/ const int fanPwmOutPin = 9; // Arduino PWMS this pin between 0 or 5 volts. const int tempSensorPin = A0; // Pin to read analog voltage from the temp sensor. const int acClutchPin = A1; // Pin to A/C Clutch via 1K/10K Voltage Devider int analogReadingForFanSlowSpeed = (int) (1023.0 * (tempSensorOhmsAtForLowSpeed / (seriesECMresistorOhms + tempSensorOhmsAtForLowSpeed))); int analogReadingForFanFullSpeed = (int) (1023.0 * (tempSensorOhmsForHighSpeed / (seriesECMresistorOhms + tempSensorOhmsForHighSpeed))); int acOnMinPWMDuty; void setup() { /* ++++++++++++++++++ Setup is run once when the arduino boots ++++++++++++++++++++++++++*/ Serial.begin(115200); // set up serial port for 115200 baud (optional) InitTimersSafe(); // set pwm frequency to 12 Hz for Pentastar pwm signal SetPinFrequency(fanPwmOutPin, 12); // set pwm frequency to 12 Hz for Pentastar brushless fan } // end setup void loop() { /* ++++++++++++++++++ Main Loop, continuously loops forever ++++++++++++++++++++++++++++*/ if (analogRead(acClutchPin) > 20 ) { // A/C is on acOnMinPWMDuty = (255 * acOnMinPwmPct) / 100; // If the A/C is on, this is the minumum actual PWM duty } else { acOnMinPWMDuty = 0; } int analogTempReading = analogRead(tempSensorPin); // read temperature sensor (range 0 to 1023) int duty = map(analogTempReading, analogReadingForFanSlowSpeed, analogReadingForFanFullSpeed, slowSpeedFanDuty, fanOnFullDuty ); // calc PWM Duty if (duty < acOnMinPWMDuty) { // assign minimum duty if A/C is on. duty = acOnMinPWMDuty; } int constrainedDuty = constrain(duty, 0, fanOnFullDuty ); // PWM duty is never allowed outside of min or max duties pwmWrite(fanPwmOutPin, 255 - constrainedDuty); // send PWM to output pin, invert for 12V transistor Serial.print("analogTempReading = "); Serial.println(analogTempReading); Serial.print("constrainedDuty = "); Serial.println(constrainedDuty); delay(1000); } // end main loop
Last edited by LSswap; 07-10-2023 at 11:16 PM.
The following users liked this post:
V8 Cowboy (07-11-2023)
#473
Here's a Summary relevent to the BMW fan PWM, Mitsubishi/Mazda PWM fan modules, etc.
Over the past 30 years European cars and trucks have had to conform to increasingly tougher pollution and fuel economy regulations from Euro 1 in 1992 to the current level Euro 6d introduced in 2021. To achieve the Euro 4 (2005) fuel economy requirement, engine makers had to strictly control the air/fuel mixture and toggle the top-of-engine temperature between a lower temperature at high loads and higher temperatures at light loads. Early on, around 1995, they started fitting sensors that measured Mass Air Flow, Manifold Air Pressure, Air Temperature, Coolant Temperature (top-of-engine and radiator outlet), etc. To comply they introduced variable valve and combustion timing and they introduced programmed cooling through electronic control of cooling fans, coolant pumps and thermostats.
BMW initially used 16 Fan levels signalled by the Engine Contol Module (ECM) pulling a constant 12V to ground via a pulse width signal at ~120 pulses per second (Hz) with various 'duty' lengths per pulse. The 12V was supplied by the fan motor controller (at a low power of just a few milli amps) and monitored by it for -
Zone 1 'OFF' is pulses with less than 3% active (Low),
Zone 2 'Standby/Heartbeat' (Low) from 3 to 15%,
Zone 3 '14 Speed Request Levels' is 30 to 90% (Low) either stepped or continuous,
Zone 4 'Error' is Low above 90% of the pulse width time period.
The fan controller then outputs a much, much higher frequency, high power, pulse width signal to operate the fans accordingly and monitors their performance. After the 'active' part of each ECM generated pulse there is at least 10% of each pulse width available for the fan controller to send a limited number of different reports back to the ECM by turning the voltage Off at and for various times.
All manufacturers around the world have developed similar systems (or just copied them), some using 'active low' and some using 'active high' signals. Some used the Battery/Alternator voltage for communications, some used 5 volts (or even less).
Euro 5 (2011) forced the manufacturers to even tighter control with vehicles using Controller Area Networks (CAN) between processing nodes with many slower Local Interconnect Networks (LIN) collecting or responding to data from multiple sensors/actuators, but they kept using the same (or very similar) communication between the ECM and the Fan Controller, and mostly still do today. [As an aside comment - CAN is/has been replaced by FlexRay networking in current vehicles]
For add-on do-it-yourself fans we can't expect to duplicate all the data gathering and processing of a modern ECM, but we can collect a lesser set, such as top-of-engine and radiator outlet temperatures, air con On, engine RPM and road Speed pulses, do some simple processing and pass these to an integrated fan/fan controller. Or we can use the existing signals to run extra cooling. Or we can use the techniques to run other equipment (such as fuel pumps). This is what this discussion is about.
The Corvet and Mitsubishi/Mazda, etc PWM fan modules provide the muscle for running fans at a very cheap price, all that is required is a system to command them properly.
My next post describes the Arduino controller system.
bye.
Over the past 30 years European cars and trucks have had to conform to increasingly tougher pollution and fuel economy regulations from Euro 1 in 1992 to the current level Euro 6d introduced in 2021. To achieve the Euro 4 (2005) fuel economy requirement, engine makers had to strictly control the air/fuel mixture and toggle the top-of-engine temperature between a lower temperature at high loads and higher temperatures at light loads. Early on, around 1995, they started fitting sensors that measured Mass Air Flow, Manifold Air Pressure, Air Temperature, Coolant Temperature (top-of-engine and radiator outlet), etc. To comply they introduced variable valve and combustion timing and they introduced programmed cooling through electronic control of cooling fans, coolant pumps and thermostats.
BMW initially used 16 Fan levels signalled by the Engine Contol Module (ECM) pulling a constant 12V to ground via a pulse width signal at ~120 pulses per second (Hz) with various 'duty' lengths per pulse. The 12V was supplied by the fan motor controller (at a low power of just a few milli amps) and monitored by it for -
Zone 1 'OFF' is pulses with less than 3% active (Low),
Zone 2 'Standby/Heartbeat' (Low) from 3 to 15%,
Zone 3 '14 Speed Request Levels' is 30 to 90% (Low) either stepped or continuous,
Zone 4 'Error' is Low above 90% of the pulse width time period.
The fan controller then outputs a much, much higher frequency, high power, pulse width signal to operate the fans accordingly and monitors their performance. After the 'active' part of each ECM generated pulse there is at least 10% of each pulse width available for the fan controller to send a limited number of different reports back to the ECM by turning the voltage Off at and for various times.
All manufacturers around the world have developed similar systems (or just copied them), some using 'active low' and some using 'active high' signals. Some used the Battery/Alternator voltage for communications, some used 5 volts (or even less).
Euro 5 (2011) forced the manufacturers to even tighter control with vehicles using Controller Area Networks (CAN) between processing nodes with many slower Local Interconnect Networks (LIN) collecting or responding to data from multiple sensors/actuators, but they kept using the same (or very similar) communication between the ECM and the Fan Controller, and mostly still do today. [As an aside comment - CAN is/has been replaced by FlexRay networking in current vehicles]
For add-on do-it-yourself fans we can't expect to duplicate all the data gathering and processing of a modern ECM, but we can collect a lesser set, such as top-of-engine and radiator outlet temperatures, air con On, engine RPM and road Speed pulses, do some simple processing and pass these to an integrated fan/fan controller. Or we can use the existing signals to run extra cooling. Or we can use the techniques to run other equipment (such as fuel pumps). This is what this discussion is about.
The Corvet and Mitsubishi/Mazda, etc PWM fan modules provide the muscle for running fans at a very cheap price, all that is required is a system to command them properly.
My next post describes the Arduino controller system.
bye.
Last edited by bruceg; 07-28-2023 at 06:51 PM.
#474
The Arduino Micro Controller System
Arduino was conceived as a training system for learning how to use micro controllers. The name Arduino comes from the 'Arduin of Ivrea' bar in Ivrea, Italy, where some of the project's founders used to meet. Micro controllers are simple (but powerfull) mini computers that have lots of useful electronic devices built into the same silicon chip; this extra circuitry can be switched on by a running program to then perform their assigned tasks without further intervention. The devices vary but nearly always include non-volitile memory (to hold progam code), multiple input & output drivers, autonomous communication channels, timers and analog-to-digital converters.
Arduino devices are complete systems on a single circuit board that incorporate power management, a micro controller, USB communication and standardized input/output connector placement. Additional circuitry, specific to a designed task, plugs into the connectors on top of the main board.
The Arduino Integrated Development Environment (IDE) overlays the very powerfull C++ programming language with a set of standard routines that have human friendly names like digitalRead(), analogWrite(), delay(), etc. The IDE has mapping files for each of the different Arduino boards; this makes programming quite easy for beginners with the underlying C++ available for performing IDE unsupported, more complex or timing and hardware critical tasks when needed. C/C++ programming is quite logical and not difficult to learn the rudiments thereof, but that's all you need when using the Arduino IDE routines.
C++ is a 'high level' language suitable for humans to understand while microcontrollers require sequences of very simple steps to perform, written in a very 'low level' machine code. A compiler program is needed to translate and assemble the machine code from the high level language source. The avr-g++ compiler uses a smart linking methodology whereby parts of a program that are not actually used are left out and bits that haven't changed since the previous compile are retained 'as-is'. It also adds in whole chunks of 'library' code, 'header' instructions and performs pre-compilation calculations to make the whole process easier.
Programs get divided into several parts. While Arduino programs are written with C++ code they are stored as 'name.ino' (where ino is the last 3 letters of Arduino). Headers (name.h) hold program specific selections all in a single location. Library files provide standard functions that are only added in when required, they consist of additional C++ files or headers or both. The IDE looks for all the parts of a program starting with the individual directory the .ino is in, then the core functions (only those actually used) are added, and additional files from a directory named 'library' or user specified directories are also included. Extensions recognized include .ino, .c, .c++, .pde, .lib, .h
The Arduino Uno board uses an Atmel ATMega328 micro controller which has 23 digital input/output drivers (only 21 are connected on the Uno, and 1 of those is used for reset) and 32,768 bytes of program memory, but the Arduino IDE interface boot loader takes up some of it. The Input/Output drivers can source or sink >20mA individually, but the maximum total for all 23 is 200mA.
There are 2048 bytes of dynamic data memory (contents lost between uses) and 1024 bytes of slower, non-volatile data memory (contents retained while power is off). A single on-board comparitor and a single analog-to-digital converter can be switched to 6 of the inputs, plus 3 internal sources. It has an on-board sub controller that handles autonomous UART communications through 2 of the input/output pins, and similar devices for SPI and I2C comms.
The Arduino Nano board is a smaller form factor of the same parts as the Uno with 2 extra (analog only in) pins added. The Arduino Mega uses the ATmega2560 with 8 times as much memory and 3.5 times the I/O. Between the Nano and the Mega are several other official and unofficial boards with various capabilities, all of which can be programmed directly from the IDE. Additionally other processors have been mapped to the IDE, these include ATtiny, ESP32, Raspberry Pi Pico, etc however these usually can't be directly programmed via USB, but require a Uno or Nano board running a data relaying program to pass programs in.
My next post will talk about code and functions relevent to operating fan controllers.
bye.
Arduino devices are complete systems on a single circuit board that incorporate power management, a micro controller, USB communication and standardized input/output connector placement. Additional circuitry, specific to a designed task, plugs into the connectors on top of the main board.
The Arduino Integrated Development Environment (IDE) overlays the very powerfull C++ programming language with a set of standard routines that have human friendly names like digitalRead(), analogWrite(), delay(), etc. The IDE has mapping files for each of the different Arduino boards; this makes programming quite easy for beginners with the underlying C++ available for performing IDE unsupported, more complex or timing and hardware critical tasks when needed. C/C++ programming is quite logical and not difficult to learn the rudiments thereof, but that's all you need when using the Arduino IDE routines.
C++ is a 'high level' language suitable for humans to understand while microcontrollers require sequences of very simple steps to perform, written in a very 'low level' machine code. A compiler program is needed to translate and assemble the machine code from the high level language source. The avr-g++ compiler uses a smart linking methodology whereby parts of a program that are not actually used are left out and bits that haven't changed since the previous compile are retained 'as-is'. It also adds in whole chunks of 'library' code, 'header' instructions and performs pre-compilation calculations to make the whole process easier.
Programs get divided into several parts. While Arduino programs are written with C++ code they are stored as 'name.ino' (where ino is the last 3 letters of Arduino). Headers (name.h) hold program specific selections all in a single location. Library files provide standard functions that are only added in when required, they consist of additional C++ files or headers or both. The IDE looks for all the parts of a program starting with the individual directory the .ino is in, then the core functions (only those actually used) are added, and additional files from a directory named 'library' or user specified directories are also included. Extensions recognized include .ino, .c, .c++, .pde, .lib, .h
The Arduino Uno board uses an Atmel ATMega328 micro controller which has 23 digital input/output drivers (only 21 are connected on the Uno, and 1 of those is used for reset) and 32,768 bytes of program memory, but the Arduino IDE interface boot loader takes up some of it. The Input/Output drivers can source or sink >20mA individually, but the maximum total for all 23 is 200mA.
There are 2048 bytes of dynamic data memory (contents lost between uses) and 1024 bytes of slower, non-volatile data memory (contents retained while power is off). A single on-board comparitor and a single analog-to-digital converter can be switched to 6 of the inputs, plus 3 internal sources. It has an on-board sub controller that handles autonomous UART communications through 2 of the input/output pins, and similar devices for SPI and I2C comms.
The Arduino Nano board is a smaller form factor of the same parts as the Uno with 2 extra (analog only in) pins added. The Arduino Mega uses the ATmega2560 with 8 times as much memory and 3.5 times the I/O. Between the Nano and the Mega are several other official and unofficial boards with various capabilities, all of which can be programmed directly from the IDE. Additionally other processors have been mapped to the IDE, these include ATtiny, ESP32, Raspberry Pi Pico, etc however these usually can't be directly programmed via USB, but require a Uno or Nano board running a data relaying program to pass programs in.
My next post will talk about code and functions relevent to operating fan controllers.
bye.
Last edited by bruceg; 07-23-2023 at 01:10 AM.
The following 4 users liked this post by bruceg:
#475
Applying Arduinos to Fan Controllers
Most modern cars use a 12V lead-acid starter battery that has the soft lead plates stiffened with a small amount of calcium; the calcium provides many benefits over plain lead batteries and lifts the optimal re-charge value to ~14.6V. So this is what the alternator is commanded to deliver across the battery. Note that the alternator output is often higher than this because of long cable runs or manufacturers choosing to use the body steel for the ground path, etc.
When electronic engine management was first applied to mass produced vehicles in the 1990s that same voltage was used for almost everything on-board including sensors and actuators. More recent vehicles tend to use low voltage CAN and LIN with proprietry (and often secret) codes passed amoungst them. This effectively prohibits easy diy access to the data unless you possess a very specific skill set.
There are threads specific to interfacing to contemporary vehicles, but here I'm only going to look into interfacing Arduinos to 'bare' sensors that are operated at alternator/battery voltage or at 5V. Arduinos operate at 5V or 3.3V while a vehicle will nominally provide ~15V with all sorts of interference and spikes above and below this. You need a filtered feed to the Arduino power supply, not just a big inductor like you would use for a radio; that's a good start, it'll handle droop and shorts to ground, but a proper high frequency, capacitive filter must follow it (these combined units are called L-C filters).
Most Arduino boards have a voltage regulator on board, but its maximum input voltage is specified as only 12V so some form of voltage reducer will be needed prior to it or replacing it. Cheap, efficient 'Buck' regulators switch on and off at high frequency to apply a voltage to an inductor and smoothing filter from which it outputs as a lower voltage. While an ebay 20V --> 5V 'phone charger' version looks like it would be ideal, the electrically noisy environment of a motor vehicle can easily destroy these, so it is best to use a 35V or even 60V input model. Just make sure it mentions a high conversion efficiency otherwise it will likely be a linear converter, the same as the one on the Arduino board.
As I mentioned in my first post there are only a few inputs required for basic control of a coolant fan - top-of-engine and radiator outlet temperatures, air con On, engine RPM and road Speed pulses. Oh, and ignition On/Off if you want to add cool down after switch off. Air con from the magnetic pulley control and Ignition are easy, alternator/battery voltage from either through a 10,000 ohm resistor to an NPN transistor to shunt 5V through another 10,000 ohm resistor (or an Arduino internal pullup) to ground with the inverted output read from the junction of the second resistor and the transistor. Add a simple, protective R/C filter adjacent to the Arduino inputs and that's done.
The simplest temperature probes are just a special type of resistor (called a thermistor) whose resistance value changes rapidly with temperate change. Positive temperate types increase resistance with increasing temperature, while cheaper, negative (inverted) temperature types decrease resistance as temperature rises. Very simple to read with a Nano, choose a resistor who's value is close to the value the thermistor will be at the temperatures of interest then put 5 volts into one end of it. The other end goes to the thermistor then on to ground. At the trigger point the voltage at the junction will be centred at 2.5V, this goes through an R/C filter into an analog-to-digital converter on-board the Arduino.
The speed signal from older vehicles will be a spinning drive cable turned directly from the output shaft of the gear box, there are many cheap back-of-speedometer readers available for this. More modern vehicles with ABS will have 5 sensors, one at each wheel and one on the drive train. If the vehicle speed sensor is a modern 'Hall Effect' type (direct magnetic field change to voltage) the output is a relatively constant height square wave that can be copied with a cheap comparator circuit and directly read by an Arduino (may need voltage division). But if it is a reluctor type (rising and falling magnetism applied to a wire coil to produce an alternating current) then copying it first requires passing it through a low power opto coupler then a specialist zero crossing detector that handles the huge dynamic range and rejects interference to produce a constant height square wave.
Tachometer interfaces are readily available, pick one, adjust the output to match the Arduino 5V and read it in.
And as for driving the fan controller, Arduinos have several autonomous pulse width modulators (PWM) on board, just calculate a duty, pass it to the modulator sub circuit and repeat every few seconds, updating only as needed. If you use the analogWrite() function the output is always PWM +ve with the duty part at the begining of each pulse being high at 5V. If you use an alternative function that includes choice between PWM +ve & PWM -ve your program will be able to use almost any brand of fan controller.
If you what to build your own fan controller electric motor control is easy - provide voltage to a coil that generates a magnetic field to interact with another magnetic field (from a stationary permanent magnet or another coil) then switch the power to a different coil when the pulling or pushing weakens after the prior coil moves past the stationary magnetic field. Repeat.
'Brushed' motors use spring loaded carbon rods (brushes) each side of a central shaft to connect power to a series of insulated metal plates fitted around the shaft. The pair of rotary switches so formed is called a commutator. Plates opposite each other pass the power to a coil of insulated wire wrapped around a frame (armature) attached to the shaft. It is possible to add additional brushes to power additional coils at the same time (or better yet positioned to be at maximum while the others are at half or one third strength), but there is a better way.
'Brushless' motors arrange the coils around a stationary base plate in sets of 3 (3, 6, 9, 12, etc) with the sets wired with all N°1s joined in parallel or in series, then all N°2s and all N°3s. Magnets are installed around the rim of a disk that rotates above (or outside) the coils which are switched in sequence by a simple set of electronic switches co-ordinated by a position sensor. These motors are cheaper to produce with simple coils around bobbins rather than winding complicated armature patterns, there is no commutator or brushes to wear out and they upscale readily by adding more coil sets or using larger coils.
Both brushed and brushless motors may be speed-regulated by varying the voltage applied to the coils, either continuously or by pulses of full voltage periods separated with various coasting periods. Pulse-&-coast is the prefered method, especially when the periods are very short with high repetition rates above 20,000 times per second. This is what automotive fan controllers output.
Most electric pumps are also driven by PWM so the Arduino program can be easily adapted or expanded to these too.
So what's available in the Arduino system for diy interfacing ? Plenty ! Go here - https://www.arduino.cc/reference/en/
These are the most relevent -
interupt, digitalRead(), pulseIn(), shiftIn() & analogRead() get data in
digitalWrite(), shiftOut(), analogWrite() & tone() put signals out
constrain() & map() adjust values
And there are a plethora of maths functions.
And that's all now for interfacing folks. But if there is a demand I will add circuit descriptions for all the interfaces mentioned above.
bye.
When electronic engine management was first applied to mass produced vehicles in the 1990s that same voltage was used for almost everything on-board including sensors and actuators. More recent vehicles tend to use low voltage CAN and LIN with proprietry (and often secret) codes passed amoungst them. This effectively prohibits easy diy access to the data unless you possess a very specific skill set.
There are threads specific to interfacing to contemporary vehicles, but here I'm only going to look into interfacing Arduinos to 'bare' sensors that are operated at alternator/battery voltage or at 5V. Arduinos operate at 5V or 3.3V while a vehicle will nominally provide ~15V with all sorts of interference and spikes above and below this. You need a filtered feed to the Arduino power supply, not just a big inductor like you would use for a radio; that's a good start, it'll handle droop and shorts to ground, but a proper high frequency, capacitive filter must follow it (these combined units are called L-C filters).
Most Arduino boards have a voltage regulator on board, but its maximum input voltage is specified as only 12V so some form of voltage reducer will be needed prior to it or replacing it. Cheap, efficient 'Buck' regulators switch on and off at high frequency to apply a voltage to an inductor and smoothing filter from which it outputs as a lower voltage. While an ebay 20V --> 5V 'phone charger' version looks like it would be ideal, the electrically noisy environment of a motor vehicle can easily destroy these, so it is best to use a 35V or even 60V input model. Just make sure it mentions a high conversion efficiency otherwise it will likely be a linear converter, the same as the one on the Arduino board.
As I mentioned in my first post there are only a few inputs required for basic control of a coolant fan - top-of-engine and radiator outlet temperatures, air con On, engine RPM and road Speed pulses. Oh, and ignition On/Off if you want to add cool down after switch off. Air con from the magnetic pulley control and Ignition are easy, alternator/battery voltage from either through a 10,000 ohm resistor to an NPN transistor to shunt 5V through another 10,000 ohm resistor (or an Arduino internal pullup) to ground with the inverted output read from the junction of the second resistor and the transistor. Add a simple, protective R/C filter adjacent to the Arduino inputs and that's done.
The simplest temperature probes are just a special type of resistor (called a thermistor) whose resistance value changes rapidly with temperate change. Positive temperate types increase resistance with increasing temperature, while cheaper, negative (inverted) temperature types decrease resistance as temperature rises. Very simple to read with a Nano, choose a resistor who's value is close to the value the thermistor will be at the temperatures of interest then put 5 volts into one end of it. The other end goes to the thermistor then on to ground. At the trigger point the voltage at the junction will be centred at 2.5V, this goes through an R/C filter into an analog-to-digital converter on-board the Arduino.
The speed signal from older vehicles will be a spinning drive cable turned directly from the output shaft of the gear box, there are many cheap back-of-speedometer readers available for this. More modern vehicles with ABS will have 5 sensors, one at each wheel and one on the drive train. If the vehicle speed sensor is a modern 'Hall Effect' type (direct magnetic field change to voltage) the output is a relatively constant height square wave that can be copied with a cheap comparator circuit and directly read by an Arduino (may need voltage division). But if it is a reluctor type (rising and falling magnetism applied to a wire coil to produce an alternating current) then copying it first requires passing it through a low power opto coupler then a specialist zero crossing detector that handles the huge dynamic range and rejects interference to produce a constant height square wave.
Tachometer interfaces are readily available, pick one, adjust the output to match the Arduino 5V and read it in.
And as for driving the fan controller, Arduinos have several autonomous pulse width modulators (PWM) on board, just calculate a duty, pass it to the modulator sub circuit and repeat every few seconds, updating only as needed. If you use the analogWrite() function the output is always PWM +ve with the duty part at the begining of each pulse being high at 5V. If you use an alternative function that includes choice between PWM +ve & PWM -ve your program will be able to use almost any brand of fan controller.
If you what to build your own fan controller electric motor control is easy - provide voltage to a coil that generates a magnetic field to interact with another magnetic field (from a stationary permanent magnet or another coil) then switch the power to a different coil when the pulling or pushing weakens after the prior coil moves past the stationary magnetic field. Repeat.
'Brushed' motors use spring loaded carbon rods (brushes) each side of a central shaft to connect power to a series of insulated metal plates fitted around the shaft. The pair of rotary switches so formed is called a commutator. Plates opposite each other pass the power to a coil of insulated wire wrapped around a frame (armature) attached to the shaft. It is possible to add additional brushes to power additional coils at the same time (or better yet positioned to be at maximum while the others are at half or one third strength), but there is a better way.
'Brushless' motors arrange the coils around a stationary base plate in sets of 3 (3, 6, 9, 12, etc) with the sets wired with all N°1s joined in parallel or in series, then all N°2s and all N°3s. Magnets are installed around the rim of a disk that rotates above (or outside) the coils which are switched in sequence by a simple set of electronic switches co-ordinated by a position sensor. These motors are cheaper to produce with simple coils around bobbins rather than winding complicated armature patterns, there is no commutator or brushes to wear out and they upscale readily by adding more coil sets or using larger coils.
Both brushed and brushless motors may be speed-regulated by varying the voltage applied to the coils, either continuously or by pulses of full voltage periods separated with various coasting periods. Pulse-&-coast is the prefered method, especially when the periods are very short with high repetition rates above 20,000 times per second. This is what automotive fan controllers output.
Most electric pumps are also driven by PWM so the Arduino program can be easily adapted or expanded to these too.
So what's available in the Arduino system for diy interfacing ? Plenty ! Go here - https://www.arduino.cc/reference/en/
These are the most relevent -
interupt, digitalRead(), pulseIn(), shiftIn() & analogRead() get data in
digitalWrite(), shiftOut(), analogWrite() & tone() put signals out
constrain() & map() adjust values
And there are a plethora of maths functions.
And that's all now for interfacing folks. But if there is a demand I will add circuit descriptions for all the interfaces mentioned above.
bye.
#476
Just a quick comment on the coding style many 'new to Arduino' people are using. Don't do any conversions yourself - you are using a COMPUTER which is very good at doing calculations, so work in temperature and fan speed as PERCENT and put all your actual desired temperature and speed - percent change points in a single header file.
Then in your controlling program use constrain() and map() to do automatic conversions. Note that map() allows REVERSING of the values it expands or contracts so once top and bottom are set (in the header file) it just works without (unneccessary) code writer intervention.
This way the code will work for any combination/configuration; all you need do is adjust the values to suit your situation/fan module in the header file.
bye.
Then in your controlling program use constrain() and map() to do automatic conversions. Note that map() allows REVERSING of the values it expands or contracts so once top and bottom are set (in the header file) it just works without (unneccessary) code writer intervention.
This way the code will work for any combination/configuration; all you need do is adjust the values to suit your situation/fan module in the header file.
bye.
The following users liked this post:
V8 Cowboy (07-25-2023)
#477
bruceg- Thank you for sharing your knowledge on this (these?) subject(s)! It helps me (and hopefully others...) better understand how Arduinos work within the parameters needed to operate PWM cooling fans.
The following users liked this post:
V8 Cowboy (07-25-2023)
#478
Joined: Mar 2003
Posts: 10,258
Likes: 1,565
From: The City of Fountains
I thought that this would be a good place to post this. Here are some basics dimensions for the 850 watt 6th gen Camaro ZL1 fan:
This fan is being trimmed and fitted to a radiator with a core size of about 18" tall by 21" wide. The blades will hang down past the radiator a little, but it is minimal.
I also have a C7 Corvette fan here and I will make a similar picture for it.
Andrew
This fan is being trimmed and fitted to a radiator with a core size of about 18" tall by 21" wide. The blades will hang down past the radiator a little, but it is minimal.
I also have a C7 Corvette fan here and I will make a similar picture for it.
Andrew
Last edited by Project GatTagO; 09-18-2023 at 11:05 AM.
#479
Joined: Mar 2003
Posts: 10,258
Likes: 1,565
From: The City of Fountains
Here are just a few pictures of the preliminary mock-up. The radiator is nothing fancy. It is one of Speedway Motors universal, dual pass models. It is the 26" model which is 26" wide and about 18" tall and the core is about 21" wide and 18" tall.
The bottom was cut to clear some of the structure of the core support.
This is the is the bottom of the passenger side.
This is the upper passenger side.
Bottom of the driver's side.
The shroud also has little tabs up at the top that perfectly capture the lip of the core header panel.
Andrew
The bottom was cut to clear some of the structure of the core support.
This is the is the bottom of the passenger side.
This is the upper passenger side.
Bottom of the driver's side.
The shroud also has little tabs up at the top that perfectly capture the lip of the core header panel.
Andrew
#480
Joined: Mar 2003
Posts: 10,258
Likes: 1,565
From: The City of Fountains
Here is the C7 Corvette fan:
There is a small portion at the top middle of the fan that has already been trimmed off. If you look up the part number, you will se what I am referring to. This fan will fit a 21x18 (WxH) radiator core very nicely. The thickness is about 3.5" at the deepest point.
Andrew
There is a small portion at the top middle of the fan that has already been trimmed off. If you look up the part number, you will se what I am referring to. This fan will fit a 21x18 (WxH) radiator core very nicely. The thickness is about 3.5" at the deepest point.
Andrew