Skip to content

Instantly share code, notes, and snippets.

@rlogiacco
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rlogiacco/c21f2015d1e797fb2202 to your computer and use it in GitHub Desktop.
Save rlogiacco/c21f2015d1e797fb2202 to your computer and use it in GitHub Desktop.
VoltageReference
#include <VoltageReference.h>
VoltageReference vRef;
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println("Calibrating voltage reference");
vRef.begin();
}
void loop() {
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
delay(500);
int analog = analogRead(A0);
int vcc = vRef.readVcc();
Serial.print("Input voltage is ");
Serial.print(vcc);
Serial.print("mV, analog pin voltage is ");
Serial.print(analog / 1024 * vcc);
Serial.print("mV");
delay(50);
}
#include <EEPROM.h>
#include <VoltageReference.h>
// sets the storage area to the very end of the EEPROM
#define VREF_EEPROM_ADDR (E2END - 2)
int address = VREF_EEPROM_ADDR;
/**
* Loads the calibration value from EEPROM
*/
uint32_t load(uint16_t address) {
uint32_t calibration = 0;
byte msb = EEPROM.read(address);
byte mid = EEPROM.read(address + 1);
byte lsb = EEPROM.read(address + 2);
calibration = (((long) msb) << 16) | ((mid << 8) | ((lsb & 0xFF) & 0xFFFF));
if (calibration == 16777215L) {
Serial.println("No calibration value stored into EEPROM, using default");
calibration = DEFAULT_REFERENCE_CALIBRATION;
} else {
Serial.print("Read from EEPROM address ");
Serial.print(address);
Serial.print(" calibration value ");
Serial.println(calibration);
}
return calibration;
}
/**
* Saves the calibration value into EEPROM
*/
void save(uint16_t address, uint32_t calibration) {
EEPROM.write(address, calibration >> 16);
EEPROM.write(address + 1, calibration >> 8);
EEPROM.write(address + 2, calibration & 0xFF);
Serial.println("Saved calibration value into EEPROM");
}
/**
* Clears the calibration value from EEPROM
*/
void clear(uint16_t address) {
EEPROM.write(address, 0xFF);
EEPROM.write(address + 1, 0xFF);
EEPROM.write(address + 2, 0xFF);
Serial.println("Cleared calibration value from EEPROM");
}
void menu() {
Serial.println("--- MENU ---");
Serial.println("\tR to read Vcc");
Serial.println("\tL to load calibration from EEPROM");
Serial.println("\tS to store calibration into EEPROM");
Serial.println("\tC to clear calibration from EEPROM");
Serial.println("\tdddd (4 digits) to calibrate for mV");
Serial.println("\tA to print EEPROM calibration start address (length 3)");
Serial.println("\tAdddd (4 digits) to set EEPROM calibration start address (length 3)");
Serial.println("\tH prints this help");
}
VoltageReference vRef;
void setup() {
Serial.begin(9600);
while (!Serial);
vRef.begin();
menu();
}
void parse() {
char c = Serial.read();
if (isalpha(c)) {
if (c == 's' || c == 'S') {
save(address, vRef.calibrate(vRef.readVcc()));
} else if (c == 'c' || c == 'C') {
clear(address);
} else if (c == 'l' || c == 'L') {
vRef.begin(load(address));
} else if (c == 'r' || c == 'R') {
Serial.print("Calculated input voltage is ");
Serial.print(vRef.readVcc());
Serial.println("mV");
} else if (c == 'a' || c == 'A') {
if (Serial.available() > 0) {
c = Serial.read();
char* buffer = new char[5];
uint8_t i = 0;
while (isdigit(c)) {
buffer[i++] = c;
c = Serial.read();
}
buffer[i++] = '\0';
address = atol(buffer);
Serial.print("Setting EEPROM start address to ");
Serial.println(address);
} else {
Serial.print("EEPROM start address is ");
Serial.println(address);
}
} else if (c == 'h' || c == 'H') {
menu();
}
} else {
char* buffer = new char[5];
uint8_t i = 0;
while (isdigit(c)) {
buffer[i++] = c;
c = Serial.read();
}
buffer[i++] = '\0';
long voltage = atol(buffer);
Serial.print("Calibrating for Vcc ");
Serial.print(voltage);
Serial.println("mV");
uint32_t calibration = vRef.calibrate(voltage);
Serial.print("Calibration value is ");
Serial.println(calibration);
vRef.begin(calibration);
}
}
void loop() {
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
if (Serial.available() > 0) {
parse();
}
}
/*
VoltageSource.cpp - VoltageSource library
Copyright (c) 2014 Roberto Lo Giacco. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/******************************************************************************
* Includes
******************************************************************************/
#include "Arduino.h"
#include "VoltageReference.h"
/******************************************************************************
* User API
******************************************************************************/
void VoltageReference::begin(uint32_t calibration) {
VoltageReference::calibration = calibration;
}
void VoltageReference::begin(uint8_t hi, uint8_t mid, uint8_t low) {
VoltageReference::calibration = mergeBytes(hi, mid, low);
}
uint16_t VoltageReference::readInternalRef() {
// Read 1.1V reference against AVcc
// Set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Start conversion
while (bit_is_set(ADCSRA, ADSC)); // measuring
uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
uint8_t high = ADCH; // unlocks both
return (high << 8) | low; // raw bandgap value;
}
uint16_t VoltageReference::readVcc() {
return calibration / readInternalRef();
}
uint32_t VoltageReference::calibrate(uint16_t milliVolts) {
return ((uint32_t)milliVolts * readInternalRef());
}
/*
VoltageSource.cpp - VoltageSource library
Copyright (c) 2014 Roberto Lo Giacco. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _VOLTAGE_REFERENCE_
#define _VOLTAGE_REFERENCE_
#include "Arduino.h"
#define SERIAL_DEBUG false
#include <SerialDebug.h>
#define DEFAULT_REFERENCE_CALIBRATION 1126400L
#define INVALID_REFERENCE_CALIBRATION 16777215L
#define getHiByte(calibration) (calibration >> 16)
#define getMidByte(calibration) (calibration >> 8)
#define getLowByte(calibration) (calibration & 0xFF)
#define mergeBytes(hi, mid, low) ((((long)hi) << 16) | ((mid << 8) | ((low & 0xFF) & 0xFFFF)))
class VoltageReference {
private:
uint32_t calibration;
/**
* Reads the internal voltage reference against Vcc
*/
uint16_t readInternalRef();
public:
/**
* Initializes the library by setting the calibration value for the 1.1V reference
* either to the provided value or to its default
*/
void begin(uint32_t reference = DEFAULT_REFERENCE_CALIBRATION);
/**
* Initializes the library by setting the calibration value for the 1.1V reference
* from a three bytes representation
*/
void begin(uint8_t hi, uint8_t mid, uint8_t low);
/**
* Reads the input voltage value applying any necessary calibration
*/
uint16_t readVcc();
/**
* Returns the calibration value to be used for the specified input voltage
*/
uint32_t calibrate(uint16_t milliVolt);
};
#endif // _VOLTAGE_REFERENCE_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment