Author Topic: Arduino Based Datalogger  (Read 736 times)

0 Members and 1 Guest are viewing this topic.

SparWeb

  • SuperHero Member
  • ******
  • Posts: 3266
  • Country: ca
    • Wind Turbine Project Field Notes
Arduino Based Datalogger
« on: September 11, 2017, 11:27:57 PM »
My personal "Rock of Sysiphus".  I've built two dataloggers before, but neither worked very well.
There wasn't anything particularly wrong with the other datalogger recipe projects, they just weren't suitable for my equipment.
The first was the Backshed PIClog, however the tachometer data was useless coming from my motor-conversion projects and the current measurement was far too crude.
My second was an attempt to add many features to a 28-pin PICAxe chip, but I got drowned in all the little details of building the board for the thing, which comes as a single microchip and needs all the power supply, clock, memory, interfacing, and pin impedance protection details taken care of before every thinking of hooking up an analog input!  Furthermore I still didn't have a good tachometer strategy so I would have ended up with more dud RPM data.

I finally hit on the tachometer solution which I documented here:
http://www.fieldlines.com/index.php/topic,149270.0.html
The key was realizing that no matter what warped and scrambled waveform comes out of my motor conversions, it comes to one phase, then the second, then the third, and then repeats - so instead of trying to measure peaks or times, all I really needed to do was cycle through series of triggers, one phase at a time, until it came back to the first.
Here's an example of the messy waveform I'm dealing with:



Yes this project was also an opportunity to invest in a classic Tek 422 oscilloscope.  Nothing newer than 1960's technology for me!



I got that tachometer working nicely back in July, and spend the next month figuring out if I wanted to make it a real data logger and pack more stuff into the box...  Yes I do!

Here are photos from July, after I "packaged" the tachometer with a pretty LCD display and everything.







I am finally able to see my way through a whole datalogger project that could actually monitor my complete system.  So far I've got 4 channels of current measurement, 4 channels of "misc" analog inputs, and a LCD display.  The analogs are all scaled 6:1 right now so that I can measure up to 30V anywhere in the system (eg. battery, solar, wind).  The Arduino runs at 5V so these analog inputs have a 5k+1k voltage divider to scale them.  At least one more (unscaled) analog input is needed so that I can measure temperature, allowing me to calibrate the current measurement somewhat.  The current sensors are boxed up separately so I'll show them later in a separate post. 

Since I'm using an Arduino MEGA 256, the board has lots of spare digital pins that I haven't used yet, but only a dozen or so analog inputs.  I have space set aside for 2 more analog inputs but there are still some more - for anything I've forgotten!  I'm running out of space anyway on the expansion board that's stacked on top.  It's getting a lot more crowded than it was in July when I took that last photo. 

I started this post before realizing that I haven't unloaded the most recent photos from my phone, which shows the current look of the datalogger.  Updates coming shortly then!
No one believes the theory except the one who developed it.  Everyone believes the experiment except the one who ran it.

System spec: 135w BP multicrystalline panels, regulated by Xantrex C40, DIY 8ft diameter wind turbine, regulated by Tri-Star TS60, 800AH x 24V AGM Battery, Xantrex SW4024

SparWeb

  • SuperHero Member
  • ******
  • Posts: 3266
  • Country: ca
    • Wind Turbine Project Field Notes
Re: Arduino Based Datalogger
« Reply #1 on: September 13, 2017, 11:43:07 PM »
Here's the schematic I'm working on:




Part 2 of the schematic:

No one believes the theory except the one who developed it.  Everyone believes the experiment except the one who ran it.

System spec: 135w BP multicrystalline panels, regulated by Xantrex C40, DIY 8ft diameter wind turbine, regulated by Tri-Star TS60, 800AH x 24V AGM Battery, Xantrex SW4024

SparWeb

  • SuperHero Member
  • ******
  • Posts: 3266
  • Country: ca
    • Wind Turbine Project Field Notes
Re: Arduino Based Datalogger
« Reply #2 on: September 27, 2017, 10:41:49 PM »
Quick update:
Lots of pieces have been added since the last posting.
I installed the kit in my system 2 weeks ago, and I'm pleased to see BELIEVABLE RPM numbers now!
I also hooked up the current sensing box, but now I have decided that running the current carrying wires to that box I should be running the sensors to the current-carrying wires.
This will force me to re-built the box a bit.  While the circuit board itself is fine, I need to run data connections out where there used to be a big-a$$ terminal block.

I have also added a bank of 6:1 scaled voltage dividers to I can connect any pin to any voltage up to 30V safely and get a proper voltage reading on the LCD.  I have only calibrated 1 channel (battery voltage) so far but the process for the rest will be just the same as for the first.

Below: the current sensor box with the sensors inside.  I'm not sticking with this arrangement but for the sake of displaying where I am right now...


Below: layout of equipment on the wall as it was last weekend.  At the very top: 12V fusebox.  Next row, from left to right:  Wind Charge controller (Morningstar TS60) - Datalogger - Solar charge controller (Xantrex C40) - current sensor box.  Photo was taken before much of the data stuff was hooked up, so the datalogger LCD still reads 0-0-0 for most things.  The wind AC comes in through the blue CAT-5 cable so that works at least.
« Last Edit: September 27, 2017, 10:45:58 PM by SparWeb »
No one believes the theory except the one who developed it.  Everyone believes the experiment except the one who ran it.

System spec: 135w BP multicrystalline panels, regulated by Xantrex C40, DIY 8ft diameter wind turbine, regulated by Tri-Star TS60, 800AH x 24V AGM Battery, Xantrex SW4024

SparWeb

  • SuperHero Member
  • ******
  • Posts: 3266
  • Country: ca
    • Wind Turbine Project Field Notes
Re: Arduino Based Datalogger
« Reply #3 on: October 04, 2017, 10:48:45 PM »
Another test run, this time with RPM, voltage, current, and timestamps all coming in simultaneously.



The output graphs look like this:



Very happy!
This is just 10 minutes of data, and there is a long way to go yet, but so nice to see believable numbers coming out of the system.
No one believes the theory except the one who developed it.  Everyone believes the experiment except the one who ran it.

System spec: 135w BP multicrystalline panels, regulated by Xantrex C40, DIY 8ft diameter wind turbine, regulated by Tri-Star TS60, 800AH x 24V AGM Battery, Xantrex SW4024

SparWeb

  • SuperHero Member
  • ******
  • Posts: 3266
  • Country: ca
    • Wind Turbine Project Field Notes
Re: Arduino Based Datalogger
« Reply #4 on: October 04, 2017, 10:58:10 PM »
Here's the schematic, in 2 parts:






And the code:

Code: [Select]
/*  Arduino-based Wind Turbine Datalogger - Steven Fahey - October 1, 2017
 *  REQUIRES ATMEGA 2560 FOR 3 INTERRUPT PINS (alternatives are Arduino Zero, Due or Leonardo)
 * May 2017
 *  Tachometer reads the state of 3 pins as interrupts in order to monitor their change
 *  in state sequentially.  By reading their state in sequence, the program can accurately
 *  measure the speed of a 3-phase generator without mistaking brief noise pulses for the
 *  main pulses. Each of the 3 interrupt pins is connected to a separate phase, and a voltage
 *  divider ties each pin to ground until the sine pulse is positive for each phase.  The
 *  voltage divider requires that a threshold of voltage is passed before the pin changes
 *  to a HIGH state.  The state of each phase is tracked with logical operators, toggled by
 *  each interrupt, rather than attempting to measure the state of the phases simultaneously.
 * July 17
 *  LCD screen is powered from digital I/O pins 21, 23, 27, 29.
 *  LCD screen may be turned off by a switch connected to digital pin 53 and ground.
 * Sept 22
 *  External Analog connections added. Roughly calibrated (but not yet temperature compensated).
 *  Formatted output to LCD using dtostrf(FLOAT,WIDTH,PRECSISION,BUFFER);
 *    FLOAT     the floating-point variable to be converted into a formatted string
 *    WIDTH     total size of string - make sure to include space for negative sign
 *    PRECISION number of decimal places expressed (don't count the decimal point
 *    BUFFER    string variable used to contain the output, create with "char val[n]"
 * Analog inputs list (applicable to AtMega2560):
 *    Pin    Purpose                   Circuit Confguration
 *    0-3    Analog inputs 0 1 2 3     received voltage scaled 1:1
 *    4-7    Analog inputs 4 5 6 7     received voltage scaled 1:6
 *    8-9    Vref from Current box     received voltage used as a factor to scale current values
 *    10-13  I0-I3 from Current box    received voltage converted to Amps + calibrated
 *    14-15  Negative from Current box (GROUNDED)
 * Future:
 *  Connect & calibrate temperature sensors on one or more analog input pins 0 thru 3.
 *  Connect to PWM pins for PULSIN() readings of PWM controllers (ie. Diversion load/solar load).
 *  Sample & average voltage & current readings.
 *  Real time clock?
 */

// LCD Libraries:
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>

// Tachometer Pins
const byte inPin1 = 18;         // Phase 1 monitoring pin
const byte inPin2 = 2;          // Phase 2 monitoring pin
const byte inPin3 = 3;          // Phase 3 monitoring pin

// LCD Control Pins
const byte lcdPower1 = 21;      // digital I/O pin used to power LCD +5V
const byte lcdPower2 = 23;      // digital I/O pin used to power LCD +5V
const byte lcdGnd1 = 27;        // digital I/O pin used to power LCD GND
const byte lcdGnd2 = 29;        // digital I/O pin used to power LCD GND
const byte lcdOffPin = 53;      // digital I/O pin used to control LCD power (toggled On or Off by external switch)

// I2C USES PINS 20 & 21
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// Name the backlight colours
#define RED 0x1
#define GREEN 0x2
#define YELLOW 0x3
#define BLUE 0x4
#define VIOLET 0x5
#define TEAL 0x6
#define WHITE 0x7
#define WHAT 0x8

// setup variables for tachometer & program flow control

int k = 0;                      // counter of samples in the average speed
const int N = 10;               // total 10 samples in the average
int check = 0;                  // Counter that runs endlessly until output time
unsigned long time0 = 0;        // holds previous phase 1 time
unsigned long time1 = 0;        // holds current phase 1 time
unsigned long time2 = 0;        // time measured to determine delay since last AC interrupt (and switch to STOP if too long)
float time3f = 0.0;             // current time, converted to seconds, since last restart
char time3s [10];               // time since last restart, converted to string for display
unsigned long period[N+5];      // Array that holds the period of N pulses (plus a few extra to allow the output to catch up).
unsigned long total = 0;        // total value of N periods
float average = 0;              // average value of N periods (to smooth the output).
float speedy = 0;               // Speed of the machine.
char speeds [10];               // string format for screen output (turbine speed)
int screen = 1;                 // state of LCD screen (0 = off, 1 = on)

// ANALOG INPUT DATA (TEMPERATURE, VOLTAGE, CURRENT)
float Tbatt = 0.0;                  // Temperature of Battery
float Tcurr = 0.0;                  // Temperature in Current sensor box
char Tbats [10];                    // String format for screen output ( Battery temp )
char Tcurs [10];                    // String format for screen output ( Current sensor temp )
char Vbatt [10];                    // String format for screen output ( Battery voltage )
float V0 = 0.0;                     // Voltage read on analog pin 0 (5v max) UNUSED
float V1 = 0.0;                     // Voltage read on analog pin 1 (5v max) UNUSED
float V2 = 0.0;                     // Voltage read on analog pin 2 (5v max) UNUSED

float V4 = 0.0;                     // Voltage read on analog pin 4 (30 max)
float V5 = 0.0;                     // Voltage read on analog pin 5 (30 max)
float V6 = 0.0;                     // Voltage read on analog pin 6 (30 max)
float V7 = 0.0;                     // Voltage read on analog pin 7 (30 max)

float V8 = 0.0;                     // Current sensors reference voltage
char Vcref [10];                    // String format for screen output
float V10 = 0.0;                    // Voltage read on analog pin 10 (current sensor 0)
float V11 = 0.0;                    // Voltage read on analog pin 11 (current sensor 1)
float V12 = 0.0;                    // Voltage read on analog pin 12 (current sensor 2)
float V13 = 0.0;                    // Voltage read on analog pin 13 (current box temp)
float I_0 = 0.0;                    // Current sensor 0
float I_1 = 0.0;                    // Current sensor 1
float I_2 = 0.0;                    // Current sensor 2
float I_3 = 0.0;                    // Current sensor 3
char I0s [10];                  // String format for screen output (Current sensors)
char I1s [10];                  // String format for screen output (Current sensors)
char I2s [10];                  // String format for screen output (Current sensors)
char I3s [10];                  // String format for screen output (Current sensors)

int an_00 = 0;                  // analog pin 0 data reading
int an_01 = 0;                  // analog pin 1 data reading
int an_02 = 0;                  // analog pin 2 data reading

int an_04 = 0;                  // analog pin 4 data reading
int an_05 = 0;                  // analog pin 5 data reading
int an_06 = 0;                  // analog pin 6 data reading
int an_07 = 0;                  // analog pin 7 data reading

int an_08 = 0;                  // analog pin 8 data reading
int an_09 = 0;                  // analog pin 9 data reading
int an_10 = 0;                  // analog pin 10 data reading
int an_11 = 0;                  // analog pin 11 data reading
int an_12 = 0;                  // analog pin 12 data reading
int an_13 = 0;                  // analog pin 13 data reading

// linear conversion factors (5v / 1023 bits = 0.0048876 v/bit)
const float m_00 = 0.0048876;              // slope of analog conversion, pin 0 (0.0048876=5/1023)
const float m_01 = 0.00465;              // slope of analog conversion, pin 1 (0.0048876=5/1023)
const float m_02 = 0.0048876;              // slope of analog conversion, pin 2 (0.0048876=5/1023)

const float m_04 = 0.0297;              // slope of analog conversion, pin 4 (0.0293255=30/1023)
const float m_05 = 0.0297;              // slope of analog conversion, pin 5
const float m_06 = 0.0283;              // slope of analog conversion, pin 6
const float m_07 = 0.0285;              // slope of analog conversion, pin 7  (rounded down to correct)

const float m_08 = 0.00466;              // slope of analog conversion, pin 8 (rounded down to correct)
const float m_10 = 0.00461;              // slope of analog conversion, pin 10
const float m_11 = 0.00468;              // slope of analog conversion, pin 11
const float m_12 = 0.00466;              // slope of analog conversion, pin 12

const float m_13 = 0.0048876;              // slope of analog conversion, pin 13

const float of_00 = 0.0;              // offset of analog conversion, pin 0
const float of_01 = 0.0;              // offset of analog conversion, pin 1
const float of_02 = 0.0;              // offset of analog conversion, pin 2

const float of_04 = 0.0;              // offset of analog conversion, pin 4
const float of_05 = 0.0;              // offset of analog conversion, pin 5
const float of_06 = 0.0;              // offset of analog conversion, pin 6
const float of_07 = 0.0;              // offset of analog conversion, pin 7

const float of_08 = 0.0;        // offset of analog conversion, pin 8 and 9
const float of_10 = -0.775;     // offset of analog conversion, pin 10 [observed I0=1.8 and 1.8 / K_amploc1 = 0.775 (temperature 0C at the time)]
const float of_11 = -0.775;     // offset of analog conversion, pin 11
const float of_12 = -0.775;     // offset of analog conversion, pin 12
const float of_13 = 0.0;        // offset of analog conversion, pin 13

const float K_amploc1 = 0.023 * 1.7666 * 1.000;      /* conversion factor for amploc current sensor (dV/A)
                                        0.023 mV/A at standard V=5.0 supply voltage
                                        1 turn of wire through the sensor [AS INSTALLED 1 OCT 2017]
                                        Supplied with 9V instead of 5V (8.83/5= 1.7666)
                                        calibration factor was 1.06
                                        I0 calibration 1.000
                                        I1 calibration 1.000
                                        I2 calibration 1.000
                                        I2 calibration 1.000
                                        */ 
const float K_speed = 1000000*60/2;    /* conversion factor microseconds into seconds
                                        * 1,000,000 microseconds per second
                                        * 60 seconds per minute
                                        * 4 poles -> _2_ pulses per phase per revolution
                                        */
const float K_temp = 1.0;             // temperature scale factor wrt voltage on analog pin (0-3 & 13)
const float Off_temp = 0.0;           // temperature offset wrt voltage on analog pin (0-3 & 13)

// float K_temp_bat = 1.0;             // temperature correction factor for battery voltage
// float Off_temp_bat = 0.0;           // temperature offset factor for battery voltage
// float K_temp_cur = 1.0;             // temperature correction factor for current sensors
// float Off_temp_cur = 0.0;           // temperature offset factor for current sensors

boolean a = false;                 // Logical values of the state of phases a, b, and c.
boolean b = false;                 // These logic values are independent of the digital pin state.
boolean c = true;                  // They are set and changed only when conditions are correct.

void setup() {
  pinMode(lcdPower1, OUTPUT);             // initialize the pins used to power the LCD
  pinMode(lcdPower2, OUTPUT);             // initialize the pins used to power the LCD
  pinMode(lcdGnd1, OUTPUT);               // initialize the pins used to power the LCD
  pinMode(lcdGnd2, OUTPUT);               // initialize the pins used to power the LCD
  pinMode(lcdOffPin, INPUT_PULLUP);       // initialize the pins used to control the LCD (pull up HIGH by default)

  Serial.begin(9600);                     // initialize serial communications at 9600 bps

  lcdOnConfig();                          // initialize the LCD screen
  screen = 1;                             // show that LCD status is now ON

  attachInterrupt(digitalPinToInterrupt(inPin1), interrupt1, RISING);     // configure interrupt1
  attachInterrupt(digitalPinToInterrupt(inPin2), interrupt2, RISING);     // configure interrupt2
  attachInterrupt(digitalPinToInterrupt(inPin3), interrupt3, RISING);     // configure interrupt3

}

void interrupt1() {
  if (a== false && b == false && c == true) {   // if this pulse doesn't follow interrupt 3 it won't do anything
    a=true;
    c=false;
    noInterrupts ();                  /* pause the interrupts, to allow time for the multi-byte long variables
                                       * to be stored.  While this won't take as long as the next phase pulse
                                       * (over 10 msec later) there may be line spikes due to switching or
                                       * harmonics etc. which are much more rapid.                     */
    time1 = micros();                 // get the current time
    period[k] = time1 - time0;        // elapsed time since last phase 1 pulse
    k++;                              // count the number of times entering this interrupt
    time0 = time1;                    // assign current time to previous time variable for use next cycle
    interrupts ();                    // reinstate interrupts
  }
}

void interrupt2() {
  if (a== true && b == false && c == false) {   // if this pulse doesn't follow interrupt 1  it won't do anything
    b=true;
    a=false;
  }
}

void interrupt3() {
  if (a== false && b == true && c == false) {   // if this pulse doesn't follow interrupt 2 it won't do anything
    c=true;
    b=false;
  }
}

void serialDisplay() {
/*  Serial.print("  V1 ");
  Serial.print(V1);
  Serial.print("  V4 ");
  Serial.print(V4);
  Serial.print("  V5 ");
  Serial.print(V5);
  Serial.print("  V6 ");
  Serial.print(V6);
  Serial.print("  V7 ");
  Serial.print(V7);
  Serial.print("  --  ");
  Serial.print("  V8 ");
  Serial.print(V8);
  Serial.print("  Vcref ");
  Serial.print(Vcref);
  Serial.print("  V10 ");
  Serial.print(V10);
  Serial.print("  V11 ");
  Serial.print(V11);
  Serial.print("  V12 ");
  Serial.print(V12);
  Serial.print("  V13 ");
  Serial.print(an_13);
  Serial.print("  I0 ");
  Serial.print(I_0);
  Serial.print("  I1 ");
  Serial.print(I_1);
  Serial.print("  I1s ");
  Serial.print(I1s);
  Serial.print("  I2 ");
  Serial.print(I_2);
  Serial.print("  --  ");
  Serial.print("  TempCurrent=");
  Serial.print(Tbatt);
  Serial.print("  TempBatt=");
  Serial.print(Tcurr);
  */
  Serial.print(" time= ");
  Serial.print(time3s);                       // Current time (seconds since last restart)
  Serial.print(" sec | Vbatt= ");
  Serial.print(Vbatt);                        // Battery Voltage (read from Analog 4)
  Serial.print(" V | Iwind= ");
  Serial.print(I0s);                          // Wind Turbine current (read from current sensor at battery terminal)
  Serial.print(" V | Idiversion= ");
  Serial.print(I2s);                          // Diversion current (read from current sensor in TS60 controller)
  Serial.print(" A | speed= ");
  Serial.println(speedy);                     // Wind Turbine speed
}

void serialTrouble() {                        // for troubleshooting purposes only
  Serial.print(" average= "); 
  Serial.print(average);
  Serial.print(", ");

  for (int j = 0; j <= N+1 ; j++) {           // Show all "k" values in period[] array
    Serial.print(j);
    Serial.print(", ");
    Serial.print(period[j]);
    Serial.print(", ");
  }

  Serial.print(" a= "); 
  Serial.print(a);
  Serial.print(" b= "); 
  Serial.print(b);
  Serial.print(" c= "); 
  Serial.print(c);
  Serial.print(" check "); 
  Serial.println(check);
}

void lcdOnConfig() {
  digitalWrite(lcdGnd1, LOW);              // Activates the return to ground (before turning LCD on)
  digitalWrite(lcdGnd2, LOW);              // Activates the return to ground (before turning LCD on)
  digitalWrite(lcdPower1, HIGH);           // Turns power to LCD on.
  digitalWrite(lcdPower2, HIGH);           // adds extra power channel (in case the LCD needs it)

  lcd.begin(16, 2);                        // set up the LCD's number of columns and rows:
  lcd.setBacklight(RED);
  delay(200);                              // flash red briefly
  lcd.clear();
  lcd.setCursor(0,0);                 
  lcd.setBacklight(WHITE);
  lcd.print("     V       RPM");           // Prepares to output battery voltage and WT speed
  lcd.setCursor(0,1);                 
  lcd.print("    A    A    A");            // Prepares to output current and temperature data
  delay(500);                              // wait for 1/2 second
  screen = 1;                              // variable shows that screen status on ON
}

void lcdOff() {
  digitalWrite(lcdPower1, LOW);              //
  digitalWrite(lcdPower2, LOW);              // ALL FOUR are required
  digitalWrite(lcdGnd1, HIGH);               // to turn power to LCD off.
  digitalWrite(lcdGnd2, HIGH);               //
  screen = 0;                                // variable shows that screen status on OFF
}

void lcdDisplay() {                          // DISPLAY SPEED ON THE LCD
  if (speedy < 10) {                         // test the speed for its range
    lcd.setBacklight(TEAL);                  //
  } else if (speedy < 160) {                 //
    lcd.setBacklight(GREEN);                 //
  } else if (speedy < 500) {                 //
    lcd.setBacklight(YELLOW);                // change background colour depending on the speed range
  } else if (speedy < 800) {                 //
    lcd.setBacklight(RED);                   //
  } else {                                   //
    lcd.setBacklight(RED);                   // in case there is no valid speed value
  }

  lcd.setCursor(0,0);
  lcd.print("b    V");                       // refresh the text on the screen
  lcd.setCursor(1,0);
  lcd.print(Vbatt);                          // Display Battery Voltage

  lcd.setCursor(6, 0);                       // put the cursor in position to show speed number
  if (speedy < 10) {                         // test the speed for its range
    lcd.print("  STOP ");                    // Stop condition is displayed on LCD
  } else if (speedy < 1000) {
      lcd.print(speeds);                     // machine speed is displayed on LCD (no decimal places)
  } else if (speedy >= 1000) {
    lcd.print("DANGER ");                    // OVERSPEED WARNING
  } else {
    lcd.print(" ERROR ");                    // something must be wrong if we get here!
  }

  lcd.setCursor(13,0);               
  lcd.print("RPM");                          // refresh the text on the screen

  lcd.setCursor(0,1);
  lcd.print(I0s);                            // Display Wind Current

//  lcd.setCursor(5,1);
//  lcd.print(I1s);                            // Display Solar Current

  lcd.setCursor(10,1);
  lcd.print(I2s);                            // Display Diversion Current

//  lcd.setCursor(11,1);
//  lcd.print(Tbatt);
}

void chekTemp() {                             // Measure the temperature
  an_01 = analogRead(1);                      // Read analog input from external temp probe (analog pin 1)
  an_13 = analogRead(13);                     // Read analog input from current box
  V1 = an_01 * m_01 + of_01;                  // convert to voltage on A1 pin
  Tbatt = V1 * K_temp + Off_temp;             // convert to external temperature
  dtostrf(Tbatt,4,1,Tbats);                   // string formatted Temp for print() only

  V13 = an_13 * m_13 + of_13;                 // convert to voltage on A13 pin
  Tcurr = V13 * K_temp + Off_temp;            // convert to temperature in current box
  dtostrf(Tcurr,4,1,Tcurs);                   // string formatted Temp for print() only

//  K_temp_bat = 1.0 * (Tbatt/20) + 0.0;        // calibration constant for battery voltage
//  K_temp_cur = 1.0 * (Tcurr/20) + 0.0;        // calibration constant for current reference voltage
}

void chekV4() {                               // Measure the voltage on analog pin 4
  an_04 = analogRead(4);                      // Read analog input
  V4 = an_04 * m_04 + of_04;                  // convert to voltage
//  V4 = V4 * K_temp_bat + Off_temp_bat;        // calibrated voltage value (4)
//  dtostrf(V4,4,1,V ?);                        // string formatted V ?? for print() only
}
void chekV5() {                               // Measure the voltage on analog pin 5
  an_05 = analogRead(5);                      // Read analog input
  V5 = an_05 * m_05 + of_05;                  // convert to voltage
//  V5 = V5 * K_temp_bat + Off_temp_bat;        // calibrated voltage value (5)
  dtostrf(V5,4,1,Vbatt);                      // string formatted Vbatt for print() only
}
void chekV6() {                               // Measure the voltage on analog pin 6
  an_06 = analogRead(6);                      // Read analog input
  V6 = an_06 * m_06 + of_06;                  // convert to voltage
//  V6 = V6 * K_temp_bat + Off_temp_bat;        // calibrated voltage value (6)
//  dtostrf(V5,4,1,V???);                       // string formatted V ??? for print() only
}
void chekV7() {                               // Measure the voltage on analog pin 7
  an_07 = analogRead(7);                      // Read analog input
  V7 = an_07 * m_07 + of_07;                  // convert to voltage
//  V7 = V7 * K_temp_bat + Off_temp_bat;        // calibrated voltage value (7)
//  dtostrf(V5,4,1,V???);                       // string formatted V ??? for print() only
}

void chekVref() {                              // Measure the battery voltage
  an_08 = (analogRead(8) + analogRead(9))/2;   // Read analog input - average of 2 inputs
  V8 = an_08 * m_08 + of_08;                   // convert to average voltage value
  dtostrf(V8,5,2,Vcref);                       // string formatted Vcref for print() only
}

void chekI_0() {                               // Measure the on circuit 0
  an_10 = analogRead(10);                      // read current sensor 0 on analog pin 10
  V10 = an_10 * m_10 + of_10;                  // convert to voltage value
//  V10 = V10 * K_temp_cur + Off_temp_cur;       // calibrated voltage value (10)
  I_0 = (V8 - V10) / K_amploc1;                // convert to current value
  dtostrf(I_0,4,1,I0s);                        // string formatted I0 for print() only
}

void chekI_1() {                               // Measure the on circuit 1
  an_11 = analogRead(11);                      // read current sensor 1 on analog pin 11
  V11 = an_11 * m_11 + of_11;                  // convert to voltage value
//  V11 = V11 * K_temp_cur + Off_temp_cur;       // calibrated voltage value (11)
  I_1 = (V8 - V11) / K_amploc1;                // convert to current value
  dtostrf(I_1,4,1,I1s);                        // string formatted I1 for print() only
}

void chekI_2() {                               // Measure the current on circuit 2
  an_12 = analogRead(12);                      // read current sensor 2 on analog pin 12
  V12 = an_12 * m_12 + of_12;                  // convert to voltage value
//  V12 = V12 * K_temp_cur + Off_temp_cur;       // calibrated voltage value (12)
  I_2 = (V8 - V12) / K_amploc1;                // convert to current value
  dtostrf(I_2,4,1,I2s);                        // string formatted I2 for print() only
}

void chekI_3() {                                // Measure the current on circuit 3
  an_13 = analogRead(13);                       // read current sensor 3 on analog pin 13
  V13 = an_13 * m_13 + of_13;                   // convert to voltage value
//  V13 = V13 * K_temp_cur + Off_temp_cur;        // calibrated voltage value (13)
  I_3 = (V8 - V13) / K_amploc1;                 // convert to current value
  dtostrf(I_3,4,1,I3s);                         // string formatted I3 for print() only
}

void calcSpeed() {                              // CALCULATE THE SPEED OF THE MACHINE
  total = 0;
  average = 0;                                  // reset all values
  speedy = 0;
  time2 = micros();                             // get the current time
  if ((time2-time1)/1000000 >= 5) {             // check that time since last interrupt hasn't been over 5 seconds
    total = 0;                                  // cancel the speed calculation if it seems to be stopped
  } else {
    for (int j = 1; j <= N ; j++) {             // the "j" loop counter used in array argument for all k
      total = total + period[j];                // total of N period measurements
    }
  }
  average = total/(N);                          // average period
  speedy = K_speed / average;                   // calculate speed of machine
  dtostrf(speedy,6,0,speeds);                   // string formatted speed RPM for print() only
  unsigned long period[N+5];                    // Fresh declaration of the array that holds the period of N pulses
}

void lcdSwCheck() {
  if (digitalRead(lcdOffPin) == HIGH) {                          // check state of screenOffPin
    lcdOff();                                                    // if High, turn the LCD off
  } else if(digitalRead(lcdOffPin) == LOW && screen == 0) {      // if Low, and screen is still off, turn the LCD on
    lcdOnConfig();                                               // do not repeatedly send the ON/reset to the LCD!
    screen = 1;
  } 
}

void loop() {
//  lcdSwCheck();                         // check if user has turned the LCD On or Off
  if (k <= N) {                         // Have there been "N" samples of RPM?
    check++;                            // If not enough, go on counting
  } else {                              //
    calcSpeed();                        // once data array is full, compute average speed of the WT
    k=0;                                // reset the data counter
    check=0;                            // reset the check counter
  }
  time3f = micros()/ 1000000;         // get the current time, convert to seconds
  dtostrf(time3f,9,1,time3s);         // string formatted time for print() only
  chekTemp();                         // read temperature sensors on battery and current box
  chekV4();                           // Read battery voltage
  chekV5();                           // Read battery voltage
  chekV6();                           // Read battery voltage
  chekV7();                           // Read battery voltage
  chekVref();                         // Read current sensor reference voltage
  chekI_0();                          // Read WT current sensor
  chekI_1();                          // Read Solar current sensor
  chekI_2();                          // Read Diversion current sensor
  chekI_3();                          // Read * Load current sensor
  if (screen == 1) lcdDisplay();      // output data to LCD
  serialDisplay();                    // output normal data to serial port
}

500 lines, baby!  I've never written such a long program before.
No one believes the theory except the one who developed it.  Everyone believes the experiment except the one who ran it.

System spec: 135w BP multicrystalline panels, regulated by Xantrex C40, DIY 8ft diameter wind turbine, regulated by Tri-Star TS60, 800AH x 24V AGM Battery, Xantrex SW4024

Bruce S

  • Global Moderator
  • Super Hero Member Plus
  • *****
  • Posts: 4550
  • Country: us
  • USA
Re: Arduino Based Datalogger
« Reply #5 on: October 05, 2017, 07:05:49 AM »
It sure is nice to see the numbers in a visual format!

Are you using those numbers to switch between star and Jerry?

I've also found the twisted pairs of CAT5 to be a great way to move data along. Every time I think I need another run of it ,,, I pull 2 instead. I've learned the hard way I'll eventually need that 2nd one.

The "code" is pretty intense, it'll take me a few cups of coffee to step through it.

Congrats!!
A kind word often goes unsaid BUT never goes unheard

SparWeb

  • SuperHero Member
  • ******
  • Posts: 3266
  • Country: ca
    • Wind Turbine Project Field Notes
Re: Arduino Based Datalogger
« Reply #6 on: October 06, 2017, 12:26:39 PM »
Every time I look for a simple connector and cable for the data inputs, I look around and around, and find stuff that's hard to mount, hard to connect, hard to pay for...
Then there's CAT 5 (and its little brother CAT 3) and all my problems are solved.
I too, and very glad I took the time run a CAT 5 along with the power cables when I buried the lines to the tower!

Nothing so fancy as automatic switching on Star/Jerry or /Delta.  Up until a month ago, there was no way to know the turbine speed, so how would the speed switch work?
Now that I do have a known speed, all of these possibilities open up.

Did another run for data last night, just in Jerry.  Put the Oscope on it just for kicks, and at night the green flickering glow was kind of eerie!  :)
Plotted last night's data on the same graph, and the line runs STRAIGHT through the data from last weekend.  Wow.

Next thing will be to connect a temp sensor and put in temperature corrections.  It's already apparent that the current sensor offsets go off  (by about 2 amps) when the unit is taken out of the warm house and into the cold shed.  As you can see in the schematic, that's no surprise and been part of the plan all along.

Last night's test in very light winds showed that, in Star, a trickle of current does come in, but at that speed the threshold to activate the RPM isn't crossed.  I could only see RPM when switched to Jerry where the turbine turns much faster.  I think the voltage divider which steps the incoming AC down 1/6 is too steep and I should change it to a 1/4 voltage divider.  Unfortunately I would need to add some 5V zeners for protection and there's almost no room on the board any more!
No one believes the theory except the one who developed it.  Everyone believes the experiment except the one who ran it.

System spec: 135w BP multicrystalline panels, regulated by Xantrex C40, DIY 8ft diameter wind turbine, regulated by Tri-Star TS60, 800AH x 24V AGM Battery, Xantrex SW4024

SparWeb

  • SuperHero Member
  • ******
  • Posts: 3266
  • Country: ca
    • Wind Turbine Project Field Notes
Re: Arduino Based Datalogger
« Reply #7 on: October 10, 2017, 10:10:32 PM »
Good clean data coming in.
Not finding any blips or wobbles.

I did manage to burn up a current sensor on the weekend.  Made a better cable for it, but had the contacts switched!
Thankfully Amploc still makes these.

No one believes the theory except the one who developed it.  Everyone believes the experiment except the one who ran it.

System spec: 135w BP multicrystalline panels, regulated by Xantrex C40, DIY 8ft diameter wind turbine, regulated by Tri-Star TS60, 800AH x 24V AGM Battery, Xantrex SW4024