Skip to content

Commit

Permalink
added Coin Battery logging
Browse files Browse the repository at this point in the history
Use command "dump gps" for a CSV file of battery voltage over time
  • Loading branch information
barry-ha committed Feb 18, 2024
1 parent 5ef1ba0 commit 7d1c114
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 8 deletions.
17 changes: 17 additions & 0 deletions Griduino.ino
Expand Up @@ -834,6 +834,7 @@ void setup() {
//uint32_t prevTimeGPS = millis();
elapsedSeconds saveGpsTimer; // timer to process and save the current GPS location
elapsedSeconds autoLogTimer; // timer to save GPS trail periodically no matter what
elapsedSeconds batteryTimer; // timer to log the coin battery voltage
uint32_t prevTimeBaro = millis();
time_t prevTimeRTC = 0; // timer to print RTC to serial port (1 second)
elapsedMillis displayClockTimer; // timer to update time-of-day display (1 second)
Expand All @@ -856,6 +857,7 @@ const uint32_t GPS_AUTOSAVE_INTERVAL = SECS_PER_10MIN; // seconds between saving
//const int BAROMETRIC_PROCESS_INTERVAL = 15*60*1000; // fifteen minutes in milliseconds
const uint LOG_PRESSURE_INTERVAL = 15*60*1000; // 15 minutes, in milliseconds
const uint LOS_ANNOUNCEMENT_INTERVAL = SECS_PER_5MIN * 1000; // msec between LOS announcements
const int LOG_COIN_BATTERY_INTERVAL = 60; // seconds between logging the coin battery voltage

void loop() {

Expand Down Expand Up @@ -1033,6 +1035,21 @@ void loop() {
}
}

// periodically log the coin battery's voltage
// todo: sensor exists only on PCB v11+
if (batteryTimer > LOG_COIN_BATTERY_INTERVAL) {
batteryTimer = 0;

const float analogRef = 3.3; // analog reference voltage
const uint16_t analogBits = 1024; // ADC resolution is 10 bits

int coin_adc = analogRead(BATTERY_ADC);
float coin_voltage = (float)coin_adc * analogRef / analogBits;
logger.info("Coin battery = %s", coin_voltage, 3);

trail.rememberBAT(coin_voltage);
}

// log GPS position every few minutes, to keep track of lingering in one spot
if (autoLogTimer > GPS_AUTOSAVE_INTERVAL) {
autoLogTimer = 0;
Expand Down
9 changes: 7 additions & 2 deletions constants.h
Expand Up @@ -212,8 +212,9 @@ struct FunctionButton {
#define rFIRSTVALIDTIME "TIM"
#define rLOSSOFSIGNAL "LOS"
#define rACQUISITIONOFSIGNAL "AOS"
#define rCOINBATTERYVOLTAGE "BAT"
#define rRESET "\0\0\0"
#define rVALIDATE rGPS rPOWERUP rPOWERDOWN rFIRSTVALIDTIME rLOSSOFSIGNAL rACQUISITIONOFSIGNAL
#define rVALIDATE rGPS rPOWERUP rPOWERDOWN rFIRSTVALIDTIME rLOSSOFSIGNAL rACQUISITIONOFSIGNAL rCOINBATTERYVOLTAGE

// Breadcrumb data definition for circular buffer
class Location {
Expand All @@ -222,7 +223,7 @@ class Location {
PointGPS loc; // has-a lat/long, degrees
time_t timestamp; // has-a GMT time
uint8_t numSatellites; // number of satellites in use (not the same as in view)
float speed; // current speed over ground in MPH
float speed; // current speed over ground in MPH (or coin battery voltage)
float direction; // direction of travel, degrees from true north
float altitude; // altitude, meters above MSL
public:
Expand Down Expand Up @@ -269,6 +270,10 @@ class Location {
return (strncmp(recordType, rACQUISITIONOFSIGNAL, sizeof(recordType)) == 0);
}

bool isCoinBatteryVoltage() const {
return (strncmp(recordType, rCOINBATTERYVOLTAGE, sizeof(recordType)) == 0);
}

// print ourself - a sanity check
void printLocation(const char *comment = NULL) { // debug
Serial.println(". Rec, ___Date___ __Time__, (__Lat__, __Long__=), Alt, Spd, Dir, Sats");
Expand Down
126 changes: 126 additions & 0 deletions examples/Coin_Battery/Coin_Battery.ino
@@ -0,0 +1,126 @@
#line 1 "C:\\Users\\barry\\Documents\\Arduino\\Griduino\\examples\\Coin_Battery\\Coin_Battery.ino"
// Please format this file with clang before check-in to GitHub
/*
Coin_Battery -- simple voltage measurement of coin battery
Version history:
2024-02-14 written for Griduino both pcb v4 and v12
Software: Barry Hansen, K7BWH, barry@k7bwh.com, Seattle, WA
Hardware: John Vanderbeck, KM7O, Seattle, WA
This example code is in the public domain.
*/

#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_I2CDevice.h>

const float analogRef = 3.3; // default analog reference voltage
const uint16_t analogBits = 1024; // default ADC resolution bits
int pcbVersion = 0; // default to unknown PCB

#line 22 "C:\\Users\\barry\\Documents\\Arduino\\Griduino\\examples\\Coin_Battery\\Coin_Battery.ino"
bool detectDevice(int address);
#line 66 "C:\\Users\\barry\\Documents\\Arduino\\Griduino\\examples\\Coin_Battery\\Coin_Battery.ino"
int pcb_detect();
#line 80 "C:\\Users\\barry\\Documents\\Arduino\\Griduino\\examples\\Coin_Battery\\Coin_Battery.ino"
void setup();
#line 93 "C:\\Users\\barry\\Documents\\Arduino\\Griduino\\examples\\Coin_Battery\\Coin_Battery.ino"
void loop();
#line 22 "C:\\Users\\barry\\Documents\\Arduino\\Griduino\\examples\\Coin_Battery\\Coin_Battery.ino"
bool detectDevice(int address) {
// https://github.com/adafruit/Adafruit_BusIO/blob/master/Adafruit_I2CDevice.h
Adafruit_I2CDevice device(address);
if (device.detected()) {
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);

delay(10);
device.end();
return true;
} else {
delay(10);
device.end();
return false;
}

/* *****
// https://learn.adafruit.com/scanning-i2c-addresses/arduino
byte error;
// The i2c_scanner uses the return value of the Write.endTransmission
// to see if a device did acknowledge the address.
//WIRE.beginTransmission(address);
//error = WIRE.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
return true;
} else if (error == 4) {
Serial.print("Unknown error at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
}
return false;
***** */
}

int pcb_detect() {
Serial.println("Scanning...");
bool i00 = detectDevice(0x00);
bool i01 = detectDevice(0x01);
bool i3E = detectDevice(0x3E);
bool i77 = detectDevice(0x77);

if (!i3E || !i77) {
return 4;
} else {
return 11;
}
}

void setup() {
Serial.begin(115200);

// Wait for Serial port to open
while (!Serial) {
delay(10);
}
delay(500);
Serial.println(__FILE__);
Serial.println("Griduino Coin Battery Measurement");
Serial.println("Sampled resolution is (3.3v)/1024 = 3 mV");
}

void loop() {
Serial.println("");
pcbVersion = pcb_detect();
Serial.print("PCB version = ");
Serial.println(pcbVersion);

int coin_adc = analogRead(A2);
float coin_voltage = (float)coin_adc * analogRef / analogBits;

Serial.print("Coin battery sampled = ");
Serial.println(coin_adc);

Serial.print("Coin battery voltage = ");
Serial.print(coin_voltage);
Serial.print(" volts");

if (coin_voltage < 2.8) {
Serial.println(" Warning! Low voltage!");
} else {
Serial.println("");
}

delay(4000);
}
6 changes: 2 additions & 4 deletions hardware.h
Expand Up @@ -118,10 +118,8 @@ On-board lights:
#define PIN_SPEAKER DAC0 // uses DAC
#endif

// ---------- Battery voltage sensor
#if defined(ARDUINO_ADAFRUIT_FEATHER_RP2040)
#define BATTERY_ADC A1
#endif
// ---------- Coin battery voltage sensor
#define BATTERY_ADC A2

// ---------- Feather RP2040 onboard led
#if defined(ARDUINO_ADAFRUIT_FEATHER_RP2040)
Expand Down
12 changes: 12 additions & 0 deletions logger.h
Expand Up @@ -39,6 +39,9 @@ enum {
#include <Arduino.h> // for "strncpy" and others
#include "logger.h" // conditional printing to Serial port

// extern
void floatToCharArray(char *result, int maxlen, double fValue, int decimalPlaces); // Griduino.ino

class Logger {

public:
Expand Down Expand Up @@ -117,6 +120,15 @@ class Logger {
Serial.println(msg);
}
}
void info(const char *pText, const float value1, const int decimalPlaces) { // one format string containing %s, one float, one int
if (print_info) {
char msg[256];
char sFloat[8];
floatToCharArray(sFloat, sizeof(sFloat), value1, decimalPlaces);
snprintf(msg, sizeof(msg), pText, sFloat);
Serial.println(msg);
}
}
void info(const char *pText, const int value1, const int value2) { // one format string, two numbers
if (print_info) {
char msg[256];
Expand Down
6 changes: 6 additions & 0 deletions model_breadcrumbs.cpp
Expand Up @@ -94,6 +94,12 @@ void Breadcrumbs::dumpHistoryGPS(int limit) {
snprintf(out, sizeof(out), "%d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d",
ii, item->recordType, sDate, sTime, grid6, sLat, sLng, sAltitude, sSpeed, sDirection, nSats);

} else if (item->isCoinBatteryVoltage()) {
char sVolts[12];
floatToCharArray(sVolts, sizeof(sVolts), item->speed, 2);
snprintf(out, sizeof(out), "%d, %s, %s, %s, %s",
ii, item->recordType, sDate, sTime, sVolts);

} else {
// format for "should not happen" messages
snprintf(out, sizeof(out), "%d, --> Type '%s' unknown: ", ii, item->recordType);
Expand Down
11 changes: 9 additions & 2 deletions model_breadcrumbs.h
Expand Up @@ -8,7 +8,7 @@
Breadcrumb trail strategy:
This is a "model" of the Model-View-Controller design pattern.
As such, it contains the data for holding all the breadcrumbs and is a
As such, it contains the data for holding all the breadcrumbs and is a
low-level component with minimal side effects and few dependencies.
This "Breadcrumbs" object will just only manage itself.
Expand All @@ -18,7 +18,7 @@
We don't reach into the "model" from here and tell it what to do.
If the controller tells us to save to file, don't tell the "model" to do anything.
When should the controller should remember a new breadcrumb?
When should the controller tell us to remember a new breadcrumb?
1. Every ten minutes
2. When we drive a visible distance on the screen
3. When we drive into a new 6-digit grid square (todo)
Expand Down Expand Up @@ -166,6 +166,13 @@ class Breadcrumbs {
remember(vLoc);
}

void rememberBAT(float volts) { // save "coin battery voltage" in history buffer
// all we have to do is save a float, so re-use the "speed" field
Location bat{rCOINBATTERYVOLTAGE, noLocation, now(), noSatellites, volts, noDirection, noAltitude};
strncpy(bat.recordType, rCOINBATTERYVOLTAGE, sizeof(bat.recordType));
remember(bat);
}

void rememberFirstValidTime(time_t vTime, uint8_t vSats) { // save "first valid time received from GPS"
// "first valid time" can happen _without_ a satellite fix,
// so the only data stored is the GMT timestamp
Expand Down

0 comments on commit 7d1c114

Please sign in to comment.