HPA controller build

dstroy

Grow God
80862BD1-8E0A-4A72-AD69-06965EA7915B.jpeg
DEEB91D3-01A4-4DF8-9463-6FA9FBAB3D0F.jpeg
5B0F4F5C-E3B1-41E6-8133-FDFA2C9D6D19.jpeg


I’m just tinning the leads into the screw terminals.

I love and hate terminating wire, it’s fun but super time consuming.

All of the power and board interconnects are in place. Just need to build power connectors.

This package has:

Mega2560
M4 express feather
3 bidirectional level shifters, slow speed mostly for i2c and shifting 3.3v control signals to 5v
Sparkfun differential i2c
Ds3231
Bme280 (barometric pressure is what I want from it)
256kb i2c fram, a place for fan profiles and whatever else

I2c, the m4, and level shifters are on UPS, M4 takes over basic feeding if the power goes out
 

dstroy

Grow God
I rearranged things to try and up the sample rate for multiple sensors, currently at ~1360 samples/second for 6 current sensors

C++:
//this program reads current sensors attached A0-A5 on an arduino mega2560

//needed for sqrt()
#include <math.h>


//analog voltage reference
#define vREF = 5.00
//number of current transformers to monitor, the compiler should yell at you if you change this number without changing pins and BURDEN_CAL at the same time
#define NUM_CURRENT_TRANSFORMERS_MONITORED 6
//transformer ratio 1000:1
#define TRANSFORMER_RATIO 1000
//current transformer pins
const int pins[NUM_CURRENT_TRANSFORMERS_MONITORED] = {A0, A1, A2, A3, A4, A5};
//burden resistor value for each current transformer
const float BURDEN_CAL[NUM_CURRENT_TRANSFORMERS_MONITORED] = {135.0, 135.0, 135.0, 135.0, 135.0, 135.0};
//value to multiply P-P value by to get RMS value
const float RMS_MULT = 1.0 / sqrt(2.0);

//current transformer sensor object
class current_transformer {
  public:
    //tried to sort by access frequency
    //sampling start time
    unsigned long start_time = millis();
    //how long to sample each analog input for, in milliseconds
    unsigned long sample_duration = 1000UL;
    //place to put incoming sensor reading
    int sensor_sample = 0;
    //pin which this sensor is associated with   
    byte pin = 0;
    //how many samples have been taken
    int samples = 0;
    //max analogRead() value
    int max_value = 0;
    //result in mV
    float result = 0.0;
    //mA peak-to-peak through resistor
    float curr_resistor_pp = 0.0;
    //mA rms through resistor
    float curr_resistor_rms = 0.0;
    //mA rms through monitored line
    float curr_wire_rms = 0.0;
};//end class current_transformer
//create power_monitor[] objects
current_transformer power_monitor[NUM_CURRENT_TRANSFORMERS_MONITORED];

void setup() {
  //set current transformer sensor pins
  for (int i = 0; i < NUM_CURRENT_TRANSFORMERS_MONITORED; i++)
  {
    //current transformer input pins set to INPUT
    pinMode(pins[i], INPUT);
    //current_transformer class object array power_monitor[]
    //set pin number in corresponding power_monitor[] object
    power_monitor[i].pin = pins[i];
  }
  //serial monitor
  Serial.begin(1000000);
}

void loop() {
  get_current_transformer_reading();
}

void get_current_transformer_reading()
{
  //cycle through sensors, pin numbers can be discontiguous
  for (int i = 0; i < (NUM_CURRENT_TRANSFORMERS_MONITORED); i++)
  {
    //sample for power_monitor[i].sample_duration milliseconds
    if ((millis() - power_monitor[i].start_time) <= power_monitor[i].sample_duration)
    {
      //get a reading from a sensor pin
      power_monitor[i].sensor_sample = analogRead(power_monitor[i].pin);
      //sample rate to help with code efficiency
      power_monitor[i].samples++;
      //if the sensed voltage is greater than the largest voltage seen this sample, set power_monitor[i].max_value
      if (power_monitor[i].sensor_sample > power_monitor[i].max_value)
      {
        //to whatever was sensed
        power_monitor[i].max_value = power_monitor[i].sensor_sample;
      }
    }
    //if the time to sample is over, it's time to calculate some things
    if ((millis() - power_monitor[i].start_time) >= power_monitor[i].sample_duration)
    {
      //try to avoid float division
      //aref / resolution = MAX_VALUE_MULT  5.0 / 1024.0 = 0.00488
#define MAX_VALUE_MULT 0.0048828125
      //power_monitor_results[].result is peak-to-peak voltage from current transformer
      //cast max_value to float
      power_monitor[i].result = float(power_monitor[i].max_value) * MAX_VALUE_MULT;
      //power_monitor_results[].curr_resistor_pp is peak-to-peak current across the burden resistor
      power_monitor[i].curr_resistor_pp = (power_monitor[i].result / BURDEN_CAL[i]) * TRANSFORMER_RATIO;
      //convert peak-to-peak voltages to RMS 1/sqrt(2) approx. .707
      power_monitor[i].curr_resistor_rms = power_monitor[i].curr_resistor_pp * RMS_MULT;
      //derive the current through the ac wire
      power_monitor[i].curr_wire_rms = power_monitor[i].curr_resistor_rms * TRANSFORMER_RATIO;
      //print out the readings
      log_current_transformer_reading(i);
      //reset class variables for relevant pin
      power_monitor[i].max_value = 0;
      power_monitor[i].samples = 0;
      power_monitor[i].start_time = millis();
    }
  }
}

void log_current_transformer_reading(int i)
{
  Serial.print(F("A"));
  Serial.print(i);
  Serial.print(F(" Samples : "));
  Serial.print(power_monitor[i].samples);
  Serial.print(F(" peak-peak : "));
  Serial.print((power_monitor[i].result * 1000.0), 3);
  Serial.print(F("mV c_t_r (peak) : "));
  Serial.print((power_monitor[i].curr_resistor_pp * 1000.0), 3);
  Serial.print(F("mA RMS : "));
  Serial.print((power_monitor[i].curr_resistor_rms * 1000.0), 3);
  Serial.print(F("mA c_t_w : "));
  Serial.print(power_monitor[i].curr_wire_rms, 3);
  Serial.println(F("mA"));
}
 

dstroy

Grow God
1579703829650.png


making the part of the program that cuts up the string from the cozir environmental sensors more efficient? trying to anyway. knocked of a few thousand micros so far.

I'm moving the cozir sensors in the HPA controller to the spi2uart

library:

ebay link:

Code:
#include <SPI.h>
#include "MULTIUART.h"


MULTIUART multiuart(53);  //CS pin = 53

#define COZIR_STRTOK_CHAR_TO_IGNORE "HTZ \r\n"
#define MULTIUART_SERIAL_ZERO_BUFFER 64

void setup()
{

  //SPI Prescaler Options
  //SPI_CLOCK_DIV4 / SPI_CLOCK_DIV16 / SPI_CLOCK_DIV64
  //SPI_CLOCK_DIV128 / SPI_CLOCK_DIV2 / SPI_CLOCK_DIV8 / SPI_CLOCK_DIV32

  multiuart.initialise(SPI_CLOCK_DIV64);  // set up the SPI and MultiUART Library
  Serial.begin(9600);               // set up Serial library at 9600 bps
  Serial1.begin(9600);

  // Initialise the UART baud rates
  // 0=1200, 1=2400, 2=4800, 3=9600, 4=19200, 5=38400, 6=57600, 7=115200

  multiuart.SetBaud(0, 3);    // UART0 = 9600 Baud
  //  multiuart.SetBaud(1, 3);    // UART1 = 9600 Baud
  //  multiuart.SetBaud(2, 3);    // UART2 = 115200 Baud
  //  multiuart.SetBaud(3, 3);    // UART3 = 115200 Baud
}

void loop()
{
  //serial loopback
  //a typical string from one of my environmental sensors
  Serial1.print("H 00345 T 01195 Z 00651\r\n");

  //  //Send out data on UART
  //  multiuart.TransmitString(0, "UART 0 Test", 12);

  serialOneCozir();

}

void serialOneCozir() {
  //start time is for debug/efficiency monitoring
  unsigned long start_time = micros();
  //reinit costs about 40 micros
  static char ttl_buf[60] = {0};
  static bool newData = false;

  static char LENGTH;
  LENGTH = multiuart.CheckRx(0);  //Check UART 0 for incoming data

  if (LENGTH > 0 && newData == false) {
    multiuart.ReceiveString(ttl_buf, 0, LENGTH); //Collect incoming data from buffer
    //for loop to copy char array should go here if we want to maintain an original of ttl_buf
    newData = true;
  }

  if (newData == true) {
    int index = 0;
    //pieces of data to point to, just humidity temp and co2 for this sensor so 3 pointers
    char *strings[3];
    char *ptr = NULL;
    ptr = strtok(ttl_buf, COZIR_STRTOK_CHAR_TO_IGNORE);
    while (ptr != NULL) {
      strings[index] = ptr;
      index++;
      ptr = strtok(NULL, COZIR_STRTOK_CHAR_TO_IGNORE);
    }
    int temp_hum = atoi(strings[0]);
    float hum = float(temp_hum / 10.0); // divide by 10
    int temp_temp = atoi(strings[1]);
    float temp = float((temp_temp - 1000) / 10.0);
    int co2 = atoi(strings[2]);
    
//    Serial.print("Humidity "); Serial.print(hum);   
//    Serial.print(" temp "); Serial.print(temp);
//    Serial.print(" co2 "); Serial.println(co2);
    unsigned long elapsed_time = micros() - start_time;
    Serial.println(elapsed_time);
    newData = false;
  }
}
 

MtRainDog

Grower
Awesome stuff here! This is pointing me in the right direction for some things I'd like to try. My experience with Arudino is limited to using ultrasonic sensors > arduino > raspberry pi, and opening a simple socket connection to poll for measurements, and record them in sql server express to be displayed in a webpage.

I'd like to go further with that, and raspberry pi's are much more capable nowadays. I'm a .Net developer, and writing .Net Core apps for the RP is right up my alley.

From what I think I'm reading here, you're using the SPI-UART bridge so you can have 4 peripherals? Or better performance than UART? Both?
 

dstroy

Grow God
Awesome stuff here! This is pointing me in the right direction for some things I'd like to try. My experience with Arudino is limited to using ultrasonic sensors > arduino > raspberry pi, and opening a simple socket connection to poll for measurements, and record them in sql server express to be displayed in a webpage.

I'd like to go further with that, and raspberry pi's are much more capable nowadays. I'm a .Net developer, and writing .Net Core apps for the RP is right up my alley.

From what I think I'm reading here, you're using the SPI-UART bridge so you can have 4 peripherals? Or better performance than UART? Both?
SPI is much faster than uart serial, and the spi2uart has its own buffer so it’s totally asynchronous from the mega, and it doesn’t have clock speed error for baud rates present on the mega at 16mhz so the communication that takes place at 9600 baud is inherently more reliable between the spi2uart and cozir environmental sensors.

I also wanted a loopback uart interface for testing.

Good luck with your projects.
 

MtRainDog

Grower
Thanks, I am pretty ignorant when it comes to embedded systems. Web servers and databases are my thing, but I've always found this stuff fascinating, and have always wanted to learn more.

Never even considered that you'd need to account for the different clock speeds of the components for the over the wire communications. Makes complete sense though. This really does help!
 
Top