EcoRenovator

EcoRenovator (https://ecorenovator.org/forum/index.php)
-   Geothermal & Heat Pumps (https://ecorenovator.org/forum/forumdisplay.php?f=10)
-   -   Arduino R290 Suction Line Superheat Calc. (https://ecorenovator.org/forum/showthread.php?t=4332)

buffalobillpatrick 02-14-15 04:37 PM

Arduino R290 Suction Line Superheat Calc.
 
Some Arduino code that calculates Suction Line Superheat for R290 (propane)

Saturation Temp / Pressure table:

HC-290 (PROPANE) PRESSURE - TEMPERATURE CHART

Must use a Pressure Sensor like this:
http://www.ebay.com/itm/271763798948...%3AMEBIDX%3AIT

Pressure must be between 30 -> 150PSI

Pressure Sensor & Temp sensor are placed close together on Suction Line.

Code:

/********************************************************
 *
 * ARDUINO R290 Calculate Suction Line Superheat.
 *
 * Note: REQUIRED SENSOR
 *      Suction Pressure Sensor:  0-150PSI with output of .5 -> 4.5vdc
 *
 * If in DEBUG mode, values are forced to test code function
 *
 * In Void Loop:
 *    , read Suction Temp sensor (analog NTC thermistor)
 *
 *    , read Suction PSI sensor
 *    , convert_raw_sensor_to_PSI
 *    , if input parameter Raw_ADC is not in bounds (between 266 -> 921)
 *    , hang forever1
 *
 *    , Calc_R290_Saturated_Temp
 *    , if input parameter Suction_PSI is not in bounds (between 30 -> 150PSI)
 *    , hang forever2
 *
 *    , calc Suction Superheat
 * Repeat
 *
 *
 * Change History:
 * 02/14/15 Coded, BBP
 *
 *
 *
 ********************************************************/

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
  #else
  #include "WProgram.h"
  #endif

#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>


#define DEBUG 1
//#define DEBUG 0


#define I2C_ADDR    0x3F // <<----- Add your address here.  Find it from I2C Scanner
                      //D3
#define BACKLIGHT_PIN    3  //define LCD digital pins
#define En_pin  2
#define Rw_pin  1            //can't use D0 & D1 Tx, Rx
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5              //can use D2 -> D12 below in code
#define D6_pin  6
#define D7_pin  7

LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

#define SDA                          A4  //RESERVE I2C for LCD         
#define SCL                          A5 

//  pinMode(A0, OUTPUT);    //This works acording
                            //  http://arduino.cc/en/Tutorial/AnalogInputPins
//  digitalWrite(A0, HIGH);  //


#define Suct_Temp_sensor_pin      A0
#define Suct_PSI_sensor_pin      A1
 
 
float  Raw_ADC, Suct_PSI, Suct_T, Saturated_Temp, Suct_Superheat;

int Y;



void setup(void)      //Start Setup
  {
       
  pinMode (Suct_Temp_sensor_pin,    INPUT);
  pinMode (Suct_PSI_sensor_pin,    INPUT);
 
 
 
 // Serial.begin(9600); // start serial communication
 // delay(10000);      //time to enable monitor window
 // Serial.println(F("........Hello world!......."));
 // delay(100);
 
 
  lcd.begin (16,2); //  <<----- My LCD is 16x2
  lcd.clear();
 
  //Switch on the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.setBacklight(HIGH);


  lcd.clear();
  lcd.home (); // go home
  lcd.print(F("R290_SUPERHEAT_1"));
  delay(10000);


  if(DEBUG)
  {     
  lcd.clear();
  lcd.home (); // go home
  lcd.print(F("DEBUG = ON"));
  delay(10000);
  }
  else
  {     
  lcd.clear();
  lcd.home (); // go home
  lcd.print(F("DEBUG = OFF"));
  delay(10000);
  }

  }    //end setup




  void loop ()
{

  Suct_T  =  (Read_10K_NTC (Suct_Temp_sensor_pin)); //read Suction Temp sensor
 
 
if(DEBUG){ Suct_T = 50;}
     
  lcd.clear();
  lcd.home (); // go home
  lcd.print(F("SUCT_T="));
  lcd.print(Suct_T); 
  lcd.print(F("*F"));
  delay(10000);
 
 
  Raw_ADC = analogRead(Suct_PSI_sensor_pin);  //read Suction PSI sensor
 
if(DEBUG){  Raw_ADC = 400;}

  Suct_PSI = convert_raw_sensor_to_PSI( Raw_ADC);
 
  lcd.clear();
  lcd.home (); // go home
  lcd.print(F("SUCT_PSI="));
  lcd.print(Suct_PSI); 
  delay(10000); 

 if (Suct_PSI == -1)  //Suct_PSI is out of bounds
  {
  lcd.clear();
  lcd.home (); // go home
  lcd.print(F("RAW_PSI_NG")); 
  lcd.setCursor(0,1);
  lcd.print(F("HANG_FOREVER_1")); 
  do{Y = Y;} while (Y == Y);  //hang forever
  }     
 
  else
  {  //else in bounds 
  Saturated_Temp = Calc_R290_Saturated_Temp(Suct_PSI);

  lcd.clear();
  lcd.home (); // go home
  lcd.print(F("SAT_T="));
  lcd.print(Saturated_Temp); 
  lcd.print(F("*F"));
  delay(10000);
 
  if (Saturated_Temp == -1)  //Suct_PSI is out of bounds
  {
  lcd.clear();
  lcd.home (); // go home
  lcd.print(F("SUCT_PSI_NG")); 
  lcd.setCursor(0,1);
  lcd.print(F("HANG_FOREVER_2")); 
  do{Y = Y;} while (Y == Y);  //hang forever
  }     
 
  else
  { 
  Suct_Superheat = Suct_T - Saturated_Temp;  //calc Suction Superheat
 
  lcd.clear();
  lcd.home (); // go home
  lcd.print(F("SUPRHEAT="));
  lcd.print(Suct_Superheat); 
  lcd.print(F("*F"));
  delay(10000);
  }
 
  }  //end else in bounds
 
}  //end forever loop





 
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}



//input parameter Raw_ADC must indicate between 30-150 PSI (266-921)
float convert_raw_sensor_to_PSI(float Raw_ADC)
{
  //Pressure sensor output .5v = 0PSI, 1.3v = 30PSI, 4.5v = 150PSI
  //analogRead results    .5v = 102,  1.3v = 266,  4.5v = 921
 
#define PSI_0                    102.0    //ADC of .5v
#define PSI_30                  266.0    //ADC of 1.3v
#define PSI_150                  921.0    //ADC of 4.5v
#define PSI_max                  150.0

float PSI;

  if ((Raw_ADC >= PSI_30) && (Raw_ADC <= PSI_150)) //Bounds check
  {
  // in bounds, continue
 
  PSI = mapfloat(Raw_ADC, PSI_30, PSI_150, 30.0, 150.0);
 
  return (PSI);
 
  }  //end if in bounds
 
  else {return (-1);}      // error return, out of bounds 
 
}  //end of convert_raw_sensor_to_PSI




//input parameter Suction_PSI must be between 30-150 PSI
float Calc_R290_Saturated_Temp(float Suction_PSI)
{

#define Array_size            14

//Array element [0]  contains Saturation_Temp *F for 30PSI,
//Array element [1]  contains Saturation_Temp *F for 40PSI,...................>
//Array element [12] contains Saturation_Temp *F for 150PSI,
//Array element [13] contains Saturation_Temp *F for 160PSI

float R290_Saturation_Temp [Array_size] = {7.93, 18.80, 28.42, 36.91, 44.59,
                                          51.63, 58.13, 64.21, 69.90, 75.27,
                                          80.35, 85.18, 89.78, 94.19};
                               
float Val, Next_val, Span, Saturation_Temp, decimals, work;

int I;

  if ((Suction_PSI >= 30.0) && (Suction_PSI <= 150.0)) //Bounds check
  {
  // in bounds, continue
 
  //convert Suction_PSI to array index
  work = ((Suction_PSI - 30.0) / 10.0);
 
  I = work;                                //drop decimals to get array index
 
  decimals = work - I; //restore decimals to allow interpolation between array points
 
  Val = R290_Saturation_Temp[I];          //get array value
  Next_val = R290_Saturation_Temp[I+1];    //get Next array value
 
  Span = Next_val - Val;                  //Calc Span

  Saturation_Temp = Val + (Span * decimals);//interpolate between array points

  return (Saturation_Temp);       

  }  //end if in bounds
 
  else {return (-1);}      // error return, out of bounds

}  // end Calc_R290_Saturated_Temp





int Read_10K_NTC (int which_sensor)

  #define sample_cnt 30
 
  float alpha =  0.9;    // factor to tune
  float average = 0.0;
  float steinhart;
 
  int I;
 
// resistance at 25 degrees C
#define THERMISTORNOMINAL 10000

// TEMP. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25

// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3892

// the value of the series resistor
#define SERIESRESISTOR 10000



 
  for (I=0; I< sample_cnt; I++)
  { 
  average =  alpha * analogRead(which_sensor) + (1-alpha) * average;
  delay(10);
  }
 
  // convert the value to resistance
  average = 1023 / average - 1;
  average = SERIESRESISTOR / average;
  steinhart = average / THERMISTORNOMINAL;    // (R/Ro)
  steinhart = log(steinhart);                  // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                  // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                // Invert
  steinhart -= 273.15;                        // convert to C
 
  return (round(steinhart * 1.8) + 32);      // round to whole number
                                              // & convert to F           
}  // end of Read_10K_NTC


Mikesolar 02-14-15 05:21 PM

BBP, did you write all this? If so, I'm impressed:D

Now, could there be one written for subcooling which can control an EEV

buffalobillpatrick 02-14-15 05:34 PM

Yep wrote it. Got the idea from BradC post

http://ecorenovator.org/forum/geothe...-gas-gear.html


"I've built the R290 PT Chart into the software, and that pressure sensor is a Carel ratiometric. The LCD gives me the saturated suction temperature (SST), and also the real temperature from the little silver probe (A Dallas DS18B20 digital unit) so I can instantly see the real-time evaporator temperature and superheat. The rotary encoder on the panel allows me full manual control over the EEV, so I can twiddle the knob and observe the effects."

NiHaoMike 02-14-15 10:32 PM

Using a pressure sensor is the hard way. All you need are two temperature sensors.

Mikesolar 02-15-15 07:39 AM

I wish i had the knowledge to write code but I don't.... yet. I am a programming luddite so it is really hard for me.:D

BBP, could you write one with 1 thermister instead of the pressure sensor and the thermister? If you want to replicate a standard TXV, one would be enough, no?

I looked on the Fujitsu circuit diagrams and do not see a pressure sensor anywhere, just numerous thermisters. As they are just plug in to the board, I don't know if one or two (or three) are used to control the EEV

buffalobillpatrick 02-15-15 11:31 AM

NiHaoMike, where would those 2 temp. sensors be placed on a coax evaporator?

See: post #108

http://ecorenovator.org/forum/geothe...html#post39145

NiHaoMike 02-15-15 12:00 PM

One on the line between the TXV outlet and heat exchanger, one on the suction line a few inches from the heat exchanger.

buffalobillpatrick 02-15-15 01:01 PM

NiHaoMike, I don't see how that can work?

That seems to assume that the refrigerant temperature going into the evaporator is exactly the temperature that ALL of the evaporation takes place?

Could't there be some sensible warming of the refrigerant in the input area of evaporator prior to the latient boiling?

Especially with a lot of Subcooling prior to TXV.

buffalobillpatrick 02-15-15 01:15 PM

Mikesolar, I think that Subcooling would be easy to add & I think that I will work on that next.

I don't know anything about controlling EEV's, I refer to others like BradC. who used a stepper motor.

Mikesolar 02-16-15 09:03 AM

One thing to remember about subcooling as that the action of the valve would be inverse to that of superheat. Where a normal TXV will open in response to a higher SH (bulb temp), the subcooling valve closes in response to a higher SC (or bulb temp).

I will have to look at Brads thread to see if he did any PID control.


All times are GMT -5. The time now is 03:30 PM.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Ad Management by RedTyger