Arduino Bottom Feed Vape Mod


Introduction to Arduino Bottom Feed Vape Mod

The purpose of this post is to simply show you how I built my Arduino Bottom Feed Vape Mod.    If you choose to implement any of this documentation in any way, please be responsible.   There are many dangers associated with using both the Lithium Batteries and the vape head.   Unforeseen failures can be catastrophic!  You have been warned!

Previously, I showed you how to build a standard mod with wifi.   The code for this box will include wifi, however, I did not add the ESP8266-01 to this box.  To add this feature, simply power the ESP8266-01 from the 3.3v regulator, and connect RX to TX, TX to RX between the processor and the ESP8266.  You will need to disconnect the wifi module from TX and RX, however to upload code to the processor.

Vape Mod BF

 

The parts list will be the same as the last box, with an additional 3034 mosfet, 7805 regulator, 370 aquarium air pump (6v), some tubing, a check valve, and a 120ml bottle.    You will also need a bottom feed 510 connector.   The one I purchased was from Varitube.  I liked the Varitube connector, because it’s threads are long enough to pass through the top of the wooden box.

How it works

Vape Mode Whole BF

The green button is the power button.   This button supplies power to the processor, and other control components.

The Yellow Button is for a 30% power boost.

The red and black buttons are for selection — Raise and lower power, as well as various selections in configuration mode.

Our top silver button is for the air pump.   This has two operating modes.   When the air pump is linked to the vape button (In configuration mode), this button will start the air pump when not vaping.   When you are vaping, the air pump is started automatically, so this button will inhibit the air pump.  If the air pump is “decoupled” from the vape button in the configuration menu, this button will simple start and stop the air pump at will.

The second silver button is for vaping.  We also use this button to enter the configuration mode when pressed 5 times within 3 seconds.  Configuration mode allows the alarm and time zone to be set.   You can also control the speed of the air pump, and couple the air pump to the vape button.    Most of the configuration is stored to the EEPROM on board the ZS-042 real time clock module.   This way, when power is cycled, or the batteries are replaced, we don’t loose the settings.

E-Juice Delivery System

Since the battery pack will put out over 8 volts, I  used a 7805 regulator to bring the voltage down to 5 volts before powering the air pump.   A 3034 MOSFET allows the processor to control when the air pump is energized, and it’s speed.

We place pressure on the top of the 120ml bottle, and this causes the e-juice to flow up to the atomizer.  A check valve at the top of the air pump prevents back flow into the air pump under certain conditions.

The initial problem I had is that pressure is maintained on the 120ml bottle, which caused the atomizer to flood.   I resolved this by placing a small pinhole in the top of the 120ml bottle.  Pressure will bleed off the 120ml bottle when the air pump is not running.

Here’s the code!  I have no claims that the code is perfect, and some of it is derived from other sources such as this.   You will also need the appropriate libraries installed in your Arduino IDE.


#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SimpleDHT.h>
#include <LowPower.h>
#include "i2c.h"
#include "i2c_BMP280.h"

BMP280 bmp280;
LiquidCrystal_I2C lcd(0x3f, 20, 4);
#define AT24C32_ADDRESS 0x57 // On-board 32k byte EEPROM; 128 pages of 32 bytes each

SimpleDHT22 dht22;

//Define the pins
const int ButtonPin = 2;
const int pinDHT22 = 3;
const int DownPowerPin = 4;
const int UpPowerPin = 5;
const int AirButton = 6;
const int BuzzerPin = 9;
const int FiringPin = 10;
const int AirMotor = 11;
const int PowerBoost = 12;
const int LedPin = 13;

// Discrete Variable Declarations
int ButtonState = 0;
int PowerBoostState = 0;
int BuzzerShutoffOK = 1;
int PowerLevelRaw = 50;
int PowerLevelScaled = 0;
int PowerSetting = 10;
int UpPowerState = 1;
int DownPowerState = 1;
int AirButtonState = 1;
int TimeZone = 5;
int TimeZoneOffset = 5;
int DaylightSavings = 0;
int AdjustDelay = 200;
int AirMotorDuty = 0;
int LockVapeMotor = 0;

// BMP280 Vars
float BMPtemperature;
float BMPpascal;
static float BMPmeters, BMPmetersold;

// LCD Mode
int LCDMode = 0;
int AlarmHour = 4;
int AlarmMinute = 0;

// Timers
unsigned long ButtonMillisStart = 0;
unsigned long ButtonMillisTimeout = 6000;

unsigned long FlashMillisStart = 0;
unsigned long FlashMillisTimeout = 100;

unsigned long SleepMillisStart = 0;
unsigned long SleepMillisTimeout = 300000;

unsigned long ModeMillisStart = 0;
unsigned long ModeMillisTimeout = 3000;

int ButtonTimeout = 0;
int VapeTime = 0;
int VapeTimeLast = 0;

// Counters
int MyCounter = 0;
int LightCounter = 0;
int ModeCounter = 0;

// One Shots
int ButtonRising = 0;
int ButtonFalling = 0;
int UpPowerONS = 0;
int DownPowerONS = 0;
char LastSecond;
int ModeFlag = 0;

// This is for the Real Time Clock

#define DS3231_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val) {
return ( (val / 10 * 16) + (val % 10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val) {
return ( (val / 16 * 10) + (val % 16) );
}

//----------------------------------------
void wakeUp()
{
// Just a handler for the pin interrupt.
}
//----------------------------------------

void setup() {
Wire.begin();
Serial.begin(9600);

//Read Settings from EEPROM

AlarmHour = readEEPROM(AT24C32_ADDRESS, 1, 1);
AlarmMinute = readEEPROM(AT24C32_ADDRESS, 1, 2);
TimeZone = readEEPROM(AT24C32_ADDRESS, 1, 3);
DaylightSavings = readEEPROM(AT24C32_ADDRESS, 1, 4);
PowerLevelRaw = readEEPROM(AT24C32_ADDRESS, 1, 5);
AirMotorDuty = readEEPROM(AT24C32_ADDRESS, 1, 6);
LockVapeMotor = readEEPROM(AT24C32_ADDRESS, 1, 7);

//Serial.print("Probe BMP280: ");
if (bmp280.initialize()) { //Serial.println("BMP Sensor found");
}
else
{
//Serial.println("BMP Sensor missing");
while (1) {}
}

// onetime-measure:
bmp280.setEnabled(0);
bmp280.triggerMeasurement();

//LCD Setup
lcd.init(); //initialize the lcd

// RTC
// set the initial time here:
// DS3231 seconds, minutes, hours, day, date, month, year
//setDS3231time(00,39,11,7,17,11,2017);

// Setup Pin Modes
pinMode(DownPowerPin, INPUT_PULLUP);
pinMode(UpPowerPin, INPUT_PULLUP);
pinMode(ButtonPin, INPUT_PULLUP);
pinMode(PowerBoost, INPUT_PULLUP);
pinMode(AirButton, INPUT_PULLUP);
pinMode(LedPin, OUTPUT);
//pinMode(AirMotor, OUTPUT); // Now Analog
lcd.noBacklight();

//Configure Wireless
lcd.backlight();
lcd.setCursor(0, 1);
lcd.print("Setting Mode");
Serial.println("AT+CWMODE=1");
delay(1000);

lcd.setCursor(0, 1);
lcd.print("Connecting Network");
Serial.println("AT+CWJAP=\"YourSSID\",\"YourPassword\"");
delay(3000);

}

// ---------------------------------------
// RTC Logic for Setting clock
// ---------------------------------------
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year) {
// sets time and date data to DS3231
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set next input to start at the seconds register
Wire.write(decToBcd(second)); // set seconds
Wire.write(decToBcd(minute)); // set minutes
Wire.write(decToBcd(hour)); // set hours
Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
Wire.write(decToBcd(month)); // set month
Wire.write(decToBcd(year)); // set year (0 to 99)
Wire.endTransmission();
}

void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)

{
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set DS3231 register pointer to 00h
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
// request seven bytes of data from DS3231 starting from register 00h
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f);
*dayOfWeek = bcdToDec(Wire.read());
*dayOfMonth = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
}

// ---------------------------------------
// End of RTC Code
// ---------------------------------------

//----------------------------------------
void loop() {
// read the state of the pushbuttons:
// Buttons default high, and ground when pressed.
// Therefore, we reverse the logic in the states.
// In the state tags, value of 1 = Pressed
ReadButtons();
OffSetTimeZone();

// Get the BMP280 Data
bmp280.awaitMeasurement();
bmp280.getTemperature(BMPtemperature);
bmp280.getPressure(BMPpascal);
bmp280.getAltitude(BMPmeters);
BMPmetersold = (BMPmetersold * 10 + BMPmeters) / 11;

bmp280.triggerMeasurement();

// get the milliseconds for the timers.
unsigned long CurrentMillis = millis();

//Low Power Setup
//attachInterrupt(0, wakeUp, LOW);
if ((CurrentMillis - SleepMillisStart) > SleepMillisTimeout) {
analogWrite(AirMotor, 0);
analogWrite(FiringPin, 0);
LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
}

// Power Level Control
if (DownPowerState) {
if (DownPowerONS == 0) {
PowerLevelRaw = PowerLevelRaw - 5;
}
DownPowerONS = 1;
if (PowerLevelRaw < 0) {
PowerLevelRaw = 0;
}
} else {
DownPowerONS = 0;
}

if (UpPowerState) {
if (UpPowerONS == 0) {
PowerLevelRaw = PowerLevelRaw + 5;
}
UpPowerONS = 1;
if (PowerLevelRaw > 255) {
PowerLevelRaw = 255;
}
} else {
UpPowerONS = 0;
}

PowerLevelScaled = PowerLevelRaw / 1;
if (PowerBoostState) {
PowerLevelScaled = PowerLevelScaled * 1.3;
}

// General Mode Handling

// ************************* Button is PRESSED *************************
if (ButtonState == HIGH) {
SleepMillisStart = CurrentMillis;
ButtonFalling = 0;

// Start Air motor if locked:
if (LockVapeMotor and !AirButtonState) {
analogWrite(AirMotor, AirMotorDuty);
}else if(LockVapeMotor and AirButtonState){
analogWrite(AirMotor,0);
}else if (!LockVapeMotor and AirButtonState){
analogWrite(AirMotor,AirMotorDuty);
}else if (!LockVapeMotor and !AirButtonState){
analogWrite(AirMotor,0);
}

// Set Mode
if (ModeCounter > 0 and ((CurrentMillis - ModeMillisStart) > ModeMillisTimeout)) {
ModeCounter = 0;
}
if (ModeCounter == 0) {
ModeMillisStart = CurrentMillis;
}

if (ModeFlag == 0) {
ModeCounter ++;
ModeFlag = 1;
}

analogWrite(BuzzerPin, 2);

// turn on the backlight on lcd

if ((CurrentMillis - FlashMillisStart) < FlashMillisTimeout) {
lcd.backlight();
} else if ((CurrentMillis - FlashMillisStart) < (FlashMillisTimeout * 2)) {
lcd.noBacklight();
} else {
FlashMillisStart = CurrentMillis;
}

VapeTime = ((CurrentMillis - ButtonMillisStart) / 1000);
if (VapeTime != VapeTimeLast) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("*** Running ***");
lcd.setCursor(0, 1);
if (PowerBoostState == 1) {
lcd.print ("High Power: ");
} else {
lcd.print ("Low Power: ");
}
lcd.print(VapeTime);
VapeTimeLast = VapeTime;
}

if ((CurrentMillis - ButtonMillisStart) < ButtonMillisTimeout) {
digitalWrite(LedPin, HIGH);
analogWrite(FiringPin, PowerLevelScaled);
} else {
ButtonTimeout = 1;
digitalWrite(LedPin, LOW);
analogWrite(BuzzerPin, 255);
analogWrite(FiringPin, 0);

// Clear One Shot

}
ButtonRising = 1;
} else {
// ************************* Button is RELEASED ************************
ButtonRising = 0;
if (LockVapeMotor and !AirButtonState){
analogWrite(AirMotor,0);
}else if (!LockVapeMotor and AirButtonState){
analogWrite(AirMotor, AirMotorDuty);
}else if (!LockVapeMotor and !AirButtonState){
analogWrite(AirMotor,0);
}else if (LockVapeMotor and AirButtonState){
analogWrite(AirMotor, AirMotorDuty);
}

ModeFlag = 0;
if (LightCounter > 10000) {
LightCounter = 0;
}
if (ButtonFalling == 0) {
LightCounter = 0;
}
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
&year);
hour = hour + TimeZoneOffset + DaylightSavings;
if (hour == 24) {
hour = 0;
} else if (hour == -1) {
hour = 23;
} else if (hour == -2) {
hour = 22;
} else if (hour == -3) {
hour = 21;
} else if (hour == -4) {
hour = 20;
}
if (second != LastSecond) {
LightCounter++;
float temperature = 0;
float humidity = 0;
int err = SimpleDHTErrSuccess;
if ((err = dht22.read2(pinDHT22, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
//Serial.print("Read DHT22 failed, err="); Serial.println(err);delay(200);
return;
}

//lcd.backlight();
if (LightCounter > 300) {
lcd.noBacklight();
} else {
lcd.backlight();
}
//lcd.clear();
lcd.setCursor(0, 0);
if (AirButtonState) {
lcd.print("Air Pump Running");

} else {
if (hour < 10) {
lcd.print("0");
}
lcd.print(hour);
lcd.print(":");
if (minute < 10) {
lcd.print("0");
}
lcd.print(minute);
lcd.print(":");
if (second < 10) {
lcd.print("0");
}
lcd.print(second);
lcd.print (" ");
temperature = temperature * 1.8 + 32;
lcd.print(temperature);
lcd.print((char)223);
lcd.print ("F ");
}

LastSecond = second;

lcd.setCursor(0, 1);
lcd.print("Humidity: ");
lcd.print(humidity);
lcd.print("% ");

lcd.setCursor(0, 2);
lcd.print("PSR: ");
lcd.print(BMPpascal / 3386.38867);
lcd.print(" In Hg ");

lcd.setCursor(0, 3);
lcd.print("PWR: ");
lcd.print(PowerLevelScaled);
lcd.print(" A: ");
if (AlarmHour < 10) {
lcd.print("0");
}
lcd.print(AlarmHour);
lcd.print(":");
if (AlarmMinute < 10) {
lcd.print("0");
}
lcd.print(AlarmMinute);
lcd.print(" ");
}
ButtonTimeout = 0;
ButtonMillisStart = CurrentMillis;
if (BuzzerShutoffOK == 1) {
analogWrite(BuzzerPin, 0);
}
digitalWrite(LedPin, LOW);
analogWrite(FiringPin, 0);

ButtonFalling = 1;
}

// Alarm Logic
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
&year);

hour = hour + TimeZoneOffset + DaylightSavings;
if (hour == 24) {
hour = 0;
} else if (hour == -1) {
hour = 23;
} else if (hour == -2) {
hour = 22;
} else if (hour == -3) {
hour = 21;
} else if (hour == -4) {
hour = 20;
}
if ((hour == AlarmHour) and (minute == AlarmMinute)) {
//Serial.println("Alarm");
BuzzerShutoffOK = 0;
analogWrite(BuzzerPin, 255);
} else {
BuzzerShutoffOK = 1;
}

if (UpPowerState and DownPowerState and PowerBoostState and ButtonState) {
analogWrite(FiringPin, 0);
analogWrite(AirMotor, 0);

lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Opening Garage Door");
lcd.setCursor(0, 1);

lcd.setCursor(0, 1);
lcd.print("Connecting Door... ");
Serial.println("AT+CIPSTART=\"TCP\",\"192.168.1.178\",80");
delay(2000);

lcd.setCursor(0, 1);
lcd.print("Setting Length... ");
Serial.println("AT+CIPSEND=20");
delay(1000);

lcd.setCursor(0, 1);
lcd.print("Sending Command... ");
Serial.println("GET /?DoorCMD=DC");
Serial.println("");
delay(3000);

lcd.setCursor(0, 1);
lcd.print("Closing Connection ");
Serial.println("AT+CIPCLOSE");
delay(1000);

lcd.clear();

}

if (ModeCounter == 5) {

analogWrite(FiringPin, 0);
analogWrite(BuzzerPin, 0);
analogWrite(AirMotor, 0);
lcd.backlight();
LCDMode = 1;
lcd.clear();
delay(500);
}

// Set the Alarm

while ((LCDMode > 0) and (LCDMode < 8)) {
ModeCounter = 0;
analogWrite(FiringPin, 0);
analogWrite(BuzzerPin, 0);
analogWrite(AirMotor, 0);

ReadButtons();
if (ButtonState and (LCDMode == 1)) {
LCDMode = 2;
lcd.clear();
delay(500);
}

ReadButtons();
if (ButtonState and (LCDMode == 2)) {
LCDMode = 3;
lcd.clear();
delay(500);
}

ReadButtons();
if (ButtonState and (LCDMode == 3)) {
LCDMode = 4;
lcd.clear();
delay(500);
}

ReadButtons();
if (ButtonState and (LCDMode == 4)) {
LCDMode = 5;
lcd.clear();
delay(500);
}

ReadButtons();
if (ButtonState and (LCDMode == 5)) {
LCDMode = 6;
lcd.clear();
delay(500);
}
ReadButtons();
if (ButtonState and (LCDMode == 6)) {
LCDMode = 7;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Raw Power = ");
lcd.print(PowerLevelRaw);
lcd.setCursor(0, 1);
lcd.print("Ready to Write!");
delay(500);
}

ReadButtons();
if (ButtonState and (LCDMode == 7)) {
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Finished Setting");
writeEEPROM(AT24C32_ADDRESS, 1, 1, AlarmHour);
writeEEPROM(AT24C32_ADDRESS, 1, 2, AlarmMinute);
writeEEPROM(AT24C32_ADDRESS, 1, 3, TimeZone);
writeEEPROM(AT24C32_ADDRESS, 1, 4, DaylightSavings);
writeEEPROM(AT24C32_ADDRESS, 1, 5, PowerLevelRaw);
writeEEPROM(AT24C32_ADDRESS, 1, 6, AirMotorDuty);
writeEEPROM(AT24C32_ADDRESS, 1, 7, LockVapeMotor);

delay(1000);
LCDMode = 0;
}

if ((LCDMode == 1) or (LCDMode == 2)) {
lcd.setCursor(0, 0);
lcd.print("Alarm: ");
if (AlarmHour < 10) {
lcd.print("0");
}
lcd.print(AlarmHour);
lcd.print(":");
if (AlarmMinute < 10) {
lcd.print("0");
}
lcd.print(AlarmMinute);
lcd.print(" ");
lcd.setCursor(0, 1);
if (LCDMode == 1) {
lcd.print(" *");
} else if (LCDMode == 2) {
lcd.print(" *");
}

if (UpPowerState and (LCDMode == 1)) {
AlarmHour ++;
delay(AdjustDelay);
}
if (DownPowerState and (LCDMode == 1)) {
AlarmHour --;
delay(AdjustDelay);
}
if (UpPowerState and (LCDMode == 2)) {
AlarmMinute ++;
delay(AdjustDelay);
}
if (DownPowerState and (LCDMode == 2)) {
AlarmMinute --;
delay(AdjustDelay);
}

if (AlarmHour > 23) {
AlarmHour = 0;
} else if (AlarmHour < 0) {
AlarmHour = 23;
}
if (AlarmMinute > 59) {
AlarmMinute = 0;
} else if (AlarmMinute < 0) {
AlarmMinute = 59;
}
}

if (LCDMode == 3) {
lcd.setCursor(0, 0);
lcd.print("Select Time Zone:");
lcd.setCursor(0, 1);
if (TimeZone == 1) {
lcd.print("Hawaii ");
} else if (TimeZone == 2) {
lcd.print ("Alaska ");
} else if (TimeZone == 3) {
lcd.print ("Pacific ");
} else if (TimeZone == 4) {
lcd.print ("Mountain ");
} else if (TimeZone == 5) {
lcd.print ("Central ");
} else if (TimeZone == 6) {
lcd.print ("Eastern ");
}

if (DownPowerState) {
TimeZone --;
delay(AdjustDelay);
}
if (UpPowerState) {
TimeZone ++;
delay(AdjustDelay);
}

if (TimeZone > 6) {
TimeZone = 6;
} else if (TimeZone < 1) {
TimeZone = 1;
}

}

if (LCDMode == 4) {
lcd.setCursor(0, 0);
lcd.print("Daylight Savings:");
lcd.setCursor(0, 1);
if (DaylightSavings == 0) {
lcd.print("No ");
} else if (DaylightSavings == 1) {
lcd.print ("Yes ");
}

if (DownPowerState) {
DaylightSavings = 0;
delay(AdjustDelay);
}
if (UpPowerState) {
DaylightSavings = 1;
delay(AdjustDelay);
}

}

if (LCDMode == 5) {
lcd.setCursor(0, 0);
lcd.print("Air Motor Duty:");
lcd.setCursor(0, 1);
lcd.print(AirMotorDuty);

if (DownPowerState) {
AirMotorDuty --;
delay(AdjustDelay);
}
if (UpPowerState) {
AirMotorDuty ++;
delay(AdjustDelay);
}
if (AirMotorDuty > 255) {
AirMotorDuty = 255;
} else if (AirMotorDuty < 0) {
AirMotorDuty = 0;
}

}

if (LCDMode == 6) {
lcd.setCursor(0, 0);
lcd.print("Lock Motor Vape:");
lcd.setCursor(0, 1);
if (LockVapeMotor == 0) {
lcd.print("No ");
} else if (LockVapeMotor == 1) {
lcd.print ("Yes ");
}

if (DownPowerState) {
LockVapeMotor = 0;
delay(AdjustDelay);
}
if (UpPowerState) {
LockVapeMotor = 1;
delay(AdjustDelay);
}

}

}
}

void OffSetTimeZone() {
if (TimeZone == 1) {
TimeZoneOffset = -4;
} else if (TimeZone == 2) {
TimeZoneOffset = -3;
}
else if (TimeZone == 3) {
TimeZoneOffset = -2;
}
else if (TimeZone == 4) {
TimeZoneOffset = -1;
}
else if (TimeZone == 5) {
TimeZoneOffset = 0;
} else if (TimeZone == 6) {
TimeZoneOffset = 1;
}
}

void ReadButtons() {
ButtonState = !digitalRead(ButtonPin);
PowerBoostState = !digitalRead(PowerBoost);
DownPowerState = !digitalRead(DownPowerPin);
UpPowerState = !digitalRead(UpPowerPin);
AirButtonState = !digitalRead(AirButton);

}

// Write one byte to the EEPROM
void writeEEPROM(uint8_t EEPROMaddress, uint8_t page, uint8_t entry, uint8_t data)
{
// Construct EEPROM address from page and entry input
// There are 128 pages and 32 entries (bytes) per page
// EEPROM address are 16-bit (2 byte) address where the MS four bits are zero (or don't care)
// the next seven MS bits are the page and the last five LS bits are the entry location on the page
uint16_t pageEntryAddress = (uint16_t) ((uint16_t) page << 5) | entry;
uint8_t highAddressByte = (uint8_t) (pageEntryAddress >> 8); // byte with the four MSBits of the address
uint8_t lowAddressByte = (uint8_t) (pageEntryAddress - ((uint16_t) highAddressByte << 8)); // byte with the eight LSbits of the address

Wire.beginTransmission(EEPROMaddress); // Initialize the Tx buffer
Wire.write(highAddressByte); // Put slave register address 1 in Tx buffer
Wire.write(lowAddressByte); // Put slave register address 2 in Tx buffer
Wire.write(data); // Put data in Tx buffer
delay(10); // maximum write cycle time per data sheet
Wire.endTransmission(); // Send the Tx buffer
delay(10);
}

// Read one byte from the EEPROM
uint8_t readEEPROM(uint8_t EEPROMaddress, uint8_t page, uint8_t entry)
{
uint16_t pageEntryAddress = (uint16_t) ((uint16_t) page << 5) | entry;
uint8_t highAddressByte = (uint8_t) (pageEntryAddress >> 8); // byte with the four MSBits of the address
uint8_t lowAddressByte = (uint8_t) (pageEntryAddress - ((uint16_t)highAddressByte << 8)); // byte with the eight LSbits of the address

uint8_t data; // `data` will store the register data
Wire.beginTransmission(EEPROMaddress); // Initialize the Tx buffer
Wire.write(highAddressByte); // Put slave register address 1 in Tx buffer
Wire.write(lowAddressByte); // Put slave register address 2 in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
Wire.requestFrom(EEPROMaddress, (uint8_t) 1); // Read one byte from slave register address
delay(10); // maximum write cycle time per data sheet
data = Wire.read(); // Fill Rx buffer with result
delay(10);
return data; // Return data read from slave register
}

 

Again…   Be sure you know what you are doing.   I would recommend always using protected batteries, and add extra safety features to prevent reverse polarity, and overcurrent conditions.  This document is simply how I built my own box for personal use.

— Ricky Bryce

Leave a comment

Your email address will not be published. Required fields are marked *

46 − 44 =