/*
Name: TeensyLowPowerDigitalScale.ino
Created: 12/2/2018 9:43:43 PM
Author: FRANKWIN10\Frank
*/
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#pragma region LOW_POWER_SUPP
//12/03/18 added for low power mode
#include <Snooze.h>
// Load just the 'timer' wake-up driver
SnoozeTimer timer;
SnoozeUSBSerial usb;
SnoozeBlock config_teensy32(usb, timer);
const int SLEEP_TIME_MSEC = 5000;
//const float INACTIVE_SCALE_THRESHOLD_KG = 1.f;
const float INACTIVE_SCALE_THRESHOLD_KG = -10.f;
//const int MIN_INACTIVE_SCALE_COUNT = 100;
const int MIN_INACTIVE_SCALE_COUNT = 20;
int numInactiveScaleCounts = 0;
#pragma endregion Low Power Support
#pragma region LOAD_CELL
#include "HX711.h" //You must have this library in your arduino library folder
#include <EEPROM.h>
#include<EEPROMAnything.h> //so I can read the last calibration value from EEPROM
#define DOUT A1
#define CLK A0
HX711 scale(DOUT, CLK);
//Change this calibration factor as per your load cell once it is found. You many need to vary it in thousands
long calibration_factor = -96650; //-106600 worked for my 40Kg max scale setup
long tare_offset = 0;
const int LED_PIN = 13;
const int CAL_FACTOR_EEPROM_ADDR = 0;
const int TARE_OFFSET_EEPROM_ADDR = CAL_FACTOR_EEPROM_ADDR + sizeof(calibration_factor);
float scaleKg = 0;
float vBatt = 0;
#pragma endregion Load Cell Support
#pragma region LCD_DISPLAY
// Hardware SPI (faster, but must use certain hardware pins):
// Note with hardware SPI MISO and SS pins aren't used but will still be read
// and written to during SPI transfer. Be careful sharing these pins!
// SCK is LCD serial clock (SCLK) - this is pin 13 on Arduino Uno
// MOSI is LCD DIN - this is pin 11 on an Arduino Uno
// pin 6 - Data/Command select (D/C)
// pin 5 - LCD chip select (CS)
// pin 4 - LCD reset (RST)
const int LCD_DC_PIN = 6;
const int LCD_CS_PIN = 5;
const int LCD_RST_PIN = 4;
const int SPI_DOUT_PIN = 11;
const int SPI_SCK_PIN = A0;
//Adafruit_PCD8544 display = Adafruit_PCD8544(6, 5, 4);//11/25/18
Adafruit_PCD8544 display = Adafruit_PCD8544(LCD_DC_PIN, LCD_CS_PIN, LCD_RST_PIN);//12/16/18 chg to identifiers
#pragma endregion Noki LCD Display
#pragma region BATT_FUEL_GUAGE
const int BATT_SYMBOL_X = 68;
const int BATT_SYMBOL_Y = 1;
const int BATT_SYMBOL_H = 8;
const int BATT_SYMBOL_W = 16;
const int DEFAULT_CHAR_HEIGHT = 8;
const int DEFAULT_CHAR_WIDTH = 5;
const int DEFAULT_CHAR_SIZE = 2;
//added 12/03/18 for battV measurements
//12/06/18 changed to internal 1.2V reference and 30K:10K divider
const int DEAD_BATT_COUNTS = 642;
const int FULL_BATT_COUNTS = 887;
const float FULL_BATT_VOLTS = 4.2;
const float DEAD_BATT_VOLTS = 3.0;
const float VOLTS_PER_COUNT = (FULL_BATT_VOLTS - DEAD_BATT_VOLTS) / (FULL_BATT_COUNTS - DEAD_BATT_COUNTS);
#pragma endregion Battery Fuel Guage
void setup()
{
Serial.begin(115200);
delay(1000); //need this to get serial printout
Serial.println("Welcome to the Teensy Low Power Digital Scale Program");
Serial1.begin(9600);
Serial1.println("Welcome via Bluetooth!");
/********************************************************
Set Low Power Timer wake up in milliseconds.
********************************************************/
timer.setTimer(SLEEP_TIME_MSEC);// milliseconds
//12/04/18 added code to set analog reference to internal 1.2V source
analogReference(INTERNAL1V1);
//initialize load cell and retrieve cal/tar values from EEPROM
EEPROM_readAnything(CAL_FACTOR_EEPROM_ADDR, calibration_factor); //read current cal scale from EEPROM
Serial.printf("The current stored scale calibration factor is %li\n", calibration_factor);
scale.set_scale(calibration_factor);
EEPROM_readAnything(TARE_OFFSET_EEPROM_ADDR, tare_offset); //read current tare offset from EEPROM
Serial.printf("The current stored tare offset factor is %li\n", tare_offset);
scale.set_offset(tare_offset);
//initialize LCD display
display.begin();
display.setContrast(60); //pretty dark
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0, 0);
display.display(); //first time - shows the Adafruit logo
delay(1000); //show Adafruit logo for 1 sec
display.clearDisplay(); // clears the screen and buffer
display.display(); //first time - shows the Adafruit logo
////initial battery and scale reading
//vBatt = UpdateBatteryDisplay();
//scaleKg = UpdateScaleDisplay();
//display.display();
}
void loop()
{
//12/06/18 now using 30K/10K voltage divider on A7 and 1.2V ref.
display.clearDisplay(); //clear memory bitmap
display.setCursor(0, 0);
vBatt = UpdateBatteryDisplay();
//scaleKg = UpdateScaleDisplay();
scaleKg = scale.get_units(3);
Serial1.printf("%5.3f\n\r", scaleKg); //to BT module
Serial.printf("%5.3f\n", scaleKg); //to serial console
display.print(scaleKg); display.println(" Kg");//to LCD display
display.display();
//if the scale has been quiet for a while, go to sleep
if (scaleKg <= INACTIVE_SCALE_THRESHOLD_KG)
{
numInactiveScaleCounts++;
if (numInactiveScaleCounts >= MIN_INACTIVE_SCALE_COUNT)
{
numInactiveScaleCounts = MIN_INACTIVE_SCALE_COUNT;
}
//numInactiveScaleCounts = (numInactiveScaleCounts >= MIN_INACTIVE_SCALE_COUNT) ?
// MIN_INACTIVE_SCALE_COUNT : numInactiveScaleCounts++;
//display.display();
}
else
{
numInactiveScaleCounts = 0; //one active measurment wakes everything up
//vBatt = UpdateBatteryDisplay();
//scaleKg = UpdateScaleDisplay();
//display.display();
}
if (numInactiveScaleCounts >= MIN_INACTIVE_SCALE_COUNT)
{
Serial.printf("Going to sleep at %li mSec\n", millis());
//numInactiveScaleCounts = 0; //this should cause system to stay awake for a second or so
display.clearDisplay();
display.display();
Snooze.sleep(config_teensy32); //sleep
}
delay(100);
}
float UpdateScaleDisplay()
{
float kG = scale.get_units(3);
//float kG = (float)random(0,40);
display.print(kG); display.println(" Kg");
return kG;
}
float UpdateBatteryDisplay()
{
int batt_counts = analogRead(A9);
float batt_volts = DEAD_BATT_VOLTS + (batt_counts - DEAD_BATT_COUNTS) * VOLTS_PER_COUNT;
display.print(batt_volts); display.println(" V");
UpdateBatterySymbol(batt_volts);
return batt_volts;
}
void UpdateBatterySymbol(float vbatt)
{
//Purpose: Update the battery symbol to show current charge state
//Inputs:
// vbatt = current battery voltage
// FULL_BATT_VOLTS = fully charged battery voltage
// DEAD_BATT_VOLTS = fully discharged battery voltage
// BATT_SYMBOL_X/Y/H/W = battery symbol loc/dims
//Outputs: Updated battery symbol
//Plan:
// Step1: draw open rect for battery symbol outline
// Step2: draw filled rect indicating charge state
// Step3: If vbatt <= DEAD_BATT_VOLTS, draw 'X' over symbol
//Step1: draw open rect for battery symbol outline
display.drawRect(BATT_SYMBOL_X, BATT_SYMBOL_Y, BATT_SYMBOL_W, BATT_SYMBOL_H, 1);
//Step2: draw filled rect indicating charge state
float Vrange = FULL_BATT_VOLTS - DEAD_BATT_VOLTS;
int fillWidth = (int)(BATT_SYMBOL_W * ((vbatt - DEAD_BATT_VOLTS) / Vrange) + 0.5f);
//Serial.printf("vbat, fillW = %4.2f,%d\n", vbatt, fillWidth);
display.fillRect(BATT_SYMBOL_X, BATT_SYMBOL_Y, fillWidth, BATT_SYMBOL_H, 1);
//Step3: If vbatt <= DEAD_BATT_VOLTS, draw 'X' over symbol
if (vbatt <= DEAD_BATT_VOLTS)
{
//try drawing lines from corner to corner
int ulX = BATT_SYMBOL_X;
int ulY = BATT_SYMBOL_Y;
int urX = BATT_SYMBOL_X + BATT_SYMBOL_W;
int urY = ulY;
int lrX = urX;
int lrY = urY + BATT_SYMBOL_H;
int llX = ulX;
int llY = lrY;
display.drawLine(ulX, ulY, lrX, lrY, 1);
display.drawLine(llX, llY, urX, urY, 1);
}
}