Hi folks. This is a project I’ve been putting off for years, and finally got started last week. Please keep in mind that about all I know about ‘C’ is that it’s the 3rd letter of the alphabet… and I’m sure that will be apparent in the bits of code I have so far. Feel free to point and laugh, as long as you explain why and how to fix it.
This is a contraption to control the AFR of a turbo blowthrough Holley carb’ed small block V8. The power valves in stock form are normally open (by a spring) and pulled closed by engine vacuum; as load increases and vacuum decays the spring pushes the valve off its seat and exposes an extra pair of fuel jets, richening the mixture. This doesn’t always work as expected when pressurized air is fed to the carb. If the main boosters are flowing before the PVs try to open, low pressure in the main well keeps them sucked shut and the spring is not strong enough to open them. Turbo engine runs lean and then expensive parts fall out the bottom. These PVs are modified, with the original spring flipped around to the other side of the valve and are now normally closed, until a positive pressure (from an outside source) pushes the valve off its seat against the spring pressure. This works well as long as the external pressure source is enough over boost pressure to open the valve (inside the carb, the boost pressure effectively becomes the new ambient pressure - the carb’s parts don’t have any way to distinguish between the two). The part that sucks is that the PV circuit has to be tuned with jetting just like the other circuits to get the right WOT/in-boost fuel mix, and controlling it with only a simple Hobbs switch or similar is a bit crude.
This project reads an array of stand-alone sensors: TPS, MAP, WBO2, and based on a combination of those sensor readings determines when to hit the PVs with the external pressure source. More than 30% throttle, and over 3PSI boost, and AFR higher than 12.5:1, the Arduino triggers the air solenoid and the power valves open, and the mixture gets richer. When AFR falls to 12.0:1, the solenoid turns off and the power valves close. This makes the PV jet area pretty much irrelevant as long as they’re big enough to flow more fuel than the desired minimum AFR. Much easier to poke some buttons and change the WOT AFR, right?
I have it working, mostly, on the bench. Uno, proto-screwshield, & 16x2 serial/i2c RGB LCD. I have a few points I’m stuck on that I’ll lay out later (some are mentioned in the comments) but for now, since I have no idea why what I’ve done so far works, I’d be eternally grateful if y’all could check my code and point out anything I’ve done horribly wrong before I go too much farther.
/*
Closed-loop power valve (PV) control for turbo/blower blowthrough Holley carbs
Example:
If TPS is above 30%, and MAP is above 3.5psi, and WBO2 is above 12.5:1, turn the PV solenoid ON
If TPS is above 30%, and MAP is above 3.5psi, and WBO2 is below 12.0:1, turn the PV solenoid OFF
PV is CLOSED unless all conditions are met
Carb's PVCR (power valve channel restrictors (an extra set of main jets)) should be sized to
supply fuel for richer mix than the desired PV 'off' point - in other words, the lower bound for
air/fuel mix should be controlled by when the Arduino turns the PV off, not by the PVCR area as usual.
*/
// include the library code:
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
// These #defines make it easy to set the backlight color
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7
// The shield uses the I2C SCL and SDA pins.
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
int TPSPin = 0; //signal return from TPS
int MAPPin = 1; //signal return from MAP
int O2Pin = 2; //analog 0-5v output from WBO2 controller
int PVPin = 13; //output to control PV
int PVStatus = 0; //used to read whether PV is commanded ON or OFF
void setup()
{
lcd.begin(16, 2);
// Initialize input & output pins
pinMode (TPSPin, INPUT);
pinMode (MAPPin, INPUT);
pinMode (O2Pin, INPUT);
pinMode (PVPin, OUTPUT);
}
void loop ()
{
// Display TPS & MAP on first row
int TPSValue = analogRead(TPSPin);
int TPSOutput = map(TPSValue,0,1023,7,105); //values used for bench testing only, shows throttle position in %
lcd.setCursor(0, 0);
lcd.print("TPS");
lcd.setCursor(4, 0);
lcd.print(TPSOutput); //used to display whole numbers only
int MAPValue = analogRead(MAPPin);
float MAPOutput = map(MAPValue,0,1023,-150,300); //not correct yet, the negative values need to display in/Hg, not PSI
lcd.setCursor(6, 0);
lcd.print("% MAP ");
lcd.setCursor(12, 0);
lcd.print(MAPOutput / 10); //used to display to one digit after decimal (XX.X), does not work that way yet!
//Display O2 & PV state on second row
int O2Value = analogRead(O2Pin);
float O2Output = map(O2Value,0,1023,735,2239); //MTX-L analog #1 used as example, 0-5v = 7.35:1-22.39:1
lcd.setCursor(0, 1);
lcd.print("AFR ");
lcd.setCursor(4, 1);
lcd.print(O2Output / 100); //used to display 2 digits after decimal, works correctly
int PVState = digitalRead(PVPin);
lcd.setCursor(10, 1);
lcd.print("PV ");
lcd.setCursor(13, 1);
delay(150); //HALP! Delay makes the display easier to read, but sensors & PV output do not need a delay- fixable?
// WBO2 hysteresis not implemented yet, no clue how to do that part!
// threshold values configured to match how those readings appear on the display
// If TPS is over 30% and MAP is over 3.5PSI, turn on the PV
if ((TPSOutput >= 30) && (MAPOutput / 10.0 >= 3.5)) // && (O2Output / 100 something important should go here)
{
digitalWrite (PVPin, HIGH);
}
else {
digitalWrite (PVPin, LOW);
}
//Display
PVStatus = digitalRead(PVPin);
if (PVStatus == HIGH) {
lcd.print(" ON"); // replace this with a 4th sensor (IAT? ECT?) and use backlight color alone to show PV state?
lcd.setBacklight(WHITE); //LCD backlight color changes as well when PV is active!
}
else {
lcd.print("OFF");
lcd.setBacklight(TEAL);
}
}