8S Arduino Cell Monitor

Become a Patron!

Introduction

Like all my other projects, I’ve decided to create my own custom version of a cell monitor. Here we have an 8S arduino based voltage cell monitor that I designed to allow the user have control on how they monitor there batteries and how its displayed.

Its a very basic and not a lot of bells and whistles but still powerful enough to allow you to monitor cell voltages with accuracy and precision. This project is open source and so you will have the ability to add features or change them.

Specifications

  1. Cell count: 8
  2. Battery type: Li-ion, LiFePO4, NiMH
  3. ADC resolution: 16-bit
  4. Voltage measurement resolution: 1mV accuracy
  5. Fault detection: Over-voltage, Under-voltage
  6. I/O: 1-CH Digital output

The main purpose this is designed for is to measure an 8S Lithium Iron Phosphate pack up to 1mV resolution.

Hardware

Now here is were the fun part starts with the hardware used to create this DIY cell monitor. The main sections we will talk about are:

  1. ADC
  2. Power Supply
  3. MCU
  4. Menu Button Controls

ADC

Here we talk about the most important part of the project and that’s the ADC section. I’ve decided to go with two external 16-Bit adcs instead of the internal adcs of the arduino.

Since we need to step down the voltage from 30V max and need the best resolution possible. If we go with the internal adcs of the arduino, with a 10-Bit ADC we will only have resolution of 17mV/Bit. Now with 16-bit adcs, we have a resolution of 0.9mV/bit which is a huge increase.

I’ve decided to go with the ADS1119IPWR which is a 16-bit I2C adc. See below for a snip-it of the schematic:

ADS1119IPWR 16-Bit ADC x2

Power Supply

In the power supply section, we have a small profile buck converter that can handle up to 36V input. For this version I did not add a series fuse for the input of the buck converter but will add in second version. One this that was added was a tvs diode to protect the buck converter.

One thing I noticed is that when you plug anything into a high capacity battery bank, you need to protect your circuit from inrush current that causes a quick spike in current voltage that could damage your circuit before you even start. Adding a TVS diode will clamp this voltage and protect your circuit.

MCU

As the title implies, we are using the Atmega328P running the minicore bootloader https://github.com/MCUdude/MiniCore .

One thing I did change from the standard arduino board is use a cmos oscillator instead of the typical crystal oscillator. Honestly this is mostly a preference but it can be modified to use the typical crystal.

Menu Button Controls

Here is the schematic section for the control buttons. Its a little more complex than the typical push button design but this helps a lot with debounce.

We have a two stage design used to eliminate electrical debounce. First we have a passive RC low pass filter and then an inverting logic gate which adds some buffer to further reduce any false triggers.

Below is the full caption for all 4 input buttons:

Software

Normally I would breakdown every section of the code but its too large to fully go through the code. But I will go over the important sections:

  1. Menu controls
  2. ADC calibration

Menu Controls

In the control menu you are able to set the UVP value for cells and pack as well as the OVP value for cells and pack. In order to get into the menu screen you need to press the menu button and hold for about a second or two.

Once you are in the menu screen, you can navigate using the up and down buttons. Now even though I have the debounce circuit and a small software delay, the movement is still not smooth but it sufficient to operate.

In order to change the values, navigate for example to the OVP value with the arrow and then click the enter button to enter the OVP value screen. Using the up/down buttons you can increase or decrease the value by 0.05 increments. Once you are satisfied with your value then you can save the value by pressing the enter button and this will save to EEPROM so that its store permanently even after the power is removed.

ADC Calibration

Now before you can get accurate measured values, you need to calibration each ADC input to fix the offset from each IC.

You can calibrate using the serial monitor with an FTDI board connected to the UART port of the cell monitor.

The simplest way of calibrating each value is to measure each cell with a multimeter and write down the values.

Next, in the serial monitor, you need to enter the following:

1002, (cell 1 value), (cell 2 value) , (cell 3 value), (cell 4 value), (cell 5 value), (cell 6 value), (cell 7 value), (cell 8 value)

example: 1002,3.111,3.154,2.967,3.546,2.567,3.222,3.234,3.555

Make sure not to include spaces as this will not calibrate if you do.

After the calibrate is complete, calibrated values are stored in EEPROM so that after power is removed then the board is still calibrated.

Conclusion

Even though you can buy an 8S lithium battery monitor with probably more features, this one gives you more flexibility and also the confidence that its doing what it is suppose to do.

If you have any comments, suggests, or feedback let me know in the comments below. Thank you.

Here is the link to the schematics and code on my github:

https://github.com/simple-ee/CellMonitor

Arduino 4S BMS (Version 7)

INTRODUCTION

Like my previous post about this project, this is a customizable arduino based 4S BMS system. This is now version 7 of hardware and version 21 of software.

The benefit of using this over other low cost solutions is that gives a lot more feedback about what exactly its doing and control over how its doing it. For example setting the limit for the over voltage protection and under voltage protection value.

IMAGES

Here is a couple pictures of my BMS in action on a 4S11P 18650 pack.

FEATURE SET AND SPECIFICATIONS

Now to the key features that makes this project different from the rest:

  1. Adjustable voltage tolerance (maximum difference between cells)
  2. Display individual voltage cell values on an oled i2C display and/or serial print monitor over UART (TX, RX, GND)
  3. Set under-voltage protection value and over-voltage values for series MOSFET
  4. Adjustable balance current with a swapping of drain resistor up to 1A safely
  5. Serial commands for adjusting variables and feedback:
    1. Under voltage protection value
    2. Over voltage protection value
    3. Cell voltage tolerance
    4. Request calibration values
    5. Request status of UVP and OVP event and reset if triggered
    6. Enter calibration mode to re-calibrate if needed for ADC inputs

DOWNLOAD ORIGINAL FILES

Schematic and original kicad files

Arduino Code

NOTE: Arduino BMS A7 hardware is supported only with the current arduino software

HARDWARE

Now lets look into the hardware for this. There are 5 important sections in this board:

  1. Power Section
  2. MCU: Arduino ATMEGA328P running at 8MHz with minicore bootloader
  3. Reference 1.25V voltage for ADC
  4. Voltage dividers for cell measurement into ADC
  5. Balance Section
  6. Series MOSFET Section

POWER SECTION

One of the most important sections in this project is the power section. Key features I was looking for was low Quiescent current because this will be battery operated.

Quiescent current is the amount of current needed to operate an IC.

The current power IC I’m using is a buck converter RT6208G. I chose a buck converter over an LDO because of efficiency, again trying to keep the current draw from the battery low. Key features of this converter is:

  1. Low quiescent current: less than 500nA or 0.5mA
  2. High input voltage: 36Vin max
  3. Small and compact
  4. Efficient: around 80-90%

One thing to mention is that the buck converter I chose is currently out of stock and will not be available until November. I’m currently working on choosing an alternative but any buck converter will work with this.

Figure 1: Power Section

Anything here is that instead of stepping down to 3V3, I stepped down the voltage to 2V7. The image above is wrong and the FB resistor values are picked for an output voltage of 2V7 but it will function the same.

The reason for going with this voltage is because I was trying to minimize the current draw from the battery. I found that 2V7 is the minimum voltage I can use while still being able to use the I2C OLED screen.

MCU and REFERENCE VOLTAGE SECTION

The next section is the Arduino MCU and the external 1.25V reference.

Figure 2: MCU and Reference Section

Here you can see where the ADC pins are attached to the cell pins for measurements. And the digital pins for the control of the mosfets for the balance section. Its pretty straight forward here

On the bottom you can see the external 1.25V voltage reference. I’m sure there are different values I could have gone with but I figured that with a 1.25V I could try and increase resolution even after the voltage dividers. Without accounting for the voltage dividers for measuring the cells, we have a 1.22mV resolution. Not too bad but obviously it will increase with the voltage dividers.

VOLTAGE DIVIDER SECTION

The next section is the voltage divider section which is used to step down the cell voltages to within the voltage reference value, in our case 1.25V max.

My values calculated were based stepping down the voltage value to within 1.20V, that is when a cell is at 4.2V then the divider will be 1.20V. This gives some margin in case the cells get overcharged.

Here you can see the divider circuit. Since the measurements are single-ended measurements and not differential, then everything is reference to ground and there for the higher in cell measurements we go the bigger the voltage divider we need.

I used 100k as the base resistor as I tried to minimize current consumption. The measurement cycle will be slower due to the arduinos 14pF capacitor but thats ok because we sample about 100 measurements to offset this.

BALANCE SECTION

The last section is the balance section. Here the controllers turns off and on the mosfets corresponding to the cell its attached to. When the software determines that ex. cell 2 is higher than the lowest cell, then D1 is triggered and an 18 ohm resistor will start draining some current to let the rest of the cells catch up.

Figure 3: Balance Section

Looking at the bottom section of this circuit ( BAT0 / BAT1 ) you can see resistor value R424, this controls how much current is drained. At full charge of the cell 4.2V, you will see a current drain of 0.23A and then a minimum drain of 0.16A when the cell is at 3.0V.

Since the series mosfets are capable of 4.2A, you can theoretically lower the resistor value to drain more current but I do not suggest draining more than 1A at least with this board.

PROTECTION MOSFET SWITCH SECTION

This section was added for an extra layer of protection and is not needed for the bms balancing functionality to operate.

I’ve added a mosfet switch that utilizes the arduinos digital pin 9 and 10 to control power mosfets that are in series on the positive line of the battery.

Figure 4: MOSFET SWITCH

Theoretically each mosfet can handle around 10A without a heatsink and about 40A per mosfet with a heatsink for a total of 120A total. But here you can add more in parallel for higher current or change the mosfet for a higher current capable one. The mosfets used here are P_Channel mosfets for high side switching.

SOFTWARE

Now to cover the software side of this board, here I will only cover the important sections in which you might want to adjust for your own purposes. Most of the variables you would want to change can be accessed and changed via serial monitor using an FTDI while only connecting the TX, RX, and GND pins.

Here I will list the important sections:

  1. Sampling frequency
  2. Tolerance adjustment
  3. Serial Commands

SAMPLING FREUENCY

//////////////////////////////////////////////
// Sampling number for analog read values.
// Will use this sample size to calculate a
// better estimation of the analog value
//////////////////////////////////////////////
int samples = 100;

Here in the samples variable you can change the value for how many samples the adc takes before creating an averaging of the cells. If you want a smoother value you can increase but I would not go past 250 samples. Remember this will also effect the amount of time it takes to display voltage values.

TOLERANCE ADJUSTMENT

//////////////////////////////////////////////
// This is the max difference that the cells
// can achieve in respect to each other
//////////////////////////////////////////////
float tol = 0.01; // 10mV max voltage difference

Here in the tol variable, it is used to as a reference for when the balancing of the cells should stop. The cells will balance until all cells are within 10mV of each other. This might not be exact because with the last 2 cells the register voltage different might be greater than 10mV due to a higher voltage divider but the measured voltage is around +/- 25mV of the actual cell voltage.

SERIAL COMMANDS

The most important part is the serial commands because this allows you to make changes without having to reflash the arduino.

Below we have a list of 6 serial commands that I will explain in details on how to enter the values into the serial monitor.


/* This is the table for entering into different modes and how to 
 *  enter commands within serial console
 *  
 *  modes:
 *  1. Display ADC calibration values = 1001
 *  2. Enter adc auto calibration     = 1002
 *  3. Adjust minimum and maximum     = 1003
 *     voltage threshold for OVP
 *     and UVP
 *  4. Used to set all digital outputs
 *     to low                         = 1004
 *  5. Erase all EEPROM values        = 1005
 *  6. Reset series switch value      = 1006
 *  7. Display status for Reset, UVP
 *     OVP state condition            = 1007
 *
 *  
 *  1.Example of displaying calibration values
 *    Serial window: mode
 *    Serial window: 1001
 *  
 *  2.Example of entering into auto calibration mode
 *    Serial window: mode,vref1,vref2,vref3,vref4
 *    Serial window: 1002,4.00,8.00,12.00,16.00
 *
 *  3.Example of entering UVP and OVP values
 *    Serial window: mode,UVP,OVP
 *    Serial window: 1003,3.10,4.15
 *    
 */

Lets look at the first command entry.

  • 1001
    • This will display the calibration values that is stored in EEPROM
  • 1002
    • This will enter calibration mode. Since there might be some offset from what the adc reads vs the actual value, I added a calibration mode that will add the offset to each adc value to try and get the values closer to the actual.
    • To enter calibration mode you will need to enter:
      • 1002,vef1,vef2,vef3,vef4
      • The vef1-4 values are the actual measurements of the battery cells
    • Calibration setup:
      • Enter 1004 first to turn off all balancing MOSFETS
      • Measure each cell value with a multimeter to get the actual value
      • Then enter calibration mode by entering 1002,3.54,3.76,3.20,3.56 as an example for vef values
  • 1003
    • This will adjust the values set for under voltage protection and over voltage protection. So if lets say 3.1V is set value for under-voltage protection then if any one of the cells drop below this value then the series FET will trigger if you have it attached.
    • This command is only valid if you use digital pin 9 and 10 for the series FET switch.
    • Enter 1003,UVP,OVP
    • 1003,3.2,4.2
  • 1004
    • Used to set all balancing values to low so that no cell is draining current. This is usually used for testing purposes.
    • Enter 1004,1 for setting all values to low
    • Enter 1004,0 to go back to normal balancing operation
  • 1005
    • This is used to erase all eeprom values
  • 1006
    • If UVP or OVP is triggered then you will need to reset this fault condition
    • Enter 1006,0
    • NOTE: If values are above or below the UVP and OVP values then resetting the 1006 command will not allow current to pass

CONCLUSION / FUTURE UPDATES

I’m very happy on how this project has progressed but its far from perfect and I will continue to optimize both the software and hardware to make it easier to integrate into a battery.

Future updates in my roadmap:

  1. Optimize the Power MOSFET Switch circuit to handle higher currents
  2. Possibly combine the mosfet control to one pin as using two might not be needed. UVP and OVP conditions open circuit the mosfet bidirectional switch
  3. Add current sense capability for overcurrent protection.
  4. My next big protection is creating a 7-8S BMS as well as a separate UVP, OVP, and Over-current protection board that will operate independently from the 8S BMS board but will still communicate via I2C to pass current data to the BMS board

If you have any questions or any suggestions or improvements please feel free to ask or comment.

Thank you and hope you enjoyed this project.

OCP and UVP Protection

I strive to provide my content for free without using ads as I personally do not like ads in most website. If you can afford to donate anything via Paypal i would great appreciate it. Thanks:

INTRODUCTION:

This project was created in order to provide protection for my battery projects. I didn’t really trust the cheap low cost protection boards you find online so I decided to try and create my own.

The protection board I’ve designed has bidirectional current detection (can detect charging and discharging currents) which in turn means you can set independent OCP( over-current protection) for discharging current and charging current.

One thing to note before hand is that the current maximum current that can flow is about 5A due to lack of heatsink on the powerFETS. Adding heatsink is necessary to allow more current

Main features:

  1. Over current protection with output latch open when tripped
  2. Under voltage protection for the whole battery pack
  3. Theoretically 45-50A pass-through current ( will require heatsink)

In the next sections I will discuss in more detail this project.

SPECIFICATIONS:

Here are some more technical details of this project

Minimum input voltage (V)10
Maximum input voltage (V)34
Maximum current (A)50A*
Quiescent current (mA)**
Undervoltage protectionYes (adjustable)
Overcurrent protection Yes (adjustable)
Short circuit protectionYes***
Overvoltage protectionNo

*Maximum current passing through this board will depend on sizing and adding a heatsink to the power mosfets

**Quiescent current has not been measured yet but it is below 1mA during normal operation with a 4S battery. This will change slightly when using more cells in series

***Theoretical the supervisor IC will latch when the overcurrent protection section detects its threshold. This will need testing to confirm

SCHEMATIC AND CIRCUIT DETAILS

Here in this section I will discuss the project in more detail by talking about the different sections used to create this whole circuit.

Lets first discuss the over-current/short-circuit protection sections of the circuit:

Bidirectional Current sensor

Here we have the heart of the over-current detection. We have the MAX4081FASA which is a bidirectional current sense IC that can handle a max VCC of 76V which is more than enough for our applications. The FASA has an internal gain of 5V/V coupled with a 10 milliohm sense resistor value ( I have two 20 milliohm in parallel for size reduction) this will allow the sense current of up to 50A.

REF1A is tied to 5V reference IC and REF1B to ground. With this we have a bias point of 2.5V meaning that when no current is passing the voltage on the OUTPUT pin 5 is 2.5V. When current is discharging into a load the output will rise up to 5V being the 50A max. When current is flowing the other direction to charge the batteries then it will go below 2.5V to 0V being 50A max.

In order to both detect charging and discharging current since I will be using this for a battery pack, I had to create a circuit that detects both an upper limit and lower limit. Hence I went with a window comparator to detect charge and discharge values.

Window comparator with latching supervisor IC

Here is where you can adjust your own over-current detection points for charging and discharging and they can be set independently from each other. The idea here is when the output from the max IC is within the window of the voltage values you set from the voltage divider values on pin 3 and pin 6, the output of the opamp will be high. As soon as the output value goes above or below those set points, it will pull the output of the op-amp low and trigger the supervisor IC.

The supervisor IC is very important because this is what controls the power mosfets allowing current to pass through. This one is different from normal supervisor ICs because when this triggers, the output is latched low and this pulls the power mosfets high causing them to stop current flow. The only way to clear the fault condition is to pull the clear pin 1 to 5V. What I have done is add the option for a push button on the board directly or pads to run the clear pin trigger somewhere else.

Here is a simple equation to calculate the discharge current detection resistor values on PIN3 of the op amp:

(0.05 V/A * X) + 2.5V = VdetectHigher ; X = current trigger desired

For charging current detection here is the equation for the lower voltage detection of the op amp PIN 6

(0.05 V/A * X) – 2.5V = Vdetectlower; X = current trigger desired

Here is the power mosfets controlled by the supervisor IC. When no fault condition is triggered then the supervisor IC pulls Q4 to high causing the 10k resistor to be tied to ground. This then creates a voltage difference between the gate and source for the powerFETS allowing current to flow. When an overcurrent fault condition is triggered the supervisor IC is then pulled low and Q4 stops conducting which in turns unties the 10k resistor from ground and makes the gate and source the same potential.

Now the under-voltage protection scheme works by using a different supervisor IC measuring the input voltage. When the voltage falls below the threshold then the output pulls low and stops current flow in the powerFET

Here you see this circuit in action. A voltage divider is used to bring down the input voltage of the pack to a range the supervisor can handle. I have defined some voltage divider resistor values for different size battery packs in which it will trigger when the threshold is hit. I only used one MOSFET for this because this will stop discharging current but will allow charging current to flow via the body diode until the input voltage is above the threshold and then turn on the mosfet.

Here you have to take some precautions not to kill the mosfet when an event triggers an under-voltage event and you try to charge the pack.

When an event happens, start charging the pack with 0.5A-1A until there is about 1V above the under-voltage value. Then maximum current charging can be applied. This part of the circuit will need more tweaking in the future

CONCLUSION / IMPROVEMENTS

Hopefully this project will help someone out. I created this to help protect my batteries and to allow the flexibility to adjust as much values as I can and have as much control of my protection circuitry as possible. Of course this is not perfect and I am still working on improvements.

IMPROVEMENTS:

  1. Figure out a way to protect Under-voltage powerFET from getting damaged when charging through the body diode initially until the supervisor IC allows current to flow through the FET and not the body diode
  2. Use DPAK powerFETS instead of IPAK due to cost. Size increase is negligible or non-existent
  3. Create a heatsink to provide maximum current discharge through mosfets. Currently the maximum current discharge without heatsink is roughly 5A without getting too hot. Will do testing after its completed.
  4. Perform thorough testing and post results.

DOWNLOAD DESIGN FILES:

Download Here:

Arduino 4S BMS: UPDATE (Version 5)

UPDATE:

This is an updated post regarding my 4S arduino based lithium ion balance management system (BMS).

If you click here, you will see the original post with details on the project.

IMPORTANT CHANGES:

  1. Replaced external voltage reference to a more stable one. Upgraded to a REF3012AIDBZT from Texas instrument.  This does not require an output capacitor for stability.
  2. Modified Buck converter RT6208GE.  Grounded pin 4 to set the max peak current to 50mA which is an average current of 25mA.  This was done to eliminate audible oscillation from the buck converter
  3. Increased copper traces for ADC pins A0-A3
  4. Better layout to increase continuous copper plane on internal layer

Minicore bootloader

updated 01/13/2019: For the new arduino version, load bootloader with 8MHz clock. I did more testing and this was more stable and accurate on the adc then the 1MHz clock setting.

I will be doing testing on these new versions and see how they perform.  I will post results as soon as I can.  Also below I will attach all files needed (schematics, gerber, bom) if you wish to make your own. 

Arduino Code Download

updated 01/13/2019: Download arduino code version A15.

Schematic and Gerber Download

ARDUINO BMS

 

CHECK UPDATED VERSION 5 HERE

CHECK UPDATED VERSION 7 HERE

INTRODUCTION

Now this might seem like it was a complete waste of time to try and reinvent the wheel with creating my owm custom BMS solution. You can buy them on ebay or alibaba or banggood for super cheap and it seems like a plug and play solution.

One problem I see with this, at least for me, is that I dont completely trust those cheap BMS system. I like to buy something that is reasonable as well as trusting that it will safely protect my cells from unbalancing. Another this is that I like to have flexibility with how I balance my cells or anything else.

Now this is where the custom arduino BMS came into play. I’ve designed this bms to handle a 4S battery pack so upto 16.8V fully charged and 14.8V nominal. The balance discharge current can be adjusted by simply replacing the discharge resistor with any value you wish. Just to add this does not have over current or over voltage protection..yet 🙂 I’m currently working on an add on for this so stay tuned for that future update.

Lets get started with all the cool details for this arduino bms.

3D RENDERING

Here i just wanted to show you the 3D rendering images of the final board. The rendering was created using kicad and its pretty nice actually for an EE cad software.

The heart of this system is the atmega328P running the minicore arduino bootloader[1]. From here you have the 4 balancing passive resistors to the right of the board. The best part of this project is that you can replace these resistors to any value you want to customize the balance current.

The one thing that this does not have is overvoltage and overcurrent protection but that will be a separate circuit later on ;).

Now we can talk about the main features below in the schematic section.

SCHEMATICS

Below are images of the full schematics for this project:

The first page of the schematic files is a hierarchy block level of the system to help understand how a lot of these subcircuits are linked together. Below I’ll breakdown all the pages and what exactly they do.

1. Hierarchy Block:

  • This is the overview block level that links the subcircuits on the separate pages. I normally like to design my projects this way if I have more than 2 subcircuits because its easier to see how things are working together

2. Power Supply

  • This section is just the power supply section to power the arduino. This is a high differential buck converter. The input voltage can go up to 36V and output down to 1.8V with an active quiescent current of only 190uA. Now the most important part is the quiescent current because we are trying to eliminate any wasted current since this is for a battery operated system and we do not want to drain the batteries faster than needed.

3. MCU

  • The MCU page has the Atmega328P and all the corresponding IO related to it. Im using A0-A3 to measure the batteries via a resistor divider
  • This page also includes the external reference voltage used instead of the built in 1.1V from the atmega328p. Its a 1.25V external voltage reference that has a better tolerance at a range of temperatures.

4. Balancing Circuit

  • This page has the balacing circuit which is incharge of discharging the battery cell that has a higher potentional. The heart of this is a bidirectional N-channel mosfet that allows current to flow in both directional either during discharge or during charging.

5. Connectors

  • This page has the power pin connectors and the BMS pads that connectors to the lithium cells.

Now that we’ve gone through the schematic lets go into the second most important part and that is the arduino code.

ARDUINO CODE

Now probably the second most important part is the arduino code that will control the mosfets triggering the discharge when a preset voltage difference is hit.


#include "Adafruit_SSD1306.h"

/* Revision: A9

* Written by: Steven Guzman

* Date: 7/10/2018

* Description: This is a customizable BMS system for a 4

* cell lithium ion pack.

*/

#include "Wire.h"

#include "avr/wdt.h"

#define OLED_RESET 4

Adafruit_SSD1306 display(OLED_RESET);

#define NUMFLAKES 10

#define XPOS 0

#define YPOS 1

#define DELTAY 2

//////////////////////////////////////////////

// This variable is used for checking on

// whether the OLED screen is attached or not

//////////////////////////////////////////////

int check = LOW;

//////////////////////////////////////////////

// Sampling number for analog read values.

// Will use this sample size to calculate a

// better estimation of the analog value

//////////////////////////////////////////////

int samples = 100;

//////////////////////////////////////////////

// This is the max difference that the cells

// can achieve in respect to each other

//////////////////////////////////////////////

float tol = 0.03;

//////////////////////////////////////////////

// To temporaly store analog values from the

// cell voltages to average out later with

// the number of samples taken

//////////////////////////////////////////////

float temp_cell[4];

//////////////////////////////////////////////

// Float array to store unconverted cell values

//////////////////////////////////////////////

float cell[4];

//////////////////////////////////////////////

// Variable array to store converted voltage

// values for cell measurement

//////////////////////////////////////////////

float B[4];

//////////////////////////////////////////////

// Variable array to store voltage differences

// between cells

//////////////////////////////////////////////

float diff[4];

/////////////////////////////////////////////////

// Variable used for digital output

// signals

/////////////////////////////////////////////////

int BAT[4];

/////////////////////////////////////////////////

// Variable used for storing the cell pack

/////////////////////////////////////////////////

float PACK = 0.000;

/////////////////////////////////////////////////

// Scaling factor used for converting

// the scaled down analogread values to there

// actual values from the voltage divider

/////////////////////////////////////////////////

float scale0 = 0.25; // 10k/(30k + 10k)

float scale1 = 0.125; // 10k/(69.8k + 10k)

float scale2 = 0.083; // 10k/(110k + 10K)

float scale3 = 0.0625; // 10k/(150k + 10k)

#if (SSD1306_LCDHEIGHT != 32)

#error("Height incorrect, please fix Adafruit_SSD1306.h!");

#endif

void setup()

{

Serial.begin(9600);

analogReference(EXTERNAL); // Configure reference voltage for

// external 1.25V

//////////////////////////////////////////////

// After switching to external reference you

// need to read a value a couple times before

// the reference has stabalized.

//////////////////////////////////////////////

analogRead(A0);

analogRead(A0);

analogRead(A0);

delay(20);

// Setup up watchdog timer to reset

// after 4 seconds

wdt_enable(WDTO_4S);

///////////////////////////////////////////////

// Variables to set the digital output

// pins 1-4

///////////////////////////////////////////////

BAT[0] = 5;

BAT[1] = 6;

BAT[2] = 7;

BAT[3] = 8;

///////////////////////////////////////////////

// Setting digital pins to output configuration

///////////////////////////////////////////////

pinMode(BAT[0], OUTPUT);

pinMode(BAT[1], OUTPUT);

pinMode(BAT[2], OUTPUT);

pinMode(BAT[3], OUTPUT);

///////////////////////////////////////////////

// Sets the digital outputs to an initial low

// state

///////////////////////////////////////////////

digitalWrite(BAT[0],LOW);

digitalWrite(BAT[1],LOW);

digitalWrite(BAT[2],LOW);

digitalWrite(BAT[3],LOW);

}

void loop()

{

Wire.requestFrom(0x3C, 1); // Pings OLED screen

///////////////////////////////////////////////

// If OLED pings back and check statement

// equals 1, then initiate the OLED screen

// and reset the check value to 0 so it will

// not continue to re-initiate. It needs to

// initiate another request one last time

///////////////////////////////////////////////

if (Wire.available() && check == HIGH )

{

display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

check = 0;

Wire.requestFrom(0x3C, 1);

}

if ( Wire.available() && check == LOW)

{

// Leave blank

}

else if (!Wire.available())

{

check = 1;

}

///////////////////////////////////////////////

// Sets the temp variable array back to zero

///////////////////////////////////////////////

for (int x = 0; x <4; x++)

{

temp_cell[x] = 0.00;

diff[x] = 0.00;

cell[x] = 0.00;

}

///////////////////////////////////////////////

// For loop used to record battery cell voltage

// information and used later to average out

// the readings

///////////////////////////////////////////////

delay(100);

////////////////////////////////////////////////

// Using true RMS calculation for computing a

// better average estimate for multiple samples.

////////////////////////////////////////////////

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

{

temp_cell[0] = temp_cell[0] + sq((analogRead(A0)/scale0)* (1.249 / 1024));

delay(1);

temp_cell[1] = temp_cell[1] + sq((analogRead(A1)/scale1) * (1.249 / 1024));

delay(1);

temp_cell[2] = temp_cell[2] + sq((analogRead(A2)/scale2) * (1.249 / 1024));

delay(1);

temp_cell[3] = temp_cell[3] + sq((analogRead(A3)/scale3) * (1.249 / 1024));

delay(1);

}

cell[0] = sqrt(temp_cell[0] / samples);

cell[1] = sqrt(temp_cell[1] / samples);

cell[2] = sqrt(temp_cell[2] / samples);

cell[3] = sqrt(temp_cell[3] / samples);

////////////////////////////////////////////////

// Scale up the cell values and then convert to

// to voltage values

////////////////////////////////////////////////

B[0] = (cell[0]);

B[1] = ((cell[1] - cell[0]));

B[2] = ((cell[2] - cell[1] ));

B[3] = ((cell[3] - cell[2] ));

PACK = B[3] + B[2] + B[1] + B[0];

///////////////////////////////////////////////////////////////////

// Compares each cell voltage to each other and then finds the

// lowest cell value. Then it stores the difference between the

// lowest cell and the remaining cells for comparison

///////////////////////////////////////////////////////////////////

if ( (B[0] <= B[1]) && (B[0] <= B[2]) && (B[0] <= B[3]))

{

diff[1] = B[1] - B[0];

diff[2] = B[2] - B[0];

diff[3] = B[3] - B[0];

}

else if ((B[1] <= B[0]) && (B[1] <= B[2]) && (B[1] <= B[3]))

{

diff[0] = B[0] - B[1];

diff[2] = B[2] - B[1];

diff[3] = B[3] - B[1];

}

else if ((B[2] <= B[0]) && (B[2] <= B[1]) && (B[2] <= B[3]))

{

diff[0] = B[0] - B[2];

diff[1] = B[1] - B[2];

diff[3] = B[3] - B[2];

}

else

{

diff[0] = B[0] - B[3];

diff[1] = B[1] - B[3];

diff[2] = B[2] - B[3];

}

//////////////////////////////////////////////////////////////////

// It enables the balancing protocol for a given cell that has a

// greater voltage difference from the lowest cell and the set

// tolerance.

//////////////////////////////////////////////////////////////////

delay(1);

for ( int x = 0; x tol )

{

digitalWrite(BAT[x], HIGH);

delay(1);

}

else

{

digitalWrite(BAT[x], LOW);

delay(1);

}

delay(1);

}

// text display tests

display.setTextSize(1);

display.setTextColor(WHITE);

display.setCursor(0,0);

display.print("V1:");

display.print(B[0]);

display.println("V");

display.print("V2:");

display.print(B[1]);

display.println("V");

display.print("V3:");

display.print(B[2]);

display.println("V");

display.print("V4:");

display.print(B[3]);

display.println("V");

display.setCursor(70,0);

display.print("VP:");

display.print(PACK);

display.print("V");

display.setCursor(70,8);

display.print("Config:");

display.print("4S");

display.display();

delay(1);

display.clearDisplay();

wdt_reset();

}

Lets break down this code in order to understand my thought process behind this.

arduino_code_sampling_section
  1. The samples variable is used to create an average sampling of the battery cells to eliminate any noise issues. The averaging technique I used in this project is a little different than most but I will explain later on
  2. The next variable is the tol variable. This variable is the maximum voltage different between the lowest cell and the rest of the cells in the 4S pack. Currently its set to a maximum of 30mV difference but this can be set to a minimum of 10mV because of the 8-bit adc on the arduino.
arduino_code_voltage_divider_section
  1. Here is the scaling factor for the adc from the cell measurements. We have different values because in order to get the best accuracy measuring in reference to ground, different values were needed for measuring cell 1 which has a max of 4.2V and cell 4 which measures a max of 16.8V.
arduino_code_oled_section
  1. This portion of the code is mainly for the OLED screen. It allows for the screen to be removed and re attached without having to reset the arduino. Before you had to initialize it in the setup but with this loop it is initialized in the main loop when it detects the screen.
arduino_code_average_section
  1. Now this section is averaging the adc values from all 4 cells to get a best measurement of the cell voltage values. Instead of using the traditional sample 25 and take the average, I’m using a true RMS calculation that will give you a slightly better voltage measurement that just taking the average. It will be at a closer measurement to your multimeter than using average sample.

CONCLUSION / ISSUES

Here is the final PCB:

I’m pretty excited to do more testing on this and I will post my technical review later on that includes current consumption, maybe a mini manual on how to use it or change values for your own build.

Again this does not include an over voltage or over current protection circuit but I decided to make that a separate board with its own controller in order to make the board as small as I could and isolate the two circuits as a redundancy. I’m still making some tweaks and might make another revision but all in all I’m very happy about it.

Some current issues that I know off.

  1. You might have to calibrate with a known good multimeter. The arduinos ADC has some weird issues with analogPin A2 measuring higher than the rest. I added a calibration value in the code to help with that.

DOWNLOAD ORIGINAL FILES

Arduino Code Download

Schematic and Gerber Download

For the Bill of Materials, I’ve embedded the datasheets for some of the major components in case you wondered why the file is larger than it should.

Footnotes

1. Minicore bootloader

Project – GRBL Controller Board

TABLE OF CONTENTS

1. Introduction
2. Bill of Materials
3. Schematic
4. 3D Redering
5. Final Thoughts
6. Download Original files

INTRODUCTION

With all the low cost CNC machines out in the market, there is also an abundant of GRBL shields for the arduino platform. Like always, I’m always looking to for ways to customize and improve whats in the market.

What I’ve created is a slightly better GRBL controller board for low cost CNC machines. This uses the Arduino Nano instead of the Uno as this allowed for more flexibility on the size of the board. It also integrates the relay switch for the spindle with an integrated flywheel diode to avoid over voltage spikes when the spindle is first turned on.

Below I’ll discuss in more detail along with the files you need to create this board.

BILL OF MATERIALS

Click here to download the bill of materials

SCHEMATIC

Here in the schematic you can see a couple of items that are different from the traditional ebay/amazon grbl shields. First of all this is not a shield per say but more of a standalone controller board.

  • Since the capacitors that are used to filter the stepper drivers are 35V rated, I’ve limited the input voltage to 24V
  • I’ve added a TVS diode at the power input that protects from over voltage spikes.
  • Used better output connectors for the stepper motor drivers
  • Added 0.1uF capacitor for the probe pin for autoleveling
  • Added x3 5V rail connectors
    • One thing to add is that these connectors are taking power from the USB port and should not be loaded more than 0.2A combined
    • I added these for low current 5V noctua fans to cool the stepper drivers
  • Added relay control on the main board to eliminate adding external relay switch for the spindle.
    • some newer versions of the grbl software, I believe v1.1 has the spindle pin and z-axis switch so thats why I included the option to switch between the two
    • I believe you can switch this back in the firmware of the grbl settings. But none the less the option is there
  • The relay controller also includes a 1000uF and a flywheel diode to prevent voltage spikes on turn-on

3D RENDERING

Here is a 3D Rendering from Kicad of the board. I’ve added this rendering because I thought it looked really cool.
FINAL THOUGHTS

Here is a picture of the final board below:

Below is the board fully soldered and it works amazing. I will add some images of the quality of boards my machine makes with the new controller board.

Future revisions of the board I will increase the 5V rail to supply up to 1A of current for high current draw fans and order accessory’s. Also, I will try to route out the limit switch pins. This will require me to remove the z-limit switch pin that connects to the spindle control but that should not be an issue.

If you have any comments or suggests please feel free to send them my way.

Thank you!!

Download original files here.

I have about 8 extra PCB boards that I’d be willing to sell. Let me know in the comments below if that’s something you’d like to buy

Project – DC Power and Efficiency Meter

btn_donateCC_LG.gif

TABLE OF CONTENTS

1. Introduction

2. Bill of Materials

3. Schematic

4. Code

5. ME Cad design

6. Final Thoughts

7. Download Original files

 INTRODUCTION

This is a fun little project that actually took me awhile to put together.  What makes this project interesting and useful is that it will display your voltage, current, and power of any device you plug it into.  What also makes this project useful is that it will calculate the efficiency of your device for example a dc dc converter.

The heart of this project is two INA219 high side current sensors from Texas Instruments.  With this sensor you can measure up to 26V DC and up to +/-3.2A with a 0.1ohm shunt resistor (if you swap out the shunt with a 0.01ohm shunt you can measure up to +/-32A)

BILL OF MATERIALS

Click Here for bill of materials

BLOCK DIAGRAM

Here you can see a block diagram showing how I connected the different boards to create this project. Since I used my CNC machine to create the boards, it’s always much easier to separate the circuits into different boards for routing.

The main board consist of an arduino pro mini to keep the footprint as small as I can and also host a 5V boost converter being power from the 18650 lithium ion battery.  In order to charge the battery without having to remove it from the enclosure, I decided to add a lithium ion charger board that connects in parallel with the battery.  Its powered by a 5V USB mini connector and can be bought on amazon.

The second board host x2 INA219 high side I2C current, voltage, and power sensor by Texas Instrument.  This IC is an amazing little thing because it takes a lot of the number crunching away from the Arduino and just sends the data over I2C that you need.

The final piece of this is the I2C liquidcrystal display for the arduino.  I used this library here for the display.  Make sure you connect the display and run an i2c address scanner on the examples for arduino because sometimes the displays have a different address than the default one listed.

SCHEMATIC

CODE


/*

 * Name: Steven Guzman

 * Date: 2018/03/18

 * Description: This is a DC power meter that measures input and output

 *              power and calculates the efficiency of the system.

 *              It can also measure voltage and current of one or two

 *              voltage sources

*/

#include

#include

#include 

LiquidCrystal_I2C lcd(0x3F,20,4); // Set the LCD address

/*

 * Below are the array values to store the measurements

 * and then used to convert float to string

 */

char float_volt1[8];  // voltage 1 array

char batt0[21];

char float_volt2[8];  // voltage 2 array

char batt1[21];

char float_current1[8]; // current 1 array

char curr1[21];

char float_current2[8]; // current 1 array

char curr2[21];

char float_eff[8];  // efficiency variable array

char line6[21];

char float_batt[6]; // battery voltage array

char line5[21];

// Analog sampling number

int sample = 20;

// Inialize current sensors.

// ina219_A default address is 0x40

Adafruit_INA219 ina219_A;

Adafruit_INA219 ina219_B(0x43);

// Variables to store current sensor data

float busvoltage1 = 0;

float busvoltage2 = 0;

float current_mA1 = 0;

float current_mA2 = 0;

float batt = 0.00;

void setup()

{

  Serial.begin(115200);

  while(!Serial)

  {

    delay(1);

  }

  ina219_A.begin();

  ina219_B.begin();

  lcd.init();

  lcd.init();

  lcd.backlight();

}

void loop()

{

  float xbat = 0.00;

  for(int x=0;x<sample;x++)

  {

    batt = analogRead(A0);

    xbat = xbat + batt;

  }

  // Read voltage levels from the voltage address

  // of the IN219 on both ICs

  busvoltage1 = ina219_B.getBusVoltage_V();

  busvoltage2 = ina219_A.getBusVoltage_V();

  // Read current levels from the current address

  // of the IN219 on both ICs

  current_mA1 = ina219_B.getCurrent_mA();

  current_mA2 = ina219_A.getCurrent_mA();

  // Average out the analog measurements

  // for the lithum ion battery voltage

  // sensing

  xbat = xbat/sample;

  float battery = xbat * (5.00/1024);

  dtostrf(battery,4,2,float_batt);

  sprintf(line5, "Battery:%-5s",float_batt);

  char temp3[] = "V";

  strcat(line5,temp3);

  // Convert float values into an char array to

  // better update on the lcd screen without

  // having to use the lcd.clear function

  dtostrf(busvoltage1,4,2,float_volt1);

  sprintf(batt0, "V1:%-5s",float_volt1);

  char temp2[] = "V";

  strcat(batt0, temp2);

  dtostrf(busvoltage2,4,2,float_volt2);

  sprintf(batt1, "V2:%-5s",float_volt2);

  char temp1[] = "V";

  strcat(batt1, temp1);

  // Convert mA to A readings

  float C1 = current_mA1/1000;

  float C2 = current_mA2/1000;

  dtostrf(C1,4,2,float_current1);

  sprintf(curr1, "C1:%-5s",float_current1);

  char temp4[] = "A";

  strcat(curr1, temp4);

  dtostrf(C2,4,2,float_current2);

  sprintf(curr2, "C2:%-5s",float_current2);

  char temp5[] = "A";

  strcat(curr2, temp5);

  float power1 = busvoltage1 * C1;

  float power2 = busvoltage2 * C2;

  float eff = (power2/power1)*100;

  dtostrf(eff,5,2,float_eff);

  sprintf(line6, "Efficiency:%-7s",float_eff);

  /*

   * Display on LCD screen all the values.

   * I used char arrays to update the values on the

   * screen.  Using the lcd.clear caused flickering

   * and was annoying.  With char array you can include

   * the units and it will update properly and not

   * overright the units.

   */

  lcd.setCursor(0,0);

  lcd.print(batt0);

  lcd.setCursor(11,0);

  lcd.print(batt1);

  lcd.setCursor(0,1);

  lcd.print(curr1);

  lcd.setCursor(11,1);

  lcd.print(curr2);

  lcd.setCursor(0,2);

  lcd.print(line6);

  lcd.setCursor(0,3);

  lcd.print(line5);

  delay(500);

}

There might be some issues with how wordpress displays the arduino code but I attached the original files at the end this tutorial.

As mentioned before, the libraries used here I obtained from other sources:

  1. Liquid crystal display library
  2. INA219 adafruit library

ME CAD DESIGN

I designed the enclosure in fusion 360 and printed the both with matterhackers pro series PETG red.  I used a monoprice maker select v2 to print this enclosure.

Here is the step file for the enclosure

FINAL THOUGHTS

This was one of my favorite projects yet because the design alone makes me feel accomplished learning everything on my own.  I still feel like I can make some upgrades to how I mount the internals and to be honest, I really rushed this part because I wanted to finish it.

Some upgrades I’m considering is using the arduinos internal 1.1V reference with a voltage divider to measure the battery voltage because it wasn’t as accurate as I wanted it to be.

Thank you for visiting and reading my project. if you have any questions or comments or suggestions please don’t hesitate to ask.

DOWNLOAD ORIGINAL FILES 

Original files

Electronics: FTDI USB TO UART

btn_donateCC_LG.gif

TABLE OF CONTENTS

1. Introduction

2. Bill of Materials

3. Schematic

4. Oshpark

5. Final Thoughts

6. Download Original files

INTRODUCTION

With the Arduino mini, there is a need for a USB to UART controller to upload your sketches and this could also be used for the ESP8266.

This project is inspired and based off the Sparkfun’s FT231X breakout board design.  I’ve created this project because 1. I like designing and soldering electronics 2. Try to create a cheaper alternative to the popular FT232RL and also add 1 or 2 features to the current FT231X breakout board.

BILL OF MATERIALS

For the bill of materials, its pretty straight forward.  I’ve attached links to digikey for each component as I find them easier to order from but you could also get the parts from arrow or mouser as well.

 

Component Description Part number Quantity Link
47pF, 0603, 50V C1608C0G1H470J080AA 2 Digikey
0.1uF, 0603, 25V CGA3E2X7R1E104K080AA 4 Digikey
10uF, 0805, 6.3V TCJN106M006R0250 1 Digikey
Micro B Connector 10118192-0001LF 1 Digikey
6-pin Header M20-7910642R 1 Digikey
N-Channel FET BSS84-FDICT-ND 1 Digikey
27 ohm, 1206 RC1206JR-0727RL 2 Digikey
10k, 0603 RT0603DRD0710KL 2 Digikey
FT231X, SSOP-20 FT231XS-U 1 Digikey

SCHEMATIC

Below I’ve attached an image of the schematic but i’ve also attached the original kicad files and a PDF version of the schematic at the end of the post.

OSHPARK

If you feel like you want to get this board made, I’ve attached a link to my oshpark project.  With oshpark, I find they make great quality boards at a great price for small sized boards.

Order from OSH Park

FINAL THOUGHTS

I know this was a short post and project but I found it important to share another option for those’s who want to find a cheaper solution and want to learn along the way.  You can find a lot cheaper solutions on amazon that are china made but i’ve read stories in some cases that they were not genuine FT232RL ICs.  If you wish to build your own, its very easy and rewarding at the same time.

In the next revision I will add LEDS for TX and RX indication as for this version I eliminated to save some cost and space.

Hope you enjoyed this post, THANK YOU 🙂

DOWNLOAD ORIGINAL FILES

https://app.box.com/s/50ap9obq89ucydbqqn54tye6ae3xiu34

CNC: CNC CONTROL BOX

btn_donateCC_LG.gif

SUMMARY

1. Introduction

2. Bill of Materials

3. Block Diagram

4. Schematics/CAD DESIGN

5. Assembly

6. Final Thoughts/ Improvements

7. Download Original Files

INTRODUCTION

Arduino and the implementation of GRBL has allow for amazing things to be created.  One of those things are low cost CNC machines that enable us to create anything we want.

I bought myself a low cost CNC engraver from amazon and after modifying it, it has been one of my best investments because as en electrical engineer I can create PCB boards to test my designs here at home and verify before getting them sent out. One problem I usually have is that I use my laptop to run the gcode software and my laptop is really big and sometimes a hassle to keep on my desk.

My solution was to create this project and make a standalone CNC machine controller to run the gcode software in a compact package.  I tried fiddling around with using a raspberry pi 2 as my main PC but I’m still a beginner with raspberry pi’s and I had issues getting the settings right.  My next option was to use a windows based machine and luckily I found just the solution.

In this tutorial I will explain how I put this together and what improvements could be made.

BILL OF MATERIALS

Component Quantity Link
Windows computer stick 1 Amazon
Wireless keyboard/mouse 1 Amazon
DIY HDMI male adapter angled 1 Adafruit
DIY HDMI female adapter 1 Adafruit
DIY HDMI Ribbon cable 20cm 1 Adafruit
3.5 inch Screen 1 Amazon
Left angled micro usb cable 1 Amazon
Top angled usb 3.0 extension 1 Amazon
USB Board
USB Female Connector 2 Sparkfun
5VWM TVS Diode 1 Digikey
0.1uF 50V X7R 1206 1 Digikey
1uF 25V X7R 0805 1 Digikey
10uF 16V X5R 0805 1 Digikey
100 OHM 0.1% 1/8W 0805 2 Digikey
TERM BLOCK 5MM 2POS 2 Digikey

BLOCK DIAGRAM

Visio_blog - block diagram

Here is the block diagram for how this project is wired.  With the exception of the enclosure itself and the usb power board, everything was bought ready to go.  I’ve added a fan as a just in case because the computer stick does generate some heat so the fan will prevent the system from over heating but so far it does not seem to be an issue with heat and therefore is an option.

The 5V and 12V supply are coming from my 24V power supply that powers my Arduino GRBL shield.  What I did was use two step down converters 1) For 5V step down and 2) For 12V step down.  I realized this might not be idle but it is my first revision of this project.

SCHEMATICS/ CAD DESIGN

The only schematics I have is for the USB power board and I created that using Kicad.  The board was basic, since both the screen and the windows computer stick ran on 5V via micro USB, I needed to distribute power from one source into two loads.  To add some safety, I did add a TVS 5VWM diode to prevent over voltage spikes from destroying the devices along with some filtering capacitors.

Electronics_pdf - cnc usb power board-1

If its a little blurry don’t worry because all original files will be included in a download link at the end.

Now for the enclosure, I designed it using Fusion 360.  Honestly, I am not a Mechanical engineer/Designer so this was my first attempt at designing something in a CAD software.  Mine you its really just a box but Fusion 360 makes it really easy to design for someone who had no prior experience.

I designed this in two pieces:

  1. The bottom portion of the enclosure:CAD_pdf - Enclosure Drawings-1
  2. The Lid for the enclosure:CAD_pdf - Lid Drawings-1

For material used for making this enclosure, I used my Maker Select V2 3D printer with PETG filament for the temperature resistance and flexibility.

I will include the STL files so you guys can 3D print this yourself.

ASSEMBLY

Now for the fun part, putting this thing together and hoping everything works without the magic white smoke lol jk.  This was actually very easy to put together though there were a couple of design hick ups.

Since I wanted to get the print out as fast as possible, I sacrificed quality of the print which is why it looks the way it does but its very function.

As I mentioned I did have some design issues after I was putting this thing together.  If you look at image 3, you can see that the usb power board is tilted up and thats because I placed the cooling fan to close.  The board was able to fit but I could not connect anything because the fan was blocking the connectors.

I decided to use hot glue to hold everything down because it wouldn’t be a DIY project if hot glue wasn’t involved.

In image 4, you can see I used some basic terminal block connectors to attach my 5V and 12V supply.  You can also see the USB port to connect the arduino grbl controller board.

FINAL THOUGHTS/IMPROVEMENTS

Overall I enjoyed putting this project together.  It’s made my project efficiency increase dramatically because I don’t have to take it out and set it up every time I want to make a board.

With anything we do, there’s always room for improvements.  In a future version of this project I plan to improve the way I connect my external 5V and 12V supply instead of using the terminal blocks.  I might possibly use some type of molex connector that can easily detach.  To reduce the amount of external connectors, I could switch out the 12V fan with a 5V fan and run it with only one step down converter.  I’m going to also move the fan placement so that I do not have to angle the usb power board.

DOWNLOAD ORIGINAL FILES

Bill of Materials

KiCad files

3D STL files

PDF Documents

Thank you for visiting and I hope you enjoyed this project.

Please leave a comment and let me know about your thoughts, improvements or any issues you see with this post.  All comments are welcomed 🙂

Arduino – Garage Door Indicator

First I would like to say thank you in advance for visiting my site.  My goal is to help anyone who loves to work with electronics.

btn_donateCC_LG.gif

TABLE OF CONTENTS

1. Introduction

2. Bill of Material

3. Block Diagram

4. Schematics

5. Arduino Uno sketch and upload

6. ESP8266 sketch and upload

7. Final thoughts

8. Download original files

INTRODUCTION

I don’t know about you guys but when it comes to closing my garage door I always seem to forget.  Most of the time I don’t even notice until the night before I head to bed.  I was getting tired of leaving it open so then I was inspired to create this project.

The garage door indicator project essentially sends you a text if the garage door is left open for more than 5 minutes.  It uses an arduino, ESP8266, and IFTTT to remind me that I left it open.

Lets get started!

BILL OF MATERIAL

Board Part Quantity Link
Arduino Board
 Arduino Pro Mini 1 Amazon
ESP8266 Board
ESP8266 ESP01 1 Amazon
RC1206JR-0710KL 4 Digikey
C1206C104K5RAC7867 2 Digikey
Boost Converter #1: Arduino Board
GRM21BR61E475MA12L 1 Digikey
MCP1640T-I 1 Digikey
GRM21BR61C106KE15K 3 Digikey
RC0805JR-07560KL 1 Digikey
TC33X-2-105E 1 Digikey
MSS5131-103ML 1 Coilcraft
Boost Converter #2: ESP8266
AAT1217ICA-3.3-T1 1 Digikey
GRM21BR61E475MA12L 1 Digikey
GRM21BR61C106KE15K 3 Digikey
RC1206JR-071ML 1 Digikey
MSS5131-472ML 1 Coilcraft
Switch: ESP8266 Power
DMG2305UX 2 Digikey / Arrow
2N7002-7-F 1 Digikey
RC1206JR-0751KL 1 Digikey
RC1206JR-0710KL 1 Digikey

BLOCK DIAGRAM

Electronics - Garden_Block diagram_01

Here the block diagram gives you a general idea of how this is connected together. I’ve made this project very modular so upgrades and replacements are easy to do.  I decided to go with two boost converters because the ESP8266 has a lot of noise issues that always messed with my arduino board and so separating the supplies and the controllers from each other did the trick.

SCHEMATICS

Below I’ve listed all the schematics that are associated with this design.  I’ve designed this project to be very modular because I CNC mill all the boards and it makes it a lot easier to work with.

If you click on the schematic images, i’ll take you to the pdf version that you can download.

Arduino nano board:

Arduino Board

ESP8266 Board:

Electronics - ESP8266 Board

Boost Converter #1:

Electronics - MCP1640

Boost Converter #2:

Electronics - AAT1217

Switch: ESP8266 Power:

Electronics - Switch ESP8266

ARDUINO NANO SKETCH

Here is the arduino sketch used in the garage door project.  Essential the arduino nano is used to first sense the status of the garage door and second to wake up the ESP8266.

The way this sketch is written is the arduino is put into an 8 second sleep state because thats the longest the watchdog timer will fire.  This is then looped in that adds up to 5 minutes.

The reed switch is connected to the interrupt pin 2 on the nano and is used to wake up the arduino  when the door is open.  Then a counter will start counting and when 5 minutes are up that the door is left open, this will activate the switch that will turn on the ESP8266.


#include "LowPower.h"

int ESP8266 = 10;

int Open = 2;

int x = 0;

void setup()

{

  pinMode(ESP8266,OUTPUT);

  pinMode(Open,INPUT);

  digitalWrite(ESP8266,LOW);

  delay(500);

}

void loop()

{

  // put your main code here, to run repeatedly:

    // Low power sleep mode is used here to put the arduino

    // in an 8s sleep state

    LowPower.powerDown(SLEEP_8S,ADC_OFF,BOD_OFF);

    if (digitalRead(Open) == HIGH)

    {

      x = x + 1;

    }

    // Here is the value entered that will

    // set the time it takes for it to

    // wake up the ESP8266

    // 2 minutes = 15

    // 4 minutes = 30

    // 5 minutes = 39

    // 10 minutes = 80

    if ( x == 39)

    {

      digitalWrite(ESP8266, HIGH);

      delay(10000);

      digitalWrite(ESP8266,LOW);

      x = 0;

    }

    if (digitalRead(Open) == LOW)

    {

      x = 0;

    }

    delay(100);

}

All sketches and libraries will be attached in the links at the end of the post under download files

ESP8266 SKETCH AND UPLOAD

After the arduino nano is configured to wake up the ESP8266, the next thing we will do is load the sketch for the ESP8266.

Now before we go into the sketch, we first need to setup an account with IFTTT.com.  After that is done then we need to create a new applet.

IFTTT - New Applet

Next, we click on If this:

IFTTT - If this

Next, we search for webhooks service:

IFTTT - Webhooks

After that, we create the trigger.  Here we enter “Door” as our trigger:

IFTTT - Trigger

Now we need to create the action, in this case send a text when this is activated.  We click on THAT now:

IFTTT - That

We search for SMS and click on the first one:

IFTTT - SMS.PNG

We now set the action, leave it as is and click on create:

IFTTT - Event.PNG

Then you click finish.

In case your phone number is not set, lets go to search:

IFTTT - sms_number.PNG

And we click on settings and edit.  Here you enter your phone number you wish to receive your text:

IFTTT - Pin.PNG

Now the last and most important part, we need to get your “mykey” needed to link ifttt with your esp8266.

We go to search again and this time type in webhooks.  Then you go to settings and you copy the highlighted key into your ESP8266 sketch:

IFTTT - Webhooks_mykey

Now you are ready to continue to the sketch.

Here is the sketch for the ESP8266.

Original sketch was taken from this link and modified slightly for my project.


///////////////////////////////////////////////////////////////////////////////////////////////////

// Name: Steven Guzman

// Date: 12/13/2017

// Description: ESP8266 code for sending a message over to IFTTT that the garage door is open

///////////////////////////////////////////////////////////////////////////////////////////////////

#include &amp;amp;lt;ESP8266WiFi.h&amp;amp;gt;

#include &amp;amp;lt;arduino.h&amp;amp;gt;

#include &amp;amp;lt;SPI.h&amp;amp;gt;

#include "DataToMaker.h"

#define SERIAL_DEBUG // Uncomment this to dissable serial debugging

// Define program constants

const char* myKey = ""Enter your key right here"; // your maker key here

const char* ssid = "Enter your SSID wifi name here"; // your router ssid here

const char* password = "Enter your password here"; // your router password here

// declare new maker event with the name "ESP"

DataToMaker event(myKey, "Door");&amp;amp;lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&amp;amp;gt;&amp;amp;amp;#65279;&amp;amp;lt;/span&amp;amp;gt;

// LEAVE SET

bool connectedToWiFI = false;

void setup()

{

#ifdef SERIAL_DEBUG

  Serial.begin(115200);

  delay(200);

  Serial.println();

#endif

  pinMode(2,INPUT);

  delay(10); // short delay

  WiFi.mode(WIFI_STA);

  ConnectWifi();

}

void loop() {

  if (wifiConnected)

  {

  debugln("connecting...");

    if (event.connect())

    {

       if (digitalRead(2) == HIGH)

      {

       event.setValue(1,"Garage Door is Open, close it NOW!!");

       debugln("Connected To Maker");

       event.post();

      }

      if (digitalRead(2) == LOW)

      {

        event.setValue(1,"Garage Door is Closed");

        debugln("Connect to Maker");

        event.post();

      }

    }

    else debugln("Failed To Connect To Maker!");

    delay(5000); // pause for 1 second

  }

  else

  {

    delay(60 * 1000); // 1 minute delay before trying to re connect

    ConnectWifi();

  }

}

bool ConnectWifi()

{

  // Connect to WiFi network

  debugln();

  debugln();

  debug("Connecting to ");

  debugln(ssid);

  unsigned long startTime = millis();

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED &amp;amp;amp;&amp;amp;amp; startTime + 30 * 1000 &amp;amp;gt;= millis()) {

    delay(500);

    debug(".");

  }

  if (WiFi.status() == WL_CONNECTED)

  {

    debugln("");

    debugln("WiFi connected");

  }

  else

  {

    WiFi.disconnect();

    debugln("");

    debugln("WiFi Timed Out!");

  }

}

bool wifiConnected()

{

  return WiFi.status() == WL_CONNECTED;

}

void debug(String message)

{

#ifdef SERIAL_DEBUG

  Serial.print(message);

#endif

}

void debugln(String message)

{

#ifdef SERIAL_DEBUG

  Serial.println(message);

#endif

}

void debugln()

{

#ifdef SERIAL_DEBUG

  Serial.println();

#endif

}

Here is the second file needed for the ESP8266:


#include &lt;Arduino.h&gt;

#include &lt;ESP8266WiFi.h&gt;

#ifndef DataToMaker_h

class DataToMaker

{

  public:

    DataToMaker(const char*, String); // constructor

    bool connect();

    bool setValue(int, String);

    void sendToMaker();

    void post();

  protected: // it is protected because the subclass needs access

    //to max distance!

  private:

    void compileData();

    WiFiClient client;

    const char* privateKey;

    String event;

    String value1, value2, value3 = "";

    bool dataAvailable;

    String postData;

};

DataToMaker::DataToMaker(const char* _privateKey, String _event)

{

  privateKey = _privateKey;

  event = _event;

}

bool DataToMaker::connect()

{

  if (client.connect("maker.ifttt.com", 80))

    return true;

  else return false;

}

void DataToMaker::post()

{

  compileData();

  client.print("POST /trigger/");

  client.print(event);

  client.print("/with/key/");

  client.print(privateKey);

  client.println(" HTTP/1.1");

  client.println("Host: maker.ifttt.com");

  client.println("User-Agent: Arduino/1.0");

  client.println("Connection: close");

  if (dataAvailable)

  { // append json values if available

    client.println("Content-Type: application/json");

    client.print("Content-Length: ");

    client.println(postData.length());

    client.println();

    client.println(postData);

  }

  else

    client.println();

}

bool DataToMaker::setValue(int valueToSet, String value)

{

  switch (valueToSet)

  {

    case 1:

      value1 = value;

      break;

    case 2:

      value2 = value;

      break;

    case 3:

      value3 = value;

      break;

    default:

      return false;

      break;

  }

  return true;

}

void DataToMaker::compileData()

{

  if (value1 != "" || value2 != "" || value3 != "")

  {

    dataAvailable = true;

    bool valueEntered = false;

    postData = "{";

    if (value1 != "")

    {

      postData.concat("\"value1\":\"");

      postData.concat(value1);

      valueEntered = true;

    }

    if (value2 != "")

    {

      if (valueEntered)postData.concat("\",");

      postData.concat("\"value2\":\"");

      postData.concat(value2);

      valueEntered = true;

    }

    if (value3 != "")

    {

      if (valueEntered)postData.concat("\",");

      postData.concat("\"value3\":\"");

      postData.concat(value3);

    }

    postData.concat("\"}");

  }

  else dataAvailable = false;

}

#endif&lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&gt;&lt;/span&gt;

Make sure to place the datatomaker file code above in the same directory as the ESP8266 code.

FINAL THOUGHTS

Here is the final project assembled:

IMG_20171216_144834.jpg

This project was not designed to be pretty but since I used my CNC machine to mill out the boards I was limited to the one side.  There is an upside to designing it this way, if one or two of the boards happen to malfunction, you can switch it out.  Or if you ever need to upgrade, you can easily swap out what you need to upgrade.

I’m planning on making a professional board and consolidating the boards into one or two boards in the future but for now I’m happy with the results.

If you have any questions please feel free to comment or if you find an error or an issue with anything posted please let me know and I’ll correct it.

THANK YOU!

DOWNLOAD FILES

Project files