requesting mathmatical and some coding assistance

My project I've been working on lately is an electric cooling fan motor controller for my brothers 79 chevy C10. I admit this project has been a pain in the neck and probably slightly more difficult than what my experience is comfortable with. (getting out of a comfort zone is how you learn and grow)

anyway, my two measurements aren't reading correctly. I would like to tackle the easy one first, battVolts and the more difficult one next, realTemp.

  1. battVolts = analogRead from a 3k to 1k voltage divider. 20vdc converted to 5vdc ie: 2.5vdc @ Arduino should display a reading of 10vdc.
  2. realTemp = analogRead from a voltage divider (R1 255ohms) and (R2 factory tempSensor) 60ohms @ 190 degreesF and 3.7k ohms @ 40 degrees F.

for the realTemp I have no idea how to do the math for that. because of the higher voltage equals a lower temp and vise versa.

any help and/or guidence would be awesome. if there is any information that is need that i left out please ask and i will get it posted ASAP. again thank you.

/*************************************************** 
  This is a library for our I2C LED Backpacks

  Designed specifically to work with the Adafruit LED 7-Segment backpacks 
  ----> http://www.adafruit.com/products/881
  ----> http://www.adafruit.com/products/880
  ----> http://www.adafruit.com/products/879
  ----> http://www.adafruit.com/products/878

  These displays use I2C to communicate, 2 pins are required to 
  interface. There are multiple selectable I2C addresses. For backpacks
  with 2 Address Select pins: 0x70, 0x71, 0x72 or 0x73. For backpacks
  with 3 Address Select pins: 0x70 thru 0x77

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/
int tempSensor = analogRead (A2);
int battSensor = analogRead (A0);
const byte fanA = 7;
const byte fanB = 8;
const byte battTestSwitch = 4;
int realTemp;


#include <Adafruit_GFX.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>
#include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc.
#include "Adafruit_LEDBackpack.h"

Adafruit_7segment matrix = Adafruit_7segment();

void setup() {
  pinMode(fanA,OUTPUT);
  pinMode(fanB,OUTPUT); 
  pinMode(battTestSwitch,INPUT_PULLUP);

Wire.setClock(100000);  // set SCL to slow speed
  
#ifndef __AVR_ATtiny85__
  Serial.begin(9600);
  Serial.println("7 Segment Backpack Test");
#endif
  matrix.begin(0x70);

  digitalWrite(fanA,LOW);
  digitalWrite(fanB,LOW);  
}

void loop() {
  
 int tempSensor = analogRead(A2);
// int realTemp

  if (digitalRead (battTestSwitch) == LOW){ 
 // battVolts = analogRead(battSensor);
 int battSensor = analogRead (A0);
 float battVolts = (battSensor * (5/1023) * 4); // 20vdc is 5vdc at arduino

 // print a hex number
  matrix.print(battVolts);
  matrix.writeDisplay();
  delay(2500); 

      // print a hex number
  matrix.print(0xA55, HEX); // spells "ass" 
  matrix.writeDisplay();
  delay(750);
  
  }
  else {
      matrix.print(realTemp);
      matrix.writeDisplay();
      delay(1000);
  }

  if (realTemp > 185 ){
    digitalWrite(fanA,HIGH);   
  }
  else {
    digitalWrite(fanA,LOW);
    digitalWrite(fanB,LOW);
  }
  if (realTemp > 215){
    digitalWrite(fanA,HIGH);
    digitalWrite(fanB,HIGH);
  }
  else {
    digitalWrite(fanA,LOW);
    digitalWrite(fanB,LOW);
  }
}

I'm not particularly familiar with it but, the map() function may work for you. The description on the reference page states you can reverse the order of the results by which values are used for high/low.

Converting an anlogRead(...) to a voltage is done like this:

float battVolts = (battSensor * 5)/1023;

Then the this value multiplied by 4 as your were trying to do.

But the arrangement of the brackets matters when you are trying to do division with integers.

float battVolts = (battSensor * 5)/1023;
Also have one number contain a decimal.
float battVolts = (battSensor * 5)/1023.0;

LandonW:
anyway, my two measurements aren't reading correctly. I would like to tackle the easy one first, battVolts and the more difficult one next, realTemp.

If your transducers are linear, then simply use Y = MX + B. where X is the input and Y in the output.

Here's an example how to do that: (example: convert degrees C into degrees F):

Take two points: 0C = 32F and 100C - 212F (they can be ANY two points).

Since we WANT F, the output (Y) is in F.

Now,

M = (Y1 - Y2) / (X1 + X2)
M = (32 - 212) / (0 - 100)
M = 1.8

Now, plug M back into the equation and solve for B:
Y = MX + B == Y - MX = B
Pick either Y (doesn't matter) but also use the same X.
B = Y1 - (1.8 * X1)
B = 32 - (1.8 * 0)
B = 32 - 0
B = 32

So your M is 1.8 and the B is 32. Now plug M and B into the equation Y = MX + B and stick any number into X. The correct answer will come out in Y.

When you grumbled in school "What will I ever use THAT for?" -- now you know! :slight_smile:

krupski:
Now,

M = (Y1 - Y2) / (X1 + X2)
M = (32 - 212) / (0 - 100)
M = 1.8

Now, plug M back into the equation and solve for B:
Y = MX + B == Y - MX = B
Pick either Y (doesn't matter) but also use the same X.
B = Y1 - (1.8 * X1)
B = 32 - (1.8 * 0)
B = 32 - 0
B = 32

So your M is 1.8 and the B is 32. Now plug M and B into the equation Y = MX + B and stick any number into X. The correct answer will come out in Y.

When you grumbled in school "What will I ever use THAT for?" -- now you know! :slight_smile:

krupski:
you have X1 + X2 and below it you have 0 - 100.

is the switching of operations from + to - correct or are you testing me?? lol
If your transducers are linear, then simply use Y = MX + B. where X is the input and Y in the output.

Here's an example how to do that: (example: convert degrees C into degrees F):

Take two points: 0C = 32F and 100C - 212F (they can be ANY two points).

Since we WANT F, the output (Y) is in F.

Now,

M = (Y1 - Y2) / (X1 + X2)
M = (32 - 212) / (0 - 100)
M = 1.8

Now, plug M back into the equation and solve for B:
Y = MX + B == Y - MX = B
Pick either Y (doesn't matter) but also use the same X.
B = Y1 - (1.8 * X1)
B = 32 - (1.8 * 0)
B = 32 - 0
B = 32

So your M is 1.8 and the B is 32. Now plug M and B into the equation Y = MX + B and stick any number into X. The correct answer will come out in Y.

When you grumbled in school "What will I ever use THAT for?" -- now you know! :slight_smile:

as per equation given Y = MX + B

X1 = 4.7vdc X2 = 1vdc Y1 = 40F Y2 = 190F

M = (X1-X2) / (Y1-Y2) blah blah blah

I found to be a dead end mathematically and way off of what would be a logical answer.

what I found to be get close is... M = (X1 / X2) / (Y1 / Y2) to continue with the formula provide above. B = -65.186. so before I plugged that number into the final Y = MX + B

B needs to = (Y1 - (M * X1)) * -1

in conclution Y = 22.38 * X + 65.186

i used graph paper to chart out X and Y with my known values and if i use 2.5 as X then Y = 121.136
on the chart it looks like it should be closer to 130ish

with that being said, does all that look correct?

Be sure to add excellent power protection circuitry to your project, at the very least a TVS diode.

Automotive electrical systems quickly fry unprotected electronics with occasional 125V spikes and even voltage reversals.

jremington:
Be sure to add excellent power protection circuitry to your project, at the very least a TVS diode.

Automotive electrical systems quickly fry unprotected electronics with occasional 125V spikes and even voltage reversals.

the circuit has reverse voltage protection. what rating of TVS diode would you recommend? a TVS is basically a zener yes?

Here is an application note. A 1.5 kW, 18V TVS diode will cost less that $1 US.

the math seems to be somewhat accurate. but now that I have it all on bread board its working inversely to voltage in vs temp displayed.

@ 0vdc it should display close to 230F, instead it shows that value @ 5vdc.

5vdc should show closer to 20F

Show your current code.

/*************************************************** 
  This is a library for our I2C LED Backpacks

  Designed specifically to work with the Adafruit LED 7-Segment backpacks 
  ----> http://www.adafruit.com/products/881
  ----> http://www.adafruit.com/products/880
  ----> http://www.adafruit.com/products/879
  ----> http://www.adafruit.com/products/878

  These displays use I2C to communicate, 2 pins are required to 
  interface. There are multiple selectable I2C addresses. For backpacks
  with 2 Address Select pins: 0x70, 0x71, 0x72 or 0x73. For backpacks
  with 3 Address Select pins: 0x70 thru 0x77

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/
float tempSensor = analogRead (A2);
float battSensor = analogRead (A0);
const byte fanA = 7;
const byte fanB = 8;
const byte battTestSwitch = 4;



#include <Adafruit_GFX.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>
#include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc.
#include "Adafruit_LEDBackpack.h"

Adafruit_7segment matrix = Adafruit_7segment();

void setup() {
  pinMode(fanA,OUTPUT);
  pinMode(fanB,OUTPUT); 
  pinMode(battTestSwitch,INPUT_PULLUP);

Wire.setClock(100000);  // set SCL to slow speed
  
 #ifndef __AVR_ATtiny85__
  Serial.begin(9600);
  Serial.println("7 Segment Backpack Test"); 
#endif
  matrix.begin(0x70); 

  matrix.print(0x8888, HEX);
  matrix.writeDisplay();
  delay(1000);
  
  digitalWrite(fanA,LOW);
  digitalWrite(fanB,LOW);  
}

void loop() {
  
  int tempSensor = analogRead(A2);
  float realTemp = ((22.71 * (tempSensor * 5) / 1023) + 63.1); // temp calculation

  if (digitalRead (battTestSwitch) == LOW){ 
 // battVolts = analogRead(battSensor);
 float battSensor = analogRead (A0);
 float battVolts = ((battSensor * 5)/1023.0 * 4); // 20vdc is 5vdc at arduino

  // print a floating point 
  matrix.print(battVolts);
  matrix.writeDisplay();
  delay(2500);

   // print a hex number
  matrix.print(0xA55, HEX); // spells "ass" 
  matrix.writeDisplay();
  delay(800);

  matrix.print(0xFACE, HEX);
  matrix.writeDisplay();
  delay(800);

  }
  else {
    
      matrix.print(realTemp);
      matrix.writeDisplay();
      delay(1000);
  }
  if (realTemp > 185 ){
    digitalWrite(fanA,HIGH);   
  }
  else {
    digitalWrite(fanA,LOW);
    digitalWrite(fanB,LOW);
  }
  if (realTemp > 215){
    digitalWrite(fanA,HIGH);
    digitalWrite(fanB,HIGH);
  }
  else {
    digitalWrite(fanA,LOW);
    digitalWrite(fanB,LOW);
  }
}

code revision... found a x1, x2...y1,y2 mix up.
this is how I did it

Y=MX+B
M=(x1/x2) / (y1/y2) x1= 4.99, x2=0.01, y1=230, y2=20
M=43.39

B= y1 - (M * x1)
B= 13.49

realTemp = 43.39 * vdc + 13.49

seems to be spot on. i guess because i was using my givin values from my chart in the formula is what was throwing it off. also i switched around x1 and x2 so that the graph would have a positive incline in relation to the vertacy instead of the actual negative one it has in real life.

/*************************************************** 
  This is a library for our I2C LED Backpacks

  Designed specifically to work with the Adafruit LED 7-Segment backpacks 
  ----> http://www.adafruit.com/products/881
  ----> http://www.adafruit.com/products/880
  ----> http://www.adafruit.com/products/879
  ----> http://www.adafruit.com/products/878

  These displays use I2C to communicate, 2 pins are required to 
  interface. There are multiple selectable I2C addresses. For backpacks
  with 2 Address Select pins: 0x70, 0x71, 0x72 or 0x73. For backpacks
  with 3 Address Select pins: 0x70 thru 0x77

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/
float tempSensor = analogRead (A2);
float battSensor = analogRead (A0);
const byte fanA = 7;
const byte fanB = 8;
const byte battTestSwitch = 4;



#include <Adafruit_GFX.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>
#include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc.
#include "Adafruit_LEDBackpack.h"

Adafruit_7segment matrix = Adafruit_7segment();

void setup() {
  pinMode(fanA,OUTPUT);
  pinMode(fanB,OUTPUT); 
  pinMode(battTestSwitch,INPUT_PULLUP);

Wire.setClock(100000);  // set SCL to slow speed
  
 #ifndef __AVR_ATtiny85__
  Serial.begin(9600);
  Serial.println("7 Segment Backpack Test"); 
#endif
  matrix.begin(0x70); 

  matrix.print(0x8888, HEX);
  matrix.writeDisplay();
  delay(1000);
  
  digitalWrite(fanA,LOW);
  digitalWrite(fanB,LOW);  
}

void loop() {
  
  int tempSensor = analogRead(A2);
  float realTemp = ((43.39 * (tempSensor * 5) / 1023) + 13.49); // temp calculation

  if (digitalRead (battTestSwitch) == LOW){ 
 // battVolts = analogRead(battSensor);
 float battSensor = analogRead (A0);
 float battVolts = ((battSensor * 5)/1023.0 * 4); // 20vdc is 5vdc at arduino

  // print a floating point 
  matrix.print(battVolts);
  matrix.writeDisplay();
  delay(2500);

   // print a hex number
  matrix.print(0xA55, HEX); // spells "ass" 
  matrix.writeDisplay();
  delay(800);

  matrix.print(0xFACE, HEX);
  matrix.writeDisplay();
  delay(800);

  }
  else {
    
      matrix.print(realTemp);
      matrix.writeDisplay();
      delay(1000);
  }
  if (realTemp > 185 ){
    digitalWrite(fanA,HIGH);   
  }
  else {
    digitalWrite(fanA,LOW);
    digitalWrite(fanB,LOW);
  }
  if (realTemp > 215){
    digitalWrite(fanA,HIGH);
    digitalWrite(fanB,HIGH);
  }
  else {
    digitalWrite(fanA,LOW);
    digitalWrite(fanB,LOW);
  }
}

thanks to all who helped with this.
my final code, and completely tested with relays and all. the only issue I had was a little bit of power loss due to the fact that its running on a 9vdc batt right now. should work with the hardware I have chosen for power supply in my real life build.

/*************************************************** 
  This is a library for our I2C LED Backpacks

  Designed specifically to work with the Adafruit LED 7-Segment backpacks 
  ----> http://www.adafruit.com/products/881
  ----> http://www.adafruit.com/products/880
  ----> http://www.adafruit.com/products/879
  ----> http://www.adafruit.com/products/878

  These displays use I2C to communicate, 2 pins are required to 
  interface. There are multiple selectable I2C addresses. For backpacks
  with 2 Address Select pins: 0x70, 0x71, 0x72 or 0x73. For backpacks
  with 3 Address Select pins: 0x70 thru 0x77

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/
float tempSensor = analogRead (A2);
float battSensor = analogRead (A0);
const byte fanA = 7;
const byte fanB = 8;
const byte battTestSwitch = 4;



#include <Adafruit_GFX.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>
#include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc.
#include "Adafruit_LEDBackpack.h"

Adafruit_7segment matrix = Adafruit_7segment();

void setup() {
  pinMode(fanA,OUTPUT);
  pinMode(fanB,OUTPUT); 
  pinMode(battTestSwitch,INPUT_PULLUP);

Wire.setClock(100000);  // set SCL to slow speed
  
 #ifndef __AVR_ATtiny85__
  Serial.begin(9600);
  Serial.println("7 Segment Backpack Test"); 
#endif
  matrix.begin(0x70); 

  matrix.print(0x8888, HEX);
  matrix.writeDisplay();
  delay(1000);
  
  digitalWrite(fanA,LOW);
  digitalWrite(fanB,LOW);  
}

void loop() {
  
  int tempSensor = analogRead(A2);
  float  realTemp = ((43.39 * (tempSensor * 5) / 1023) + 13.49); // temp calculation

  if (digitalRead (battTestSwitch) == LOW){ 
 // battVolts = analogRead(battSensor);
 float battSensor = analogRead (A0);
 float battVolts = ((battSensor * 5)/1023.0 * 4); // 20vdc is 5vdc at arduino

  // print a floating point 
  matrix.print(battVolts);
  matrix.writeDisplay();
  delay(2500);

   // print a hex number
  matrix.print(0xA55, HEX); // spells "ass" 
  matrix.writeDisplay();
  delay(800);

  matrix.print(0xFACE, HEX);
  matrix.writeDisplay();
  delay(800);

  }
  else {
    
     matrix.print(realTemp);
      matrix.writeDisplay();
      delay(2500);

  if (realTemp > 185 ){
    digitalWrite(fanA,HIGH);   
  }
  if (realTemp > 210){
    digitalWrite(fanA,HIGH);
    digitalWrite(fanB,HIGH);
  }
  if (realTemp < 175){      // to keep relay from bouncing
    digitalWrite(fanA,LOW);
    digitalWrite(fanB,LOW);
  }
  }

}

LandonW:
with that being said, does all that look correct?

OK, I did it in BASIC: Example of converting an Arduino ADC into a voltage where 0 is 0 and 1023 is 5.

[b]list
100 x1=0
110 x2=1023
120 y1=0
130 y2=5
140 m=(y1-y2)/(x1-x2)
150 b=y1-(m*x1)
160 x=512
170 y=(m*x)+b
180 print y[/b]

I plugged in "512" and got this:

[b]run
 2.502444
[/b]

Seems to me to be working.

Sticking in your values:

[b]list
100 x1=4.7
110 x2=1
120 y1=40
130 y2=190
140 m=(y1-y2)/(x1-x2)
150 b=y1-(m*x1)
160 print "m is "+str$(m)+", b is "+str$(b)
170 x=2.5
180 y=(m*x)+b
190 print x,y[/b]

...yields:

[b]run
m is -40.54054, b is  230.5405
 2.5           129.1892[/b]

LandonW:
code revision... found a x1, x2...y1,y2 mix up.
this is how I did it

Y=MX+B
M=(x1/x2) / (y1/y2) x1= 4.99, x2=0.01, y1=230, y2=20
M=43.39

You're doing it wrong.

dougp:
I'm not particularly familiar with it but, the map() function may work for you. The description on the reference page states you can reverse the order of the results by which values are used for high/low.

map() in Arduino is fubar because it only works with ints.

The proper thing to do is scrap is and re-write it with doubles, or else use Y=MX+B.

jremington:
Be sure to add excellent power protection circuitry to your project, at the very least a TVS diode.

Automotive electrical systems quickly fry unprotected electronics with occasional 125V spikes and even voltage reversals.

A clamping diode in a hostile environment is useless unless it switches faster than the transient you need to absorb.

That's why it's good (if possible) to feed vehicle power through a simple R/C filter to slow down transients so that the diode(s) can clamp them before it gets to the sensitive stuff.

Back in the '70s, car temp gages were usually a simple analog milliAmmeter in series with a nonlinear thermistor sensor, 1 wire from the gage and the engine block for ground, the gage dial was also nonlinear to match the sensor, numbers spread out on one end and scrunched up on the other.