Arduino code - florindumitrescu94/DashBoard_PowerBox_V3 GitHub Wiki

Introduction

Prerequisites

Now, that we have built the device, we need to program the Arduino, so it can communicate with the computer.
For this, we will need to install the Arduino IDE found here. Download the most recent Arduino IDE Version.

After downloading and installing the IDE, you will need to install the DHTStable.h and EEPROM.h (if not already installed) libraries from the Library manager. Go to Sketch > Include Library > Manage libraries, then search "DHTStable". Install the most recent version (1.1.2 as of the time I am making this tutorial). Same process for the EEPROM.h library, install the latest version.

You might also need to install CH340 drivers. If you are running Windows 11, you might have trouble connecting an older version of the Nano board, so you can go here and look for the most recent drivers.

Code explanation

There are some functions that I feel I need to explain the way they funciton. What has not been explained here is fairly straightforward and can be understood easily by checking the code.

PWM automation function

This function runs in a loop whenever the PWM_AUTO_A or PWM_AUTO_B value is set to 1 and sets the values of the PWM output based on the difference between the ambiental temperature and the calculated dew point temperature (the same code repeats for PWM_B.

void RUN_AUTO_PWM_A() {

 if (PWM_AUTO_A == 1)

{   

double delta_td = TEMP-DEWPOINT;

int delta_t = round(delta_td);

if (delta_t <= 10)

{

  int pwm_val = (10-delta_t) * level_a;

  if (pwm_val >=100)

  {

    pwm_val = 100;

  }

 SET_PWM_POWER(1,pwm_val);

}

else 

{

  SET_PWM_POWER(1,0);


}

}

}

The "level_a" determines the aggressivity of the dew heater automation and can be set between Low, Mid and High.

The aggressivity levels function as a multiplier for the calculation.

Temperature difference = Temperature - Dew point; if (Temperature difference <= 10) { PWM Value = (10-Temperature difference) * aggressivity level }

The PWM Automation only kicks in when the difference between the ambiental temperature and the dew point temperature is lower than 10 (when the relative humidity is greater than 50%). The aggressivity level determines how fast the PWM value reaches 100%.

Example:

Temperature = 25 degrees

Dew point = 19 degrees

The temperature difference = 6 degrees

The value sent to the PWM is now (10-6)=4 * aggresivity level.

The modifiers are as follows:

Low = 10 Mid = 15 High = 20

So, for each of these three, the PWM value will be set as shown below:

40% for Low

60% for Mid

80% for High

As we can see, the PWM will reach 100% at 0 degrees (Ambiental - Dew point) difference for Low, at around 3 degrees for Mid and 5 degrees for High.

Measuring voltage, current, power and total power consumption

Since we are dealing with mostly PWM controlled power, calculating the current usage without implying a means to average out the readings will yeld very jumpy and innacurate results. Therefore, I have implemented an array that gets updated over time, then average the sum of all the values in the array to obtain the average current usage over 150 cycles. The GET_POWER() function runs in a loop every 200mS.

To determine the total power consumption since device has been connected, we need to measure the total power consumption in W*h per each cycle, then add that up to a total. Since the Arduino Nano floating point only allows for 2 decimals of precision, we need to first calculate the power in milliseconds, then divide that power by 3600000 (number of milliseconds in an hour).

//MEASURE AND CALCULATE POWER USAGE  

void GET_POWER() {  


time1=millis();  //records time when function starts    

if (AVERAGE_COUNT == 150) AVERAGE_COUNT = 0;  // Resets the average counter used as an array index to average current consumption over 150 cycles.       

float VOLTAGE_SAMPLE_SUM=0;

for (int v=0;v<150;v++) 

{

  PIN_VALUE_V =  analogRead(VM);

  VOLTAGE_SAMPLE_SUM +=PIN_VALUE_V;     

}

VOLTAGE_SAMPLE_SUM /=150;

VOLT_TEMP = (VOLTAGE_SAMPLE_SUM * 5.0) / 1024.0;   

VOLT = VOLT_TEMP / 0.0982;   // Tune this last number (VDIV ratio) until it will show the correct voltage (compare by reading the voltage with a voltmeter)    

if (VOLT < 0.1) VOLT=0.0;    

CURRENT_SAMPLE_SUM=0;    // Resets the sum of all the samples gathered in the next step

for (int i=0;i<150;i++)   

{  

  PIN_VALUE_A= analogRead(AM);  

  CURRENT_SAMPLE_SUM = CURRENT_SAMPLE_SUM + PIN_VALUE_A;  //Gathers 150 readings from the A1 pin   

}   

AMP_AVERAGE[AVERAGE_COUNT] = (ACS_Bias - ((CURRENT_SAMPLE_SUM/150)*(5.0/1024.0))) / ACS_resolution;  // Calculates the current for the current cycle, then sets the current array value.   

AVGAMP=0;  //Resets the variable, as it is later used to sum up all the values in the AMP_AVERAGE array.   

for (int c=0;c<150;c++) AVGAMP += AMP_AVERAGE[c];   

AMP = AVGAMP/150;     

if (AMP< 0.01) AMP=0.0;   

PWR = VOLT * AMP;    

AVERAGE_COUNT = AVERAGE_COUNT + 1;   

time2=millis();   //records time when function ends    

PWR_TOTAL_S = PWR_TOTAL_S + ((PWR*(time2-time1))/1000); // total power in W*s    

PWR_TOTAL = PWR_TOTAL_S/3600;  // Total power used in W*h    

}

Semaphore

To avoid freezing the arduino by giving it too many instructions at once, with some help from another coder, I have implemented a system to run certain functions on separate loop cycles.

switch (FSMState) {

case stateIdle:

  // wait REFRESH milliseconds between Read cycles

  now = millis();

  if ( now > last + REFRESH )

    FSMState = statePower;

  else

    FSMState = stateIdle;

  break;

case statePower:

  GET_AMBIENT();

  now = millis();

  FSMState = stateAutoPWM;

  last = now;

  break;

case stateAutoPWM:

  now = millis();

  if ( now > lastm + PWMREFRESH ) {

    RUN_AUTO_PWM();

    lastm = now;

  }

  last = now;

  FSMState = stateIdle;

  break;

}

}

Prepare code

After all the prerequisites are installed,either download the arduino file or create a new Arduino sketch and, copy the code from the DashBoard_PowerBox_V3.ino file and paste it in your sketch.

Now it's time to make some changes in the code to fit your components.

Since the Arduino nano's floating and double types can only hold 2 decimals and our formulas need 3 or more decimals, we will need to change some numbers directly in the code (we can't use constants and then divisions, since we will only get two decimals and the readings will be off).

First,we need to set the voltage divider ratio by taking the values we have previously measured for vdiv_10k and vdiv_100k and dividing vdiv_10k by vdiv_100k. We should get a number of around 0.1, but if the number is lower or higher, use 4 decimals from the number you got .(example: 0.0982). We might not obtain the right voltage right away, so we can tune this value until we obtain the correct voltage reading as measured by a voltmeter.

Lastly, we need to set the correct variant of the ACS Sensor and tune the reading. This will determine the resolution of the current reading (but also the headroom) and ensure accurate reading.

Tuning ACS reading.

Since all components have a margin of error, the ACS sensor will have one, too. The line in the code that calculates the current is this:

AMP_AVERAGE[AVERAGE_COUNT] = (2.494 - ((CURRENT_SAMPLE_SUM/150)*(5.0/1024.0))) / ACS_resolution;

Notice the first number in this formula.

Since the ACS712 sensor can read both positive and negative currents, the bias voltage (the voltage that comes out of pin 3 of the chip) is roughtly 2.5V. As we have mounted the chip so that the current flows from pins 1 and 2 to pins 3 and 4, the voltage output on pin A1 will increase as the current increases. Therefore, we need to subtract this value from the bias voltage, then multiply the value by -1, to get a positive, correct current value. However, due to manufacturing errors and component tolerances, this bias voltage will not always be exactly 2.5V.
As this can offset the current reading, we need to measure and tune this value so that the current reading 0 when no current flows through the sensor.
To do this, we can measure the voltage coming out of pin 3 with a precise voltmeter and replace this value with the measured one.

Uploading the code

Connect the board

Once the code has been prepared, we can upload it to the Arduino board. Connect your Arduino to the computer using a USB cable. In the Arduino IDE, click on the Boards list and select the "Unknown" option.

image

Once the pop-up window appears, search and select Arduino Nano from the list and select the correct COM port.

image

In the Tools tab, you should see these selections:

image

Press the Compile button first to check for any syntax errors in the code, then click Upload.
Once completed, the message at the bottom should say Done Uploading.

Error uploading

You might have some errors when uploading the code.

DHTStable library is not found.

You need to install the DHTStable library (please see the Prerequisites section of this page). If you've already installed the library, try to restart the Arduino IDE, or install a different version.

Upload timed out

There might be a chance that your board uses the Old Bootloader. In this case, you need to tell the Arduino IDE to use the Old bootloader by selecting it here, in the Tools tab:

image

Error uploading to the board

If you get this error, you might have something else connected to that COM port, or you have selected an incorrect COM port. A situation I have encountered is that, whenever I have Cura open, it somehow blocks the port my Arduino is connected to, possibly because my 3D printer has the same COM port assigned to it. Tried closing all other applications, check the COM port and try again.

To easily determine which COM port your Arduino is connected to, open Device Manager and expand the Ports (COM & LPT) section. Then disconnect your Arduino. Note which COM port has dissapeared. Connect it again and note the new COM port. That will be your Arduino's COM port.

image

RESET Suppression cap, how to upload

If you have elected to add a cap between the RST and GND pins, to supress the Reset signal coming from the USB to Serial chip, you will need to press the Reset button on the Arduino as soon as the message from the IDE changes from Compiling Sketch to Uploading... Click the "Upload" button in the IDE, wait for the sketch to compile, then, when it starts trying to Upload the signal, hit the Reset button on the Arduino. If you've done it right, the Rx LED will flicker very fast and the IDE will show "Done uploading". If not, keep repeating these steps until succesful.