Skip to content

Instantly share code, notes, and snippets.

@cellularmitosis
Last active March 12, 2021 06:39
Show Gist options
  • Save cellularmitosis/054c7cde5505afff3770de49766e8a2d to your computer and use it in GitHub Desktop.
Save cellularmitosis/054c7cde5505afff3770de49766e8a2d to your computer and use it in GitHub Desktop.
Arduino PWM-based pressure regulator sketch.

Blog 2021/2/20

<- previous | index | next ->

Arduino PWM-based pressure regulator sketch

WARNING: UNTESTED

Here's my first attempt at writing an Arduino sketch to PWM a fuel pressure pump. The goal is to build a "returnless" fuel pressure system for a DIY EFI project I'm about to start for my motorcycle.

As soon as my fuel pump arrives from eBay I can start testing and tweaking this sketch 😃

// Arduino PWM-based returnless fuel pressure regulator.
// Copyright 2021 Jason Pepas.
// Released under the terms of the MIT License, see https://opensource.org/licenses/MIT
#include <stdint.h>
typedef int pin_t; // an Arduino pin number.
typedef int adc_t; // an Arduino 10-bit ADC value (0-1023).
typedef int pwm_t; // an Arduino PWM output value (0-255).
typedef int psi_t; // Pounds per square inch.
// Pin assignments:
pin_t g_transducerPin = 0;
pin_t g_pumpPin = 1;
pin_t g_errorLEDPin = 2;
// Global state. These are initialized in setup().
adc_t g_targetPressureADC;
pwm_t g_pumpPWM;
void die() {
while(1) {
digitalWrite(g_errorLEDPin, HIGH);
}
}
uint8_t shiftValueFor(uint8_t oversample) {
switch (oversample) {
case 2: return 1;
case 4: return 2;
case 8: return 3;
case 16: return 4;
case 32: return 5;
case 64: return 6;
default: die();
}
}
adc_t readFuelPressure(pin_t sensorPin) {
// Note: arduino analogRead takes about 100us (10kHz) according to
// http://yaab-arduino.blogspot.com/2015/02/fast-sampling-from-analog-input.html
// An oversample rate of 64x fits 10-bit values neatly into a 16-bit unsigned accumulator, at about 150Hz.
// Arduino PWM is typically 490Hz, so we will spit out at least three pulses before changing PWM value.
uint8_t oversample = 64;
uint16_t accumulator = 0;
for (uint8_t i=0; i < oversample; i++) {
int reading = analogRead(sensorPin);
accumulator += reading;
}
accumulator = accumulator >> shiftValueFor(oversample);
return (adc_t)accumulator;
}
int clamped(int value, int minimum, int maximum) {
if (value < minimum) {
return minimum;
} else if (value > maximum) {
return maximum;
} else {
return value;
}
}
pwm_t calculatePumpPWM(pwm_t currentPWM, adc_t currentPressureADC, adc_t targetPressureADC) {
pwm_t minimumPWM = 0;
pwm_t maximumPWM = 255;
adc_t pressureEStopADC = 600;
if (currentPressureADC >= pressureEStopADC) {
return 0;
} else if ((currentPressureADC < targetPressureADC) && (currentPWM < maximumPWM)) {
int delta = (targetPressureADC - currentPressureADC) > 1;
pwm_t newPWM = currentPWM + delta;
return clamped(newPWM, minimumPWM, maximumPWM);
} else if ((currentPressureADC > targetPressureADC) && (currentPWM > minimumPWM)) {
int delta = (currentPressureADC - targetPressureADC) > 1;
pwm_t newPWM = currentPWM - delta;
return clamped(newPWM, minimumPWM, maximumPWM);
} else {
return clamped(currentPWM, minimumPWM, maximumPWM);
}
}
adc_t calculateTargetPressureADC(psi_t targetPSI) {
float transducerScaleMin = 0.5;
float transducerScaleMax = 4.5;
float transducerFullScalePSI = 100;
float targetPressureADC = ((transducerScaleMax - transducerScaleMin) / transducerFullScalePSI) * targetPSI;
return (adc_t)targetPressureADC;
}
void setup() {
g_transducerPin = 0;
g_pumpPin = 1;
g_pumpPWM = 0;
psi_t targetPressurePSI = 45;
g_targetPressureADC = calculateTargetPressureADC(targetPressurePSI);
}
void loop() {
adc_t currentPressureADC = readFuelPressure(g_transducerPin);
pwm_t pwm = calculatePumpPWM(g_pumpPWM, currentPressureADC, g_targetPressureADC);
analogWrite(g_pumpPin, pwm);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment