Skip to content

Commit

Permalink
tach divider for vans tach sender
Browse files Browse the repository at this point in the history
misc cleankup
  • Loading branch information
tomcourt authored and tomcourt committed Jul 9, 2017
1 parent 39d75f5 commit 9dd5c32
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 48 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ For thermocouple sensors the board will detect both open and short. It directly

For the voltage sensor a 4:1 voltage divider consisting of a 1k and 3.01k (1%) resistor is used. This limits the draw to .1 watt at 20 volts or .05 at 14 volts.

Typical sensors are Stewart Warner. The tachometer is supplied with 12 volts, a hall effect sensor that returns 5 volt pulses, 8/16 PPR, TBD. The manifold pressure sensor is believed to be 0-100mV ratio-metric. Either a better ADC (Adafruit ADS1015) will be needed or a new manifold pressure sensor.
Typical sensors are Stewart Warner. The tachometer is supplied with 12 volts, a hall effect sensor that returns about 10 volt pulses, 4 pulses per revolution. The manifold pressure sensor is believed to be 0-100mV ratio-metric. Either a better ADC (Adafruit ADS1015) will be needed or a new manifold pressure sensor.

For a sensor that might contain a voltage higher than Vcc using a voltage divider as used on the voltage sensor will cause a significant load which could create issues if still attached to a backup gauge. Alternatively a 15K ohm resistor between the sensor and the pin will safely clip voltages between 20.5 and -15.5 volts. The goal here is to limit the internal clamping diodes to no more than 1ma after the .7 volt diode drop.

Expand Down Expand Up @@ -202,7 +202,9 @@ To prevent having to re-acknowledge warnings there would be both temporal and ra

### Future stuff
* Record engine data by having the Engiuno pipe text to a port on the Stratux. The startup script on the stratux starts netcat (nc) in the background to record the text to a file. The script would also truncate the file at on powerup to limit its growth.
* It may be possible to support 2 thermocouples without the thermocouple multiplexer shield by using the differential mode ADC, 40x gain and a thermistor. Only 8 bits are usable with 40x, the noisy lower bits help with oversampling though. 488 uV per count works out to 21.5 deg. F resolution with a K type thermocouple. The 2.56 volt internal reference would double the resolution and oversampling could probably quadruple it (16x oversample).
* It may be possible to support 2 (or maybe more) thermocouples without the thermocouple multiplexer shield by using the differential mode ADC, 40x gain and a CJC sensor(Analog TMP36). Only 8 bits are usable with 40x, the noisy lower bits help with oversampling though. 488 uV per count works out to 21.5 deg. F resolution with a K type thermocouple. The 2.56 volt internal reference would double the resolution and oversampling could probably quadruple it (16x oversample). ADC0 and ADC1 are the negative side, any other ADC pin may be positive. With a filtering cap (10nF) several thermocouples could share a pin. The internal ATMEGA temperature sensor needs both offset and gain calibration, a 10 deg-C rise is typical as well, 2 point calibration may be much to expect for users. **TBD** - move the voltage divider sensor to ADC5 to allow future use of thermocouples.
* A custom shield might be helpful particularly if it were populated. Jumpers would select resistors and maybe filter caps. This would eliminate most to all of the soldering involved. A 4 bit latch on the thermocouple mux would free up 4 more analog pins on the Leanardo.
* A custom aux display board would also help. A single LED drive chip could be used as one chip can support 8 LED segments. A bright master caution/warning LED would be easy. And a smaller 7 segment LED module could be used to allow fitting the display in a 2.5" hole.
* The Arduino Yun would support airplanes lacking a Stratux. The code would need to use the 'bridge' objects instead of the ethernet objects. Use #ifdef AVR_YUN to flex the code.
* Themes - a dark theme could be created easily enough by adjusting the styles. A larger text theme for the gauges would involve more defines and stringizing them for the SVG.
* Warning lights instead of auxillary display? A board with 4 caution/warning LEDs (red/green common cathode [bicolor LED]). Turning red and green on produces yellow. Alternatively use a module like the [BOB-13884] to provide 3 RGB LED's.
Expand Down
38 changes: 27 additions & 11 deletions enguino/config.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
// Uncommenting the following line shows a box around each instrumment and around the viewable area of the page. Use to help arrange gauges.
// #define BOUNDING_BOX

#define TACH_DIVIDER 4

const char *green = "green";
const char *yellow = "yellow";
const char *red = "red";

#define divisor 13 // 1<<13 = 8192, this allows factors between -2.0 to 1.999
// for the 0-1023 ADC values, multiply range by 8 for full scale

#define MX(x) (int)((x)*(1<<divisor) + 0.5)
#define GMX(range) (int)(1000.0 / (range) * (1<<divisor) + 0.5)
#define GB(low) (int)(-((low) + 0.5))
#define ADCtoDivV (5.0/1023.0) // multiply this by adc input to get DC volts
#define ADCtoV10 (40 * ADCtoDivV) // 1:4 voltage divider
#define V10toADC (1/(40 * ADCtoDivV)) // 1:4 voltage divide
#define MX(x) (int)((x)*(1<<divisor) + 0.5) // expressed as floating point converted to integer m
#define GMX(range) (int)(1000.0 / (range) * (1<<divisor) + 0.5)
#define GB(low) (int)(-((low) + 0.5))
#define ADCtoDivV (5.0/1023.0) // multiply this by adc input to get DC volts
#define ADCtoV10 (40 * ADCtoDivV) // 1:4 voltage divider, results in tenths of a volt
#define V10toADC (1/(40 * ADCtoDivV)) // 1:4 voltage divide

// Sensor defintions and scaling
// -----------------------------
Expand All @@ -24,14 +26,27 @@ const char *red = "red";
// The MX macro converts a floating point factor for m into an integer factor. The gauge pointers vary from 0 to 1000.
// Use GB() and GMX to set the graphs b and m values based on lowest input and input range (hi-low) respectively.

// sensor-type range
// -------------- --------
// st_r240to33 0 - 1000 proportional resistive sensor
// st_thermistorC 0 - 1500 degrees C. in tenths
// st_thermistorF 32 - 2732 degrees F. in tenths
// st_volts 0 - 1023 ADC units 4.88 mV/per
// st_k_type_tcC 0 - 4000 0-1000 degrees C. in quarters
// st_j_type_tcC 0 - 4000 0-1000 degrees C. in quarters
// st_k_type_tcF 0 - 4000 32-1832 degrees F. in quarters
// st_j_type_tcF 0 - 4000 32-1832 degrees F. in quarters
// st_tachometer
// st_fuel_flow

// sensor-type, pin, decimal, voffset, vfactor, moffset, mfactor, lowAlarm, lowAlert, highAlert, highAlarm
const Sensor vtS = { st_volts, 0, 1, 0, MX(ADCtoV10), GB(100*V10toADC), GMX(60*V10toADC), 110, 130, 9999, 160 };
const Sensor opS = { st_r240to33, 1, 0, 0, MX(0.1), 0, MX(1.0), 25, 55, 9999, 95 };
const Sensor opS = { st_r240to33, 1, 0, 0, MX(.1), 0, MX(1.), 25, 55, 9999, 95 };
const Sensor otS = { st_thermistorF, 2, 0, 0, MX(.1), GB(50*10), GMX(200*10), -1, 140, 9999, 250 };
const Sensor fpS = { st_r240to33, 3, 1, 0, MX(0.1), 0, MX(1.0), 5, 20, 60, 80 };
const Sensor flS = { st_r240to33, 4, 1, 0, MX(0.16), 0, MX(1.0), 25, 50, 9999, 999 };
const Sensor fpS = { st_r240to33, 3, 1, 0, MX(.15), 0, MX(1.), 5, 20, 60, 80 };
const Sensor flS = { st_r240to33, 4, 1, 0, MX(.16), 0, MX(1.), 25, 50, 9999, 999 };
const Sensor taS = { st_tachometer, 15, 0, 0, MX(1.), 0, GMX(3000), -1, 500, 9999, 2700 };
const Sensor maS = { st_volts, -1, 1, 100, 2000, 0, 8008, -1, -1, 9999, 9999 };
const Sensor maS = { st_volts, -1, 1, 100, 2000, 0, MX(1.), -1, -1, 9999, 9999 };
const Sensor chS = { st_k_type_tcF, 16, 0, 0, MX(.25), GB(100*4), GMX(400*4), -1, 150, 400, 500 };
const Sensor egS = { st_k_type_tcF, 20, 0, 0, MX(.25), GB(1000*4), GMX(600*4), -1, -1, 9999, 9999 };

Expand Down Expand Up @@ -93,7 +108,8 @@ const Gauge gauges[] = {
};

// Guage layout for aux display
#define XTEXT(a,b,c,d) { .literal = {LED_TEXT(a,b,c,d)} } // literals must not be blank in last 2 letters
// Change layout to literal, sensor, sensor. Where a sensor value is displayed in the top line if literal is blank, otherwise sensor is used for alarm state of top line
#define XTEXT(a,b,c,d) { .literal = {LED_TEXT(a,b,c,d)} } // literals must have characters in one of the last 2 letters
#define XSENSOR(x) { .sensor = {&x, 0} }
const AuxDisplay auxdisplay[] = {
XTEXT( ,b,A,t), XSENSOR(vtS),
Expand Down
7 changes: 0 additions & 7 deletions enguino/egTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,6 @@ typedef struct {
} InterpolateTable;

enum SensorType {st_r240to33, st_thermistorF, st_thermistorC, st_volts, st_k_type_tcF, st_j_type_tcF, st_k_type_tcC, st_j_type_tcC, st_tachometer, st_fuel_flow};
// st_r240to33 - 0 - 1000 proportional resistive sensor
// st_thermistor - 0 - 1500 degrees C. in tenths
// st_volts - 0 - 1023 ADC units 4.88 mV/per
// st_k_type_tc - 0 - 4000 0-1000 degrees C. in quarters
// st_j_type_tc - 0 - 4000 0-1000 degrees C. in quarters
// st_tachometer
// st_fuel_flow

// for K style in deg. C, use a multiply of 4096 (0.25), offset 0
// for K style in deg. F, use a multiplier of 7373 (0.25 * 1.8), offset -32
Expand Down
43 changes: 24 additions & 19 deletions enguino/enguino.ino
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ volatile byte rpmP;

bool dim;
bool didKeyDown;
bool didChangeDim;
byte auxScreen = 2;

// printLED functions for the auxiliary display
Expand Down Expand Up @@ -115,7 +116,7 @@ int readSensor(const Sensor *s, byte n = 0) {
int r[4];
memcpy(r, rpm, sizeof(rpm));
interrupts();
sort(r, sizeof(r)/sizeof(int));
sort(r, N(r));
v = (r[1]+r[2])>>1;
}
else if (p < 16) {
Expand All @@ -133,7 +134,7 @@ int readSensor(const Sensor *s, byte n = 0) {
v = tcTemp[p-16];
interrupts();
if (t == st_j_type_tcC || t == st_j_type_tcF)
v = int(multiply(v - tcTemp[8], 25599) >> 15) + tcTemp[8];
v = multiplyAndScale(v - tcTemp[8], 25599, 15) + tcTemp[8];
if (t == st_k_type_tcF || t == st_j_type_tcF)
toF = 32 * 4;
}
Expand Down Expand Up @@ -194,7 +195,7 @@ eeSettings:

void tachIRQ() {
unsigned long newTachTime = micros();
rpm[rpmP++ & 3] = (60000000L/24) / (newTachTime - lastTachTime);
rpm[rpmP++ & 3] = (60000000L/TACH_DIVIDER) / (newTachTime - lastTachTime);
lastTachTime = newTachTime;
tachDidPulse = true;
}
Expand All @@ -211,11 +212,11 @@ bool isAlarm(Sensor *s, int v) {
return v < s->lowAlarm || v > s->highAlarm;
}

void auxDisplay(byte i) {
void auxDisplay(byte inx) {
int v;
Sensor *s = 0;
for (signed char n=1; n>=0; n--) {
AuxDisplay *a = auxdisplay+(i+n);
AuxDisplay *a = auxdisplay+(inx+n);
if (a->sensor.zero == 0) {
commandLED(n, HT16K33_BLINK_OFF);
s = a->sensor.s;
Expand Down Expand Up @@ -262,21 +263,20 @@ void setup() {
// while (!Serial)
// ; // wait for serial port to connect. Stops here until Serial Monitor is started. Good for debugging setup

pinMode(0, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(2),tachIRQ,RISING);

delay(1); // delay to allow LED display chip to startup
eeInit();
tcTempSetup();
// setup LED last to allow 1mS for HT16K33
printLEDSetup();
printLED(0,LED_TEXT(h,o,b,b));
printLED(1,ee_status.hobbs>>2,1);
delay(1000);
auxDisplay(0);
delay(1000);

attachInterrupt(digitalPinToInterrupt(2),tachIRQ,RISING);

pinMode(0, INPUT_PULLUP);
// attachInterrupt(digitalPinToInterrupt(0),switchIRQ,FALLING);

switchPress = 0;

// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
Expand All @@ -289,18 +289,23 @@ void loop() {
if (switchPress) {
if (!didKeyDown) {
auxScreen += 2;
if (auxScreen >= sizeof(auxdisplay)/sizeof(auxdisplay[0]))
if (auxScreen >= N(auxdisplay))
auxScreen = 2;
}
switchPress = 0;
didChangeDim = false;
didKeyDown = false;
}
if (switchDown >= 32) {
if (!didKeyDown)
dim = !dim;
for (byte line=0; line<2; line++)
commandLED(line, dim?HT16K33_BRIGHT_MIN:HT16K33_BRIGHT_MAX);
didKeyDown = true;
if (switchDown >= 32 && !didChangeDim) {
dim = !dim;
for (byte line=0; line<2; line++)
commandLED(line, dim?HT16K33_BRIGHT_MIN:HT16K33_BRIGHT_MAX);
didChangeDim = true;
didKeyDown = true;
}
else if (switchDown >= 8) {
auxScreen = 2;
didKeyDown = true;
}

client = server.available();
Expand Down
4 changes: 2 additions & 2 deletions enguino/printGauges.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// Implementation for printPrefix and pringGauge

int scaleMark(const Sensor *s, int val) {
int mark = int(multiply(s->mfactor, val+s->moffset) >> divisor);
int mark = multiplyAndScale(s->mfactor, val+s->moffset, divisor);
if (mark < 0)
mark = 0;
if (mark > 1000)
Expand All @@ -12,7 +12,7 @@ int scaleMark(const Sensor *s, int val) {
int scaleValue(const Sensor *s, int val) {
if (val == FAULT)
return val;
return int(multiply(s->vfactor,val) >> divisor) + s->voffset;
return multiplyAndScale(s->vfactor,val, divisor) + s->voffset;
}

// vertical gauge is
Expand Down
6 changes: 3 additions & 3 deletions enguino/printWeb.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ void printSetupPage() {
"}\n"
"</style>\n"
"<form action='/'>\n"
"<input type='radio' name='x' value='a' checked/>Add fuel<br>\n"
"<input type='radio' name='x' value='f'/>Set fuel capacity<br>\n"
"<input type='radio' name='x' value='h'/>Set hobbs<br>\n"
"<input type='radio' name='x' value='a' checked/>Add fuel &#8530;<br>\n"
"<input type='radio' name='x' value='f'/>Set fuel capacity &#8530;<br>\n"
"<input type='radio' name='x' value='h'/>Set hobbs &#8530;<br>\n"
"<input type='radio' name='x' value='k'/>Set fuel flow k<br>\n"
"<br>\n"
"<input type='number' name='n' pattern='[0-9]*'/>\n"
Expand Down
6 changes: 2 additions & 4 deletions enguino/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,12 @@ asm volatile ( \
)

// multiply 16 x 16 signed values and return the 32 bit result
// this is a smaller and faster version of: (long(a) * long(b);
long multiply(int a, int b) {
long res;

MultiS16X16to32(res, a, b);
return res;
// this is a smaller and faster version of:
// return (long(a) * long(b);
}

int multiplyAndScale(int a, int b, byte shift) {
Expand All @@ -85,9 +84,8 @@ int interpolate(const InterpolateTable *table, int value) {
if (--i == 0)
return FAULT;
int x1 = x + (1 << *diff);
if (value < x1) {
if (value < x1)
return int((multiply(*result,x1-value) + multiply(result[1], value-x)) >> *diff);
}
x = x1;
diff++;
result++;
Expand Down

0 comments on commit 9dd5c32

Please sign in to comment.