This commit is contained in:
Tower committed 2026-04-16 13:16:16 +02:00
1 parent 77b0a7014d
commit 3da9f9f8ee
95 files changed
+11054

No files matched your search

@@ -0,0 +1,10 @@
# Author: diplfranzhoepfinger
# reference: https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html
# URL: https://github.com/milesburton/Arduino-Temperature-Control-Library
# DATE: 15.02.2023
idf_component_register(
SRCS "DallasTemperature.cpp"
INCLUDE_DIRS "."
PRIV_REQUIRES OneWire arduino
)
@@ -0,0 +1,818 @@
#include "DallasTemperature.h"
#if ARDUINO >= 100
#include "Arduino.h"
#else
extern "C" {
#include "WConstants.h"
}
#endif
// OneWire commands
#define STARTCONVO 0x44 // Tells device to take a temperature reading
#define COPYSCRATCH 0x48 // Copy scratchpad to EEPROM
#define READSCRATCH 0xBE // Read from scratchpad
#define WRITESCRATCH 0x4E // Write to scratchpad
#define RECALLSCRATCH 0xB8 // Recall from EEPROM to scratchpad
#define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power
#define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition
// Scratchpad locations
#define TEMP_LSB 0
#define TEMP_MSB 1
#define HIGH_ALARM_TEMP 2
#define LOW_ALARM_TEMP 3
#define CONFIGURATION 4
#define INTERNAL_BYTE 5
#define COUNT_REMAIN 6
#define COUNT_PER_C 7
#define SCRATCHPAD_CRC 8
// Device resolution
#define TEMP_9_BIT 0x1F
#define TEMP_10_BIT 0x3F
#define TEMP_11_BIT 0x5F
#define TEMP_12_BIT 0x7F
#define NO_ALARM_HANDLER ((AlarmHandler *)0)
// DSROM FIELDS
#define DSROM_FAMILY 0
#define DSROM_CRC 7
DallasTemperature::DallasTemperature() {
_wire = nullptr;
devices = 0;
ds18Count = 0;
parasite = false;
bitResolution = 9;
waitForConversion = true;
checkForConversion = true;
autoSaveScratchPad = true;
useExternalPullup = false;
#if REQUIRESALARMS
setAlarmHandler(NO_ALARM_HANDLER);
alarmSearchJunction = -1;
alarmSearchExhausted = 0;
#endif
}
DallasTemperature::DallasTemperature(OneWire* _oneWire) : DallasTemperature() {
setOneWire(_oneWire);
}
DallasTemperature::DallasTemperature(OneWire* _oneWire, uint8_t _pullupPin) : DallasTemperature(_oneWire) {
setPullupPin(_pullupPin);
}
void DallasTemperature::setOneWire(OneWire* _oneWire) {
_wire = _oneWire;
devices = 0;
ds18Count = 0;
parasite = false;
bitResolution = 9;
waitForConversion = true;
checkForConversion = true;
autoSaveScratchPad = true;
}
void DallasTemperature::setPullupPin(uint8_t _pullupPin) {
useExternalPullup = true;
pullupPin = _pullupPin;
pinMode(pullupPin, OUTPUT);
deactivateExternalPullup();
}
void DallasTemperature::begin(void) {
DeviceAddress deviceAddress;
for (uint8_t retry = 0; retry < MAX_INITIALIZATION_RETRIES; retry++) {
_wire->reset_search();
devices = 0;
ds18Count = 0;
delay(INITIALIZATION_DELAY_MS);
while (_wire->search(deviceAddress)) {
if (validAddress(deviceAddress)) {
devices++;
if (validFamily(deviceAddress)) {
ds18Count++;
if (!parasite && readPowerSupply(deviceAddress)) {
parasite = true;
}
uint8_t b = getResolution(deviceAddress);
if (b > bitResolution) {
bitResolution = b;
}
}
}
}
if (devices > 0) break;
}
}
void DallasTemperature::activateExternalPullup() {
if (useExternalPullup) digitalWrite(pullupPin, LOW);
}
void DallasTemperature::deactivateExternalPullup() {
if (useExternalPullup) digitalWrite(pullupPin, HIGH);
}
bool DallasTemperature::validFamily(const uint8_t* deviceAddress) {
switch (deviceAddress[0]) {
case DS18S20MODEL:
case DS18B20MODEL:
case DS1822MODEL:
case DS1825MODEL:
case DS28EA00MODEL:
return true;
default:
return false;
}
}
bool DallasTemperature::validAddress(const uint8_t* deviceAddress) {
return (_wire->crc8(const_cast<uint8_t*>(deviceAddress), 7) == deviceAddress[7]);
}
bool DallasTemperature::getAddress(uint8_t* deviceAddress, uint8_t index) {
if (index < devices) {
uint8_t depth = 0;
_wire->reset_search();
while (depth <= index && _wire->search(deviceAddress)) {
if (depth == index && validAddress(deviceAddress)) {
return true;
}
depth++;
}
}
return false;
}
uint8_t DallasTemperature::getDeviceCount(void) {
return devices;
}
uint8_t DallasTemperature::getDS18Count(void) {
return ds18Count;
}
bool DallasTemperature::isConnected(const uint8_t* deviceAddress) {
ScratchPad scratchPad;
return isConnected(deviceAddress, scratchPad);
}
bool DallasTemperature::isConnected(const uint8_t* deviceAddress, uint8_t* scratchPad) {
bool b = readScratchPad(deviceAddress, scratchPad);
return b && !isAllZeros(scratchPad) && (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]);
}
bool DallasTemperature::readPowerSupply(const uint8_t* deviceAddress) {
bool parasiteMode = false;
_wire->reset();
if (deviceAddress == nullptr) {
_wire->skip();
} else {
_wire->select(deviceAddress);
}
_wire->write(READPOWERSUPPLY);
if (_wire->read_bit() == 0) {
parasiteMode = true;
}
_wire->reset();
return parasiteMode;
}
bool DallasTemperature::isParasitePowerMode(void) {
return parasite;
}
bool DallasTemperature::isAllZeros(const uint8_t* const scratchPad, const size_t length) {
for (size_t i = 0; i < length; i++) {
if (scratchPad[i] != 0) return false;
}
return true;
}
bool DallasTemperature::readScratchPad(const uint8_t* deviceAddress, uint8_t* scratchPad) {
int b = _wire->reset();
if (b == 0) return false;
_wire->select(deviceAddress);
_wire->write(READSCRATCH);
for (uint8_t i = 0; i < 9; i++) {
scratchPad[i] = _wire->read();
}
b = _wire->reset();
return (b == 1);
}
void DallasTemperature::writeScratchPad(const uint8_t* deviceAddress, const uint8_t* scratchPad) {
_wire->reset();
_wire->select(deviceAddress);
_wire->write(WRITESCRATCH);
_wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp
_wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp
// DS1820 and DS18S20 have no configuration register
if (deviceAddress[0] != DS18S20MODEL) {
_wire->write(scratchPad[CONFIGURATION]);
}
if (autoSaveScratchPad) {
saveScratchPad(deviceAddress);
} else {
_wire->reset();
}
}
bool DallasTemperature::saveScratchPad(const uint8_t* deviceAddress) {
if (_wire->reset() == 0) return false;
if (deviceAddress == nullptr)
_wire->skip();
else
_wire->select(deviceAddress);
_wire->write(COPYSCRATCH, parasite);
// Specification: NV Write Cycle Time is typically 2ms, max 10ms
// Waiting 20ms to allow for sensors that take longer in practice
if (!parasite) {
delay(20);
} else {
activateExternalPullup();
delay(20);
deactivateExternalPullup();
}
return (_wire->reset() == 1);
}
bool DallasTemperature::recallScratchPad(const uint8_t* deviceAddress) {
if (_wire->reset() == 0) return false;
if (deviceAddress == nullptr)
_wire->skip();
else
_wire->select(deviceAddress);
_wire->write(RECALLSCRATCH, parasite);
// Specification: Strong pullup only needed when writing to EEPROM
unsigned long start = millis();
while (_wire->read_bit() == 0) {
if (millis() - start > 20) return false;
yield();
}
return (_wire->reset() == 1);
}
int32_t DallasTemperature::getTemp(const uint8_t* deviceAddress, byte retryCount) {
ScratchPad scratchPad;
byte retries = 0;
while (retries++ <= retryCount) {
if (isConnected(deviceAddress, scratchPad)) {
return calculateTemperature(deviceAddress, scratchPad);
}
}
return DEVICE_DISCONNECTED_RAW;
}
float DallasTemperature::getTempC(const uint8_t* deviceAddress, byte retryCount) {
return rawToCelsius(getTemp(deviceAddress, retryCount));
}
float DallasTemperature::getTempF(const uint8_t* deviceAddress) {
return rawToFahrenheit(getTemp(deviceAddress));
}
float DallasTemperature::getTempCByIndex(uint8_t index) {
DeviceAddress deviceAddress;
if (!getAddress(deviceAddress, index)) {
return DEVICE_DISCONNECTED_C;
}
return getTempC((uint8_t*)deviceAddress);
}
float DallasTemperature::getTempFByIndex(uint8_t index) {
DeviceAddress deviceAddress;
if (!getAddress(deviceAddress, index)) {
return DEVICE_DISCONNECTED_F;
}
return getTempF((uint8_t*)deviceAddress);
}
void DallasTemperature::setResolution(uint8_t newResolution) {
bitResolution = constrain(newResolution, 9, 12);
DeviceAddress deviceAddress;
_wire->reset_search();
for (uint8_t i = 0; i < devices; i++) {
if (_wire->search(deviceAddress) && validAddress(deviceAddress)) {
setResolution(deviceAddress, bitResolution, true);
}
}
}
bool DallasTemperature::setResolution(const uint8_t* deviceAddress, uint8_t newResolution, bool skipGlobalBitResolutionCalculation) {
bool success = false;
if (deviceAddress[0] == DS18S20MODEL) {
success = true;
} else {
newResolution = constrain(newResolution, 9, 12);
uint8_t newValue = 0;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
switch (newResolution) {
case 12: newValue = TEMP_12_BIT; break;
case 11: newValue = TEMP_11_BIT; break;
case 10: newValue = TEMP_10_BIT; break;
case 9:
default: newValue = TEMP_9_BIT; break;
}
if (scratchPad[CONFIGURATION] != newValue) {
scratchPad[CONFIGURATION] = newValue;
writeScratchPad(deviceAddress, scratchPad);
}
success = true;
}
}
if (!skipGlobalBitResolutionCalculation && success) {
bitResolution = newResolution;
if (devices > 1) {
DeviceAddress deviceAddr;
_wire->reset_search();
for (uint8_t i = 0; i < devices; i++) {
if (bitResolution == 12) break;
if (_wire->search(deviceAddr) && validAddress(deviceAddr)) {
uint8_t b = getResolution(deviceAddr);
if (b > bitResolution) bitResolution = b;
}
}
}
}
return success;
}
uint8_t DallasTemperature::getResolution() {
return bitResolution;
}
uint8_t DallasTemperature::getResolution(const uint8_t* deviceAddress) {
if (deviceAddress[0] == DS18S20MODEL) return 12;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
if (deviceAddress[0] == DS1825MODEL && scratchPad[CONFIGURATION] & 0x80) {
return 12;
}
switch (scratchPad[CONFIGURATION]) {
case TEMP_12_BIT: return 12;
case TEMP_11_BIT: return 11;
case TEMP_10_BIT: return 10;
case TEMP_9_BIT: return 9;
}
}
return 0;
}
float DallasTemperature::toFahrenheit(float celsius) {
return (celsius * 1.8f) + 32.0f;
}
float DallasTemperature::toCelsius(float fahrenheit) {
return (fahrenheit - 32.0f) * 0.555555556f;
}
float DallasTemperature::rawToCelsius(int32_t raw) {
if (raw <= DEVICE_DISCONNECTED_RAW)
return DEVICE_DISCONNECTED_C;
return (float)raw * 0.0078125f; // 1/128
}
float DallasTemperature::rawToFahrenheit(int32_t raw) {
if (raw <= DEVICE_DISCONNECTED_RAW)
return DEVICE_DISCONNECTED_F;
return rawToCelsius(raw) * 1.8f + 32.0f;
}
int16_t DallasTemperature::celsiusToRaw(float celsius) {
return static_cast<int16_t>(celsius * 128.0f);
}
uint16_t DallasTemperature::millisToWaitForConversion(uint8_t bitResolution) {
switch (bitResolution) {
case 9: return 94;
case 10: return 188;
case 11: return 375;
default: return 750;
}
}
uint16_t DallasTemperature::millisToWaitForConversion() {
return millisToWaitForConversion(bitResolution);
}
void DallasTemperature::setWaitForConversion(bool flag) {
waitForConversion = flag;
}
bool DallasTemperature::getWaitForConversion() {
return waitForConversion;
}
void DallasTemperature::setCheckForConversion(bool flag) {
checkForConversion = flag;
}
bool DallasTemperature::getCheckForConversion() {
return checkForConversion;
}
bool DallasTemperature::isConversionComplete() {
uint8_t b = _wire->read_bit();
return (b == 1);
}
void DallasTemperature::setAutoSaveScratchPad(bool flag) {
autoSaveScratchPad = flag;
}
bool DallasTemperature::getAutoSaveScratchPad() {
return autoSaveScratchPad;
}
DallasTemperature::request_t DallasTemperature::requestTemperatures() {
request_t req = {};
req.result = true;
_wire->reset();
_wire->skip();
_wire->write(STARTCONVO, parasite);
req.timestamp = millis();
if (!waitForConversion) return req;
blockTillConversionComplete(bitResolution, req.timestamp);
return req;
}
DallasTemperature::request_t DallasTemperature::requestTemperaturesByAddress(const uint8_t* deviceAddress) {
request_t req = {};
uint8_t deviceBitResolution = getResolution(deviceAddress);
if (deviceBitResolution == 0) {
req.result = false;
return req;
}
_wire->reset();
_wire->select(deviceAddress);
_wire->write(STARTCONVO, parasite);
req.timestamp = millis();
req.result = true;
if (!waitForConversion) return req;
blockTillConversionComplete(deviceBitResolution, req.timestamp);
return req;
}
DallasTemperature::request_t DallasTemperature::requestTemperaturesByIndex(uint8_t index) {
DeviceAddress deviceAddress;
getAddress(deviceAddress, index);
return requestTemperaturesByAddress(deviceAddress);
}
void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution) {
unsigned long start = millis();
blockTillConversionComplete(bitResolution, start);
}
void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution, unsigned long start) {
if (checkForConversion && !parasite) {
while (!isConversionComplete() && ((unsigned long)(millis() - start) < (unsigned long)MAX_CONVERSION_TIMEOUT)) {
yield();
}
} else {
unsigned long delayInMillis = millisToWaitForConversion(bitResolution);
activateExternalPullup();
delay(delayInMillis);
deactivateExternalPullup();
}
}
void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution, request_t req) {
if (req.result) {
blockTillConversionComplete(bitResolution, req.timestamp);
}
}
int32_t DallasTemperature::calculateTemperature(const uint8_t* deviceAddress, uint8_t* scratchPad) {
int32_t fpTemperature = 0;
// looking thru the spec sheets of all supported devices, bit 15 is always the signing bit
int32_t neg = 0x0;
if (scratchPad[TEMP_MSB] & 0x80)
neg = 0xFFF80000;
// detect MAX31850
if (deviceAddress[0] == DS1825MODEL && scratchPad[CONFIGURATION] & 0x80) {
if (scratchPad[TEMP_LSB] & 1) { // Fault Detected
if (scratchPad[HIGH_ALARM_TEMP] & 1) {
return DEVICE_FAULT_OPEN_RAW;
} else if (scratchPad[HIGH_ALARM_TEMP] >> 1 & 1) {
return DEVICE_FAULT_SHORTGND_RAW;
} else if (scratchPad[HIGH_ALARM_TEMP] >> 2 & 1) {
return DEVICE_FAULT_SHORTVDD_RAW;
} else {
return DEVICE_DISCONNECTED_RAW;
}
}
// We must mask out bit 1 (reserved) and 0 (fault) on TEMP_LSB
fpTemperature = (((int32_t)scratchPad[TEMP_MSB]) << 11)
| (((int32_t)scratchPad[TEMP_LSB] & 0xFC) << 3)
| neg;
} else {
fpTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 11)
| (((int16_t)scratchPad[TEMP_LSB]) << 3)
| neg;
}
// detect POR and insufficient power conditions
if (deviceAddress[DSROM_FAMILY] == DS18B20MODEL) {
if (scratchPad[0] == 0x50 && scratchPad[1] == 0x05 && scratchPad[6] == 0x0C) {
return DEVICE_POWER_ON_RESET_RAW;
} else if (scratchPad[0] == 0xFF && scratchPad[1] == 0x07) {
return DEVICE_INSUFFICIENT_POWER_RAW;
}
}
/*
DS1820 and DS18S20 have a 9-bit temperature register.
Resolutions greater than 9-bit can be calculated using the data from
the temperature, and COUNT REMAIN and COUNT PER °C registers in the
scratchpad. The resolution of the calculation depends on the model.
While the COUNT PER °C register is hard-wired to 16 (10h) in a
DS18S20, it changes with temperature in DS1820.
After reading the scratchpad, the TEMP_READ value is obtained by
truncating the 0.5°C bit (bit 0) from the temperature data. The
extended resolution temperature can then be calculated using the
following equation:
COUNT_PER_C - COUNT_REMAIN
TEMPERATURE = TEMP_READ - 0.25 + --------------------------
COUNT_PER_C
Hagai Shatz simplified this to integer arithmetic for a 12 bits
value for a DS18S20, and James Cameron added legacy DS1820 support.
See - http://myarduinotoy.blogspot.co.uk/2013/02/12bit-result-from-ds18s20.html
*/
if ((deviceAddress[DSROM_FAMILY] == DS18S20MODEL) && (scratchPad[COUNT_PER_C] != 0)) {
fpTemperature = (((fpTemperature & 0xfff0) << 3) - 32
+ (((scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) << 7)
/ scratchPad[COUNT_PER_C])) | neg;
}
return fpTemperature;
}
#if REQUIRESALARMS
void DallasTemperature::setAlarmHandler(const AlarmHandler* handler) {
_AlarmHandler = handler;
}
void DallasTemperature::setHighAlarmTemp(const uint8_t* deviceAddress, int8_t celsius) {
// make sure the alarm temperature is within the device's range
if (celsius > 125) celsius = 125;
else if (celsius < -55) celsius = -55;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
scratchPad[HIGH_ALARM_TEMP] = (uint8_t)celsius;
writeScratchPad(deviceAddress, scratchPad);
}
}
void DallasTemperature::setLowAlarmTemp(const uint8_t* deviceAddress, int8_t celsius) {
// make sure the alarm temperature is within the device's range
if (celsius > 125) celsius = 125;
else if (celsius < -55) celsius = -55;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
scratchPad[LOW_ALARM_TEMP] = (uint8_t)celsius;
writeScratchPad(deviceAddress, scratchPad);
}
}
int8_t DallasTemperature::getHighAlarmTemp(const uint8_t* deviceAddress) {
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad))
return (int8_t)scratchPad[HIGH_ALARM_TEMP];
return DEVICE_DISCONNECTED_C;
}
int8_t DallasTemperature::getLowAlarmTemp(const uint8_t* deviceAddress) {
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad))
return (int8_t)scratchPad[LOW_ALARM_TEMP];
return DEVICE_DISCONNECTED_C;
}
void DallasTemperature::resetAlarmSearch() {
alarmSearchJunction = -1;
alarmSearchExhausted = 0;
for (uint8_t i = 0; i < 7; i++) {
alarmSearchAddress[i] = 0;
}
}
bool DallasTemperature::alarmSearch(uint8_t* newAddr) {
uint8_t i;
int8_t lastJunction = -1;
uint8_t done = 1;
if (alarmSearchExhausted)
return false;
if (!_wire->reset())
return false;
_wire->write(ALARMSEARCH);
for (i = 0; i < 64; i++) {
uint8_t a = _wire->read_bit();
uint8_t nota = _wire->read_bit();
uint8_t ibyte = i / 8;
uint8_t ibit = 1 << (i & 7);
if (a && nota)
return false;
if (!a && !nota) {
if (i == alarmSearchJunction) {
a = 1;
alarmSearchJunction = lastJunction;
} else if (i < alarmSearchJunction) {
if (alarmSearchAddress[ibyte] & ibit) {
a = 1;
} else {
a = 0;
done = 0;
lastJunction = i;
}
} else {
a = 0;
alarmSearchJunction = i;
done = 0;
}
}
if (a)
alarmSearchAddress[ibyte] |= ibit;
else
alarmSearchAddress[ibyte] &= ~ibit;
_wire->write_bit(a);
}
if (done)
alarmSearchExhausted = 1;
for (i = 0; i < 8; i++)
newAddr[i] = alarmSearchAddress[i];
return true;
}
bool DallasTemperature::hasAlarm(const uint8_t* deviceAddress) {
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
int8_t temp = calculateTemperature(deviceAddress, scratchPad) >> 7;
return (temp <= (int8_t)scratchPad[LOW_ALARM_TEMP] ||
temp >= (int8_t)scratchPad[HIGH_ALARM_TEMP]);
}
return false;
}
bool DallasTemperature::hasAlarm(void) {
DeviceAddress deviceAddress;
resetAlarmSearch();
return alarmSearch(deviceAddress);
}
void DallasTemperature::processAlarms(void) {
if (!hasAlarmHandler())
return;
resetAlarmSearch();
DeviceAddress alarmAddr;
while (alarmSearch(alarmAddr)) {
if (validAddress(alarmAddr)) {
_AlarmHandler(alarmAddr);
}
}
}
bool DallasTemperature::hasAlarmHandler() {
return (_AlarmHandler != NO_ALARM_HANDLER);
}
#endif
#if REQUIRESNEW
void* DallasTemperature::operator new(unsigned int size) {
void* p = malloc(size);
memset(p, 0, size);
return p;
}
void DallasTemperature::operator delete(void* p) {
free(p);
}
#endif
bool DallasTemperature::verifyDeviceCount(void) {
uint8_t actualCount = 0;
float temp;
requestTemperatures();
do {
temp = getTempCByIndex(actualCount);
if (temp > DEVICE_DISCONNECTED_C) {
actualCount++;
}
} while (temp > DEVICE_DISCONNECTED_C && actualCount < 255);
if (actualCount > devices) {
devices = actualCount;
begin();
return true;
}
return false;
}
void DallasTemperature::setUserData(const uint8_t* deviceAddress, int16_t data) {
// return when stored value == new value
if (getUserData(deviceAddress) == data)
return;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
scratchPad[HIGH_ALARM_TEMP] = data >> 8;
scratchPad[LOW_ALARM_TEMP] = data & 255;
writeScratchPad(deviceAddress, scratchPad);
}
}
void DallasTemperature::setUserDataByIndex(uint8_t deviceIndex, int16_t data) {
DeviceAddress deviceAddress;
if (getAddress(deviceAddress, deviceIndex)) {
setUserData((uint8_t*)deviceAddress, data);
}
}
int16_t DallasTemperature::getUserData(const uint8_t* deviceAddress) {
int16_t data = 0;
ScratchPad scratchPad;
if (isConnected(deviceAddress, scratchPad)) {
data = scratchPad[HIGH_ALARM_TEMP] << 8;
data += scratchPad[LOW_ALARM_TEMP];
}
return data;
}
int16_t DallasTemperature::getUserDataByIndex(uint8_t deviceIndex) {
DeviceAddress deviceAddress;
getAddress(deviceAddress, deviceIndex);
return getUserData((uint8_t*)deviceAddress);
}
@@ -0,0 +1,200 @@
#ifndef DallasTemperature_h
#define DallasTemperature_h
#define DALLASTEMPLIBVERSION "4.0.5"
// Configuration
#ifndef REQUIRESNEW
#define REQUIRESNEW false
#endif
#ifndef REQUIRESALARMS
#define REQUIRESALARMS true
#endif
// Includes
#include <inttypes.h>
#include <Arduino.h>
#ifdef __STM32F1__
#include <OneWireSTM.h>
#else
#include <OneWire.h>
#endif
// Constants for device models
#define DS18S20MODEL 0x10 // also DS1820
#define DS18B20MODEL 0x28 // also MAX31820
#define DS1822MODEL 0x22
#define DS1825MODEL 0x3B // also MAX31850
#define DS28EA00MODEL 0x42
// Error Codes
#define DEVICE_DISCONNECTED_C -127
#define DEVICE_DISCONNECTED_F -196.6
#define DEVICE_DISCONNECTED_RAW -7040
#define DEVICE_FAULT_OPEN_C -254
#define DEVICE_FAULT_OPEN_F -425.199982
#define DEVICE_FAULT_OPEN_RAW -32512
#define DEVICE_FAULT_SHORTGND_C -253
#define DEVICE_FAULT_SHORTGND_F -423.399994
#define DEVICE_FAULT_SHORTGND_RAW -32384
#define DEVICE_FAULT_SHORTVDD_C -252
#define DEVICE_FAULT_SHORTVDD_F -421.599976
#define DEVICE_FAULT_SHORTVDD_RAW -32256
#define DEVICE_POWER_ON_RESET_C -251
#define DEVICE_POWER_ON_RESET_F -419.799988
#define DEVICE_POWER_ON_RESET_RAW -32128
#define DEVICE_INSUFFICIENT_POWER_C -250
#define DEVICE_INSUFFICIENT_POWER_F -418.0
#define DEVICE_INSUFFICIENT_POWER_RAW -32000
// Configuration Constants
#define MAX_CONVERSION_TIMEOUT 750
#define MAX_INITIALIZATION_RETRIES 3
#define INITIALIZATION_DELAY_MS 50
typedef uint8_t DeviceAddress[8];
class DallasTemperature {
public:
struct request_t {
bool result;
unsigned long timestamp;
operator bool() { return result; }
};
// Constructors
DallasTemperature();
DallasTemperature(OneWire*);
DallasTemperature(OneWire*, uint8_t);
// Setup & Configuration
void setOneWire(OneWire*);
void setPullupPin(uint8_t);
void begin(void);
bool verifyDeviceCount(void);
// Device Information
uint8_t getDeviceCount(void);
uint8_t getDS18Count(void);
bool validAddress(const uint8_t*);
bool validFamily(const uint8_t* deviceAddress);
bool getAddress(uint8_t*, uint8_t);
bool isConnected(const uint8_t*);
bool isConnected(const uint8_t*, uint8_t*);
// Scratchpad Operations
bool readScratchPad(const uint8_t*, uint8_t*);
void writeScratchPad(const uint8_t*, const uint8_t*);
bool readPowerSupply(const uint8_t* deviceAddress = nullptr);
// Resolution Control
uint8_t getResolution();
void setResolution(uint8_t);
uint8_t getResolution(const uint8_t*);
bool setResolution(const uint8_t*, uint8_t, bool skipGlobalBitResolutionCalculation = false);
// Conversion Configuration
void setWaitForConversion(bool);
bool getWaitForConversion(void);
void setCheckForConversion(bool);
bool getCheckForConversion(void);
// Temperature Operations
request_t requestTemperatures(void);
request_t requestTemperaturesByAddress(const uint8_t*);
request_t requestTemperaturesByIndex(uint8_t);
int32_t getTemp(const uint8_t*, byte retryCount = 0);
float getTempC(const uint8_t*, byte retryCount = 0);
float getTempF(const uint8_t*);
float getTempCByIndex(uint8_t);
float getTempFByIndex(uint8_t);
// Conversion Status
bool isParasitePowerMode(void);
bool isConversionComplete(void);
static uint16_t millisToWaitForConversion(uint8_t);
uint16_t millisToWaitForConversion();
// EEPROM Operations
bool saveScratchPadByIndex(uint8_t);
bool saveScratchPad(const uint8_t* = nullptr);
bool recallScratchPadByIndex(uint8_t);
bool recallScratchPad(const uint8_t* = nullptr);
void setAutoSaveScratchPad(bool);
bool getAutoSaveScratchPad(void);
#if REQUIRESALARMS
typedef void AlarmHandler(const uint8_t*);
void setHighAlarmTemp(const uint8_t*, int8_t);
void setLowAlarmTemp(const uint8_t*, int8_t);
int8_t getHighAlarmTemp(const uint8_t*);
int8_t getLowAlarmTemp(const uint8_t*);
void resetAlarmSearch(void);
bool alarmSearch(uint8_t*);
bool hasAlarm(const uint8_t*);
bool hasAlarm(void);
void processAlarms(void);
void setAlarmHandler(const AlarmHandler*);
bool hasAlarmHandler();
#endif
// User Data Operations
void setUserData(const uint8_t*, int16_t);
void setUserDataByIndex(uint8_t, int16_t);
int16_t getUserData(const uint8_t*);
int16_t getUserDataByIndex(uint8_t);
// Temperature Conversion Utilities
static float toFahrenheit(float);
static float toCelsius(float);
static float rawToCelsius(int32_t);
static int16_t celsiusToRaw(float);
static float rawToFahrenheit(int32_t);
#if REQUIRESNEW
void* operator new(unsigned int);
void operator delete(void*);
#endif
// Conversion Completion Methods
void blockTillConversionComplete(uint8_t);
void blockTillConversionComplete(uint8_t, unsigned long);
void blockTillConversionComplete(uint8_t, request_t);
private:
typedef uint8_t ScratchPad[9];
// Internal State
bool parasite;
bool useExternalPullup;
uint8_t pullupPin;
uint8_t bitResolution;
bool waitForConversion;
bool checkForConversion;
bool autoSaveScratchPad;
uint8_t devices;
uint8_t ds18Count;
OneWire* _wire;
// Internal Methods
int32_t calculateTemperature(const uint8_t*, uint8_t*);
bool isAllZeros(const uint8_t* const scratchPad, const size_t length = 9);
void activateExternalPullup(void);
void deactivateExternalPullup(void);
#if REQUIRESALARMS
uint8_t alarmSearchAddress[8];
int8_t alarmSearchJunction;
uint8_t alarmSearchExhausted;
AlarmHandler* _AlarmHandler;
#endif
};
#endif // DallasTemperature_h
+3
View File
@@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "arduino_ci", "~> 1.6.2"
+10
View File
@@ -0,0 +1,10 @@
MIT License
Copyright (c) 2024 Miles Burton
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+129
View File
@@ -0,0 +1,129 @@
# 🌡️ Arduino Temperature Control Library
[![Arduino CI](https://github.com/milesburton/Arduino-Temperature-Control-Library/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/milesburton/Arduino-Temperature-Control-Library/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/milesburton/Arduino-Temperature-Control-Library/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/milesburton/Arduino-Temperature-Control-Library/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/milesburton/Arduino-Temperature-Control-Library/actions/workflows/jsoncheck.yml)
[![GitHub issues](https://img.shields.io/github/issues/milesburton/Arduino-Temperature-Control-Library.svg)](https://github.com/milesburton/Arduino-Temperature-Control-Library/issues)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/milesburton/Arduino-Temperature-Control-Library/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/milesburton/Arduino-Temperature-Control-Library.svg?maxAge=3600)](https://github.com/milesburton/Arduino-Temperature-Control-Library/releases)
[![Commits since latest](https://img.shields.io/github/commits-since/milesburton/Arduino-Temperature-Control-Library/latest)](https://github.com/milesburton/Arduino-Temperature-Control-Library/commits/master)
A robust and feature-complete Arduino library for Maxim Temperature Integrated Circuits.
## 📌 Supported Devices
| device | power | notes |
|:-----------|:---------:|:--------|
| DS18B20 | 3-5 V | the reference
| DS18S20 | 3-5 V | 9 bit only
| DS1822 | 3-5 V |
| DS1820 | 5 V | 9 bit only
| MAX31820 | 3 V ⚠️ |
| MAX31850/1 | 3-3.7V ⚠️ | thermocouple
## 🚀 Installation
### Using Arduino IDE Library Manager (Recommended)
1. Open Arduino IDE
2. Go to Tools > Manage Libraries...
3. Search for "DallasTemperature"
4. Click Install
5. Also install the required "OneWire" library by Paul Stoffregen using the same method
### Manual Installation
1. Download the latest release from [GitHub releases](https://github.com/milesburton/Arduino-Temperature-Control-Library/releases)
2. In Arduino IDE, go to Sketch > Include Library > Add .ZIP Library...
3. Select the downloaded ZIP file
4. Repeat steps 1-3 for the required "OneWire" library
## 📝 Basic Usage
1. **Hardware Setup**
- Connect a 4k7 Ω pull-up resistor between the 1-Wire data line and 5V power. Note this applies to the Arduino platform, for ESP32 and 8266 you'll need to adjust the resistor value accordingly.
- For DS18B20: Ground pins 1 and 3 (the centre pin is the data line)
- For reliable readings, see pull-up requirements in the [DS18B20 datasheet](https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf) (page 7)
2. **Code Example**
```cpp
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is connected to GPIO 4
#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup(void) {
Serial.begin(9600);
sensors.begin();
}
void loop(void) {
sensors.requestTemperatures();
delay(750);
float tempC = sensors.getTempCByIndex(0);
Serial.print("Temperature: ");
Serial.print(tempC);
Serial.println("°C");
delay(1000);
}
```
## 🛠️ Advanced Features
- Multiple sensors on the same bus
- Temperature conversion by address (`getTempC(address)` and `getTempF(address)`)
- Asynchronous mode (added in v3.7.0)
- Configurable resolution
### Configuration Options
You can slim down the code by defining the following at the top of DallasTemperature.h:
```cpp
#define REQUIRESNEW // Use if you want to minimise code size
#define REQUIRESALARMS // Use if you need alarm functionality
```
## 📚 Additional Documentation
Visit our [Wiki](https://www.milesburton.com/w/index.php/Dallas_Temperature_Control_Library) for detailed documentation.
## 🔧 Library Development
If you want to contribute to the library development:
### Using Dev Container
The project includes a development container configuration for VS Code that provides a consistent development environment.
1. **Prerequisites**
- Visual Studio Code
- Docker
- VS Code Remote - Containers extension
2. **Development Commands**
Within the dev container, use:
- `arduino-build` - Compile the library and examples
- `arduino-test` - Run the test suite
- `arduino-build-test` - Complete build and test process
> Note: Currently compiling against arduino:avr:uno environment
## ✨ Credits
- Original development by Miles Burton <mail@milesburton.com>
- Multiple sensor support by Tim Newsome <nuisance@casualhacker.net>
- Address-based temperature reading by Guil Barros gfbarros@bappos.com
- Async mode by Rob Tillaart rob.tillaart@gmail.com
## 📄 License
MIT License | Copyright (c) 2025 Miles Burton
Full license text available in [LICENSE](LICENSE) file.
@@ -0,0 +1,19 @@
board_manager:
additional_urls: []
daemon:
port: "50051"
directories:
data: $GITHUB_WORKSPACE/.arduino15
downloads: $GITHUB_WORKSPACE/.arduino15/staging
user: $GITHUB_WORKSPACE/libraries
library:
enable_unsafe_install: true
logging:
file: ""
format: text
level: info
metrics:
addr: :9090
enabled: true
sketch:
always_export_binaries: false
+66
View File
@@ -0,0 +1,66 @@
#!/bin/bash
# Set error handling
set -e
# Function to display usage
show_usage() {
echo "Usage: ./build.sh [option]"
echo "Options:"
echo " build - Only compile library and examples"
echo " test - Only compile and run tests"
echo " all - Build everything and run tests (default)"
}
# Function to compile for a specific board
compile_for_board() {
local fqbn=$1
local sketch=$2
echo "📦 Compiling $sketch for $fqbn..."
arduino-cli compile --fqbn $fqbn "$sketch" --library .
}
# Function to build library and examples
build() {
echo "🔨 Building library and examples..."
# Compile all examples
echo "🔍 Compiling examples..."
for example in examples/*/*.ino; do
if [ -f "$example" ]; then
echo "Building example: $example"
compile_for_board "arduino:avr:uno" "$example"
fi
done
}
# Function to run tests
run_tests() {
echo "🧪 Running tests..."
for test in test/*/*.ino; do
if [ -f "$test" ]; then
echo "Running test: $test"
compile_for_board "arduino:avr:uno" "$test"
fi
done
}
# Main execution
case "${1:-all}" in
"build")
build
;;
"test")
run_tests
;;
"all")
build
run_tests
;;
*)
show_usage
exit 1
;;
esac
echo "✅ Process completed!"
@@ -0,0 +1,161 @@
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// arrays to hold device addresses
DeviceAddress insideThermometer, outsideThermometer;
void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");
// Start up the library
sensors.begin();
// locate devices on the bus
Serial.print("Found ");
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(" devices.");
// search for devices on the bus and assign based on an index.
if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1");
// show the addresses we found on the bus
Serial.print("Device 0 Address: ");
printAddress(insideThermometer);
Serial.println();
Serial.print("Device 0 Alarms: ");
printAlarms(insideThermometer);
Serial.println();
Serial.print("Device 1 Address: ");
printAddress(outsideThermometer);
Serial.println();
Serial.print("Device 1 Alarms: ");
printAlarms(outsideThermometer);
Serial.println();
Serial.println("Setting alarm temps...");
// alarm when temp is higher than 30C
sensors.setHighAlarmTemp(insideThermometer, 30);
// alarm when temp is lower than -10C
sensors.setLowAlarmTemp(insideThermometer, -10);
// alarm when temp is higher than 31C
sensors.setHighAlarmTemp(outsideThermometer, 31);
// alarn when temp is lower than 27C
sensors.setLowAlarmTemp(outsideThermometer, 27);
Serial.print("New Device 0 Alarms: ");
printAlarms(insideThermometer);
Serial.println();
Serial.print("New Device 1 Alarms: ");
printAlarms(outsideThermometer);
Serial.println();
}
// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
Serial.print("Temp C: ");
Serial.print(tempC);
Serial.print(" Temp F: ");
Serial.print(DallasTemperature::toFahrenheit(tempC));
}
void printAlarms(uint8_t deviceAddress[])
{
char temp;
temp = sensors.getHighAlarmTemp(deviceAddress);
Serial.print("High Alarm: ");
Serial.print(temp, DEC);
Serial.print("C/");
Serial.print(DallasTemperature::toFahrenheit(temp));
Serial.print("F | Low Alarm: ");
temp = sensors.getLowAlarmTemp(deviceAddress);
Serial.print(temp, DEC);
Serial.print("C/");
Serial.print(DallasTemperature::toFahrenheit(temp));
Serial.print("F");
}
// main function to print information about a device
void printData(DeviceAddress deviceAddress)
{
Serial.print("Device Address: ");
printAddress(deviceAddress);
Serial.print(" ");
printTemperature(deviceAddress);
Serial.println();
}
void checkAlarm(DeviceAddress deviceAddress)
{
if (sensors.hasAlarm(deviceAddress))
{
Serial.print("ALARM: ");
printData(deviceAddress);
}
}
void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
sensors.requestTemperatures();
Serial.println("DONE");
// Method 1:
// check each address individually for an alarm condition
checkAlarm(insideThermometer);
checkAlarm(outsideThermometer);
/*
// Alternate method:
// Search the bus and iterate through addresses of devices with alarms
// space for the alarm device's address
DeviceAddress alarmAddr;
Serial.println("Searching for alarms...");
// resetAlarmSearch() must be called before calling alarmSearch()
sensors.resetAlarmSearch();
// alarmSearch() returns 0 when there are no devices with alarms
while (sensors.alarmSearch(alarmAddr))
{
Serial.print("ALARM: ");
printData(alarmAddr);
}
*/
}
@@ -0,0 +1,143 @@
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// arrays to hold device addresses
DeviceAddress insideThermometer, outsideThermometer;
// function that will be called when an alarm condition exists during DallasTemperatures::processAlarms();
void newAlarmHandler(const uint8_t* deviceAddress)
{
Serial.println("Alarm Handler Start");
printAlarmInfo(deviceAddress);
printTemp(deviceAddress);
Serial.println();
Serial.println("Alarm Handler Finish");
}
void printCurrentTemp(DeviceAddress deviceAddress)
{
printAddress(deviceAddress);
printTemp(deviceAddress);
Serial.println();
}
void printAddress(const DeviceAddress deviceAddress)
{
Serial.print("Address: ");
for (uint8_t i = 0; i < 8; i++)
{
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
Serial.print(" ");
}
void printTemp(const DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
if (tempC != DEVICE_DISCONNECTED_C)
{
Serial.print("Current Temp C: ");
Serial.print(tempC);
}
else Serial.print("DEVICE DISCONNECTED");
Serial.print(" ");
}
void printAlarmInfo(const DeviceAddress deviceAddress)
{
char temp;
printAddress(deviceAddress);
temp = sensors.getHighAlarmTemp(deviceAddress);
Serial.print("High Alarm: ");
Serial.print(temp, DEC);
Serial.print("C");
Serial.print(" Low Alarm: ");
temp = sensors.getLowAlarmTemp(deviceAddress);
Serial.print(temp, DEC);
Serial.print("C");
Serial.print(" ");
}
void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");
// Start up the library
sensors.begin();
// locate devices on the bus
Serial.print("Found ");
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(" devices.");
// search for devices on the bus and assign based on an index
if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1");
Serial.print("Device insideThermometer ");
printAlarmInfo(insideThermometer);
Serial.println();
Serial.print("Device outsideThermometer ");
printAlarmInfo(outsideThermometer);
Serial.println();
// set alarm ranges
Serial.println("Setting alarm temps...");
sensors.setHighAlarmTemp(insideThermometer, 26);
sensors.setLowAlarmTemp(insideThermometer, 22);
sensors.setHighAlarmTemp(outsideThermometer, 25);
sensors.setLowAlarmTemp(outsideThermometer, 21);
Serial.print("New insideThermometer ");
printAlarmInfo(insideThermometer);
Serial.println();
Serial.print("New outsideThermometer ");
printAlarmInfo(outsideThermometer);
Serial.println();
// attach alarm handler
sensors.setAlarmHandler(&newAlarmHandler);
}
void loop(void)
{
// ask the devices to measure the temperature
sensors.requestTemperatures();
// if an alarm condition exists as a result of the most recent
// requestTemperatures() request, it exists until the next time
// requestTemperatures() is called AND there isn't an alarm condition
// on the device
if (sensors.hasAlarm())
{
Serial.println("Oh noes! There is at least one alarm on the bus.");
}
// call alarm handler function defined by sensors.setAlarmHandler
// for each device reporting an alarm
sensors.processAlarms();
if (!sensors.hasAlarm())
{
// just print out the current temperature
printCurrentTemp(insideThermometer);
printCurrentTemp(outsideThermometer);
}
delay(1000);
}
@@ -0,0 +1,376 @@
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
/*
SETUP INSTRUCTIONS
1) Change WiFi SSID and Password:
const char* ssid = "YourSSID";
const char* password = "YourPassword";
2) Polling Interval (milliseconds):
const unsigned long READ_INTERVAL = 10000; // 10 seconds
3) Number of Readings (History Length):
const int HISTORY_LENGTH = 360; // 1 hour at 10-second intervals
*/
const char* ssid = "YourSSID";
const char* password = "YourPassword";
const int oneWireBus = 4;
const int MAX_SENSORS = 8;
const int HISTORY_LENGTH = 360;
const unsigned long READ_INTERVAL = 10000;
DeviceAddress sensorAddresses[MAX_SENSORS];
float tempHistory[MAX_SENSORS][HISTORY_LENGTH];
int historyIndex = 0;
int numberOfDevices = 0;
unsigned long lastReadTime = 0;
OneWire oneWire(oneWireBus);
DallasTemperature sensors(&oneWire);
ESP8266WebServer server(80);
String getAddressString(DeviceAddress deviceAddress);
void handleRoot();
void handleSensorList();
void handleTemperature();
void handleHistory();
void updateHistory();
const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<title>Arduino Temperature Control Library - Sensor Data Graph</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1"></script>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.1.2/dist/tailwind.min.css"
rel="stylesheet">
</head>
<body class="bg-gray-100 font-sans min-h-screen flex flex-col">
<div class="container mx-auto p-6 flex-grow">
<h1 class="text-2xl font-semibold text-gray-800 mb-4">
Arduino Temperature Control Library - Sensor Data
</h1>
<div class="flex mb-6">
<div class="cursor-pointer px-4 py-2 bg-blue-500 text-white rounded-lg shadow
hover:bg-blue-400 active:scale-95"
onclick="showTab('dashboard')">
Dashboard
</div>
<div class="cursor-pointer px-4 py-2 bg-gray-200 rounded-lg shadow
hover:bg-gray-300 active:scale-95 ml-4"
onclick="showTab('api')">
API Docs
</div>
<div class="cursor-pointer px-4 py-2 bg-gray-200 rounded-lg shadow
hover:bg-gray-300 active:scale-95 ml-4"
onclick="showTab('setup')">
Setup
</div>
</div>
<div id="dashboard" class="tab-content">
<button class="px-6 py-2 bg-green-500 text-white rounded-lg shadow
hover:bg-green-400 active:scale-95"
onclick="refreshData()">
Refresh Data
</button>
<div id="sensors" class="mt-6">
<div class="text-gray-600">Loading sensor data...</div>
</div>
</div>
<div id="api" class="tab-content hidden mt-8">
<h2 class="text-xl font-semibold text-gray-800 mb-4">API</h2>
<div class="bg-white p-6 rounded-lg shadow">
<div class="mb-4">
<span class="font-semibold text-blue-500">GET</span>
<a href="/temperature" class="text-blue-500 hover:underline">/temperature</a>
<pre class="bg-gray-100 p-4 rounded mt-2">
{
"sensors": [
{
"id": 0,
"address": "28FF457D1234AB12",
"celsius": 23.45,
"fahrenheit": 74.21
}
]
}
</pre>
</div>
<div class="mb-4">
<span class="font-semibold text-blue-500">GET</span>
<a href="/sensors" class="text-blue-500 hover:underline">/sensors</a>
<pre class="bg-gray-100 p-4 rounded mt-2">
{
"sensors": [
{
"id": 0,
"address": "28FF457D1234AB12"
}
]
}
</pre>
</div>
<div>
<span class="font-semibold text-blue-500">GET</span>
<a href="/history" class="text-blue-500 hover:underline">/history</a>
<pre class="bg-gray-100 p-4 rounded mt-2">
{
"interval_ms": 10000,
"sensors": [
{
"id": 0,
"address": "28FF457D1234AB12",
"history": [23.45, 23.50, 23.48]
}
]
}
</pre>
</div>
</div>
</div>
<div id="setup" class="tab-content hidden mt-8">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Setup Instructions</h2>
<div class="bg-white p-6 rounded-lg shadow leading-relaxed">
<p class="mb-4">
Edit the .ino code to change SSID, password, read interval, and number
of stored readings (HISTORY_LENGTH).
</p>
</div>
</div>
</div>
<footer class="bg-gray-800 text-white p-4 mt-auto text-center">
<p>&copy; 2025 Miles Burton. All Rights Reserved.</p>
<p>
Licensed under the
<a href="https://opensource.org/licenses/MIT" class="text-blue-400 hover:underline">
MIT License
</a>.
</p>
</footer>
<script>
const showTab = (name) => {
document.querySelectorAll('.tab-content').forEach(c => c.classList.add('hidden'));
document.getElementById(name).classList.remove('hidden');
};
const buildSensorsHTML = (sensors) => {
return sensors.map(s => {
const chartId = "chart-" + s.id;
return `
<div class="bg-white p-6 rounded-lg shadow mb-6">
<div class="text-lg font-semibold text-blue-500">
${s.celsius.toFixed(2)}°C / ${s.fahrenheit.toFixed(2)}°F
</div>
<div class="text-sm text-gray-600 mt-2">
Sensor ID: ${s.id} (${s.address})
</div>
<div class="mt-4" style="height: 300px;">
<canvas id="${chartId}"></canvas>
</div>
</div>
`;
}).join('');
};
const drawChart = (chartId, dataPoints) => {
const ctx = document.getElementById(chartId);
if (!ctx) return;
new Chart(ctx, {
type: 'line',
data: {
labels: dataPoints.map(p => p.x),
datasets: [{
label: 'Temp (°C)',
data: dataPoints,
borderColor: 'red',
backgroundColor: 'rgba(255,0,0,0.1)',
borderWidth: 2,
pointRadius: 3,
lineTension: 0.1,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
tooltip: {
mode: 'index',
intersect: false,
callbacks: {
label: (ctx) => {
const t = ctx.parsed.x;
const d = new Date(t);
return `${ctx.dataset.label}: ${ctx.parsed.y.toFixed(2)}°C at ${d.toLocaleTimeString()}`;
}
}
}
},
interaction: { mode: 'nearest', intersect: true },
scales: {
x: {
type: 'linear',
position: 'bottom',
ticks: {
autoSkip: true,
maxTicksLimit: 10,
callback: (v) => new Date(v).toLocaleTimeString()
}
},
y: {
grid: { color: 'rgba(0,0,0,0.05)' }
}
}
}
});
};
const refreshData = async () => {
try {
const sensorsDiv = document.getElementById('sensors');
sensorsDiv.innerHTML = '<div class="text-gray-600">Loading sensor data...</div>';
const td = await fetch('/temperature');
const tempData = await td.json();
const hd = await fetch('/history');
const historyData = await hd.json();
sensorsDiv.innerHTML = buildSensorsHTML(tempData.sensors);
tempData.sensors.forEach(s => {
const chartId = "chart-" + s.id;
const sensorHist = historyData.sensors.find(h => h.id === s.id);
if (!sensorHist) return;
const total = sensorHist.history.length;
const arr = sensorHist.history.map((v, i) => {
return { x: Date.now() - (total - 1 - i)*10000, y: v };
});
drawChart(chartId, arr);
});
} catch(e) {
console.error(e);
document.getElementById('sensors').innerHTML =
'<div class="text-gray-600">Error loading data.</div>';
}
};
refreshData();
setInterval(refreshData, 30000);
</script>
</body>
</html>
)=====";
void setup() {
Serial.begin(115200);
Serial.println(WiFi.localIP());
sensors.begin();
for (int i = 0; i < MAX_SENSORS; i++) {
for (int j = 0; j < HISTORY_LENGTH; j++) {
tempHistory[i][j] = 0;
}
}
numberOfDevices = sensors.getDeviceCount();
if (numberOfDevices > MAX_SENSORS) {
numberOfDevices = MAX_SENSORS;
}
for (int i = 0; i < numberOfDevices; i++) {
sensors.getAddress(sensorAddresses[i], i);
}
sensors.setResolution(12);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
server.on("/", HTTP_GET, handleRoot);
server.on("/temperature", HTTP_GET, handleTemperature);
server.on("/sensors", HTTP_GET, handleSensorList);
server.on("/history", HTTP_GET, handleHistory);
server.begin();
}
void loop() {
server.handleClient();
unsigned long t = millis();
if (t - lastReadTime >= READ_INTERVAL) {
updateHistory();
lastReadTime = t;
}
}
void updateHistory() {
sensors.requestTemperatures();
for (int i = 0; i < numberOfDevices; i++) {
float tempC = sensors.getTempC(sensorAddresses[i]);
tempHistory[i][historyIndex] = tempC;
}
historyIndex = (historyIndex + 1) % HISTORY_LENGTH;
}
void handleRoot() {
server.send(200, "text/html", MAIN_page);
}
void handleSensorList() {
String json = "{\"sensors\":[";
for (int i = 0; i < numberOfDevices; i++) {
if (i > 0) json += ",";
json += "{\"id\":" + String(i) + ",\"address\":\"" + getAddressString(sensorAddresses[i]) + "\"}";
}
json += "]}";
server.send(200, "application/json", json);
}
void handleTemperature() {
sensors.requestTemperatures();
String json = "{\"sensors\":[";
for (int i = 0; i < numberOfDevices; i++) {
if (i > 0) json += ",";
float c = sensors.getTempC(sensorAddresses[i]);
float f = sensors.toFahrenheit(c);
json += "{\"id\":" + String(i) + ",\"address\":\"" + getAddressString(sensorAddresses[i]) + "\",";
json += "\"celsius\":" + String(c) + ",\"fahrenheit\":" + String(f) + "}";
}
json += "]}";
server.send(200, "application/json", json);
}
void handleHistory() {
String json = "{\"interval_ms\":" + String(READ_INTERVAL) + ",\"sensors\":[";
for (int i = 0; i < numberOfDevices; i++) {
if (i > 0) json += ",";
json += "{\"id\":" + String(i) + ",\"address\":\"" + getAddressString(sensorAddresses[i]) + "\",\"history\":[";
for (int j = 0; j < HISTORY_LENGTH; j++) {
int idx = (historyIndex - j + HISTORY_LENGTH) % HISTORY_LENGTH;
if (j > 0) json += ",";
json += String(tempHistory[i][idx]);
}
json += "]}";
}
json += "]}";
server.send(200, "application/json", json);
}
String getAddressString(DeviceAddress deviceAddress) {
String addr;
for (uint8_t i = 0; i < 8; i++) {
if (deviceAddress[i] < 16) addr += "0";
addr += String(deviceAddress[i], HEX);
}
return addr;
}
@@ -0,0 +1,63 @@
# 🌡️ Arduino Sketch: DS18B20 Sensor via Wi-Fi (REST Endpoints & Dashboard)
This **example Sketch** demonstrates how to use the [Arduino Temperature Control Library](https://github.com/milesburton/Arduino-Temperature-Control-Library) on an **ESP8266** or **ESP32** to read temperature data from **Maxim (Dallas) DS18B20** sensors. The Sketch publishes the readings via Wi-Fi in two ways:
1. **REST Endpoints** - Ideal for Node-RED, Home Assistant, or other automation platforms.
2. **A Human-Friendly Dashboard** - A simple web interface, powered by [Chart.js](https://www.chartjs.org/) and [Tailwind CSS](https://tailwindcss.com/), displaying current and historical temperatures.
---
## 🔎 Features
- Reads from one or more **DS18B20** temperature sensors
- Configurable **polling interval** (in milliseconds) and **history length** (number of readings)
- **Lightweight dashboard** that visualises the last N readings
- **REST endpoints** for easy integration:
- `/temperature` - current readings
- `/sensors` - sensor addresses
- `/history` - historical data
---
## 📚 Potential Use Cases
- **Node-RED** automation flows: Perform regular HTTP GET requests against `/temperature` or `/history`
- **Home Assistant** integrations: Use built-in REST sensors to track temperature over time
- **Extensible to other sensor types** (humidity, light, pressure, etc.) by following the same approach
---
## 🛠️ Getting Started
1. **Clone or download** this repository
2. **Open the Sketch** (the `.ino` file) in the Arduino IDE (or other environment)
3. **Install dependencies**:
- [Arduino Temperature Control Library](https://github.com/milesburton/Arduino-Temperature-Control-Library)
- ESP8266 or ESP32 core for Arduino
4. **Set your Wi-Fi credentials** in the code:
```cpp
const char* ssid = "YourNetwork";
const char* password = "YourPassword";
```
5. **Adjust** the interval and history:
```cpp
// Configuration
const unsigned long READ_INTERVAL = 10000; // e.g. 10 seconds
const int HISTORY_LENGTH = 360; // 1 hour at 10-second intervals
```
6. **Connect** the DS18B20 sensor(s) to the ESP, using OneWire with a pull-up resistor
7. **Upload** the Sketch to your device
8. **Check** the serial monitor for the IP
9. **Navigate** to that IP in your browser to see the chart-based interface
---
## ❓ Questions & Support
- **Library Matters**: If you have issues with the **Arduino Temperature Control Library** itself, please open a ticket in the [official repository](https://github.com/milesburton/Arduino-Temperature-Control-Library/issues)
- **This Sketch**: For help customising this example, dealing with Wi-Fi issues, or setting up the chart dashboard, and other device-specific tweaks, please visit the [Arduino Forum](https://forum.arduino.cc/). You will find many friendly developers there ready to help.
---
## 📜 License
This project is distributed under the [MIT License](https://opensource.org/licenses/MIT).
---
We hope you find this Sketch useful for monitoring temperatures - both in a machine-readable (REST) and human-friendly (web dashboard) format. Happy hacking! 🚀
@@ -0,0 +1,35 @@
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino, while external pullup P-MOSFET gate into port 3
#define ONE_WIRE_BUS 2
#define ONE_WIRE_PULLUP 3
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire, ONE_WIRE_PULLUP);
void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");
// Start up the library
sensors.begin();
}
void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
for (int i = 0; i < sensors.getDeviceCount(); i++) {
Serial.println("Temperature for Device " + String(i) + " is: " + String(sensors.getTempCByIndex(i)));
}
}
@@ -0,0 +1,43 @@
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire ds18x20[] = { 3, 7 };
const int oneWireCount = sizeof(ds18x20) / sizeof(OneWire);
DallasTemperature sensor[oneWireCount];
void setup(void) {
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature Multiple Bus Control Library Simple Demo");
Serial.print("============Ready with ");
Serial.print(oneWireCount);
Serial.println(" Sensors================");
// Start up the library on all defined bus-wires
DeviceAddress deviceAddress;
for (int i = 0; i < oneWireCount; i++) {
sensor[i].setOneWire(&ds18x20[i]);
sensor[i].begin();
if (sensor[i].getAddress(deviceAddress, 0)) sensor[i].setResolution(deviceAddress, 12);
}
}
void loop(void) {
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
for (int i = 0; i < oneWireCount; i++) {
sensor[i].requestTemperatures();
}
Serial.println("DONE");
delay(1000);
for (int i = 0; i < oneWireCount; i++) {
float temperature = sensor[i].getTempCByIndex(0);
Serial.print("Temperature for the sensor ");
Serial.print(i);
Serial.print(" is ");
Serial.println(temperature);
}
Serial.println();
}
@@ -0,0 +1,148 @@
// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
#define TEMPERATURE_PRECISION 9
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// arrays to hold device addresses
DeviceAddress insideThermometer, outsideThermometer;
// Assign address manually. The addresses below will need to be changed
// to valid device addresses on your bus. Device address can be retrieved
// by using either oneWire.search(deviceAddress) or individually via
// sensors.getAddress(deviceAddress, index)
// DeviceAddress insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
// DeviceAddress outsideThermometer = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 };
void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");
// Start up the library
sensors.begin();
// locate devices on the bus
Serial.print("Locating devices...");
Serial.print("Found ");
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(" devices.");
// report parasite power requirements
Serial.print("Parasite power is: ");
if (sensors.isParasitePowerMode()) Serial.println("ON");
else Serial.println("OFF");
// Search for devices on the bus and assign based on an index. Ideally,
// you would do this to initially discover addresses on the bus and then
// use those addresses and manually assign them (see above) once you know
// the devices on your bus (and assuming they don't change).
//
// method 1: by index
if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1");
// method 2: search()
// search() looks for the next device. Returns 1 if a new address has been
// returned. A zero might mean that the bus is shorted, there are no devices,
// or you have already retrieved all of them. It might be a good idea to
// check the CRC to make sure you didn't get garbage. The order is
// deterministic. You will always get the same devices in the same order
//
// Must be called before search()
//oneWire.reset_search();
// assigns the first address found to insideThermometer
//if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
// assigns the seconds address found to outsideThermometer
//if (!oneWire.search(outsideThermometer)) Serial.println("Unable to find address for outsideThermometer");
// show the addresses we found on the bus
Serial.print("Device 0 Address: ");
printAddress(insideThermometer);
Serial.println();
Serial.print("Device 1 Address: ");
printAddress(outsideThermometer);
Serial.println();
// set the resolution to 9 bit per device
sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION);
sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION);
Serial.print("Device 0 Resolution: ");
Serial.print(sensors.getResolution(insideThermometer), DEC);
Serial.println();
Serial.print("Device 1 Resolution: ");
Serial.print(sensors.getResolution(outsideThermometer), DEC);
Serial.println();
}
// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
// zero pad the address if necessary
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
if (tempC == DEVICE_DISCONNECTED_C)
{
Serial.println("Error: Could not read temperature data");
return;
}
Serial.print("Temp C: ");
Serial.print(tempC);
Serial.print(" Temp F: ");
Serial.print(DallasTemperature::toFahrenheit(tempC));
}
// function to print a device's resolution
void printResolution(DeviceAddress deviceAddress)
{
Serial.print("Resolution: ");
Serial.print(sensors.getResolution(deviceAddress));
Serial.println();
}
// main function to print information about a device
void printData(DeviceAddress deviceAddress)
{
Serial.print("Device Address: ");
printAddress(deviceAddress);
Serial.print(" ");
printTemperature(deviceAddress);
Serial.println();
}
/*
Main function, calls the temperatures in a loop.
*/
void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
sensors.requestTemperatures();
Serial.println("DONE");
// print the device information
printData(insideThermometer);
printData(outsideThermometer);
}
@@ -0,0 +1,106 @@
//
// FILE: SaveRecallScratchPad.ino
// AUTHOR: GitKomodo
// VERSION: 0.0.1
// PURPOSE: Show DallasTemperature lib functionality to
// save/recall ScratchPad values to/from EEPROM
//
// HISTORY:
// 0.0.1 = 2020-02-18 initial version
//
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress deviceAddress;
void setup()
{
Serial.begin(9600);
Serial.println(__FILE__);
Serial.println("Dallas Temperature Demo");
sensors.begin();
// Get ID of first sensor (at index 0)
sensors.getAddress(deviceAddress, 0);
// By default configuration and alarm/userdata registers are also saved to EEPROM
// when they're changed. Sensors recall these values automatically when powered up.
// Turn OFF automatic saving of configuration and alarm/userdata registers to EEPROM
sensors.setAutoSaveScratchPad(false);
// Change configuration and alarm/userdata registers on the scratchpad
int8_t resolution = 12;
sensors.setResolution(deviceAddress, resolution);
int16_t userdata = 24680;
sensors.setUserData(deviceAddress, userdata);
// Save configuration and alarm/userdata registers to EEPROM
sensors.saveScratchPad(deviceAddress);
// saveScratchPad can also be used without a parameter to save the configuration
// and alarm/userdata registers of ALL connected sensors to EEPROM:
//
// sensors.saveScratchPad();
//
// Or the configuration and alarm/userdata registers of a sensor can be saved to
// EEPROM by index:
//
// sensors.saveScratchPadByIndex(0);
// Print current values on the scratchpad (resolution = 12, userdata = 24680)
printValues();
}
void loop() {
// Change configuration and alarm/userdata registers on the scratchpad
int8_t resolution = 10;
sensors.setResolution(deviceAddress, resolution);
int16_t userdata = 12345;
sensors.setUserData(deviceAddress, userdata);
// Print current values on the scratchpad (resolution = 10, userdata = 12345)
printValues();
delay(2000);
// Recall configuration and alarm/userdata registers from EEPROM
sensors.recallScratchPad(deviceAddress);
// recallScratchPad can also be used without a parameter to recall the configuration
// and alarm/userdata registers of ALL connected sensors from EEPROM:
//
// sensors.recallScratchPad();
//
// Or the configuration and alarm/userdata registers of a sensor can be recalled
// from EEPROM by index:
//
// sensors.recallScratchPadByIndex(0);
// Print current values on the scratchpad (resolution = 12, userdata = 24680)
printValues();
delay(2000);
}
void printValues() {
Serial.println();
Serial.println("Current values on the scratchpad:");
Serial.print("Resolution:\t");
Serial.println(sensors.getResolution(deviceAddress));
Serial.print("User data:\t");
Serial.println(sensors.getUserData(deviceAddress));
}
@@ -0,0 +1,47 @@
//
// This sketch does not use the ALARM registers and uses those 2 bytes as a counter
// these 2 bytes can be used for other purposes as well e.g. last temperature or
// a specific ID.
//
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
int count = 0;
void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");
// Start up the library
sensors.begin();
}
void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
Serial.print("Temperature for the device 1 (index 0) is: ");
Serial.println(sensors.getTempCByIndex(0));
count++;
sensors.setUserDataByIndex(0, count);
int x = sensors.getUserDataByIndex(0);
Serial.println(count);
}
@@ -0,0 +1,52 @@
// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
/*
* The setup function. We only start the sensors here
*/
void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");
// Start up the library
sensors.begin();
}
/*
* Main function, get and show the temperature
*/
void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
delay(1500);
// After we got the temperatures, we can print them here.
// We use the function ByIndex, and as an example get the temperature from the first sensor only.
float tempC = sensors.getTempCByIndex(0);
// Check if reading was successful
if (tempC != DEVICE_DISCONNECTED_C)
{
Serial.print("Temperature for the device 1 (index 0) is: ");
Serial.println(tempC);
}
else
{
Serial.println("Error: Could not read temperature data");
}
}
@@ -0,0 +1,122 @@
// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// arrays to hold device address
DeviceAddress insideThermometer;
/*
* Setup function. Here we do the basics
*/
void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");
// locate devices on the bus
Serial.print("Locating devices...");
sensors.begin();
Serial.print("Found ");
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(" devices.");
// report parasite power requirements
Serial.print("Parasite power is: ");
if (sensors.isParasitePowerMode()) Serial.println("ON");
else Serial.println("OFF");
// Assign address manually. The addresses below will need to be changed
// to valid device addresses on your bus. Device address can be retrieved
// by using either oneWire.search(deviceAddress) or individually via
// sensors.getAddress(deviceAddress, index)
// Note that you will need to use your specific address here
//insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
// Method 1:
// Search for devices on the bus and assign based on an index. Ideally,
// you would do this to initially discover addresses on the bus and then
// use those addresses and manually assign them (see above) once you know
// the devices on your bus (and assuming they don't change).
if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
// method 2: search()
// search() looks for the next device. Returns 1 if a new address has been
// returned. A zero might mean that the bus is shorted, there are no devices,
// or you have already retrieved all of them. It might be a good idea to
// check the CRC to make sure you didn't get garbage. The order is
// deterministic. You will always get the same devices in the same order
//
// Must be called before search()
//oneWire.reset_search();
// assigns the first address found to insideThermometer
//if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
// show the addresses we found on the bus
Serial.print("Device 0 Address: ");
printAddress(insideThermometer);
Serial.println();
// set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
sensors.setResolution(insideThermometer, 9);
Serial.print("Device 0 Resolution: ");
Serial.print(sensors.getResolution(insideThermometer), DEC);
Serial.println();
}
// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
// method 1 - slower
//Serial.print("Temp C: ");
//Serial.print(sensors.getTempC(deviceAddress));
//Serial.print(" Temp F: ");
//Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit
// method 2 - faster
float tempC = sensors.getTempC(deviceAddress);
if (tempC == DEVICE_DISCONNECTED_C)
{
Serial.println("Error: Could not read temperature data");
return;
}
Serial.print("Temp C: ");
Serial.print(tempC);
Serial.print(" Temp F: ");
Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}
/*
* Main function. It will request the tempC from the sensors and display on Serial.
*/
void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
delay(1500);
// It responds almost immediately. Let's print out the data
printTemperature(insideThermometer); // Use a simple function to print out the data
}
// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
@@ -0,0 +1,129 @@
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
#define TEMPERATURE_PRECISION 9 // Lower resolution
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
int numberOfDevices; // Number of temperature devices found
DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address
void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");
// Start up the library
sensors.begin();
// Grab a count of devices on the wire
numberOfDevices = sensors.getDeviceCount();
// locate devices on the bus
Serial.print("Locating devices...");
Serial.print("Found ");
Serial.print(numberOfDevices, DEC);
Serial.println(" devices.");
// report parasite power requirements
Serial.print("Parasite power is: ");
if (sensors.isParasitePowerMode()) Serial.println("ON");
else Serial.println("OFF");
// Loop through each device, print out address
for (int i = 0; i < numberOfDevices; i++)
{
// Search the wire for address
if (sensors.getAddress(tempDeviceAddress, i))
{
Serial.print("Found device ");
Serial.print(i, DEC);
Serial.print(" with address: ");
printAddress(tempDeviceAddress);
Serial.println();
Serial.print("Setting resolution to ");
Serial.println(TEMPERATURE_PRECISION, DEC);
// set the resolution to TEMPERATURE_PRECISION bit (Each Dallas/Maxim device is capable of several different resolutions)
sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);
Serial.print("Resolution actually set to: ");
Serial.print(sensors.getResolution(tempDeviceAddress), DEC);
Serial.println();
} else {
Serial.print("Found ghost device at ");
Serial.print(i, DEC);
Serial.print(" but could not detect address. Check power and cabling");
}
}
}
// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
// method 1 - slower
//Serial.print("Temp C: ");
//Serial.print(sensors.getTempC(deviceAddress));
//Serial.print(" Temp F: ");
//Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit
// method 2 - faster
float tempC = sensors.getTempC(deviceAddress);
if (tempC == DEVICE_DISCONNECTED_C)
{
Serial.println("Error: Could not read temperature data");
return;
}
Serial.print("Temp C: ");
Serial.print(tempC);
Serial.print(" Temp F: ");
Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}
void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
// Loop through each device, print out temperature data
for (int i = 0; i < numberOfDevices; i++)
{
// Search the wire for address
if (sensors.getAddress(tempDeviceAddress, i))
{
// Output the device ID
Serial.print("Temperature for device: ");
Serial.println(i, DEC);
// It responds almost immediately. Let's print out the data
printTemperature(tempDeviceAddress); // Use a simple function to print out the data
}
//else ghost device! Check your power requirements and cabling
}
}
// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
@@ -0,0 +1,77 @@
//
// FILE: Timing.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.0.3
// PURPOSE: show performance of DallasTemperature lib
// compared to datasheet times per resolution
//
// HISTORY:
// 0.0.1 2017-07-25 initial version
// 0.0.2 2020-02-13 updates to work with current lib version
// 0.0.3 2020-02-20 added timing measurement of setResolution
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensor(&oneWire);
uint32_t start, stop;
void setup()
{
Serial.begin(9600);
Serial.println(__FILE__);
Serial.print("DallasTemperature Library version: ");
Serial.println(DALLASTEMPLIBVERSION);
sensor.begin();
}
void loop()
{
float ti[4] = { 94, 188, 375, 750 };
Serial.println();
Serial.println("Test takes about 30 seconds for 4 resolutions");
Serial.println("RES\tTIME\tACTUAL\tGAIN");
for (int r = 9; r < 13; r++)
{
start = micros();
sensor.setResolution(r);
Serial.println(micros() - start);
start = micros();
sensor.setResolution(r);
Serial.println(micros() - start);
uint32_t duration = run(20);
float avgDuration = duration / 20.0;
Serial.print(r);
Serial.print("\t");
Serial.print(ti[r - 9]);
Serial.print("\t");
Serial.print(avgDuration, 2);
Serial.print("\t");
Serial.print(avgDuration * 100 / ti[r - 9], 1);
Serial.println("%");
}
delay(1000);
}
uint32_t run(int runs)
{
float t;
start = millis();
for (int i = 0; i < runs; i++)
{
sensor.requestTemperatures();
t = sensor.getTempCByIndex(0);
}
stop = millis();
return stop - start;
}
@@ -0,0 +1,45 @@
//
// FILE: TwoPin_DS18B20.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: two pins for two sensors demo
// DATE: 2014-06-13
// URL: http://forum.arduino.cc/index.php?topic=216835.msg1764333#msg1764333
//
// Released to the public domain
//
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS_1 2
#define ONE_WIRE_BUS_2 4
OneWire oneWire_in(ONE_WIRE_BUS_1);
OneWire oneWire_out(ONE_WIRE_BUS_2);
DallasTemperature sensor_inhouse(&oneWire_in);
DallasTemperature sensor_outhouse(&oneWire_out);
void setup(void)
{
Serial.begin(9600);
Serial.println("Dallas Temperature Control Library Demo - TwoPin_DS18B20");
sensor_inhouse.begin();
sensor_outhouse.begin();
}
void loop(void)
{
Serial.print("Requesting temperatures...");
sensor_inhouse.requestTemperatures();
sensor_outhouse.requestTemperatures();
Serial.println(" done");
Serial.print("Inhouse: ");
Serial.println(sensor_inhouse.getTempCByIndex(0));
Serial.print("Outhouse: ");
Serial.println(sensor_outhouse.getTempCByIndex(0));
}
@@ -0,0 +1,115 @@
//
// FILE: UserDataDemo.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: use of alarm field as user identification demo
// DATE: 2019-12-23
// URL:
//
// Released to the public domain
//
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
uint8_t deviceCount = 0;
// Add 4 prepared sensors to the bus
// use the UserDataWriteBatch demo to prepare 4 different labeled sensors
struct
{
int id;
DeviceAddress addr;
} T[4];
float getTempByID(int id)
{
for (uint8_t index = 0; index < deviceCount; index++)
{
if (T[index].id == id)
{
return sensors.getTempC(T[index].addr);
}
}
return -999;
}
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
// zero pad the address if necessary
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
void setup(void)
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println("Dallas Temperature Demo");
sensors.begin();
// count devices
deviceCount = sensors.getDeviceCount();
Serial.print("#devices: ");
Serial.println(deviceCount);
// Read ID's per sensor
// and put them in T array
for (uint8_t index = 0; index < deviceCount; index++)
{
// go through sensors
sensors.getAddress(T[index].addr, index);
T[index].id = sensors.getUserData(T[index].addr);
}
// Check all 4 sensors are set
for (uint8_t index = 0; index < deviceCount; index++)
{
Serial.println();
Serial.println(T[index].id);
printAddress(T[index].addr);
Serial.println();
}
Serial.println();
}
void loop(void)
{
Serial.println();
Serial.print(millis());
Serial.println("\treq temp");
sensors.requestTemperatures();
Serial.print(millis());
Serial.println("\tGet temp by address");
for (int i = 0; i < 4; i++)
{
Serial.print(millis());
Serial.print("\t temp:\t");
Serial.println(sensors.getTempC(T[i].addr));
}
Serial.print(millis());
Serial.println("\tGet temp by ID"); // assume ID = 0, 1, 2, 3
for (int id = 0; id < 4; id++)
{
Serial.print(millis());
Serial.print("\t temp:\t");
Serial.println(getTempByID(id));
}
delay(1000);
}
// END OF FILE
@@ -0,0 +1,107 @@
//
// FILE: UserDataWriteBatch.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: use of alarm field as user identification demo
// DATE: 2019-12-23
// URL:
//
// Released to the public domain
//
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
uint8_t deviceCount = 0;
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
// zero pad the address if necessary
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
void setup(void)
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println("Write user ID to DS18B20\n");
sensors.begin();
// count devices
deviceCount = sensors.getDeviceCount();
Serial.print("#devices: ");
Serial.println(deviceCount);
Serial.println();
Serial.println("current ID's");
for (uint8_t index = 0; index < deviceCount; index++)
{
DeviceAddress t;
sensors.getAddress(t, index);
printAddress(t);
Serial.print("\t\tID: ");
int id = sensors.getUserData(t);
Serial.println(id);
}
Serial.println();
Serial.print("Enter ID for batch: ");
int c = 0;
int id = 0;
while (c != '\n' && c != '\r')
{
c = Serial.read();
switch (c)
{
case '0'...'9':
id *= 10;
id += (c - '0');
break;
default:
break;
}
}
Serial.println();
Serial.println(id);
Serial.println();
Serial.println("Start labeling ...");
for (uint8_t index = 0; index < deviceCount; index++)
{
Serial.print(".");
DeviceAddress t;
sensors.getAddress(t, index);
sensors.setUserData(t, id);
}
Serial.println();
Serial.println();
Serial.println("Show results ...");
for (uint8_t index = 0; index < deviceCount; index++)
{
DeviceAddress t;
sensors.getAddress(t, index);
printAddress(t);
Serial.print("\t\tID: ");
int id = sensors.getUserData(t);
Serial.println(id);
}
Serial.println("Done ...");
}
void loop(void) {}
// END OF FILE
@@ -0,0 +1,66 @@
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
void setup(void)
{
// start serial port
Serial.begin(115200);
Serial.println("Dallas Temperature Control Library - Async Demo");
Serial.println("\nDemo shows the difference in length of the call\n\n");
// Start up the library
sensors.begin();
}
void loop(void)
{
// Request temperature conversion (traditional)
Serial.println("Before blocking requestForConversion");
unsigned long start = millis();
sensors.requestTemperatures();
unsigned long stop = millis();
Serial.println("After blocking requestForConversion");
Serial.print("Time used: ");
Serial.println(stop - start);
// get temperature
Serial.print("Temperature: ");
Serial.println(sensors.getTempCByIndex(0));
Serial.println("\n");
// Request temperature conversion - non-blocking / async
Serial.println("Before NON-blocking/async requestForConversion");
start = millis();
sensors.setWaitForConversion(false); // makes it async
sensors.requestTemperatures();
sensors.setWaitForConversion(true);
stop = millis();
Serial.println("After NON-blocking/async requestForConversion");
Serial.print("Time used: ");
Serial.println(stop - start);
// 9 bit resolution by default
// Note the programmer is responsible for the right delay
// we could do something usefull here instead of the delay
int resolution = 9;
delay(750 / (1 << (12 - resolution)));
// get temperature
Serial.print("Temperature: ");
Serial.println(sensors.getTempCByIndex(0));
Serial.println("\n\n\n\n");
delay(1500);
}
@@ -0,0 +1,80 @@
//
// Sample of using Async reading of Dallas Temperature Sensors
//
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
DeviceAddress tempDeviceAddress;
int resolution = 12;
unsigned long lastTempRequest = 0;
int delayInMillis = 0;
float temperature = 0.0;
int idle = 0;
//
// SETUP
//
void setup(void)
{
Serial.begin(115200);
Serial.println("Dallas Temperature Control Library - Async Demo");
Serial.print("Library Version: ");
Serial.println(DALLASTEMPLIBVERSION);
Serial.println("\n");
sensors.begin();
sensors.getAddress(tempDeviceAddress, 0);
sensors.setResolution(tempDeviceAddress, resolution);
sensors.setWaitForConversion(false);
sensors.requestTemperatures();
delayInMillis = 750 / (1 << (12 - resolution));
lastTempRequest = millis();
pinMode(13, OUTPUT);
}
void loop(void)
{
if (millis() - lastTempRequest >= delayInMillis) // waited long enough??
{
digitalWrite(13, LOW);
Serial.print(" Temperature: ");
temperature = sensors.getTempCByIndex(0);
Serial.println(temperature, resolution - 8);
Serial.print(" Resolution: ");
Serial.println(resolution);
Serial.print("Idle counter: ");
Serial.println(idle);
Serial.println();
idle = 0;
// immediately after fetching the temperature we request a new sample
// in the async modus
// for the demo we let the resolution change to show differences
resolution++;
if (resolution > 12) resolution = 9;
sensors.setResolution(tempDeviceAddress, resolution);
sensors.requestTemperatures();
delayInMillis = 750 / (1 << (12 - resolution));
lastTempRequest = millis();
}
digitalWrite(13, HIGH);
// we can do usefull things here
// for the demo we just count the idle time in millis
delay(1);
idle++;
}
@@ -0,0 +1,67 @@
//
// FILE: oneWireSearch.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.02
// PURPOSE: scan for 1-Wire devices + code snippet generator
// DATE: 2015-june-30
// URL: http://forum.arduino.cc/index.php?topic=333923
//
// inspired by http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html
//
// Released to the public domain
//
// 0.1.00 initial version
// 0.1.01 first published version
// 0.1.02 small output changes
#include <OneWire.h>
void setup()
{
Serial.begin(115200);
Serial.println("//\n// Start oneWireSearch.ino \n//");
for (uint8_t pin = 2; pin < 13; pin++)
{
findDevices(pin);
}
Serial.println("\n//\n// End oneWireSearch.ino \n//");
}
void loop()
{
}
uint8_t findDevices(int pin)
{
OneWire ow(pin);
uint8_t address[8];
uint8_t count = 0;
if (ow.search(address))
{
Serial.print("\nuint8_t pin");
Serial.print(pin, DEC);
Serial.println("[][8] = {");
do {
count++;
Serial.println(" {");
for (uint8_t i = 0; i < 8; i++)
{
Serial.print("0x");
if (address[i] < 0x10) Serial.print("0");
Serial.print(address[i], HEX);
if (i < 7) Serial.print(", ");
}
Serial.println(" },");
} while (ow.search(address));
Serial.println("};");
Serial.print("// nr devices found: ");
Serial.println(count);
}
return count;
}
@@ -0,0 +1,92 @@
//
// FILE: readPowerSupply.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-02-10
//
// Released to the public domain
//
// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// arrays to hold device addresses
DeviceAddress insideThermometer, outsideThermometer;
// Assign address manually. The addresses below will beed to be changed
// to valid device addresses on your bus. Device address can be retrieved
// by using either oneWire.search(deviceAddress) or individually via
// sensors.getAddress(deviceAddress, index)
// DeviceAddress insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
// DeviceAddress outsideThermometer = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 };
int devCount = 0;
/*
* The setup function. We only start the sensors here
*/
void setup(void)
{
Serial.begin(115200);
Serial.println("Arduino Temperature Control Library Demo - readPowerSupply");
sensors.begin();
devCount = sensors.getDeviceCount();
Serial.print("#devices: ");
Serial.println(devCount);
// report parasite power requirements
Serial.print("Parasite power is: ");
if (sensors.readPowerSupply()) Serial.println("ON"); // no address means "scan all devices for parasite mode"
else Serial.println("OFF");
// Search for devices on the bus and assign based on an index.
if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1");
// show the addresses we found on the bus
Serial.print("Device 0 Address: ");
printAddress(insideThermometer);
Serial.println();
Serial.print("Power = parasite: ");
Serial.println(sensors.readPowerSupply(insideThermometer));
Serial.println();
Serial.println();
Serial.print("Device 1 Address: ");
printAddress(outsideThermometer);
Serial.println();
Serial.print("Power = parasite: ");
Serial.println(sensors.readPowerSupply(outsideThermometer));
Serial.println();
Serial.println();
}
// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
// zero pad the address if necessary
if (deviceAddress[i] < 0x10) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
// empty on purpose
void loop(void)
{
}
// END OF FILE
+93
View File
@@ -0,0 +1,93 @@
#######################################
# Syntax Coloring Map For DallasTemperature
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
DallasTemperature KEYWORD1
OneWire KEYWORD1
AlarmHandler KEYWORD1
DeviceAddress KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
setOneWire KEYWORD2
setPullupPin KEYWORD2
setResolution KEYWORD2
getResolution KEYWORD2
getTemp KEYWORD2
getTempC KEYWORD2
toFahrenheit KEYWORD2
getTempF KEYWORD2
getTempCByIndex KEYWORD2
getTempFByIndex KEYWORD2
rawToCelsius KEYWORD2
rawToFahrenheit KEYWORD2
setWaitForConversion KEYWORD2
getWaitForConversion KEYWORD2
requestTemperatures KEYWORD2
requestTemperaturesByAddress KEYWORD2
requestTemperaturesByIndex KEYWORD2
setCheckForConversion KEYWORD2
getCheckForConversion KEYWORD2
isConversionComplete KEYWORD2
millisToWaitForConversion KEYWORD2
isParasitePowerMode KEYWORD2
begin KEYWORD2
getDeviceCount KEYWORD2
getDS18Count KEYWORD2
getAddress KEYWORD2
validAddress KEYWORD2
validFamily KEYWORD2
isConnected KEYWORD2
readScratchPad KEYWORD2
writeScratchPad KEYWORD2
readPowerSupply KEYWORD2
saveScratchPadByIndex KEYWORD2
saveScratchPad KEYWORD2
recallScratchPadByIndex KEYWORD2
recallScratchPad KEYWORD2
setAutoSaveScratchPad KEYWORD2
getAutoSaveScratchPad KEYWORD2
setHighAlarmTemp KEYWORD2
setLowAlarmTemp KEYWORD2
getHighAlarmTemp KEYWORD2
getLowAlarmTemp KEYWORD2
resetAlarmSearch KEYWORD2
alarmSearch KEYWORD2
hasAlarm KEYWORD2
toCelsius KEYWORD2
processAlarms KEYWORD2
setAlarmHandler KEYWORD2
hasAlarmHandler KEYWORD2
setUserData KEYWORD2
setUserDataByIndex KEYWORD2
getUserData KEYWORD2
getUserDataByIndex KEYWORD2
calculateTemperature KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
DEVICE_DISCONNECTED_C LITERAL1
DEVICE_DISCONNECTED_F LITERAL1
DEVICE_DISCONNECTED_RAW LITERAL1
DEVICE_FAULT_OPEN_C LITERAL1
DEVICE_FAULT_OPEN_F LITERAL1
DEVICE_FAULT_OPEN_RAW LITERAL1
DEVICE_FAULT_SHORTGND_C LITERAL1
DEVICE_FAULT_SHORTGND_F LITERAL1
DEVICE_FAULT_SHORTGND_RAW LITERAL1
DEVICE_FAULT_SHORTVDD_C LITERAL1
DEVICE_FAULT_SHORTVDD_F LITERAL1
DEVICE_FAULT_SHORTVDD_RAW LITERAL1
DEVICE_POWER_ON_RESET_C LITERAL1
DEVICE_POWER_ON_RESET_F LITERAL1
DEVICE_POWER_ON_RESET_RAW LITERAL1
DEVICE_INSUFFICIENT_POWER_C LITERAL1
DEVICE_INSUFFICIENT_POWER_F LITERAL1
DEVICE_INSUFFICIENT_POWER_RAW LITERAL1
+40
View File
@@ -0,0 +1,40 @@
{
"name": "DallasTemperature",
"keywords": "onewire, 1-wire, bus, sensor, temperature, DS18B20, DS18S20, DS1822, DS1820, MAX31850",
"description": "Arduino Library for Dallas Temperature ICs (DS18B20, DS18S20, DS1822, DS1820, MAX31850)",
"repository":
{
"type": "git",
"url": "https://github.com/milesburton/Arduino-Temperature-Control-Library.git"
},
"authors":
[
{
"name": "Miles Burton",
"email": "mail@milesburton.com",
"url": "http://www.milesburton.com",
"maintainer": true
},
{
"name": "Tim Newsome",
"email": "nuisance@casualhacker.net"
},
{
"name": "Guil Barros",
"email": "gfbarros@bappos.com"
},
{
"name": "Rob Tillaart",
"email": "rob.tillaart@gmail.com"
}
],
"dependencies":
{
"paulstoffregen/OneWire": "^2.3.5"
},
"version": "4.0.6",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",
"headers": "DallasTemperature.h"
}
@@ -0,0 +1,9 @@
name=DallasTemperature
version=4.0.6
author=Miles Burton <mail@milesburton.com>, Tim Newsome <nuisance@casualhacker.net>, Guil Barros <gfbarros@bappos.com>, Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Miles Burton <mail@milesburton.com>
sentence=Arduino library for Dallas/Maxim temperature ICs
paragraph=Support for DS18B20 and other Dallas/Maxim 1-Wire temperature sensors
category=Sensors
url=https://github.com/milesburton/Arduino-Temperature-Control-Library
architectures=*
@@ -0,0 +1,20 @@
#include <DallasTemperature.h>
#include <ArduinoUnitTests.h>
unittest(test_initialization) {
OneWire oneWire(2); // Simulate OneWire on pin 2
DallasTemperature sensors(&oneWire);
sensors.begin();
assertEqual(0, sensors.getDeviceCount());
}
unittest(test_parasite_power_mode) {
OneWire oneWire(2);
DallasTemperature sensors(&oneWire);
sensors.begin();
assertFalse(sensors.isParasitePowerMode());
}
unittest_main()
@@ -0,0 +1,84 @@
// FILE: unit_test_001.cpp
// AUTHOR: Miles Burton / Rob Tillaart
// DATE: 2021-01-10
// PURPOSE: unit tests for the Arduino-Temperature-Control-Library
// https://github.com/MilesBurton/Arduino-Temperature-Control-Library
#include <ArduinoUnitTests.h>
#include <Arduino.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Mock pin for testing
#define ONE_WIRE_BUS 2
unittest_setup() {
fprintf(stderr, "VERSION: %s\n", DALLASTEMPLIBVERSION);
}
unittest_teardown() {
fprintf(stderr, "\n");
}
// Test constants defined in the library
unittest(test_models) {
assertEqual(0x10, DS18S20MODEL);
assertEqual(0x28, DS18B20MODEL);
assertEqual(0x22, DS1822MODEL);
assertEqual(0x3B, DS1825MODEL);
assertEqual(0x42, DS28EA00MODEL);
}
// Test error codes defined in the library
unittest(test_error_code) {
assertEqual(DEVICE_DISCONNECTED_C, -127);
assertEqual(DEVICE_DISCONNECTED_F, -196.6);
assertEqual(DEVICE_DISCONNECTED_RAW, -7040);
assertEqual(DEVICE_FAULT_OPEN_C, -254);
assertEqualFloat(DEVICE_FAULT_OPEN_F, -425.2, 0.1);
assertEqual(DEVICE_FAULT_OPEN_RAW, -32512);
assertEqual(DEVICE_FAULT_SHORTGND_C, -253);
assertEqualFloat(DEVICE_FAULT_SHORTGND_F, -423.4, 0.1);
assertEqual(DEVICE_FAULT_SHORTGND_RAW, -32384);
assertEqual(DEVICE_FAULT_SHORTVDD_C, -252);
assertEqualFloat(DEVICE_FAULT_SHORTVDD_F, -421.6, 0.1);
assertEqual(DEVICE_FAULT_SHORTVDD_RAW, -32256);
assertEqual(DEVICE_POWER_ON_RESET_C, -251);
assertEqualFloat(DEVICE_POWER_ON_RESET_F, -419.8, 0.1);
assertEqual(DEVICE_POWER_ON_RESET_RAW, -32128);
assertEqual(DEVICE_INSUFFICIENT_POWER_C, -250);
assertEqualFloat(DEVICE_INSUFFICIENT_POWER_F, -418.0, 0.1);
assertEqual(DEVICE_INSUFFICIENT_POWER_RAW, -32000);
}
// Test basic initialization and functionality of the DallasTemperature library
unittest(test_initialization) {
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
sensors.begin();
// Initially, there should be no devices detected
assertEqual(0, sensors.getDeviceCount());
assertFalse(sensors.isParasitePowerMode());
}
// Simulate a basic temperature read (mocked)
unittest(test_temperature_read) {
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
sensors.begin();
// Mock reading temperature
float tempC = sensors.getTempCByIndex(0);
assertEqual(DEVICE_DISCONNECTED_C, tempC); // Simulated no device connected
}
unittest_main()
+25
View File
@@ -0,0 +1,25 @@
= Liquid Crystal Library for Arduino =
This library allows an Arduino board to control LiquidCrystal displays (LCDs) based on the Hitachi HD44780 (or a compatible) chipset, which is found on most text-based LCDs.
For more information about this library please visit us at
http://www.arduino.cc/en/Reference/LiquidCrystal
== License ==
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
Copyright (c) 2010 Arduino LLC. 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
@@ -0,0 +1,78 @@
/*
LiquidCrystal Library - Autoscroll
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch demonstrates the use of the autoscroll()
and noAutoscroll() functions to make new text scroll or not.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalAutoscroll
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
}
void loop() {
// set the cursor to (0,0):
lcd.setCursor(0, 0);
// print from 0 to 9:
for (int thisChar = 0; thisChar < 10; thisChar++) {
lcd.print(thisChar);
delay(500);
}
// set the cursor to (16,1):
lcd.setCursor(16, 1);
// set the display to automatically scroll:
lcd.autoscroll();
// print from 0 to 9:
for (int thisChar = 0; thisChar < 10; thisChar++) {
lcd.print(thisChar);
delay(500);
}
// turn off automatic scrolling
lcd.noAutoscroll();
// clear screen for the next loop:
lcd.clear();
}
@@ -0,0 +1,65 @@
/*
LiquidCrystal Library - Blink
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD and makes the
cursor block blink.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalBlink
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
}
void loop() {
// Turn off the blinking cursor:
lcd.noBlink();
delay(3000);
// Turn on the blinking cursor:
lcd.blink();
delay(3000);
}
@@ -0,0 +1,65 @@
/*
LiquidCrystal Library - Cursor
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD and
uses the cursor() and noCursor() methods to turn
on and off the cursor.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalCursor
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
}
void loop() {
// Turn off the cursor:
lcd.noCursor();
delay(500);
// Turn on the cursor:
lcd.cursor();
delay(500);
}
@@ -0,0 +1,147 @@
/*
LiquidCrystal Library - Custom Characters
Demonstrates how to add custom characters on an LCD display.
The LiquidCrystal library works with all LCD displays that are
compatible with the Hitachi HD44780 driver. There are many of
them out there, and you can usually tell them by the 16-pin interface.
This sketch prints "I <heart> Arduino!" and a little dancing man
to the LCD.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K potentiometer:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
* 10K poterntiometer on pin A0
created 21 Mar 2011
by Tom Igoe
modified 11 Nov 2013
by Scott Fitzgerald
modified 7 Nov 2016
by Arturo Guadalupi
Based on Adafruit's example at
https://github.com/adafruit/SPI_VFD/blob/master/examples/createChar/createChar.pde
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalCustomCharacter
Also useful:
http://icontexto.com/charactercreator/
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// make some custom characters:
byte heart[8] = {
0b00000,
0b01010,
0b11111,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000
};
byte smiley[8] = {
0b00000,
0b00000,
0b01010,
0b00000,
0b00000,
0b10001,
0b01110,
0b00000
};
byte frownie[8] = {
0b00000,
0b00000,
0b01010,
0b00000,
0b00000,
0b00000,
0b01110,
0b10001
};
byte armsDown[8] = {
0b00100,
0b01010,
0b00100,
0b00100,
0b01110,
0b10101,
0b00100,
0b01010
};
byte armsUp[8] = {
0b00100,
0b01010,
0b00100,
0b10101,
0b01110,
0b00100,
0b00100,
0b01010
};
void setup() {
// initialize LCD and set up the number of columns and rows:
lcd.begin(16, 2);
// create a new character
lcd.createChar(0, heart);
// create a new character
lcd.createChar(1, smiley);
// create a new character
lcd.createChar(2, frownie);
// create a new character
lcd.createChar(3, armsDown);
// create a new character
lcd.createChar(4, armsUp);
// set the cursor to the top left
lcd.setCursor(0, 0);
// Print a message to the lcd.
lcd.print("I ");
lcd.write(byte(0)); // when calling lcd.write() '0' must be cast as a byte
lcd.print(" Arduino! ");
lcd.write((byte)1);
}
void loop() {
// read the potentiometer on A0:
int sensorReading = analogRead(A0);
// map the result to 200 - 1000:
int delayTime = map(sensorReading, 0, 1023, 200, 1000);
// set the cursor to the bottom row, 5th position:
lcd.setCursor(4, 1);
// draw the little man, arms down:
lcd.write(3);
delay(delayTime);
lcd.setCursor(4, 1);
// draw him arms up:
lcd.write(4);
delay(delayTime);
}
@@ -0,0 +1,65 @@
/*
LiquidCrystal Library - display() and noDisplay()
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD and uses the
display() and noDisplay() functions to turn on and off
the display.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalDisplay
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
}
void loop() {
// Turn off the display:
lcd.noDisplay();
delay(500);
// Turn on the display:
lcd.display();
delay(500);
}
@@ -0,0 +1,65 @@
/*
LiquidCrystal Library - Hello World
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD
and shows the time.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* LCD VSS pin to ground
* LCD VCC pin to 5V
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalHelloWorld
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
}
void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
lcd.setCursor(0, 1);
// print the number of seconds since reset:
lcd.print(millis() / 1000);
}
@@ -0,0 +1,90 @@
/*
LiquidCrystal Library - scrollDisplayLeft() and scrollDisplayRight()
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD and uses the
scrollDisplayLeft() and scrollDisplayRight() methods to scroll
the text.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalScroll
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
delay(1000);
}
void loop() {
// scroll 13 positions (string length) to the left
// to move it offscreen left:
for (int positionCounter = 0; positionCounter < 13; positionCounter++) {
// scroll one position left:
lcd.scrollDisplayLeft();
// wait a bit:
delay(150);
}
// scroll 29 positions (string length + display length) to the right
// to move it offscreen right:
for (int positionCounter = 0; positionCounter < 29; positionCounter++) {
// scroll one position right:
lcd.scrollDisplayRight();
// wait a bit:
delay(150);
}
// scroll 16 positions (display length + string length) to the left
// to move it back to center:
for (int positionCounter = 0; positionCounter < 16; positionCounter++) {
// scroll one position left:
lcd.scrollDisplayLeft();
// wait a bit:
delay(150);
}
// delay at the end of the full loop:
delay(1000);
}
@@ -0,0 +1,69 @@
/*
LiquidCrystal Library - Serial Input
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch displays text sent over the serial port
(e.g. from the Serial Monitor) on an attached LCD.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalSerialDisplay
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// initialize the serial communications:
Serial.begin(9600);
}
void loop() {
// when characters arrive over the serial port...
if (Serial.available()) {
// wait a bit for the entire message to arrive
delay(100);
// clear the screen
lcd.clear();
// read all the available characters
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read());
}
}
}
@@ -0,0 +1,90 @@
/*
LiquidCrystal Library - TextDirection
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch demonstrates how to use leftToRight() and rightToLeft()
to move the cursor.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalTextDirection
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
int thisChar = 'a';
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// turn on the cursor:
lcd.cursor();
}
void loop() {
// reverse directions at 'm':
if (thisChar == 'm') {
// go right for the next letter
lcd.rightToLeft();
}
// reverse again at 's':
if (thisChar == 's') {
// go left for the next letter
lcd.leftToRight();
}
// reset at 'z':
if (thisChar > 'z') {
// go to (0,0):
lcd.home();
// start again at 0
thisChar = 'a';
}
// print the character
lcd.write(thisChar);
// wait a second:
delay(1000);
// increment the letter:
thisChar++;
}
@@ -0,0 +1,76 @@
/*
LiquidCrystal Library - setCursor
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints to all the positions of the LCD using the
setCursor() method:
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalSetCursor
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// these constants won't change. But you can change the size of
// your LCD using them:
const int numRows = 2;
const int numCols = 16;
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(numCols, numRows);
}
void loop() {
// loop from ASCII 'a' to ASCII 'z':
for (int thisLetter = 'a'; thisLetter <= 'z'; thisLetter++) {
// loop over the columns:
for (int thisRow = 0; thisRow < numRows; thisRow++) {
// loop over the rows:
for (int thisCol = 0; thisCol < numCols; thisCol++) {
// set the cursor position:
lcd.setCursor(thisCol, thisRow);
// print the letter:
lcd.write(thisLetter);
delay(200);
}
}
}
}
+38
View File
@@ -0,0 +1,38 @@
#######################################
# Syntax Coloring Map For LiquidCrystal
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
LiquidCrystal KEYWORD1 LiquidCrystal
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
clear KEYWORD2
home KEYWORD2
print KEYWORD2
setCursor KEYWORD2
cursor KEYWORD2
noCursor KEYWORD2
blink KEYWORD2
noBlink KEYWORD2
display KEYWORD2
noDisplay KEYWORD2
autoscroll KEYWORD2
noAutoscroll KEYWORD2
leftToRight KEYWORD2
rightToLeft KEYWORD2
scrollDisplayLeft KEYWORD2
scrollDisplayRight KEYWORD2
createChar KEYWORD2
setRowOffsets KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
@@ -0,0 +1,9 @@
name=LiquidCrystal
version=1.0.7
author=Arduino, Adafruit
maintainer=Arduino <info@arduino.cc>
sentence=Allows communication with alphanumerical liquid crystal displays (LCDs).
paragraph=This library allows an Arduino/Genuino board to control LiquidCrystal displays (LCDs) based on the Hitachi HD44780 (or a compatible) chipset, which is found on most text-based LCDs. The library works with in either 4 or 8 bit mode (i.e. using 4 or 8 data lines in addition to the rs, enable, and, optionally, the rw control lines).
category=Display
url=http://www.arduino.cc/en/Reference/LiquidCrystal
architectures=*
@@ -0,0 +1,326 @@
#include "LiquidCrystal.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"
// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set:
// DL = 1; 8-bit interface data
// N = 0; 1-line display
// F = 0; 5x8 dot character font
// 3. Display on/off control:
// D = 0; Display off
// C = 0; Cursor off
// B = 0; Blinking off
// 4. Entry mode set:
// I/D = 1; Increment by 1
// S = 0; No shift
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}
void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
_rs_pin = rs;
_rw_pin = rw;
_enable_pin = enable;
_data_pins[0] = d0;
_data_pins[1] = d1;
_data_pins[2] = d2;
_data_pins[3] = d3;
_data_pins[4] = d4;
_data_pins[5] = d5;
_data_pins[6] = d6;
_data_pins[7] = d7;
if (fourbitmode)
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
else
_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
begin(16, 1);
}
void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
if (lines > 1) {
_displayfunction |= LCD_2LINE;
}
_numlines = lines;
setRowOffsets(0x00, 0x40, 0x00 + cols, 0x40 + cols);
// for some 1 line displays you can select a 10 pixel high font
if ((dotsize != LCD_5x8DOTS) && (lines == 1)) {
_displayfunction |= LCD_5x10DOTS;
}
pinMode(_rs_pin, OUTPUT);
// we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
if (_rw_pin != 255) {
pinMode(_rw_pin, OUTPUT);
}
pinMode(_enable_pin, OUTPUT);
// Do these once, instead of every time a character is drawn for speed reasons.
for (int i=0; i<((_displayfunction & LCD_8BITMODE) ? 8 : 4); ++i)
{
pinMode(_data_pins[i], OUTPUT);
}
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
// according to datasheet, we need at least 40ms after power rises above 2.7V
// before sending commands. Arduino can turn on way before 4.5V so we'll wait 50
delayMicroseconds(50000);
// Now we pull both RS and R/W low to begin commands
digitalWrite(_rs_pin, LOW);
digitalWrite(_enable_pin, LOW);
if (_rw_pin != 255) {
digitalWrite(_rw_pin, LOW);
}
//put the LCD into 4 bit or 8 bit mode
if (! (_displayfunction & LCD_8BITMODE)) {
// this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02);
} else {
// this is according to the hitachi HD44780 datasheet
// page 45 figure 23
// Send function set command sequence
command(LCD_FUNCTIONSET | _displayfunction);
delayMicroseconds(4500); // wait more than 4.1ms
// second try
command(LCD_FUNCTIONSET | _displayfunction);
delayMicroseconds(150);
// third go
command(LCD_FUNCTIONSET | _displayfunction);
}
// finally, set # lines, font size, etc.
command(LCD_FUNCTIONSET | _displayfunction);
// turn the display on with no cursor or blinking default
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
display();
// clear it off
clear();
// Initialize to default text direction (for romance languages)
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
// set the entry mode
command(LCD_ENTRYMODESET | _displaymode);
}
void LiquidCrystal::setRowOffsets(int row0, int row1, int row2, int row3)
{
_row_offsets[0] = row0;
_row_offsets[1] = row1;
_row_offsets[2] = row2;
_row_offsets[3] = row3;
}
/********** high level commands, for the user! */
void LiquidCrystal::clear()
{
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void LiquidCrystal::home()
{
command(LCD_RETURNHOME); // set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
{
const size_t max_lines = sizeof(_row_offsets) / sizeof(*_row_offsets);
if ( row >= max_lines ) {
row = max_lines - 1; // we count rows starting w/0
}
if ( row >= _numlines ) {
row = _numlines - 1; // we count rows starting w/0
}
command(LCD_SETDDRAMADDR | (col + _row_offsets[row]));
}
// Turn the display on/off (quickly)
void LiquidCrystal::noDisplay() {
_displaycontrol &= ~LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal::display() {
_displaycontrol |= LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turns the underline cursor on/off
void LiquidCrystal::noCursor() {
_displaycontrol &= ~LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal::cursor() {
_displaycontrol |= LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turn on and off the blinking cursor
void LiquidCrystal::noBlink() {
_displaycontrol &= ~LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal::blink() {
_displaycontrol |= LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// These commands scroll the display without changing the RAM
void LiquidCrystal::scrollDisplayLeft(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void LiquidCrystal::scrollDisplayRight(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
// This is for text that flows Left to Right
void LiquidCrystal::leftToRight(void) {
_displaymode |= LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This is for text that flows Right to Left
void LiquidCrystal::rightToLeft(void) {
_displaymode &= ~LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'right justify' text from the cursor
void LiquidCrystal::autoscroll(void) {
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'left justify' text from the cursor
void LiquidCrystal::noAutoscroll(void) {
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
location &= 0x7; // we only have 8 locations 0-7
command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++) {
write(charmap[i]);
}
}
/*********** mid level commands, for sending data/cmds */
inline void LiquidCrystal::command(uint8_t value) {
send(value, LOW);
}
inline size_t LiquidCrystal::write(uint8_t value) {
send(value, HIGH);
return 1; // assume sucess
}
/************ low level data pushing commands **********/
// write either command or data, with automatic 4/8-bit selection
void LiquidCrystal::send(uint8_t value, uint8_t mode) {
digitalWrite(_rs_pin, mode);
// if there is a RW pin indicated, set it low to Write
if (_rw_pin != 255) {
digitalWrite(_rw_pin, LOW);
}
if (_displayfunction & LCD_8BITMODE) {
write8bits(value);
} else {
write4bits(value>>4);
write4bits(value);
}
}
void LiquidCrystal::pulseEnable(void) {
digitalWrite(_enable_pin, LOW);
delayMicroseconds(1);
digitalWrite(_enable_pin, HIGH);
delayMicroseconds(1); // enable pulse must be >450ns
digitalWrite(_enable_pin, LOW);
delayMicroseconds(100); // commands need > 37us to settle
}
void LiquidCrystal::write4bits(uint8_t value) {
for (int i = 0; i < 4; i++) {
digitalWrite(_data_pins[i], (value >> i) & 0x01);
}
pulseEnable();
}
void LiquidCrystal::write8bits(uint8_t value) {
for (int i = 0; i < 8; i++) {
digitalWrite(_data_pins[i], (value >> i) & 0x01);
}
pulseEnable();
}
+108
View File
@@ -0,0 +1,108 @@
#ifndef LiquidCrystal_h
#define LiquidCrystal_h
#include <inttypes.h>
#include "Print.h"
// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
class LiquidCrystal : public Print {
public:
LiquidCrystal(uint8_t rs, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
LiquidCrystal(uint8_t rs, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
void init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
void clear();
void home();
void noDisplay();
void display();
void noBlink();
void blink();
void noCursor();
void cursor();
void scrollDisplayLeft();
void scrollDisplayRight();
void leftToRight();
void rightToLeft();
void autoscroll();
void noAutoscroll();
void setRowOffsets(int row1, int row2, int row3, int row4);
void createChar(uint8_t, uint8_t[]);
void setCursor(uint8_t, uint8_t);
virtual size_t write(uint8_t);
void command(uint8_t);
using Print::write;
private:
void send(uint8_t, uint8_t);
void write4bits(uint8_t);
void write8bits(uint8_t);
void pulseEnable();
uint8_t _rs_pin; // LOW: command. HIGH: character.
uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
uint8_t _enable_pin; // activated by a HIGH pulse.
uint8_t _data_pins[8];
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _initialized;
uint8_t _numlines;
uint8_t _row_offsets[4];
};
#endif
@@ -0,0 +1,127 @@
# Adafruit Community Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and leaders pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level or type of
experience, education, socio-economic status, nationality, personal appearance,
race, religion, or sexual identity and orientation.
## Our Standards
We are committed to providing a friendly, safe and welcoming environment for
all.
Examples of behavior that contributes to creating a positive environment
include:
* Be kind and courteous to others
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Collaborating with other community members
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and sexual attention or advances
* The use of inappropriate images, including in a community member's avatar
* The use of inappropriate language, including in a community member's nickname
* Any spamming, flaming, baiting or other attention-stealing behavior
* Excessive or unwelcome helping; answering outside the scope of the question
asked
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate
The goal of the standards and moderation guidelines outlined here is to build
and maintain a respectful community. We ask that you don’t just aim to be
"technically unimpeachable", but rather try to be your best self.
We value many things beyond technical expertise, including collaboration and
supporting others within our community. Providing a positive experience for
other community members can have a much more significant impact than simply
providing the correct answer.
## Our Responsibilities
Project leaders are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project leaders have the right and responsibility to remove, edit, or
reject messages, comments, commits, code, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any community member for other behaviors that they deem
inappropriate, threatening, offensive, or harmful.
## Moderation
Instances of behaviors that violate the Adafruit Community Code of Conduct
may be reported by any member of the community. Community members are
encouraged to report these situations, including situations they witness
involving other community members.
You may report in the following ways:
In any situation, you may send an email to <support@adafruit.com>.
On the Adafruit Discord, you may send an open message from any channel
to all Community Helpers by tagging @community helpers. You may also send an
open message from any channel, or a direct message to @kattni#1507,
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
@Andon#8175.
Email and direct message reports will be kept confidential.
In situations on Discord where the issue is particularly egregious, possibly
illegal, requires immediate action, or violates the Discord terms of service,
you should also report the message directly to Discord.
These are the steps for upholding our community’s standards of conduct.
1. Any member of the community may report any situation that violates the
Adafruit Community Code of Conduct. All reports will be reviewed and
investigated.
2. If the behavior is an egregious violation, the community member who
committed the violation may be banned immediately, without warning.
3. Otherwise, moderators will first respond to such behavior with a warning.
4. Moderators follow a soft "three strikes" policy - the community member may
be given another chance, if they are receptive to the warning and change their
behavior.
5. If the community member is unreceptive or unreasonable when warned by a
moderator, or the warning goes unheeded, they may be banned for a first or
second offense. Repeated offenses will result in the community member being
banned.
## Scope
This Code of Conduct and the enforcement policies listed above apply to all
Adafruit Community venues. This includes but is not limited to any community
spaces (both public and private), the entire Adafruit Discord server, and
Adafruit GitHub repositories. Examples of Adafruit Community spaces include
but are not limited to meet-ups, audio chats on the Adafruit Discord, or
interaction at a conference.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. As a community
member, you are representing our community, and are expected to behave
accordingly.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at
<https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>,
and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
For other projects adopting the Adafruit Community Code of
Conduct, please contact the maintainers of those projects for enforcement.
If you wish to use this code of conduct for your own project, consider
explicitly mentioning your moderation policy or making a copy with your
own moderation policy so as to avoid confusion.
@@ -0,0 +1,58 @@
// this example is public domain. enjoy!
// https://learn.adafruit.com/thermocouple/
#include <max6675.h>
#include <LiquidCrystal.h>
#include <Wire.h>
int thermoDO = 4;
int thermoCS = 5;
int thermoCLK = 6;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
int vccPin = 3;
int gndPin = 2;
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
// make a cute degree symbol
uint8_t degree[8] = {140,146,146,140,128,128,128,128};
void setup() {
Serial.begin(9600);
// use Arduino pins
pinMode(vccPin, OUTPUT); digitalWrite(vccPin, HIGH);
pinMode(gndPin, OUTPUT); digitalWrite(gndPin, LOW);
lcd.begin(16, 2);
lcd.createChar(0, degree);
// wait for MAX chip to stabilize
delay(500);
}
void loop() {
// basic readout test, just print the current temp
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("MAX6675 test");
// go to line #1
lcd.setCursor(0,1);
lcd.print(thermocouple.readCelsius());
#if ARDUINO >= 100
lcd.write((byte)0);
#else
lcd.print(0, BYTE);
#endif
lcd.print("C ");
lcd.print(thermocouple.readFahrenheit());
#if ARDUINO >= 100
lcd.write((byte)0);
#else
lcd.print(0, BYTE);
#endif
lcd.print('F');
delay(1000);
}
@@ -0,0 +1,30 @@
// this example is public domain. enjoy!
// https://learn.adafruit.com/thermocouple/
#include "max6675.h"
int thermoDO = 4;
int thermoCS = 5;
int thermoCLK = 6;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
void setup() {
Serial.begin(9600);
Serial.println("MAX6675 test");
// wait for MAX chip to stabilize
delay(500);
}
void loop() {
// basic readout test, just print the current temp
Serial.print("C = ");
Serial.println(thermocouple.readCelsius());
Serial.print("F = ");
Serial.println(thermocouple.readFahrenheit());
// For the MAX6675 to update, you must delay AT LEAST 250ms between reads!
delay(1000);
}
+22
View File
@@ -0,0 +1,22 @@
#######################################
# Syntax Coloring Map for NewSoftSerial
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
max6675 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
readCelsius KEYWORD2
readFahrenheit KEYWORD2
readFarenheit KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
@@ -0,0 +1,10 @@
name=MAX6675 library
version=1.1.0
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Arduino library for interfacing with MAX6675 thermocouple amplifier
paragraph=Arduino library for interfacing with MAX6675 thermocouple amplifier
category=Sensors
url=https://github.com/adafruit/MAX6675-library
architectures=*
depends=LiquidCrystal
+26
View File
@@ -0,0 +1,26 @@
Software License Agreement (BSD License)
Copyright (c) 2019, Limor Fried for Adafruit Industries
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+82
View File
@@ -0,0 +1,82 @@
// this library is public domain. enjoy!
// https://learn.adafruit.com/thermocouple/
#include "max6675.h"
/**************************************************************************/
/*!
@brief Initialize a MAX6675 sensor
@param SCLK The Arduino pin connected to Clock
@param CS The Arduino pin connected to Chip Select
@param MISO The Arduino pin connected to Data Out
*/
/**************************************************************************/
MAX6675::MAX6675(int8_t SCLK, int8_t CS, int8_t MISO) {
sclk = SCLK;
cs = CS;
miso = MISO;
// define pin modes
pinMode(cs, OUTPUT);
pinMode(sclk, OUTPUT);
pinMode(miso, INPUT);
digitalWrite(cs, HIGH);
}
/**************************************************************************/
/*!
@brief Read the Celsius temperature
@returns Temperature in C or NAN on failure!
*/
/**************************************************************************/
float MAX6675::readCelsius(void) {
uint16_t v;
digitalWrite(cs, LOW);
delayMicroseconds(10);
v = spiread();
v <<= 8;
v |= spiread();
digitalWrite(cs, HIGH);
if (v & 0x4) {
// uh oh, no thermocouple attached!
return NAN;
// return -100;
}
v >>= 3;
return v * 0.25;
}
/**************************************************************************/
/*!
@brief Read the Fahenheit temperature
@returns Temperature in F or NAN on failure!
*/
/**************************************************************************/
float MAX6675::readFahrenheit(void) { return readCelsius() * 9.0 / 5.0 + 32; }
byte MAX6675::spiread(void) {
int i;
byte d = 0;
for (i = 7; i >= 0; i--) {
digitalWrite(sclk, LOW);
delayMicroseconds(10);
if (digitalRead(miso)) {
// set the bit to 0 no matter what
d |= (1 << i);
}
digitalWrite(sclk, HIGH);
delayMicroseconds(10);
}
return d;
}
+30
View File
@@ -0,0 +1,30 @@
// this library is public domain. enjoy!
// https://learn.adafruit.com/thermocouple/
#ifndef ADAFRUIT_MAX6675_H
#define ADAFRUIT_MAX6675_H
#include "Arduino.h"
/**************************************************************************/
/*!
@brief Class for communicating with thermocouple sensor
*/
/**************************************************************************/
class MAX6675 {
public:
MAX6675(int8_t SCLK, int8_t CS, int8_t MISO);
float readCelsius(void);
float readFahrenheit(void);
/*! @brief For compatibility with older versions
@returns Temperature in F or NAN on failure! */
float readFarenheit(void) { return readFahrenheit(); }
private:
int8_t sclk, miso, cs;
uint8_t spiread(void);
};
#endif
+603
View File
@@ -0,0 +1,603 @@
/*
Copyright (c) 2007, Jim Studt (original old version - many contributors since)
The latest version of this library may be found at:
http://www.pjrc.com/teensy/td_libs_OneWire.html
OneWire has been maintained by Paul Stoffregen (paul@pjrc.com) since
January 2010.
DO NOT EMAIL for technical support, especially not for ESP chips!
All project support questions must be posted on public forums
relevant to the board or chips used. If using Arduino, post on
Arduino's forum. If using ESP, post on the ESP community forums.
There is ABSOLUTELY NO TECH SUPPORT BY PRIVATE EMAIL!
Github's issue tracker for OneWire should be used only to report
specific bugs. DO NOT request project support via Github. All
project and tech support questions must be posted on forums, not
github issues. If you experience a problem and you are not
absolutely sure it's an issue with the library, ask on a forum
first. Only use github to report issues after experts have
confirmed the issue is with OneWire rather than your project.
Back in 2010, OneWire was in need of many bug fixes, but had
been abandoned the original author (Jim Studt). None of the known
contributors were interested in maintaining OneWire. Paul typically
works on OneWire every 6 to 12 months. Patches usually wait that
long. If anyone is interested in more actively maintaining OneWire,
please contact Paul (this is pretty much the only reason to use
private email about OneWire).
OneWire is now very mature code. No changes other than adding
definitions for newer hardware support are anticipated.
ESP32 mods authored by stickbreaker:
@stickbreaker 30APR2018 add IRAM_ATTR to read_bit() write_bit() to solve ICache miss timing failure.
thanks @everslick re: https://github.com/espressif/arduino-esp32/issues/1335
Altered by garyd9 for clean merge with Paul Stoffregen's source
Version 2.3:
Unknown chip fallback mode, Roger Clark
Teensy-LC compatibility, Paul Stoffregen
Search bug fix, Love Nystrom
Version 2.2:
Teensy 3.0 compatibility, Paul Stoffregen, paul@pjrc.com
Arduino Due compatibility, http://arduino.cc/forum/index.php?topic=141030
Fix DS18B20 example negative temperature
Fix DS18B20 example's low res modes, Ken Butcher
Improve reset timing, Mark Tillotson
Add const qualifiers, Bertrik Sikken
Add initial value input to crc16, Bertrik Sikken
Add target_search() function, Scott Roberts
Version 2.1:
Arduino 1.0 compatibility, Paul Stoffregen
Improve temperature example, Paul Stoffregen
DS250x_PROM example, Guillermo Lovato
PIC32 (chipKit) compatibility, Jason Dangel, dangel.jason AT gmail.com
Improvements from Glenn Trewitt:
- crc16() now works
- check_crc16() does all of calculation/checking work.
- Added read_bytes() and write_bytes(), to reduce tedious loops.
- Added ds2408 example.
Delete very old, out-of-date readme file (info is here)
Version 2.0: Modifications by Paul Stoffregen, January 2010:
http://www.pjrc.com/teensy/td_libs_OneWire.html
Search fix from Robin James
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27
Use direct optimized I/O in all cases
Disable interrupts during timing critical sections
(this solves many random communication errors)
Disable interrupts during read-modify-write I/O
Reduce RAM consumption by eliminating unnecessary
variables and trimming many to 8 bits
Optimize both crc8 - table version moved to flash
Modified to work with larger numbers of devices - avoids loop.
Tested in Arduino 11 alpha with 12 sensors.
26 Sept 2008 -- Robin James
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27
Updated to work with arduino-0008 and to include skip() as of
2007/07/06. --RJL20
Modified to calculate the 8-bit CRC directly, avoiding the need for
the 256-byte lookup table to be loaded in RAM. Tested in arduino-0010
-- Tom Pollard, Jan 23, 2008
Jim Studt's original library was modified by Josh Larios.
Tom Pollard, pollard@alum.mit.edu, contributed around May 20, 2008
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Much of the code was inspired by Derek Yerger's code, though I don't
think much of that remains. In any event that was..
(copyleft) 2006 by Derek Yerger - Free to distribute freely.
The CRC code was excerpted and inspired by the Dallas Semiconductor
sample code bearing this copyright.
//---------------------------------------------------------------------------
// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// Except as contained in this notice, the name of Dallas Semiconductor
// shall not be used except as stated in the Dallas Semiconductor
// Branding Policy.
//--------------------------------------------------------------------------
*/
#include <Arduino.h>
#include "OneWire.h"
#include "util/OneWire_direct_gpio.h"
#ifdef ARDUINO_ARCH_ESP32
// due to the dual core esp32, a critical section works better than disabling interrupts
# define noInterrupts() {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;portENTER_CRITICAL(&mux)
# define interrupts() portEXIT_CRITICAL(&mux);}
// for info on this, search "IRAM_ATTR" at https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/general-notes.html
# define CRIT_TIMING IRAM_ATTR
#else
# define CRIT_TIMING
#endif
void OneWire::begin(uint8_t pin)
{
pinMode(pin, INPUT);
bitmask = PIN_TO_BITMASK(pin);
baseReg = PIN_TO_BASEREG(pin);
#if ONEWIRE_SEARCH
reset_search();
#endif
}
// Perform the onewire reset function. We will wait up to 250uS for
// the bus to come high, if it doesn't then it is broken or shorted
// and we return a 0;
//
// Returns 1 if a device asserted a presence pulse, 0 otherwise.
//
uint8_t CRIT_TIMING OneWire::reset(void)
{
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
__attribute__((unused)) volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
uint8_t r;
uint8_t retries = 125;
noInterrupts();
DIRECT_MODE_INPUT(reg, mask);
interrupts();
// wait until the wire is high... just in case
do {
if (--retries == 0) return 0;
delayMicroseconds(2);
} while ( !DIRECT_READ(reg, mask));
noInterrupts();
DIRECT_WRITE_LOW(reg, mask);
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
interrupts();
delayMicroseconds(480);
noInterrupts();
DIRECT_MODE_INPUT(reg, mask); // allow it to float
delayMicroseconds(70);
r = !DIRECT_READ(reg, mask);
interrupts();
delayMicroseconds(410);
return r;
}
//
// Write a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
void CRIT_TIMING OneWire::write_bit(uint8_t v)
{
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
__attribute__((unused)) volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
if (v & 1) {
noInterrupts();
DIRECT_WRITE_LOW(reg, mask);
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
delayMicroseconds(10);
DIRECT_WRITE_HIGH(reg, mask); // drive output high
interrupts();
delayMicroseconds(55);
} else {
noInterrupts();
DIRECT_WRITE_LOW(reg, mask);
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
delayMicroseconds(65);
DIRECT_WRITE_HIGH(reg, mask); // drive output high
interrupts();
delayMicroseconds(5);
}
}
//
// Read a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
uint8_t CRIT_TIMING OneWire::read_bit(void)
{
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
__attribute__((unused)) volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
uint8_t r;
noInterrupts();
DIRECT_MODE_OUTPUT(reg, mask);
DIRECT_WRITE_LOW(reg, mask);
delayMicroseconds(3);
DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise
delayMicroseconds(10);
r = DIRECT_READ(reg, mask);
interrupts();
delayMicroseconds(53);
return r;
}
//
// Write a byte. The writing code uses the active drivers to raise the
// pin high, if you need power after the write (e.g. DS18S20 in
// parasite power mode) then set 'power' to 1, otherwise the pin will
// go tri-state at the end of the write to avoid heating in a short or
// other mishap.
//
void OneWire::write(uint8_t v, uint8_t power /* = 0 */) {
uint8_t bitMask;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
OneWire::write_bit( (bitMask & v)?1:0);
}
if ( !power) {
noInterrupts();
DIRECT_MODE_INPUT(baseReg, bitmask);
DIRECT_WRITE_LOW(baseReg, bitmask);
interrupts();
}
}
void OneWire::write_bytes(const uint8_t *buf, uint16_t count, bool power /* = 0 */) {
for (uint16_t i = 0 ; i < count ; i++)
write(buf[i]);
if (!power) {
noInterrupts();
DIRECT_MODE_INPUT(baseReg, bitmask);
DIRECT_WRITE_LOW(baseReg, bitmask);
interrupts();
}
}
//
// Read a byte
//
uint8_t OneWire::read() {
uint8_t bitMask;
uint8_t r = 0;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
if ( OneWire::read_bit()) r |= bitMask;
}
return r;
}
void OneWire::read_bytes(uint8_t *buf, uint16_t count) {
for (uint16_t i = 0 ; i < count ; i++)
buf[i] = read();
}
//
// Do a ROM select
//
void OneWire::select(const uint8_t rom[8])
{
uint8_t i;
write(0x55); // Choose ROM
for (i = 0; i < 8; i++) write(rom[i]);
}
//
// Do a ROM skip
//
void OneWire::skip()
{
write(0xCC); // Skip ROM
}
void OneWire::depower()
{
noInterrupts();
DIRECT_MODE_INPUT(baseReg, bitmask);
interrupts();
}
#if ONEWIRE_SEARCH
//
// You need to use this function to start a search again from the beginning.
// You do not need to do it for the first search, though you could.
//
void OneWire::reset_search()
{
// reset the search state
LastDiscrepancy = 0;
LastDeviceFlag = false;
LastFamilyDiscrepancy = 0;
for(int i = 7; ; i--) {
ROM_NO[i] = 0;
if ( i == 0) break;
}
}
// Setup the search to find the device type 'family_code' on the next call
// to search(*newAddr) if it is present.
//
void OneWire::target_search(uint8_t family_code)
{
// set the search state to find SearchFamily type devices
ROM_NO[0] = family_code;
for (uint8_t i = 1; i < 8; i++)
ROM_NO[i] = 0;
LastDiscrepancy = 64;
LastFamilyDiscrepancy = 0;
LastDeviceFlag = false;
}
//
// Perform a search. If this function returns a '1' then it has
// enumerated the next device and you may retrieve the ROM from the
// OneWire::address variable. If there are no devices, no further
// devices, or something horrible happens in the middle of the
// enumeration then a 0 is returned. If a new device is found then
// its address is copied to newAddr. Use OneWire::reset_search() to
// start over.
//
// --- Replaced by the one from the Dallas Semiconductor web site ---
//--------------------------------------------------------------------------
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
// search state.
// Return TRUE : device found, ROM number in ROM_NO buffer
// FALSE : device not found, end of search
//
bool OneWire::search(uint8_t *newAddr, bool search_mode /* = true */)
{
uint8_t id_bit_number;
uint8_t last_zero, rom_byte_number;
bool search_result;
uint8_t id_bit, cmp_id_bit;
unsigned char rom_byte_mask, search_direction;
// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
rom_byte_mask = 1;
search_result = false;
// if the last call was not the last one
if (!LastDeviceFlag) {
// 1-Wire reset
if (!reset()) {
// reset the search
LastDiscrepancy = 0;
LastDeviceFlag = false;
LastFamilyDiscrepancy = 0;
return false;
}
// issue the search command
if (search_mode == true) {
write(0xF0); // NORMAL SEARCH
} else {
write(0xEC); // CONDITIONAL SEARCH
}
// loop to do the search
do
{
// read a bit and its complement
id_bit = read_bit();
cmp_id_bit = read_bit();
// check for no devices on 1-wire
if ((id_bit == 1) && (cmp_id_bit == 1)) {
break;
} else {
// all devices coupled have 0 or 1
if (id_bit != cmp_id_bit) {
search_direction = id_bit; // bit write value for search
} else {
// if this discrepancy if before the Last Discrepancy
// on a previous next then pick the same as last time
if (id_bit_number < LastDiscrepancy) {
search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
} else {
// if equal to last pick 1, if not then pick 0
search_direction = (id_bit_number == LastDiscrepancy);
}
// if 0 was picked then record its position in LastZero
if (search_direction == 0) {
last_zero = id_bit_number;
// check for Last discrepancy in family
if (last_zero < 9)
LastFamilyDiscrepancy = last_zero;
}
}
// set or clear the bit in the ROM byte rom_byte_number
// with mask rom_byte_mask
if (search_direction == 1)
ROM_NO[rom_byte_number] |= rom_byte_mask;
else
ROM_NO[rom_byte_number] &= ~rom_byte_mask;
// serial number search direction write bit
write_bit(search_direction);
// increment the byte counter id_bit_number
// and shift the mask rom_byte_mask
id_bit_number++;
rom_byte_mask <<= 1;
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
if (rom_byte_mask == 0) {
rom_byte_number++;
rom_byte_mask = 1;
}
}
}
while(rom_byte_number < 8); // loop until through all ROM bytes 0-7
// if the search was successful then
if (!(id_bit_number < 65)) {
// search successful so set LastDiscrepancy,LastDeviceFlag,search_result
LastDiscrepancy = last_zero;
// check for last device
if (LastDiscrepancy == 0) {
LastDeviceFlag = true;
}
search_result = true;
}
}
// if no device found then reset counters so next 'search' will be like a first
if (!search_result || !ROM_NO[0]) {
LastDiscrepancy = 0;
LastDeviceFlag = false;
LastFamilyDiscrepancy = 0;
search_result = false;
} else {
for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i];
}
return search_result;
}
#endif
#if ONEWIRE_CRC
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
//
#if ONEWIRE_CRC8_TABLE
// Dow-CRC using polynomial X^8 + X^5 + X^4 + X^0
// Tiny 2x16 entry CRC table created by Arjen Lentz
// See http://lentz.com.au/blog/calculating-crc-with-a-tiny-32-entry-lookup-table
static const uint8_t PROGMEM dscrc2x16_table[] = {
0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83,
0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41,
0x00, 0x9D, 0x23, 0xBE, 0x46, 0xDB, 0x65, 0xF8,
0x8C, 0x11, 0xAF, 0x32, 0xCA, 0x57, 0xE9, 0x74
};
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
// and the registers. (Use tiny 2x16 entry CRC table)
uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
while (len--) {
crc = *addr++ ^ crc; // just re-using crc as intermediate
crc = pgm_read_byte(dscrc2x16_table + (crc & 0x0f)) ^
pgm_read_byte(dscrc2x16_table + 16 + ((crc >> 4) & 0x0f));
}
return crc;
}
#else
//
// Compute a Dallas Semiconductor 8 bit CRC directly.
// this is much slower, but a little smaller, than the lookup table.
//
uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
while (len--) {
#if defined(__AVR__)
crc = _crc_ibutton_update(crc, *addr++);
#else
uint8_t inbyte = *addr++;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
#endif
}
return crc;
}
#endif
#if ONEWIRE_CRC16
bool OneWire::check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc)
{
crc = ~crc16(input, len, crc);
return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];
}
uint16_t OneWire::crc16(const uint8_t* input, uint16_t len, uint16_t crc)
{
#if defined(__AVR__)
for (uint16_t i = 0 ; i < len ; i++) {
crc = _crc16_update(crc, input[i]);
}
#else
static const uint8_t oddparity[16] =
{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
for (uint16_t i = 0 ; i < len ; i++) {
// Even though we're just copying a byte from the input,
// we'll be doing 16-bit computation with it.
uint16_t cdata = input[i];
cdata = (cdata ^ crc) & 0xff;
crc >>= 8;
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4])
crc ^= 0xC001;
cdata <<= 6;
crc ^= cdata;
cdata <<= 1;
crc ^= cdata;
}
#endif
return crc;
}
#endif
#endif
// undef defines for no particular reason
#ifdef ARDUINO_ARCH_ESP32
# undef noInterrupts() {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;portENTER_CRITICAL(&mux)
# undef interrupts() portEXIT_CRITICAL(&mux);}
#endif
// for info on this, search "IRAM_ATTR" at https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/general-notes.html
#undef CRIT_TIMING
+182
View File
@@ -0,0 +1,182 @@
#ifndef OneWire_h
#define OneWire_h
#ifdef __cplusplus
#include <stdint.h>
#if defined(__AVR__)
#include <util/crc16.h>
#endif
#if ARDUINO >= 100
#include <Arduino.h> // for delayMicroseconds, digitalPinToBitMask, etc
#else
#include "WProgram.h" // for delayMicroseconds
#include "pins_arduino.h" // for digitalPinToBitMask, etc
#endif
// You can exclude certain features from OneWire. In theory, this
// might save some space. In practice, the compiler automatically
// removes unused code (technically, the linker, using -fdata-sections
// and -ffunction-sections when compiling, and Wl,--gc-sections
// when linking), so most of these will not result in any code size
// reduction. Well, unless you try to use the missing features
// and redesign your program to not need them! ONEWIRE_CRC8_TABLE
// is the exception, because it selects a fast but large algorithm
// or a small but slow algorithm.
// you can exclude onewire_search by defining that to 0
#ifndef ONEWIRE_SEARCH
#define ONEWIRE_SEARCH 1
#endif
// You can exclude CRC checks altogether by defining this to 0
#ifndef ONEWIRE_CRC
#define ONEWIRE_CRC 1
#endif
// Select the table-lookup method of computing the 8-bit CRC
// by setting this to 1. The lookup table enlarges code size by
// about 250 bytes. It does NOT consume RAM (but did in very
// old versions of OneWire). If you disable this, a slower
// but very compact algorithm is used.
#ifndef ONEWIRE_CRC8_TABLE
#define ONEWIRE_CRC8_TABLE 1
#endif
// You can allow 16-bit CRC checks by defining this to 1
// (Note that ONEWIRE_CRC must also be 1.)
#ifndef ONEWIRE_CRC16
#define ONEWIRE_CRC16 1
#endif
// Board-specific macros for direct GPIO
#include "util/OneWire_direct_regtype.h"
class OneWire
{
private:
IO_REG_TYPE bitmask;
volatile IO_REG_TYPE *baseReg;
#if ONEWIRE_SEARCH
// global search state
unsigned char ROM_NO[8];
uint8_t LastDiscrepancy;
uint8_t LastFamilyDiscrepancy;
bool LastDeviceFlag;
#endif
public:
OneWire() { }
OneWire(uint8_t pin) { begin(pin); }
void begin(uint8_t pin);
// Perform a 1-Wire reset cycle. Returns 1 if a device responds
// with a presence pulse. Returns 0 if there is no device or the
// bus is shorted or otherwise held low for more than 250uS
uint8_t reset(void);
// Issue a 1-Wire rom select command, you do the reset first.
void select(const uint8_t rom[8]);
// Issue a 1-Wire rom skip command, to address all on bus.
void skip(void);
// Write a byte. If 'power' is one then the wire is held high at
// the end for parasitically powered devices. You are responsible
// for eventually depowering it by calling depower() or doing
// another read or write.
void write(uint8_t v, uint8_t power = 0);
void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0);
// Read a byte.
uint8_t read(void);
void read_bytes(uint8_t *buf, uint16_t count);
// Write a bit. The bus is always left powered at the end, see
// note in write() about that.
void write_bit(uint8_t v);
// Read a bit.
uint8_t read_bit(void);
// Stop forcing power onto the bus. You only need to do this if
// you used the 'power' flag to write() or used a write_bit() call
// and aren't about to do another read or write. You would rather
// not leave this powered if you don't have to, just in case
// someone shorts your bus.
void depower(void);
#if ONEWIRE_SEARCH
// Clear the search state so that if will start from the beginning again.
void reset_search();
// Setup the search to find the device type 'family_code' on the next call
// to search(*newAddr) if it is present.
void target_search(uint8_t family_code);
// Look for the next device. Returns 1 if a new address has been
// returned. A zero might mean that the bus is shorted, there are
// no devices, or you have already retrieved all of them. It
// might be a good idea to check the CRC to make sure you didn't
// get garbage. The order is deterministic. You will always get
// the same devices in the same order.
bool search(uint8_t *newAddr, bool search_mode = true);
#endif
#if ONEWIRE_CRC
// Compute a Dallas Semiconductor 8 bit CRC, these are used in the
// ROM and scratchpad registers.
static uint8_t crc8(const uint8_t *addr, uint8_t len);
#if ONEWIRE_CRC16
// Compute the 1-Wire CRC16 and compare it against the received CRC.
// Example usage (reading a DS2408):
// // Put everything in a buffer so we can compute the CRC easily.
// uint8_t buf[13];
// buf[0] = 0xF0; // Read PIO Registers
// buf[1] = 0x88; // LSB address
// buf[2] = 0x00; // MSB address
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
// if (!CheckCRC16(buf, 11, &buf[11])) {
// // Handle error.
// }
//
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param inverted_crc - The two CRC16 bytes in the received data.
// This should just point into the received data,
// *not* at a 16-bit integer.
// @param crc - The crc starting value (optional)
// @return True, iff the CRC matches.
static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0);
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
// the integrity of data received from many 1-Wire devices. Note that the
// CRC computed here is *not* what you'll get from the 1-Wire network,
// for two reasons:
// 1) The CRC is transmitted bitwise inverted.
// 2) Depending on the endian-ness of your processor, the binary
// representation of the two-byte return value may have a different
// byte order than the two bytes you get from 1-Wire.
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param crc - The crc starting value (optional)
// @return The CRC16, as defined by Dallas Semiconductor.
static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0);
#endif
#endif
};
// Prevent this name from leaking into Arduino sketches
#ifdef IO_REG_TYPE
#undef IO_REG_TYPE
#endif
#endif // __cplusplus
#endif // OneWire_h
+64
View File
@@ -0,0 +1,64 @@
Please use this form only to report code defects or bugs.
For any question, even questions directly pertaining to this code, post your question on the forums related to the board you are using.
Arduino: forum.arduino.cc
Teensy: forum.pjrc.com
ESP8266: www.esp8266.com
ESP32: www.esp32.com
Adafruit Feather/Metro/Trinket: forums.adafruit.com
Particle Photon: community.particle.io
If you are experiencing trouble but not certain of the cause, or need help using this code, ask on the appropriate forum. This is not the place to ask for support or help, even directly related to this code. Only use this form you are certain you have discovered a defect in this code!
Please verify the problem occurs when using the very latest version, using the newest version of Arduino and any other related software.
----------------------------- Remove above -----------------------------
### Description
Describe your problem.
### Steps To Reproduce Problem
Please give detailed instructions needed for anyone to attempt to reproduce the problem.
### Hardware & Software
Board
Shields / modules used
Arduino IDE version
Teensyduino version (if using Teensy)
Version info & package name (from Tools > Boards > Board Manager)
Operating system & version
Any other software or hardware?
### Arduino Sketch
```cpp
// Change the code below by your sketch (please try to give the smallest code which demonstrates the problem)
#include <Arduino.h>
// libraries: give links/details so anyone can compile your code for the same result
void setup() {
}
void loop() {
}
```
### Errors or Incorrect Output
If you see any errors or incorrect output, please show it here. Please use copy & paste to give an exact copy of the message. Details matter, so please show (not merely describe) the actual message or error exactly as it appears.
@@ -0,0 +1,112 @@
#include <OneWire.h>
// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// https://github.com/milesburton/Arduino-Temperature-Control-Library
OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary)
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
byte i;
byte present = 0;
byte type_s;
byte data[9];
byte addr[8];
float celsius, fahrenheit;
if ( !ds.search(addr)) {
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delay(250);
return;
}
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr[i], HEX);
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return;
}
Serial.println();
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
Serial.print(" Data = ");
Serial.print(present, HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.print(" Celsius, ");
Serial.print(fahrenheit);
Serial.println(" Fahrenheit");
}
@@ -0,0 +1,74 @@
#include <OneWire.h>
/*
* DS2408 8-Channel Addressable Switch
*
* Writte by Glenn Trewitt, glenn at trewitt dot org
*
* Some notes about the DS2408:
* - Unlike most input/output ports, the DS2408 doesn't have mode bits to
* set whether the pins are input or output. If you issue a read command,
* they're inputs. If you write to them, they're outputs.
* - For reading from a switch, you should use 10K pull-up resisters.
*/
OneWire net(10); // on pin 10
void PrintBytes(const uint8_t* addr, uint8_t count, bool newline=false) {
for (uint8_t i = 0; i < count; i++) {
Serial.print(addr[i]>>4, HEX);
Serial.print(addr[i]&0x0f, HEX);
}
if (newline)
Serial.println();
}
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
byte addr[8];
if (!net.search(addr)) {
Serial.print("No more addresses.\n");
net.reset_search();
delay(1000);
return;
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.print("CRC is not valid!\n");
return;
}
if (addr[0] != 0x29) {
PrintBytes(addr, 8);
Serial.print(" is not a DS2408.\n");
return;
}
Serial.print(" Reading DS2408 ");
PrintBytes(addr, 8);
Serial.println();
uint8_t buf[13]; // Put everything in the buffer so we can compute CRC easily.
buf[0] = 0xF0; // Read PIO Registers
buf[1] = 0x88; // LSB address
buf[2] = 0x00; // MSB address
net.write_bytes(buf, 3);
net.read_bytes(buf+3, 10); // 3 cmd bytes, 6 data bytes, 2 0xFF, 2 CRC16
net.reset();
if (!OneWire::check_crc16(buf, 11, &buf[11])) {
Serial.print("CRC failure in DS2408 at ");
PrintBytes(addr, 8, true);
return;
}
Serial.print(" DS2408 data = ");
// First 3 bytes contain command, register address.
Serial.println(buf[3], BIN);
}
@@ -0,0 +1,75 @@
/*
DS250x add-only programmable memory reader w/SKIP ROM.
The DS250x is a 512/1024bit add-only PROM(you can add data but cannot change the old one) that's used mainly for device identification purposes
like serial number, mfgr data, unique identifiers, etc. It uses the Maxim 1-wire bus.
This sketch will use the SKIP ROM function that skips the 1-Wire search phase since we only have one device connected in the bus on digital pin 6.
If more than one device is connected to the bus, it will fail.
Sketch will not verify if device connected is from the DS250x family since the skip rom function effectively skips the family-id byte readout.
thus it is possible to run this sketch with any Maxim OneWire device in which case the command CRC will most likely fail.
Sketch will only read the first page of memory(32bits) starting from the lower address(0000h), if more than 1 device is present, then use the sketch with search functions.
Remember to put a 4.7K pullup resistor between pin 6 and +Vcc
To change the range or ammount of data to read, simply change the data array size, LSB/MSB addresses and for loop iterations
This example code is in the public domain and is provided AS-IS.
Built with Arduino 0022 and PJRC OneWire 2.0 library http://www.pjrc.com/teensy/td_libs_OneWire.html
created by Guillermo Lovato <glovato@gmail.com>
march/2011
*/
#include <OneWire.h>
OneWire ds(6); // OneWire bus on digital pin 6
void setup() {
Serial.begin (9600);
}
void loop() {
byte i; // This is for the for loops
boolean present; // device present var
byte data[32]; // container for the data from device
byte leemem[3] = { // array with the commands to initiate a read, DS250x devices expect 3 bytes to start a read: command,LSB&MSB adresses
0xF0 , 0x00 , 0x00 }; // 0xF0 is the Read Data command, followed by 00h 00h as starting address(the beginning, 0000h)
byte ccrc; // Variable to store the command CRC
byte ccrc_calc;
present = ds.reset(); // OneWire bus reset, always needed to start operation on the bus, returns a 1/TRUE if there's a device present.
ds.skip(); // Skip ROM search
if (present == true) { // We only try to read the data if there's a device present
Serial.println("DS250x device present");
ds.write(leemem[0],1); // Read data command, leave ghost power on
ds.write(leemem[1],1); // LSB starting address, leave ghost power on
ds.write(leemem[2],1); // MSB starting address, leave ghost power on
ccrc = ds.read(); // DS250x generates a CRC for the command we sent, we assign a read slot and store it's value
ccrc_calc = OneWire::crc8(leemem, 3); // We calculate the CRC of the commands we sent using the library function and store it
if ( ccrc_calc != ccrc) { // Then we compare it to the value the ds250x calculated, if it fails, we print debug messages and abort
Serial.println("Invalid command CRC!");
Serial.print("Calculated CRC:");
Serial.println(ccrc_calc,HEX); // HEX makes it easier to observe and compare
Serial.print("DS250x readback CRC:");
Serial.println(ccrc,HEX);
return; // Since CRC failed, we abort the rest of the loop and start over
}
Serial.println("Data is: "); // For the printout of the data
for ( i = 0; i < 32; i++) { // Now it's time to read the PROM data itself, each page is 32 bytes so we need 32 read commands
data[i] = ds.read(); // we store each read byte to a different position in the data array
Serial.print(data[i]); // printout in ASCII
Serial.print(" "); // blank space
}
Serial.println();
delay(5000); // Delay so we don't saturate the serial output
}
else { // Nothing is connected in the bus
Serial.println("Nothing connected");
delay(3000);
}
}
+38
View File
@@ -0,0 +1,38 @@
#######################################
# Syntax Coloring Map For OneWire
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
OneWire KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
reset KEYWORD2
write_bit KEYWORD2
read_bit KEYWORD2
write KEYWORD2
write_bytes KEYWORD2
read KEYWORD2
read_bytes KEYWORD2
select KEYWORD2
skip KEYWORD2
depower KEYWORD2
reset_search KEYWORD2
search KEYWORD2
crc8 KEYWORD2
crc16 KEYWORD2
check_crc16 KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
#######################################
# Constants (LITERAL1)
#######################################
+61
View File
@@ -0,0 +1,61 @@
{
"name": "OneWire",
"description": "Control 1-Wire protocol (DS18S20, DS18B20, DS2408 and etc)",
"keywords": "onewire, 1-wire, bus, sensor, temperature, ibutton",
"authors": [
{
"name": "Paul Stoffregen",
"email": "paul@pjrc.com",
"url": "http://www.pjrc.com",
"maintainer": true
},
{
"name": "Jim Studt"
},
{
"name": "Tom Pollard",
"email": "pollard@alum.mit.edu"
},
{
"name": "Derek Yerger"
},
{
"name": "Josh Larios"
},
{
"name": "Robin James"
},
{
"name": "Glenn Trewitt"
},
{
"name": "Jason Dangel",
"email": "dangel.jason AT gmail.com"
},
{
"name": "Guillermo Lovato"
},
{
"name": "Ken Butcher"
},
{
"name": "Mark Tillotson"
},
{
"name": "Bertrik Sikken"
},
{
"name": "Scott Roberts"
}
],
"repository": {
"type": "git",
"url": "https://github.com/PaulStoffregen/OneWire"
},
"version": "2.3.8",
"homepage": "https://www.pjrc.com/teensy/td_libs_OneWire.html",
"frameworks": "Arduino",
"examples": [
"examples/*/*.pde"
]
}
+10
View File
@@ -0,0 +1,10 @@
name=OneWire
version=2.3.8
author=Jim Studt, Tom Pollard, Robin James, Glenn Trewitt, Jason Dangel, Guillermo Lovato, Paul Stoffregen, Scott Roberts, Bertrik Sikken, Mark Tillotson, Ken Butcher, Roger Clark, Love Nystrom
maintainer=Paul Stoffregen
sentence=Access 1-wire temperature sensors, memory and other chips.
paragraph=
category=Communication
url=http://www.pjrc.com/teensy/td_libs_OneWire.html
architectures=*
@@ -0,0 +1,519 @@
#ifndef OneWire_Direct_GPIO_h
#define OneWire_Direct_GPIO_h
// This header should ONLY be included by OneWire.cpp. These defines are
// meant to be private, used within OneWire.cpp, but not exposed to Arduino
// sketches or other libraries which may include OneWire.h.
#include <stdint.h>
// Platform specific I/O definitions
#if defined(__AVR__)
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint8_t
#define IO_REG_BASE_ATTR asm("r30")
#define IO_REG_MASK_ATTR
#if defined(__AVR_ATmega4809__)
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) ((*((base)-8)) &= ~(mask))
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)-8)) |= (mask))
#define DIRECT_WRITE_LOW(base, mask) ((*((base)-4)) &= ~(mask))
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)-4)) |= (mask))
#else
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask))
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask))
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask))
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask))
#endif
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__)
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
#define PIN_TO_BITMASK(pin) (1)
#define IO_REG_TYPE uint8_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR __attribute__ ((unused))
#define DIRECT_READ(base, mask) (*((base)+512))
#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0)
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1)
#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1)
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1)
#elif defined(__MKL26Z64__)
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint8_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, mask) ((*((base)+16) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) (*((base)+20) &= ~(mask))
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+20) |= (mask))
#define DIRECT_WRITE_LOW(base, mask) (*((base)+8) = (mask))
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+4) = (mask))
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, mask) ((*((base)+2) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) (*((base)+1) &= ~(mask))
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+1) |= (mask))
#define DIRECT_WRITE_LOW(base, mask) (*((base)+34) = (mask))
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+33) = (mask))
#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__)
// Arduino 1.5.1 may have a bug in delayMicroseconds() on Arduino Due.
// http://arduino.cc/forum/index.php/topic,141030.msg1076268.html#msg1076268
// If you have trouble with OneWire on Arduino Due, please check the
// status of delayMicroseconds() before reporting a bug in OneWire!
#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask))
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask))
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask))
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask))
#ifndef PROGMEM
#define PROGMEM
#endif
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
#endif
#elif defined(__PIC32MX__)
#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10
#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04
#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24
#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28
#elif defined(ARDUINO_ARCH_ESP8266)
// Special note: I depend on the ESP community to maintain these definitions and
// submit good pull requests. I can not answer any ESP questions or help you
// resolve any problems related to ESP chips. Please do not contact me and please
// DO NOT CREATE GITHUB ISSUES for ESP support. All ESP questions must be asked
// on ESP community forums.
#define PIN_TO_BASEREG(pin) ((volatile uint32_t*) GPO)
#define PIN_TO_BITMASK(pin) (1UL << (pin))
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
static inline __attribute__((always_inline))
void directModeInput(IO_REG_TYPE mask)
{
if(mask > 0x8000)
{
GP16FFS(GPFFS_GPIO(16));
GPC16 = 0;
GP16E &= ~1;
}
else
{
GPE &= ~(mask);
}
}
static inline __attribute__((always_inline))
void directModeOutput(IO_REG_TYPE mask)
{
if(mask > 0x8000)
{
GP16FFS(GPFFS_GPIO(16));
GPC16 = 0;
GP16E |= 1;
}
else
{
GPE |= (mask);
}
}
static inline __attribute__((always_inline))
bool directRead(IO_REG_TYPE mask)
{
if(mask > 0x8000)
return GP16I & 0x01;
else
return ((GPI & (mask)) ? true : false);
}
#define DIRECT_READ(base, mask) directRead(mask)
#define DIRECT_MODE_INPUT(base, mask) directModeInput(mask)
#define DIRECT_MODE_OUTPUT(base, mask) directModeOutput(mask)
#define DIRECT_WRITE_LOW(base, mask) (mask > 0x8000) ? GP16O &= ~1 : (GPOC = (mask))
#define DIRECT_WRITE_HIGH(base, mask) (mask > 0x8000) ? GP16O |= 1 : (GPOS = (mask))
#elif defined(ARDUINO_ARCH_ESP32)
#include <driver/rtc_io.h>
#include <soc/gpio_struct.h>
#define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) (pin)
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
static inline __attribute__((always_inline))
IO_REG_TYPE directRead(IO_REG_TYPE pin)
{
#if CONFIG_IDF_TARGET_ESP32C3
return (GPIO.in.val >> pin) & 0x1;
#else // plain ESP32
if ( pin < 32 )
return (GPIO.in >> pin) & 0x1;
else if ( pin < 46 )
return (GPIO.in1.val >> (pin - 32)) & 0x1;
#endif
return 0;
}
static inline __attribute__((always_inline))
void directWriteLow(IO_REG_TYPE pin)
{
#if CONFIG_IDF_TARGET_ESP32C3
GPIO.out_w1tc.val = ((uint32_t)1 << pin);
#else // plain ESP32
if ( pin < 32 )
GPIO.out_w1tc = ((uint32_t)1 << pin);
else if ( pin < 46 )
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
#endif
}
static inline __attribute__((always_inline))
void directWriteHigh(IO_REG_TYPE pin)
{
#if CONFIG_IDF_TARGET_ESP32C3
GPIO.out_w1ts.val = ((uint32_t)1 << pin);
#else // plain ESP32
if ( pin < 32 )
GPIO.out_w1ts = ((uint32_t)1 << pin);
else if ( pin < 46 )
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
#endif
}
static inline __attribute__((always_inline))
void directModeInput(IO_REG_TYPE pin)
{
#if CONFIG_IDF_TARGET_ESP32C3
GPIO.enable_w1tc.val = ((uint32_t)1 << (pin));
#else
if ( digitalPinIsValid(pin) )
{
#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
if ( rtc_reg ) // RTC pins PULL settings
{
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
}
#endif
// Input
if ( pin < 32 )
GPIO.enable_w1tc = ((uint32_t)1 << pin);
else
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
}
#endif
}
static inline __attribute__((always_inline))
void directModeOutput(IO_REG_TYPE pin)
{
#if CONFIG_IDF_TARGET_ESP32C3
GPIO.enable_w1ts.val = ((uint32_t)1 << (pin));
#else
if ( digitalPinIsValid(pin) && pin <= 33 ) // pins above 33 can be only inputs
{
#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
if ( rtc_reg ) // RTC pins PULL settings
{
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
}
#endif
// Output
if ( pin < 32 )
GPIO.enable_w1ts = ((uint32_t)1 << pin);
else // already validated to pins <= 33
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
}
#endif
}
#define DIRECT_READ(base, pin) directRead(pin)
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(pin)
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(pin)
#define DIRECT_MODE_INPUT(base, pin) directModeInput(pin)
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(pin)
// https://github.com/PaulStoffregen/OneWire/pull/47
// https://github.com/stickbreaker/OneWire/commit/6eb7fc1c11a15b6ac8c60e5671cf36eb6829f82c
#ifdef interrupts
#undef interrupts
#endif
#ifdef noInterrupts
#undef noInterrupts
#endif
#define noInterrupts() {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;portENTER_CRITICAL(&mux)
#define interrupts() portEXIT_CRITICAL(&mux);}
//#warning "ESP32 OneWire testing"
#elif defined(ARDUINO_ARCH_STM32)
#define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) ((uint32_t)digitalPinToPinName(pin))
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, pin) digitalReadFast((PinName)pin)
#define DIRECT_WRITE_LOW(base, pin) digitalWriteFast((PinName)pin, LOW)
#define DIRECT_WRITE_HIGH(base, pin) digitalWriteFast((PinName)pin, HIGH)
#define DIRECT_MODE_INPUT(base, pin) pin_function((PinName)pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0))
#define DIRECT_MODE_OUTPUT(base, pin) pin_function((PinName)pin, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0))
#elif defined(__SAMD21G18A__)
#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, mask) (((*((base)+8)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) = (mask))
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+2)) = (mask))
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+5)) = (mask))
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+6)) = (mask))
#elif defined(__ASR6501__)
#define PIN_IN_PORT(pin) (pin % PIN_NUMBER_IN_PORT)
#define PORT_FROM_PIN(pin) (pin / PIN_NUMBER_IN_PORT)
#define PORT_OFFSET(port) (PORT_REG_SHFIT * port)
#define PORT_ADDRESS(pin) (CYDEV_GPIO_BASE + PORT_OFFSET(PORT_FROM_PIN(pin)))
#define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) (pin)
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, pin) CY_SYS_PINS_READ_PIN(PORT_ADDRESS(pin)+4, PIN_IN_PORT(pin))
#define DIRECT_WRITE_LOW(base, pin) CY_SYS_PINS_CLEAR_PIN(PORT_ADDRESS(pin), PIN_IN_PORT(pin))
#define DIRECT_WRITE_HIGH(base, pin) CY_SYS_PINS_SET_PIN(PORT_ADDRESS(pin), PIN_IN_PORT(pin))
#define DIRECT_MODE_INPUT(base, pin) CY_SYS_PINS_SET_DRIVE_MODE(PORT_ADDRESS(pin)+8, PIN_IN_PORT(pin), CY_SYS_PINS_DM_DIG_HIZ)
#define DIRECT_MODE_OUTPUT(base, pin) CY_SYS_PINS_SET_DRIVE_MODE(PORT_ADDRESS(pin)+8, PIN_IN_PORT(pin), CY_SYS_PINS_DM_STRONG)
#elif defined(RBL_NRF51822)
#define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) (pin)
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, pin) nrf_gpio_pin_read(pin)
#define DIRECT_WRITE_LOW(base, pin) nrf_gpio_pin_clear(pin)
#define DIRECT_WRITE_HIGH(base, pin) nrf_gpio_pin_set(pin)
#define DIRECT_MODE_INPUT(base, pin) nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL)
#define DIRECT_MODE_OUTPUT(base, pin) nrf_gpio_cfg_output(pin)
#elif defined(__arc__) /* Arduino101/Genuino101 specifics */
#include "scss_registers.h"
#include "portable.h"
#include "avr/pgmspace.h"
#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId)
#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType)
#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase)
#define DIR_OFFSET_SS 0x01
#define DIR_OFFSET_SOC 0x04
#define EXT_PORT_OFFSET_SS 0x0A
#define EXT_PORT_OFFSET_SOC 0x50
/* GPIO registers base address */
#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase)
#define PIN_TO_BITMASK(pin) pin
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
static inline __attribute__((always_inline))
IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
{
IO_REG_TYPE ret;
if (SS_GPIO == GPIO_TYPE(pin)) {
ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS));
} else {
ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC);
}
return ((ret >> GPIO_ID(pin)) & 0x01);
}
static inline __attribute__((always_inline))
void directModeInput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
{
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)),
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
} else {
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin));
}
}
static inline __attribute__((always_inline))
void directModeOutput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
{
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)),
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
} else {
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin));
}
}
static inline __attribute__((always_inline))
void directWriteLow(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
{
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base);
} else {
MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin));
}
}
static inline __attribute__((always_inline))
void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
{
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base);
} else {
MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin));
}
}
#define DIRECT_READ(base, pin) directRead(base, pin)
#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin)
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin)
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin)
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin)
#elif defined(__riscv)
/*
* Tested on highfive1
*
* Stable results are achieved operating in the
* two high speed modes of the highfive1. It
* seems to be less reliable in slow mode.
*/
#define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) digitalPinToBitMask(pin)
#define IO_REG_TYPE uint32_t
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
static inline __attribute__((always_inline))
IO_REG_TYPE directRead(IO_REG_TYPE mask)
{
return ((GPIO_REG(GPIO_INPUT_VAL) & mask) != 0) ? 1 : 0;
}
static inline __attribute__((always_inline))
void directModeInput(IO_REG_TYPE mask)
{
GPIO_REG(GPIO_OUTPUT_XOR) &= ~mask;
GPIO_REG(GPIO_IOF_EN) &= ~mask;
GPIO_REG(GPIO_INPUT_EN) |= mask;
GPIO_REG(GPIO_OUTPUT_EN) &= ~mask;
}
static inline __attribute__((always_inline))
void directModeOutput(IO_REG_TYPE mask)
{
GPIO_REG(GPIO_OUTPUT_XOR) &= ~mask;
GPIO_REG(GPIO_IOF_EN) &= ~mask;
GPIO_REG(GPIO_INPUT_EN) &= ~mask;
GPIO_REG(GPIO_OUTPUT_EN) |= mask;
}
static inline __attribute__((always_inline))
void directWriteLow(IO_REG_TYPE mask)
{
GPIO_REG(GPIO_OUTPUT_VAL) &= ~mask;
}
static inline __attribute__((always_inline))
void directWriteHigh(IO_REG_TYPE mask)
{
GPIO_REG(GPIO_OUTPUT_VAL) |= mask;
}
#define DIRECT_READ(base, mask) directRead(mask)
#define DIRECT_WRITE_LOW(base, mask) directWriteLow(mask)
#define DIRECT_WRITE_HIGH(base, mask) directWriteHigh(mask)
#define DIRECT_MODE_INPUT(base, mask) directModeInput(mask)
#define DIRECT_MODE_OUTPUT(base, mask) directModeOutput(mask)
#elif defined(__MBED__)
#include "platform/mbed_critical.h"
#include "DigitalInOut.h"
#include <cmsis_os2.h>
#define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) (new mbed::DigitalInOut(digitalPinToPinName(pin)))
#define IO_REG_TYPE mbed::DigitalInOut*
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, pin) (*pin)
#define DIRECT_WRITE_LOW(base, pin) (*pin = 0)
#define DIRECT_WRITE_HIGH(base, pin) (*pin = 1)
#define DIRECT_MODE_INPUT(base, pin) (pin->input())
#define DIRECT_MODE_OUTPUT(base, pin) (pin->output())
#undef interrupts
#undef noInterrupts
#define noInterrupts() osThreadSetPriority(osThreadGetId(), osPriorityRealtime) //core_util_critical_section_enter()
#define interrupts() osThreadSetPriority(osThreadGetId(), osPriorityNormal) //core_util_critical_section_exit()
#elif defined(ARDUINO_ARCH_MBED_RP2040)|| defined(ARDUINO_ARCH_RP2040)
#define delayMicroseconds(time) busy_wait_us(time)
#define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) (pin)
#define IO_REG_TYPE unsigned int
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, pin) digitalRead(pin)
#define DIRECT_WRITE_LOW(base, pin) digitalWrite(pin, LOW)
#define DIRECT_WRITE_HIGH(base, pin) digitalWrite(pin, HIGH)
#define DIRECT_MODE_INPUT(base, pin) pinMode(pin,INPUT)
#define DIRECT_MODE_OUTPUT(base, pin) pinMode(pin,OUTPUT)
#warning "OneWire. RP2040 in Fallback mode. Using API calls for pinMode,digitalRead and digitalWrite."
#else
#define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) (pin)
#define IO_REG_TYPE unsigned int
#define IO_REG_BASE_ATTR
#define IO_REG_MASK_ATTR
#define DIRECT_READ(base, pin) digitalRead(pin)
#define DIRECT_WRITE_LOW(base, pin) digitalWrite(pin, LOW)
#define DIRECT_WRITE_HIGH(base, pin) digitalWrite(pin, HIGH)
#define DIRECT_MODE_INPUT(base, pin) pinMode(pin,INPUT)
#define DIRECT_MODE_OUTPUT(base, pin) pinMode(pin,OUTPUT)
#warning "OneWire. Fallback mode. Using API calls for pinMode,digitalRead and digitalWrite. Operation of this library is not guaranteed on this architecture."
#endif
#endif
@@ -0,0 +1,59 @@
#ifndef OneWire_Direct_RegType_h
#define OneWire_Direct_RegType_h
#include <stdint.h>
// Platform specific I/O register type
#if defined(__AVR__)
#define IO_REG_TYPE uint8_t
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__)
#define IO_REG_TYPE uint8_t
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
#define IO_REG_TYPE uint32_t
#elif defined(__MKL26Z64__)
#define IO_REG_TYPE uint8_t
#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__)
#define IO_REG_TYPE uint32_t
#elif defined(__PIC32MX__)
#define IO_REG_TYPE uint32_t
#elif defined(ARDUINO_ARCH_ESP8266)
#define IO_REG_TYPE uint32_t
#elif defined(ARDUINO_ARCH_ESP32)
#define IO_REG_TYPE uint32_t
#define IO_REG_MASK_ATTR
#elif defined(ARDUINO_ARCH_STM32)
#define IO_REG_TYPE uint32_t
#elif defined(__SAMD21G18A__)
#define IO_REG_TYPE uint32_t
#elif defined(__ASR6501__)
#define IO_REG_TYPE uint32_t
#elif defined(RBL_NRF51822)
#define IO_REG_TYPE uint32_t
#elif defined(__arc__) /* Arduino101/Genuino101 specifics */
#define IO_REG_TYPE uint32_t
#elif defined(__MBED__)
#include "DigitalInOut.h"
#define IO_REG_TYPE mbed::DigitalInOut*
#elif defined(__riscv)
#define IO_REG_TYPE uint32_t
#else
#define IO_REG_TYPE unsigned int
#endif
#endif
+77
View File
@@ -0,0 +1,77 @@
# RTClib [![Build Status](https://github.com/adafruit/RTClib/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/RTClib/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/RTClib/html/index.html)
This is a fork of JeeLab's fantastic real time clock library for Arduino.
Works great with Adafruit RTC breakouts:
- [DS3231 Precision RTC](https://www.adafruit.com/product/3013) (breakout) and [Stemma QT version](https://www.adafruit.com/product/5188)
- [PCF8523 RTC](https://www.adafruit.com/product/3295)
- [DS1307 RTC](https://www.adafruit.com/product/3296)
Please note that dayOfTheWeek() ranges from 0 to 6 inclusive with 0 being 'Sunday'.
<!-- START COMPATIBILITY TABLE -->
## Compatibility
MCU | Tested Works | Doesn't Work | Not Tested | Notes
------------------ | :----------: | :----------: | :---------: | -----
Atmega328 @ 16MHz | X | | |
Atmega328 @ 12MHz | X | | |
Atmega32u4 @ 16MHz | X | | | Use SDA/SCL on pins D3 &amp; D2
Atmega32u4 @ 8MHz | X | | | Use SDA/SCL on pins D3 &amp; D2
ESP8266 | X | | | SDA/SCL default to pins 4 &amp; 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL)
Atmega2560 @ 16MHz | X | | | Use SDA/SCL on Pins 20 &amp; 21
ATSAM3X8E | X | | | Use SDA1 and SCL1
ATSAM21D | X | | |
ATtiny85 @ 16MHz | X | | |
ATtiny85 @ 8MHz | X | | |
Intel Curie @ 32MHz | | | X |
STM32F2 | | | X |
* ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini
* ATmega328 @ 12MHz : Adafruit Pro Trinket 3V
* ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0
* ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro
* ESP8266 : Adafruit Huzzah
* ATmega2560 @ 16MHz : Arduino Mega
* ATSAM3X8E : Arduino Due
* ATSAM21D : Arduino Zero, M0 Pro
* ATtiny85 @ 16MHz : Adafruit Trinket 5V
* ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V
<!-- END COMPATIBILITY TABLE -->
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
# Dependencies
* [Adafruit BusIO](https://github.com/adafruit/Adafruit_BusIO)
# Contributing
Contributions are welcome! Please read our [Code of Conduct](https://github.com/adafruit/RTClib/blob/master/code-of-conduct.md)
before contributing to help this project stay welcoming.
## Documentation and doxygen
For the detailed API documentation, see https://adafruit.github.io/RTClib/html/index.html
Documentation is produced by doxygen. Contributions should include documentation for any new code added.
Some examples of how to use doxygen can be found in these guide pages:
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips
## Code formatting and clang-format
The code should be formatted according to the [LLVM Coding Standards](https://llvm.org/docs/CodingStandards.html), which is the default of the clang-format tool. The easiest way to ensure conformance is to [install clang-format](https://llvm.org/builds/) and run
```shell
clang-format -i <source_file>
```
See [Formatting with clang-format](https://learn.adafruit.com/the-well-automated-arduino-library/formatting-with-clang-format) for details.
Written by JeeLabs
MIT license, check license.txt for more information
All text above must be included in any redistribution
To install, use the Arduino Library Manager and search for "RTClib" and install the library.
+127
View File
@@ -0,0 +1,127 @@
# Adafruit Community Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and leaders pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level or type of
experience, education, socio-economic status, nationality, personal appearance,
race, religion, or sexual identity and orientation.
## Our Standards
We are committed to providing a friendly, safe and welcoming environment for
all.
Examples of behavior that contributes to creating a positive environment
include:
* Be kind and courteous to others
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Collaborating with other community members
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and sexual attention or advances
* The use of inappropriate images, including in a community member's avatar
* The use of inappropriate language, including in a community member's nickname
* Any spamming, flaming, baiting or other attention-stealing behavior
* Excessive or unwelcome helping; answering outside the scope of the question
asked
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate
The goal of the standards and moderation guidelines outlined here is to build
and maintain a respectful community. We ask that you don’t just aim to be
"technically unimpeachable", but rather try to be your best self.
We value many things beyond technical expertise, including collaboration and
supporting others within our community. Providing a positive experience for
other community members can have a much more significant impact than simply
providing the correct answer.
## Our Responsibilities
Project leaders are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project leaders have the right and responsibility to remove, edit, or
reject messages, comments, commits, code, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any community member for other behaviors that they deem
inappropriate, threatening, offensive, or harmful.
## Moderation
Instances of behaviors that violate the Adafruit Community Code of Conduct
may be reported by any member of the community. Community members are
encouraged to report these situations, including situations they witness
involving other community members.
You may report in the following ways:
In any situation, you may send an email to <support@adafruit.com>.
On the Adafruit Discord, you may send an open message from any channel
to all Community Helpers by tagging @community helpers. You may also send an
open message from any channel, or a direct message to @kattni#1507,
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
@Andon#8175.
Email and direct message reports will be kept confidential.
In situations on Discord where the issue is particularly egregious, possibly
illegal, requires immediate action, or violates the Discord terms of service,
you should also report the message directly to Discord.
These are the steps for upholding our community’s standards of conduct.
1. Any member of the community may report any situation that violates the
Adafruit Community Code of Conduct. All reports will be reviewed and
investigated.
2. If the behavior is an egregious violation, the community member who
committed the violation may be banned immediately, without warning.
3. Otherwise, moderators will first respond to such behavior with a warning.
4. Moderators follow a soft "three strikes" policy - the community member may
be given another chance, if they are receptive to the warning and change their
behavior.
5. If the community member is unreceptive or unreasonable when warned by a
moderator, or the warning goes unheeded, they may be banned for a first or
second offense. Repeated offenses will result in the community member being
banned.
## Scope
This Code of Conduct and the enforcement policies listed above apply to all
Adafruit Community venues. This includes but is not limited to any community
spaces (both public and private), the entire Adafruit Discord server, and
Adafruit GitHub repositories. Examples of Adafruit Community spaces include
but are not limited to meet-ups, audio chats on the Adafruit Discord, or
interaction at a conference.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. As a community
member, you are representing our community, and are expected to behave
accordingly.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at
<https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>,
and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
For other projects adopting the Adafruit Community Code of
Conduct, please contact the maintainers of those projects for enforcement.
If you wish to use this code of conduct for your own project, consider
explicitly mentioning your moderation policy or making a copy with your
own moderation policy so as to avoid confusion.
@@ -0,0 +1,122 @@
/* Example implementation of an alarm using DS3231
*
* VCC and GND of RTC should be connected to some power source
* SDA, SCL of RTC should be connected to SDA, SCL of arduino
* SQW should be connected to CLOCK_INTERRUPT_PIN
* CLOCK_INTERRUPT_PIN needs to work with interrupts
*/
#include <RTClib.h>
// #include <Wire.h>
RTC_DS3231 rtc;
// the pin that is connected to SQW
#define CLOCK_INTERRUPT_PIN 2
void setup() {
Serial.begin(9600);
// initializing the rtc
if(!rtc.begin()) {
Serial.println("Couldn't find RTC!");
Serial.flush();
while (1) delay(10);
}
if(rtc.lostPower()) {
// this will adjust to the date and time at compilation
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
//we don't need the 32K Pin, so disable it
rtc.disable32K();
// Making it so, that the alarm will trigger an interrupt
pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING);
// set alarm 1, 2 flag to false (so alarm 1, 2 didn't happen so far)
// if not done, this easily leads to problems, as both register aren't reset on reboot/recompile
rtc.clearAlarm(1);
rtc.clearAlarm(2);
// stop oscillating signals at SQW Pin
// otherwise setAlarm1 will fail
rtc.writeSqwPinMode(DS3231_OFF);
// turn off alarm 2 (in case it isn't off already)
// again, this isn't done at reboot, so a previously set alarm could easily go overlooked
rtc.disableAlarm(2);
// schedule an alarm 10 seconds in the future
if(!rtc.setAlarm1(
rtc.now() + TimeSpan(10),
DS3231_A1_Second // this mode triggers the alarm when the seconds match. See Doxygen for other options
)) {
Serial.println("Error, alarm wasn't set!");
}else {
Serial.println("Alarm will happen in 10 seconds!");
}
}
void loop() {
// print current time
char date[10] = "hh:mm:ss";
rtc.now().toString(date);
Serial.print(date);
// the stored alarm value + mode
DateTime alarm1 = rtc.getAlarm1();
Ds3231Alarm1Mode alarm1mode = rtc.getAlarm1Mode();
char alarm1Date[12] = "DD hh:mm:ss";
alarm1.toString(alarm1Date);
Serial.print(" [Alarm1: ");
Serial.print(alarm1Date);
Serial.print(", Mode: ");
switch (alarm1mode) {
case DS3231_A1_PerSecond: Serial.print("PerSecond"); break;
case DS3231_A1_Second: Serial.print("Second"); break;
case DS3231_A1_Minute: Serial.print("Minute"); break;
case DS3231_A1_Hour: Serial.print("Hour"); break;
case DS3231_A1_Date: Serial.print("Date"); break;
case DS3231_A1_Day: Serial.print("Day"); break;
}
// the value at SQW-Pin (because of pullup 1 means no alarm)
Serial.print("] SQW: ");
Serial.print(digitalRead(CLOCK_INTERRUPT_PIN));
// whether a alarm fired
Serial.print(" Fired: ");
Serial.print(rtc.alarmFired(1));
// Serial.print(" Alarm2: ");
// Serial.println(rtc.alarmFired(2));
// control register values (see https://datasheets.maximintegrated.com/en/ds/DS3231.pdf page 13)
// Serial.print(" Control: 0b");
// Serial.println(read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), BIN);
// resetting SQW and alarm 1 flag
// using setAlarm1, the next alarm could now be configurated
if (rtc.alarmFired(1)) {
rtc.clearAlarm(1);
Serial.print(" - Alarm cleared");
}
Serial.println();
delay(2000);
}
void onAlarm() {
Serial.println("Alarm occured!");
}
/*static uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
Wire.beginTransmission(addr);
Wire.write((byte)reg);
Wire.endTransmission();
Wire.requestFrom(addr, (byte)1);
return Wire.read();
}*/
@@ -0,0 +1,120 @@
/* Using DS3231 (or other supported RTC) with a custom TwoWire instance
*
* If using a microcontroller which supports additional i2c ports,
* such as the SAMD21's SERCOMX, a user can define a custom i2c bus
* to use with an RTC.
* This example builds the custom i2c bus using SERCOM0 and leverages the "wiring_private.h" APIs
*
* Connecting the device:
* VCC and GND of RTC should be connected to some power source
* SDA, SCL of RTC should be connected to the custom SDA and SCL pins.
* In this particular example we are using a Nano 33 IoT and routing
* the custom Wire instance over pins 6 (SDA) and 5 (SCL)
*
* This example will work with Arduino Zero, any Arduino MKR board based on SAMD21, Nano 33 IoT
* and any board by Adafruit, Sparkfun, Seeed Studio based on the same microcontroller
*
*/
#include <Wire.h>
#include "wiring_private.h"
#include <RTClib.h>
/* Defining the custom TwoWire instance for SAMD21 */
TwoWire myWire(&sercom0, 6, 5); // Create the new wire instance assigning it to pin 0 and 1
extern "C"{
void SERCOM0_Handler(void);
void SERCOM0_Handler(void) {
myWire.onService();
}
}
/* Creating a new DS3231 object */
RTC_DS3231 myRTC;
String daysNames[] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
String monthsNames[] = {
"-",
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
void setup() {
Serial.begin(57600);
Serial.println("start");
unsigned long setupStartTime = millis();
/*** Waiting for Serial to be ready or timeout ***/
while(!Serial && millis() - setupStartTime < 3000);
/*
* Initialising pins 6 and 5 to be routed to the SERCOM0 pads 0 and 1 in order
* to be used as SDA and SCL. Without this step the periphearl won't be patched through
*/
pinPeripheral(6, PIO_SERCOM_ALT); // PAD[0] //Assign SDA function to pin 0
pinPeripheral(5, PIO_SERCOM_ALT); // PAD[1] //Assign SCL function to pin 1
/* We now pass our custom TwoWire object to the RTC instance */
myRTC.begin(&myWire);
/*
* From this moment on every operation on the RTC will work as expected
* But the i2c bus being used will be the one we manually created using SERCOM0
*/
/*
* Creating a Date object with
* YEAR, MONTH, DAY (2021, January, 1)
* HOUR, MINUTE, SECONDS (0, 0, 0)
* Midnight of January 1st, 2021
*/
DateTime newDT = DateTime(2021, 1, 1, 0, 0, 0);
/* Pushing that date/time to the RTC */
myRTC.adjust(newDT);
Serial.println("setup done");
}
void loop() {
/* creating a temporary date/time object to store the data coming from the RTC */
DateTime dt = myRTC.now();
/* printing that data to the Serial port in a meaningful format */
Serial.println("************");
Serial.print(daysNames[dt.dayOfTheWeek()]);
Serial.print(" ");
Serial.print(monthsNames[dt.month()]);
Serial.print(" ");
Serial.print(dt.day());
Serial.print(", ");
Serial.println(dt.year());
Serial.print(dt.hour());
Serial.print(":");
Serial.print(dt.minute());
Serial.print(":");
Serial.println(dt.second());
/* Delays are bad, but let's not flood the Serial for this silly example */
delay(500);
}
@@ -0,0 +1,105 @@
// Simple date conversions and calculations
#include "RTClib.h"
void showDate(const char* txt, const DateTime& dt) {
Serial.print(txt);
Serial.print(' ');
Serial.print(dt.year(), DEC);
Serial.print('/');
Serial.print(dt.month(), DEC);
Serial.print('/');
Serial.print(dt.day(), DEC);
Serial.print(' ');
Serial.print(dt.hour(), DEC);
Serial.print(':');
Serial.print(dt.minute(), DEC);
Serial.print(':');
Serial.print(dt.second(), DEC);
Serial.print(" = ");
Serial.print(dt.unixtime());
Serial.print("s / ");
Serial.print(dt.unixtime() / 86400L);
Serial.print("d since 1970");
Serial.println();
}
void showTimeSpan(const char* txt, const TimeSpan& ts) {
Serial.print(txt);
Serial.print(" ");
Serial.print(ts.days(), DEC);
Serial.print(" days ");
Serial.print(ts.hours(), DEC);
Serial.print(" hours ");
Serial.print(ts.minutes(), DEC);
Serial.print(" minutes ");
Serial.print(ts.seconds(), DEC);
Serial.print(" seconds (");
Serial.print(ts.totalseconds(), DEC);
Serial.print(" total seconds)");
Serial.println();
}
void setup () {
Serial.begin(57600);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
DateTime dt0 (0, 1, 1, 0, 0, 0);
showDate("dt0", dt0);
DateTime dt1 (1, 1, 1, 0, 0, 0);
showDate("dt1", dt1);
DateTime dt2 (2009, 1, 1, 0, 0, 0);
showDate("dt2", dt2);
DateTime dt3 (2009, 1, 2, 0, 0, 0);
showDate("dt3", dt3);
DateTime dt4 (2009, 1, 27, 0, 0, 0);
showDate("dt4", dt4);
DateTime dt5 (2009, 2, 27, 0, 0, 0);
showDate("dt5", dt5);
DateTime dt6 (2009, 12, 27, 0, 0, 0);
showDate("dt6", dt6);
DateTime dt7 (dt6.unixtime() + 3600); // One hour later.
showDate("dt7", dt7);
DateTime dt75 = dt6 + TimeSpan(0, 1, 0, 0); // One hour later with TimeSpan addition.
showDate("dt7.5", dt75);
DateTime dt8 (dt6.unixtime() + 86400L); // One day later.
showDate("dt8", dt8);
DateTime dt85 = dt6 + TimeSpan(1, 0, 0, 0); // One day later with TimeSpan addition.
showDate("dt8.5", dt85);
DateTime dt9 (dt6.unixtime() + 7 * 86400L); // One week later.
showDate("dt9", dt9);
DateTime dt95 = dt6 + TimeSpan(7, 0, 0, 0); // One week later with TimeSpan addition.
showDate("dt9.5", dt95);
DateTime dt10 = dt6 + TimeSpan(0, 0, 42, 42); // Fourty two minutes and fourty two seconds later.
showDate("dt10", dt10);
DateTime dt11 = dt6 - TimeSpan(7, 0, 0, 0); // One week ago.
showDate("dt11", dt11);
TimeSpan ts1 = dt6 - dt5;
showTimeSpan("dt6-dt5", ts1);
TimeSpan ts2 = dt10 - dt6;
showTimeSpan("dt10-dt6", ts2);
}
void loop () {
}
@@ -0,0 +1,82 @@
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
#include "RTClib.h"
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
void setup () {
Serial.begin(57600);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
if (! rtc.isrunning()) {
Serial.println("RTC is NOT running, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
void loop () {
DateTime now = rtc.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" (");
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
Serial.print(") ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
Serial.print(" since midnight 1/1/1970 = ");
Serial.print(now.unixtime());
Serial.print("s = ");
Serial.print(now.unixtime() / 86400L);
Serial.println("d");
// calculate a date which is 7 days, 12 hours, 30 minutes, and 6 seconds into the future
DateTime future (now + TimeSpan(7,12,30,6));
Serial.print(" now + 7d + 12h + 30m + 6s: ");
Serial.print(future.year(), DEC);
Serial.print('/');
Serial.print(future.month(), DEC);
Serial.print('/');
Serial.print(future.day(), DEC);
Serial.print(' ');
Serial.print(future.hour(), DEC);
Serial.print(':');
Serial.print(future.minute(), DEC);
Serial.print(':');
Serial.print(future.second(), DEC);
Serial.println();
Serial.println();
delay(3000);
}
@@ -0,0 +1,63 @@
// SQW/OUT pin mode using a DS1307 RTC connected via I2C.
//
// According to the data sheet (http://datasheets.maxim-ic.com/en/ds/DS1307.pdf), the
// DS1307's SQW/OUT pin can be set to low, high, 1Hz, 4.096kHz, 8.192kHz, or 32.768kHz.
//
// This sketch reads the state of the pin, then iterates through the possible values at
// 5 second intervals.
//
// NOTE:
// You must connect a pull up resistor (~10kohm) from the SQW pin up to VCC. Without
// this pull up the wave output will not work!
#include "RTClib.h"
RTC_DS1307 rtc;
int mode_index = 0;
Ds1307SqwPinMode modes[] = { DS1307_OFF, DS1307_ON, DS1307_SquareWave1HZ, DS1307_SquareWave4kHz, DS1307_SquareWave8kHz, DS1307_SquareWave32kHz};
void print_mode() {
Ds1307SqwPinMode mode = rtc.readSqwPinMode();
Serial.print("Sqw Pin Mode: ");
switch(mode) {
case DS1307_OFF: Serial.println("OFF"); break;
case DS1307_ON: Serial.println("ON"); break;
case DS1307_SquareWave1HZ: Serial.println("1Hz"); break;
case DS1307_SquareWave4kHz: Serial.println("4.096kHz"); break;
case DS1307_SquareWave8kHz: Serial.println("8.192kHz"); break;
case DS1307_SquareWave32kHz: Serial.println("32.768kHz"); break;
default: Serial.println("UNKNOWN"); break;
}
}
void setup () {
Serial.begin(57600);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
print_mode();
}
void loop () {
rtc.writeSqwPinMode(modes[mode_index++]);
print_mode();
if (mode_index > 5) {
mode_index = 0;
}
delay(5000);
}
@@ -0,0 +1,62 @@
// Example of using the non-volatile RAM storage on the DS1307.
// You can write up to 56 bytes from address 0 to 55.
// Data will be persisted as long as the DS1307 has battery power.
#include "RTClib.h"
RTC_DS1307 rtc;
void printnvram(uint8_t address) {
Serial.print("Address 0x");
Serial.print(address, HEX);
Serial.print(" = 0x");
Serial.println(rtc.readnvram(address), HEX);
}
void setup () {
Serial.begin(57600);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
// Print old RAM contents on startup.
Serial.println("Current NVRAM values:");
for (int i = 0; i < 6; ++i) {
printnvram(i);
}
// Write some bytes to non-volatile RAM storage.
// NOTE: You can only read and write from addresses 0 to 55 (i.e. 56 byte values).
Serial.println("Writing NVRAM values.");
// Example writing one byte at a time:
rtc.writenvram(0, 0xFE);
rtc.writenvram(1, 0xED);
// Example writing multiple bytes:
uint8_t writeData[4] = { 0xBE, 0xEF, 0x01, 0x02 };
rtc.writenvram(2, writeData, 4);
// Read bytes from non-volatile RAM storage.
Serial.println("Reading NVRAM values:");
// Example reading one byte at a time.
Serial.println(rtc.readnvram(0), HEX);
Serial.println(rtc.readnvram(1), HEX);
// Example reading multiple bytes:
uint8_t readData[4] = {0};
rtc.readnvram(readData, 4, 2);
Serial.println(readData[0], HEX);
Serial.println(readData[1], HEX);
Serial.println(readData[2], HEX);
Serial.println(readData[3], HEX);
}
void loop () {
// Do nothing in the loop.
}
@@ -0,0 +1,86 @@
// Date and time functions using a DS3231 RTC connected via I2C and Wire lib
#include "RTClib.h"
RTC_DS3231 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
void setup () {
Serial.begin(57600);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
if (rtc.lostPower()) {
Serial.println("RTC lost power, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
void loop () {
DateTime now = rtc.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" (");
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
Serial.print(") ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
Serial.print(" since midnight 1/1/1970 = ");
Serial.print(now.unixtime());
Serial.print("s = ");
Serial.print(now.unixtime() / 86400L);
Serial.println("d");
// calculate a date which is 7 days, 12 hours, 30 minutes, 6 seconds into the future
DateTime future (now + TimeSpan(7,12,30,6));
Serial.print(" now + 7d + 12h + 30m + 6s: ");
Serial.print(future.year(), DEC);
Serial.print('/');
Serial.print(future.month(), DEC);
Serial.print('/');
Serial.print(future.day(), DEC);
Serial.print(' ');
Serial.print(future.hour(), DEC);
Serial.print(':');
Serial.print(future.minute(), DEC);
Serial.print(':');
Serial.print(future.second(), DEC);
Serial.println();
Serial.print("Temperature: ");
Serial.print(rtc.getTemperature());
Serial.println(" C");
Serial.println();
delay(3000);
}
@@ -0,0 +1,100 @@
/***********************************************************************
Combining RTClib with the avr-libc timing functions
===================================================
The standard way of getting the current time and date with RTClib is to
call the now() method of the appropriate RTC class. This, however, is
somewhat slow, as it involves communicating with the RTC through the I2C
bus. An alternative, more lightweight method involves configuring the
RTC to deliver one pulse per second to an interrupt pin, and counting
the seconds in the interrupt handler. The timekeeping is then entirely
handled in the Arduino, with no I2C communication with the RTC other
than during the initialization phase.
On AVR-based Arduinos (Uno, Nano, Micro, ...), the Arduino core library
is built on top of avr-libc, which is an implementation of the standard
C library for the AVR platform. This library provides the standard C
functions for handling time:[1] time(), gmtime(), mktime(), etc. The
time() function is normally used to retrieve the current time from the
operating system, but since we have no operating system, the avr-libc
provides its own non-standard functions for implementing a time source:
- set_system_time() initializes the library's idea of the current time
- system_tick() steps the system time by one second.
This sketch demonstrates how to combine RTClib and avr-libc in order to
handle the timekeeping entirely on the Arduino from an interrupt
delivered by the RTC:
- RTClib is used to configure the RTC and retrieve the initial time
- avr-libc is used for regular timekeeping
This sketch only works on AVR-based Arduinos, as it relies on
non-standard functions provided by avr-libc.
[1] https://www.nongnu.org/avr-libc/user-manual/group__avr__time.html
***********************************************************************/
#include <RTClib.h>
#include <time.h> // standard C timing functions
// Pin receiving the one-pulse-per-second signal from the RTC.
// This should be an interrupt-capable pin.
const uint8_t pin1pps = 2;
// We will use the PCF8523 RTC, which has the handy "Second Timer".
// Other RTCs could be used with their "square wave" output configured
// to 1 Hz.
RTC_PCF8523 rtc;
void setup() {
// Initialize the serial port.
Serial.begin(57600);
while (!Serial); // wait for serial port to connect. Needed for native USB
// Initialize the RTC.
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
if (!rtc.initialized() || rtc.lostPower()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
rtc.deconfigureAllTimers(); // undo previous configuration, if any
// Initialize the system time from the RTC time. Both avr-libc and
// DateTime::secondstime() use the start of year 2000 as their
// reference "epoch".
set_system_time(rtc.now().secondstime());
// Keep the time in sync using the one-pulse-per-second output of the
// RTC as an interrupt source and calling system_tick() from the
// interrupt service routine.
pinMode(pin1pps, INPUT_PULLUP);
rtc.enableSecondTimer();
attachInterrupt(digitalPinToInterrupt(pin1pps), system_tick, FALLING);
}
void loop() {
// From here on, we only use the standard C timing functions.
// time() returns the current time as a single number of type time_t,
// this is the number of seconds elapsed since a reference "epoch".
time_t now = time(nullptr);
// gmtime() converts the time to a broken-down form (year, month...)
// similar to the DateTime class. Unlike localtime(), it doesn't
// attempt timezone conversions.
struct tm *broken_down_time = gmtime(&now);
// asctime() returns a textual representation of the date and time as
// a C string (pointer to a character array). The format is similar to
// the DateTime::toString() format "DDD MMM DD hh:mm:ss YYYY".
Serial.println(asctime(broken_down_time));
delay(1000);
}
@@ -0,0 +1,115 @@
// Date and time functions using a PCF8523 RTC connected via I2C and Wire lib
#include "RTClib.h"
RTC_PCF8523 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
void setup () {
Serial.begin(57600);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
if (! rtc.initialized() || rtc.lostPower()) {
Serial.println("RTC is NOT initialized, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
//
// Note: allow 2 seconds after inserting battery or applying external power
// without battery before calling adjust(). This gives the PCF8523's
// crystal oscillator time to stabilize. If you call adjust() very quickly
// after the RTC is powered, lostPower() may still return true.
}
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
// When the RTC was stopped and stays connected to the battery, it has
// to be restarted by clearing the STOP bit. Let's do this to ensure
// the RTC is running.
rtc.start();
// The PCF8523 can be calibrated for:
// - Aging adjustment
// - Temperature compensation
// - Accuracy tuning
// The offset mode to use, once every two hours or once every minute.
// The offset Offset value from -64 to +63. See the Application Note for calculation of offset values.
// https://www.nxp.com/docs/en/application-note/AN11247.pdf
// The deviation in parts per million can be calculated over a period of observation. Both the drift (which can be negative)
// and the observation period must be in seconds. For accuracy the variation should be observed over about 1 week.
// Note: any previous calibration should cancelled prior to any new observation period.
// Example - RTC gaining 43 seconds in 1 week
float drift = 43; // seconds plus or minus over oservation period - set to 0 to cancel previous calibration.
float period_sec = (7 * 86400); // total obsevation period in seconds (86400 = seconds in 1 day: 7 days = (7 * 86400) seconds )
float deviation_ppm = (drift / period_sec * 1000000); // deviation in parts per million (μs)
float drift_unit = 4.34; // use with offset mode PCF8523_TwoHours
// float drift_unit = 4.069; //For corrections every min the drift_unit is 4.069 ppm (use with offset mode PCF8523_OneMinute)
int offset = round(deviation_ppm / drift_unit);
// rtc.calibrate(PCF8523_TwoHours, offset); // Un-comment to perform calibration once drift (seconds) and observation period (seconds) are correct
// rtc.calibrate(PCF8523_TwoHours, 0); // Un-comment to cancel previous calibration
Serial.print("Offset is "); Serial.println(offset); // Print to control offset
}
void loop () {
DateTime now = rtc.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" (");
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
Serial.print(") ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
Serial.print(" since midnight 1/1/1970 = ");
Serial.print(now.unixtime());
Serial.print("s = ");
Serial.print(now.unixtime() / 86400L);
Serial.println("d");
// calculate a date which is 7 days, 12 hours and 30 seconds into the future
DateTime future (now + TimeSpan(7,12,30,6));
Serial.print(" now + 7d + 12h + 30m + 6s: ");
Serial.print(future.year(), DEC);
Serial.print('/');
Serial.print(future.month(), DEC);
Serial.print('/');
Serial.print(future.day(), DEC);
Serial.print(' ');
Serial.print(future.hour(), DEC);
Serial.print(':');
Serial.print(future.minute(), DEC);
Serial.print(':');
Serial.print(future.second(), DEC);
Serial.println();
Serial.println();
delay(3000);
}
@@ -0,0 +1,164 @@
/**************************************************************************/
/*
Countdown Timer using a PCF8523 RTC connected via I2C and Wire lib
with the INT/SQW pin wired to an interrupt-capable input.
According to the data sheet, the PCF8523 can run countdown timers
from 244 microseconds to 10.625 days:
https://www.nxp.com/docs/en/data-sheet/PCF8523.pdf#page=34
This sketch sets a countdown timer, and executes code when it reaches 0,
then blinks the built-in LED like BlinkWithoutDelay, but without millis()!
NOTE:
You must connect the PCF8523's interrupt pin to your Arduino or other
microcontroller on an input pin that can handle interrupts, and that has a
pullup resistor. The pin will be briefly pulled low each time the countdown
reaches 0. This example will not work without the interrupt pin connected!
On Adafruit breakout boards, the interrupt pin is labeled 'INT' or 'SQW'.
*/
/**************************************************************************/
#include "RTClib.h"
RTC_PCF8523 rtc;
// Input pin with interrupt capability
// const int timerInterruptPin = 2; // Most Arduinos
const int timerInterruptPin = 5; // Adafruit Feather M0/M4/nRF52840
// Variables modified during an interrupt must be declared volatile
volatile bool countdownInterruptTriggered = false;
volatile int numCountdownInterrupts = 0;
void setup () {
Serial.begin(57600);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
pinMode(LED_BUILTIN, OUTPUT);
// Set the pin attached to PCF8523 INT to be an input with pullup to HIGH.
// The PCF8523 interrupt pin will briefly pull it LOW at the end of a given
// countdown period, then it will be released to be pulled HIGH again.
pinMode(timerInterruptPin, INPUT_PULLUP);
Serial.println(F("\nStarting PCF8523 Countdown Timer example."));
Serial.print(F("Configured to expect PCF8523 INT/SQW pin connected to input pin: "));
Serial.println(timerInterruptPin);
Serial.println(F("This example will not work without the interrupt pin connected!\n\n"));
// Timer configuration is not cleared on an RTC reset due to battery backup!
rtc.deconfigureAllTimers();
Serial.println(F("First, use the PCF8523's 'Countdown Timer' with an interrupt."));
Serial.println(F("Set the countdown for 10 seconds and we'll let it run for 2 rounds."));
Serial.println(F("Starting Countdown Timer now..."));
// These are the PCF8523's built-in "Timer Source Clock Frequencies".
// They are predefined time periods you choose as your base unit of time,
// depending on the length of countdown timer you need.
// The minimum length of your countdown is 1 time period.
// The maximum length of your countdown is 255 time periods.
//
// PCF8523_FrequencyHour = 1 hour, max 10.625 days (255 hours)
// PCF8523_FrequencyMinute = 1 minute, max 4.25 hours
// PCF8523_FrequencySecond = 1 second, max 4.25 minutes
// PCF8523_Frequency64Hz = 1/64 of a second (15.625 milliseconds), max 3.984 seconds
// PCF8523_Frequency4kHz = 1/4096 of a second (244 microseconds), max 62.256 milliseconds
//
//
// These are the PCF8523's optional 'Low Pulse Widths' of time the interrupt
// pin is held LOW at the end of every countdown (frequency 64Hz or longer).
//
// PCF8523_LowPulse3x64Hz = 46.875 ms 3/64ths second (default)
// PCF8523_LowPulse4x64Hz = 62.500 ms 4/64ths second
// PCF8523_LowPulse5x64Hz = 78.125 ms 5/64ths second
// PCF8523_LowPulse6x64Hz = 93.750 ms 6/64ths second
// PCF8523_LowPulse8x64Hz = 125.000 ms 8/64ths second
// PCF8523_LowPulse10x64Hz = 156.250 ms 10/64ths second
// PCF8523_LowPulse12x64Hz = 187.500 ms 12/64ths second
// PCF8523_LowPulse14x64Hz = 218.750 ms 14/64ths second
//
//
// Uncomment an example below:
// rtc.enableCountdownTimer(PCF8523_FrequencyHour, 24); // 1 day
// rtc.enableCountdownTimer(PCF8523_FrequencyMinute, 150); // 2.5 hours
rtc.enableCountdownTimer(PCF8523_FrequencySecond, 10); // 10 seconds
// rtc.enableCountdownTimer(PCF8523_Frequency64Hz, 32); // 1/2 second
// rtc.enableCountdownTimer(PCF8523_Frequency64Hz, 16); // 1/4 second
// rtc.enableCountdownTimer(PCF8523_Frequency4kHz, 205); // 50 milliseconds
attachInterrupt(digitalPinToInterrupt(timerInterruptPin), countdownOver, FALLING);
// This message proves we're not blocked while counting down!
Serial.println(F(" While we're waiting, a word of caution:"));
Serial.println(F(" When starting a new countdown timer, the first time period is not of fixed"));
Serial.println(F(" duration. The amount of inaccuracy for the first time period is up to one full"));
Serial.println(F(" clock frequency. Example: just the first second of the first round of a new"));
Serial.println(F(" countdown based on PCF8523_FrequencySecond may be off by as much as 1 second!"));
Serial.println(F(" For critical timing, consider starting actions on the first interrupt."));
}
// Triggered by the PCF8523 Countdown Timer interrupt at the end of a countdown
// period. Meanwhile, the PCF8523 immediately starts the countdown again.
void countdownOver () {
// Set a flag to run code in the loop():
countdownInterruptTriggered = true;
numCountdownInterrupts++;
}
// Triggered by the PCF8523 Second Timer every second.
void toggleLed () {
// Run certain types of fast executing code here:
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
void loop () {
if (countdownInterruptTriggered && numCountdownInterrupts == 1) {
Serial.println(F("1st countdown interrupt triggered. Accurate timekeeping starts now."));
countdownInterruptTriggered = false; // don't come in here again
} else if (countdownInterruptTriggered && numCountdownInterrupts == 2) {
Serial.println(F("2nd countdown interrupt triggered. Disabling countdown and detaching interrupt.\n\n"));
rtc.disableCountdownTimer();
detachInterrupt(digitalPinToInterrupt(timerInterruptPin));
delay(2000);
Serial.println(F("Now, set up the PCF8523's 'Second Timer' to toggle the built-in LED at 1Hz..."));
attachInterrupt(digitalPinToInterrupt(timerInterruptPin), toggleLed, FALLING);
rtc.enableSecondTimer();
Serial.println(F("Look for the built-in LED to flash 1 second ON, 1 second OFF, repeat. "));
Serial.println(F("Meanwhile this program will use delay() to block code execution briefly"));
Serial.println(F("before moving on to the last example. Notice the LED keeps blinking!\n\n"));
delay(20000); // less accurate, blocks execution here. Meanwhile Second Timer keeps running.
rtc.disableSecondTimer();
detachInterrupt(digitalPinToInterrupt(timerInterruptPin));
Serial.println(F("Lastly, set up a Countdown Timer that works without attaching an interrupt..."));
rtc.enableCountdownTimer(PCF8523_Frequency64Hz, 32, PCF8523_LowPulse8x64Hz);
Serial.println(F("Look for the LED to turn on every 1/2 second and stay lit for 1/8th of a second."));
Serial.println(F("The countdown was set to a source clock frequency of 64 Hz (1/64th of a second)"));
Serial.println(F("for a length of 32 time periods. 32 * 1/64th of a second is 1/2 of a second."));
Serial.println(F("The low pulse duration was set to 125 ms, or 1/8th of a second."));
Serial.println(F("The loop() keeps the built-in LED set to the opposite state of the INT/SQW pin."));
countdownInterruptTriggered = false; // don't come in here again
}
// While countdown running, INT/SQW pullup to HIGH, set LED to LOW (off)
// When countdown is over, INT/SQW pulled down LOW, set LED to HIGH (on)
digitalWrite(LED_BUILTIN, !digitalRead(timerInterruptPin));
}
@@ -0,0 +1,92 @@
// Date and time functions using a PCF8563 RTC connected via I2C and Wire lib
#include "RTClib.h"
RTC_PCF8563 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
void setup () {
Serial.begin(115200);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
if (rtc.lostPower()) {
Serial.println("RTC is NOT initialized, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
//
// Note: allow 2 seconds after inserting battery or applying external power
// without battery before calling adjust(). This gives the PCF8523's
// crystal oscillator time to stabilize. If you call adjust() very quickly
// after the RTC is powered, lostPower() may still return true.
}
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
// When the RTC was stopped and stays connected to the battery, it has
// to be restarted by clearing the STOP bit. Let's do this to ensure
// the RTC is running.
rtc.start();
}
void loop () {
DateTime now = rtc.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" (");
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
Serial.print(") ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
Serial.print(" since midnight 1/1/1970 = ");
Serial.print(now.unixtime());
Serial.print("s = ");
Serial.print(now.unixtime() / 86400L);
Serial.println("d");
// calculate a date which is 7 days, 12 hours and 30 seconds into the future
DateTime future (now + TimeSpan(7,12,30,6));
Serial.print(" now + 7d + 12h + 30m + 6s: ");
Serial.print(future.year(), DEC);
Serial.print('/');
Serial.print(future.month(), DEC);
Serial.print('/');
Serial.print(future.day(), DEC);
Serial.print(' ');
Serial.print(future.hour(), DEC);
Serial.print(':');
Serial.print(future.minute(), DEC);
Serial.print(':');
Serial.print(future.second(), DEC);
Serial.println();
Serial.println();
delay(3000);
}
@@ -0,0 +1,89 @@
// Date and time functions using a PCF8563 RTC connected via I2C and Wire lib
#include "RTClib.h"
RTC_PCF8563 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
// use D2 for INT0; attach to CLKOUT pin on RTC
const uint8_t INT_PIN = 2;
// flag to update serial; set in interrupt callback
volatile uint8_t tick_tock = 1;
// INT0 interrupt callback; update tick_tock flag
void set_tick_tock(void) {
tick_tock = 1;
}
void setup () {
Serial.begin(115200);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
pinMode(INT_PIN, INPUT); // set up interrupt pin
digitalWrite(INT_PIN, HIGH); // turn on pullup resistors
// attach interrupt to set_tick_tock callback on rising edge of INT0
attachInterrupt(digitalPinToInterrupt(INT_PIN), set_tick_tock, RISING);
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
if (rtc.lostPower()) {
Serial.println("RTC is NOT initialized, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
//
// Note: allow 2 seconds after inserting battery or applying external power
// without battery before calling adjust(). This gives the PCF8523's
// crystal oscillator time to stabilize. If you call adjust() very quickly
// after the RTC is powered, lostPower() may still return true.
}
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
// When the RTC was stopped and stays connected to the battery, it has
// to be restarted by clearing the STOP bit. Let's do this to ensure
// the RTC is running.
rtc.start();
// turn on 1Hz clock out, used as INT0 for serial update every second
rtc.writeSqwPinMode(PCF8563_SquareWave1Hz);
}
void loop () {
// check if time display should be output
if(tick_tock) {
DateTime now = rtc.now();
char time_format[] = "hh:mm:ss AP";
char date_format[] = "MM/DD/YYYY";
Serial.println(now.toString(time_format));
Serial.println(now.toString(date_format));
Serial.println();
tick_tock = 0;
}
}
@@ -0,0 +1,59 @@
// Date and time functions using just software, based on millis() & timer
#include "RTClib.h"
RTC_Millis rtc;
void setup () {
Serial.begin(57600);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
// following line sets the RTC to the date & time this sketch was compiled
rtc.begin(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
void loop () {
DateTime now = rtc.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
Serial.print(" seconds since 1970: ");
Serial.println(now.unixtime());
// calculate a date which is 7 days and 30 seconds into the future
DateTime future (now.unixtime() + 7 * 86400L + 30);
Serial.print(" now + 7d + 30s: ");
Serial.print(future.year(), DEC);
Serial.print('/');
Serial.print(future.month(), DEC);
Serial.print('/');
Serial.print(future.day(), DEC);
Serial.print(' ');
Serial.print(future.hour(), DEC);
Serial.print(':');
Serial.print(future.minute(), DEC);
Serial.print(':');
Serial.print(future.second(), DEC);
Serial.println();
Serial.println();
delay(3000);
}
@@ -0,0 +1,62 @@
/* Timestamp functions using a DS1307 RTC connected via I2C and Wire lib
**
** Useful for file name
** ` SD.open(time.timestamp()+".log", FILE_WRITE) `
**
**
** Created: 2015-06-01 by AxelTB
** Last Edit:
*/
#include "RTClib.h"
RTC_DS1307 rtc;
void setup () {
Serial.begin(57600);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
if (! rtc.isrunning()) {
Serial.println("RTC is NOT running, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
void loop() {
DateTime time = rtc.now();
//Full Timestamp
Serial.println(String("DateTime::TIMESTAMP_FULL:\t")+time.timestamp(DateTime::TIMESTAMP_FULL));
//Date Only
Serial.println(String("DateTime::TIMESTAMP_DATE:\t")+time.timestamp(DateTime::TIMESTAMP_DATE));
//Full Timestamp
Serial.println(String("DateTime::TIMESTAMP_TIME:\t")+time.timestamp(DateTime::TIMESTAMP_TIME));
Serial.println("\n");
//Delay 5s
delay(5000);
}
@@ -0,0 +1,66 @@
#include <Wire.h>
#include <RTClib.h>
RTC_DS1307 rtc;
void setup () {
Serial.begin(57600);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
if (! rtc.isrunning()) {
Serial.println("RTC is NOT running, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
void loop() {
DateTime now = rtc.now();
//buffer can be defined using following combinations:
//hh - the hour with a leading zero (00 to 23)
//mm - the minute with a leading zero (00 to 59)
//ss - the whole second with a leading zero where applicable (00 to 59)
//YYYY - the year as four digit number
//YY - the year as two digit number (00-99)
//MM - the month as number with a leading zero (01-12)
//MMM - the abbreviated English month name ('Jan' to 'Dec')
//DD - the day as number with a leading zero (01 to 31)
//DDD - the abbreviated English day name ('Mon' to 'Sun')
char buf1[] = "hh:mm";
Serial.println(now.toString(buf1));
char buf2[] = "YYMMDD-hh:mm:ss";
Serial.println(now.toString(buf2));
char buf3[] = "Today is DDD, MMM DD YYYY";
Serial.println(now.toString(buf3));
char buf4[] = "MM-DD-YYYY";
Serial.println(now.toString(buf4));
delay(1000);
}
+83
View File
@@ -0,0 +1,83 @@
#######################################
# Syntax Coloring Map For RTClib
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
DateTime KEYWORD1
TimeSpan KEYWORD1
RTC_DS1307 KEYWORD1
RTC_DS3231 KEYWORD1
RTC_PCF8523 KEYWORD1
RTC_PCF8563 KEYWORD1
RTC_Millis KEYWORD1
RTC_Micros KEYWORD1
Ds1307SqwPinMode KEYWORD1
Ds3231SqwPinMode KEYWORD1
Ds3231Alarm1Mode KEYWORD1
Ds3231Alarm2Mode KEYWORD1
Pcf8523SqwPinMode KEYWORD1
PCF8523TimerClockFreq KEYWORD1
PCF8523TimerIntPulse KEYWORD1
Pcf8523OffsetMode KEYWORD1
Pcf8563SqwPinMode KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
isValid KEYWORD2
year KEYWORD2
month KEYWORD2
day KEYWORD2
hour KEYWORD2
twelveHour KEYWORD2
isPM KEYWORD2
minute KEYWORD2
second KEYWORD2
dayOfTheWeek KEYWORD2
secondstime KEYWORD2
unixtime KEYWORD2
days KEYWORD2
hours KEYWORD2
minutes KEYWORD2
seconds KEYWORD2
totalseconds KEYWORD2
begin KEYWORD2
adjust KEYWORD2
adjustDrift KEYWORD2
isrunning KEYWORD2
now KEYWORD2
readSqwPinMode KEYWORD2
writeSqwPinMode KEYWORD2
timestamp KEYWORD2
toString KEYWORD2
readnvram KEYWORD2
writenvram KEYWORD2
setAlarm1 KEYWORD2
setAlarm2 KEYWORD2
disableAlarm KEYWORD2
clearAlarm KEYWORD2
alarmFired KEYWORD2
getTemperature KEYWORD2
lostPower KEYWORD2
initialized KEYWORD2
enableSecondTimer KEYWORD2
disableSecondTimer KEYWORD2
enableCountdownTimer KEYWORD2
disableCountdownTimer KEYWORD2
deconfigureAllTimers KEYWORD2
calibrate KEYWORD2
enable32K KEYWORD2
disable32K KEYWORD2
isEnabled32K KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
TIMESTAMP_FULL LITERAL1
TIMESTAMP_DATE LITERAL1
TIMESTAMP_TIME LITERAL1
+10
View File
@@ -0,0 +1,10 @@
name=RTClib
version=2.1.4
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=A fork of Jeelab's fantastic RTC library
paragraph=Works with DS1307, DS3231, PCF8523, PCF8563 on multiple architectures
category=Timing
url=https://github.com/adafruit/RTClib
architectures=*
depends=Adafruit BusIO
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Adafruit Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+134
View File
@@ -0,0 +1,134 @@
#include "RTClib.h"
#define DS1307_ADDRESS 0x68 ///< I2C address for DS1307
#define DS1307_CONTROL 0x07 ///< Control register
#define DS1307_NVRAM 0x08 ///< Start of RAM registers - 56 bytes, 0x08 to 0x3f
/**************************************************************************/
/*!
@brief Start I2C for the DS1307 and test succesful connection
@param wireInstance pointer to the I2C bus
@return True if Wire can find DS1307 or false otherwise.
*/
/**************************************************************************/
bool RTC_DS1307::begin(TwoWire *wireInstance) {
if (i2c_dev)
delete i2c_dev;
i2c_dev = new Adafruit_I2CDevice(DS1307_ADDRESS, wireInstance);
if (!i2c_dev->begin())
return false;
return true;
}
/**************************************************************************/
/*!
@brief Is the DS1307 running? Check the Clock Halt bit in register 0
@return 1 if the RTC is running, 0 if not
*/
/**************************************************************************/
uint8_t RTC_DS1307::isrunning(void) { return !(read_register(0) >> 7); }
/**************************************************************************/
/*!
@brief Set the date and time in the DS1307
@param dt DateTime object containing the desired date/time
*/
/**************************************************************************/
void RTC_DS1307::adjust(const DateTime &dt) {
uint8_t buffer[8] = {0,
bin2bcd(dt.second()),
bin2bcd(dt.minute()),
bin2bcd(dt.hour()),
0,
bin2bcd(dt.day()),
bin2bcd(dt.month()),
bin2bcd(dt.year() - 2000U)};
i2c_dev->write(buffer, 8);
}
/**************************************************************************/
/*!
@brief Get the current date and time from the DS1307
@return DateTime object containing the current date and time
*/
/**************************************************************************/
DateTime RTC_DS1307::now() {
uint8_t buffer[7];
buffer[0] = 0;
i2c_dev->write_then_read(buffer, 1, buffer, 7);
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5]),
bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]),
bcd2bin(buffer[0] & 0x7F));
}
/**************************************************************************/
/*!
@brief Read the current mode of the SQW pin
@return Mode as Ds1307SqwPinMode enum
*/
/**************************************************************************/
Ds1307SqwPinMode RTC_DS1307::readSqwPinMode() {
return static_cast<Ds1307SqwPinMode>(read_register(DS1307_CONTROL) & 0x93);
}
/**************************************************************************/
/*!
@brief Change the SQW pin mode
@param mode The mode to use
*/
/**************************************************************************/
void RTC_DS1307::writeSqwPinMode(Ds1307SqwPinMode mode) {
write_register(DS1307_CONTROL, mode);
}
/**************************************************************************/
/*!
@brief Read data from the DS1307's NVRAM
@param buf Pointer to a buffer to store the data - make sure it's large
enough to hold size bytes
@param size Number of bytes to read
@param address Starting NVRAM address, from 0 to 55
*/
/**************************************************************************/
void RTC_DS1307::readnvram(uint8_t *buf, uint8_t size, uint8_t address) {
uint8_t addrByte = DS1307_NVRAM + address;
i2c_dev->write_then_read(&addrByte, 1, buf, size);
}
/**************************************************************************/
/*!
@brief Write data to the DS1307 NVRAM
@param address Starting NVRAM address, from 0 to 55
@param buf Pointer to buffer containing the data to write
@param size Number of bytes in buf to write to NVRAM
*/
/**************************************************************************/
void RTC_DS1307::writenvram(uint8_t address, const uint8_t *buf, uint8_t size) {
uint8_t addrByte = DS1307_NVRAM + address;
i2c_dev->write(buf, size, true, &addrByte, 1);
}
/**************************************************************************/
/*!
@brief Shortcut to read one byte from NVRAM
@param address NVRAM address, 0 to 55
@return The byte read from NVRAM
*/
/**************************************************************************/
uint8_t RTC_DS1307::readnvram(uint8_t address) {
uint8_t data;
readnvram(&data, 1, address);
return data;
}
/**************************************************************************/
/*!
@brief Shortcut to write one byte to NVRAM
@param address NVRAM address, 0 to 55
@param data One byte to write
*/
/**************************************************************************/
void RTC_DS1307::writenvram(uint8_t address, uint8_t data) {
writenvram(address, &data, 1);
}
+384
View File
@@ -0,0 +1,384 @@
#include "RTClib.h"
#define DS3231_ADDRESS 0x68 ///< I2C address for DS3231
#define DS3231_TIME 0x00 ///< Time register
#define DS3231_ALARM1 0x07 ///< Alarm 1 register
#define DS3231_ALARM2 0x0B ///< Alarm 2 register
#define DS3231_CONTROL 0x0E ///< Control register
#define DS3231_STATUSREG 0x0F ///< Status register
#define DS3231_TEMPERATUREREG \
0x11 ///< Temperature register (high byte - low byte is at 0x12), 10-bit
///< temperature value
/**************************************************************************/
/*!
@brief Start I2C for the DS3231 and test succesful connection
@param wireInstance pointer to the I2C bus
@return True if Wire can find DS3231 or false otherwise.
*/
/**************************************************************************/
bool RTC_DS3231::begin(TwoWire *wireInstance) {
if (i2c_dev)
delete i2c_dev;
i2c_dev = new Adafruit_I2CDevice(DS3231_ADDRESS, wireInstance);
if (!i2c_dev->begin())
return false;
return true;
}
/**************************************************************************/
/*!
@brief Check the status register Oscillator Stop Flag to see if the DS3231
stopped due to power loss
@return True if the bit is set (oscillator stopped) or false if it is
running
*/
/**************************************************************************/
bool RTC_DS3231::lostPower(void) {
return read_register(DS3231_STATUSREG) >> 7;
}
/**************************************************************************/
/*!
@brief Set the date and flip the Oscillator Stop Flag
@param dt DateTime object containing the date/time to set
*/
/**************************************************************************/
void RTC_DS3231::adjust(const DateTime &dt) {
uint8_t buffer[8] = {DS3231_TIME,
bin2bcd(dt.second()),
bin2bcd(dt.minute()),
bin2bcd(dt.hour()),
bin2bcd(dowToDS3231(dt.dayOfTheWeek())),
bin2bcd(dt.day()),
bin2bcd(dt.month()),
bin2bcd(dt.year() - 2000U)};
i2c_dev->write(buffer, 8);
uint8_t statreg = read_register(DS3231_STATUSREG);
statreg &= ~0x80; // flip OSF bit
write_register(DS3231_STATUSREG, statreg);
}
/**************************************************************************/
/*!
@brief Get the current date/time
@return DateTime object with the current date/time
*/
/**************************************************************************/
DateTime RTC_DS3231::now() {
uint8_t buffer[7];
buffer[0] = 0;
i2c_dev->write_then_read(buffer, 1, buffer, 7);
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x7F),
bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]),
bcd2bin(buffer[0] & 0x7F));
}
/**************************************************************************/
/*!
@brief Read the SQW pin mode
@return Pin mode, see Ds3231SqwPinMode enum
*/
/**************************************************************************/
Ds3231SqwPinMode RTC_DS3231::readSqwPinMode() {
int mode;
mode = read_register(DS3231_CONTROL) & 0x1C;
if (mode & 0x04)
mode = DS3231_OFF;
return static_cast<Ds3231SqwPinMode>(mode);
}
/**************************************************************************/
/*!
@brief Set the SQW pin mode
@param mode Desired mode, see Ds3231SqwPinMode enum
*/
/**************************************************************************/
void RTC_DS3231::writeSqwPinMode(Ds3231SqwPinMode mode) {
uint8_t ctrl = read_register(DS3231_CONTROL);
ctrl &= ~0x04; // turn off INTCON
ctrl &= ~0x18; // set freq bits to 0
write_register(DS3231_CONTROL, ctrl | mode);
}
/**************************************************************************/
/*!
@brief Get the current temperature from the DS3231's temperature sensor
@return Current temperature (float)
*/
/**************************************************************************/
float RTC_DS3231::getTemperature() {
uint8_t buffer[2] = {DS3231_TEMPERATUREREG, 0};
i2c_dev->write_then_read(buffer, 1, buffer, 2);
return (float)buffer[0] + (buffer[1] >> 6) * 0.25f;
}
/**************************************************************************/
/*!
@brief Set alarm 1 for DS3231
@param dt DateTime object
@param alarm_mode Desired mode, see Ds3231Alarm1Mode enum
@return False if control register is not set, otherwise true
*/
/**************************************************************************/
bool RTC_DS3231::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) {
uint8_t ctrl = read_register(DS3231_CONTROL);
if (!(ctrl & 0x04)) {
return false;
}
uint8_t A1M1 = (alarm_mode & 0x01) << 7; // Seconds bit 7.
uint8_t A1M2 = (alarm_mode & 0x02) << 6; // Minutes bit 7.
uint8_t A1M3 = (alarm_mode & 0x04) << 5; // Hour bit 7.
uint8_t A1M4 = (alarm_mode & 0x08) << 4; // Day/Date bit 7.
uint8_t DY_DT = (alarm_mode & 0x10)
<< 2; // Day/Date bit 6. Date when 0, day of week when 1.
uint8_t day = (DY_DT) ? dowToDS3231(dt.dayOfTheWeek()) : dt.day();
uint8_t buffer[5] = {DS3231_ALARM1, uint8_t(bin2bcd(dt.second()) | A1M1),
uint8_t(bin2bcd(dt.minute()) | A1M2),
uint8_t(bin2bcd(dt.hour()) | A1M3),
uint8_t(bin2bcd(day) | A1M4 | DY_DT)};
i2c_dev->write(buffer, 5);
write_register(DS3231_CONTROL, ctrl | 0x01); // AI1E
return true;
}
/**************************************************************************/
/*!
@brief Set alarm 2 for DS3231
@param dt DateTime object
@param alarm_mode Desired mode, see Ds3231Alarm2Mode enum
@return False if control register is not set, otherwise true
*/
/**************************************************************************/
bool RTC_DS3231::setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode) {
uint8_t ctrl = read_register(DS3231_CONTROL);
if (!(ctrl & 0x04)) {
return false;
}
uint8_t A2M2 = (alarm_mode & 0x01) << 7; // Minutes bit 7.
uint8_t A2M3 = (alarm_mode & 0x02) << 6; // Hour bit 7.
uint8_t A2M4 = (alarm_mode & 0x04) << 5; // Day/Date bit 7.
uint8_t DY_DT = (alarm_mode & 0x08)
<< 3; // Day/Date bit 6. Date when 0, day of week when 1.
uint8_t day = (DY_DT) ? dowToDS3231(dt.dayOfTheWeek()) : dt.day();
uint8_t buffer[4] = {DS3231_ALARM2, uint8_t(bin2bcd(dt.minute()) | A2M2),
uint8_t(bin2bcd(dt.hour()) | A2M3),
uint8_t(bin2bcd(day) | A2M4 | DY_DT)};
i2c_dev->write(buffer, 4);
write_register(DS3231_CONTROL, ctrl | 0x02); // AI2E
return true;
}
/**************************************************************************/
/*!
@brief Get the date/time value of Alarm1
@return DateTime object with the Alarm1 data set in the
day, hour, minutes, and seconds fields
*/
/**************************************************************************/
DateTime RTC_DS3231::getAlarm1() {
uint8_t buffer[5] = {DS3231_ALARM1, 0, 0, 0, 0};
i2c_dev->write_then_read(buffer, 1, buffer, 5);
uint8_t seconds = bcd2bin(buffer[0] & 0x7F);
uint8_t minutes = bcd2bin(buffer[1] & 0x7F);
// Fetching the hour assumes 24 hour time (never 12)
// because this library exclusively stores the time
// in 24 hour format. Note that the DS3231 supports
// 12 hour storage, and sets bits to indicate the type
// that is stored.
uint8_t hour = bcd2bin(buffer[2] & 0x3F);
// Determine if the alarm is set to fire based on the
// day of the week, or an explicit date match.
bool isDayOfWeek = (buffer[3] & 0x40) >> 6;
uint8_t day;
if (isDayOfWeek) {
// Alarm set to match on day of the week
day = bcd2bin(buffer[3] & 0x0F);
} else {
// Alarm set to match on day of the month
day = bcd2bin(buffer[3] & 0x3F);
}
// On the first week of May 2000, the day-of-the-week number
// matches the date number.
return DateTime(2000, 5, day, hour, minutes, seconds);
}
/**************************************************************************/
/*!
@brief Get the date/time value of Alarm2
@return DateTime object with the Alarm2 data set in the
day, hour, and minutes fields
*/
/**************************************************************************/
DateTime RTC_DS3231::getAlarm2() {
uint8_t buffer[4] = {DS3231_ALARM2, 0, 0, 0};
i2c_dev->write_then_read(buffer, 1, buffer, 4);
uint8_t minutes = bcd2bin(buffer[0] & 0x7F);
// Fetching the hour assumes 24 hour time (never 12)
// because this library exclusively stores the time
// in 24 hour format. Note that the DS3231 supports
// 12 hour storage, and sets bits to indicate the type
// that is stored.
uint8_t hour = bcd2bin(buffer[1] & 0x3F);
// Determine if the alarm is set to fire based on the
// day of the week, or an explicit date match.
bool isDayOfWeek = (buffer[2] & 0x40) >> 6;
uint8_t day;
if (isDayOfWeek) {
// Alarm set to match on day of the week
day = bcd2bin(buffer[2] & 0x0F);
} else {
// Alarm set to match on day of the month
day = bcd2bin(buffer[2] & 0x3F);
}
// On the first week of May 2000, the day-of-the-week number
// matches the date number.
return DateTime(2000, 5, day, hour, minutes, 0);
}
/**************************************************************************/
/*!
@brief Get the mode for Alarm1
@return Ds3231Alarm1Mode enum value for the current Alarm1 mode
*/
/**************************************************************************/
Ds3231Alarm1Mode RTC_DS3231::getAlarm1Mode() {
uint8_t buffer[5] = {DS3231_ALARM1, 0, 0, 0, 0};
i2c_dev->write_then_read(buffer, 1, buffer, 5);
uint8_t alarm_mode = (buffer[0] & 0x80) >> 7 // A1M1 - Seconds bit
| (buffer[1] & 0x80) >> 6 // A1M2 - Minutes bit
| (buffer[2] & 0x80) >> 5 // A1M3 - Hour bit
| (buffer[3] & 0x80) >> 4 // A1M4 - Day/Date bit
| (buffer[3] & 0x40) >> 2; // DY_DT
// Determine which mode the fetched alarm bits map to
switch (alarm_mode) {
case DS3231_A1_PerSecond:
case DS3231_A1_Second:
case DS3231_A1_Minute:
case DS3231_A1_Hour:
case DS3231_A1_Date:
case DS3231_A1_Day:
return (Ds3231Alarm1Mode)alarm_mode;
default:
// Default if the alarm mode cannot be read
return DS3231_A1_Date;
}
}
/**************************************************************************/
/*!
@brief Get the mode for Alarm2
@return Ds3231Alarm2Mode enum value for the current Alarm2 mode
*/
/**************************************************************************/
Ds3231Alarm2Mode RTC_DS3231::getAlarm2Mode() {
uint8_t buffer[4] = {DS3231_ALARM2, 0, 0, 0};
i2c_dev->write_then_read(buffer, 1, buffer, 4);
uint8_t alarm_mode = (buffer[0] & 0x80) >> 7 // A2M2 - Minutes bit
| (buffer[1] & 0x80) >> 6 // A2M3 - Hour bit
| (buffer[2] & 0x80) >> 5 // A2M4 - Day/Date bit
| (buffer[2] & 0x40) >> 3; // DY_DT
// Determine which mode the fetched alarm bits map to
switch (alarm_mode) {
case DS3231_A2_PerMinute:
case DS3231_A2_Minute:
case DS3231_A2_Hour:
case DS3231_A2_Date:
case DS3231_A2_Day:
return (Ds3231Alarm2Mode)alarm_mode;
default:
// Default if the alarm mode cannot be read
return DS3231_A2_Date;
}
}
/**************************************************************************/
/*!
@brief Disable alarm
@param alarm_num Alarm number to disable
*/
/**************************************************************************/
void RTC_DS3231::disableAlarm(uint8_t alarm_num) {
uint8_t ctrl = read_register(DS3231_CONTROL);
ctrl &= ~(1 << (alarm_num - 1));
write_register(DS3231_CONTROL, ctrl);
}
/**************************************************************************/
/*!
@brief Clear status of alarm
@param alarm_num Alarm number to clear
*/
/**************************************************************************/
void RTC_DS3231::clearAlarm(uint8_t alarm_num) {
uint8_t status = read_register(DS3231_STATUSREG);
status &= ~(0x1 << (alarm_num - 1));
write_register(DS3231_STATUSREG, status);
}
/**************************************************************************/
/*!
@brief Get status of alarm
@param alarm_num Alarm number to check status of
@return True if alarm has been fired otherwise false
*/
/**************************************************************************/
bool RTC_DS3231::alarmFired(uint8_t alarm_num) {
return (read_register(DS3231_STATUSREG) >> (alarm_num - 1)) & 0x1;
}
/**************************************************************************/
/*!
@brief Enable 32KHz Output
@details The 32kHz output is enabled by default. It requires an external
pull-up resistor to function correctly
*/
/**************************************************************************/
void RTC_DS3231::enable32K(void) {
uint8_t status = read_register(DS3231_STATUSREG);
status |= (0x1 << 0x03);
write_register(DS3231_STATUSREG, status);
}
/**************************************************************************/
/*!
@brief Disable 32KHz Output
*/
/**************************************************************************/
void RTC_DS3231::disable32K(void) {
uint8_t status = read_register(DS3231_STATUSREG);
status &= ~(0x1 << 0x03);
write_register(DS3231_STATUSREG, status);
}
/**************************************************************************/
/*!
@brief Get status of 32KHz Output
@return True if enabled otherwise false
*/
/**************************************************************************/
bool RTC_DS3231::isEnabled32K(void) {
return (read_register(DS3231_STATUSREG) >> 0x03) & 0x01;
}
+33
View File
@@ -0,0 +1,33 @@
#include "RTClib.h"
/**************************************************************************/
/*!
@brief Set the current date/time of the RTC_Micros clock.
@param dt DateTime object with the desired date and time
*/
/**************************************************************************/
void RTC_Micros::adjust(const DateTime &dt) {
lastMicros = micros();
lastUnix = dt.unixtime();
}
/**************************************************************************/
/*!
@brief Adjust the RTC_Micros clock to compensate for system clock drift
@param ppm Adjustment to make. A positive adjustment makes the clock faster.
*/
/**************************************************************************/
void RTC_Micros::adjustDrift(int ppm) { microsPerSecond = 1000000 - ppm; }
/**************************************************************************/
/*!
@brief Get the current date/time from the RTC_Micros clock.
@return DateTime object containing the current date/time
*/
/**************************************************************************/
DateTime RTC_Micros::now() {
uint32_t elapsedSeconds = (micros() - lastMicros) / microsPerSecond;
lastMicros += elapsedSeconds * microsPerSecond;
lastUnix += elapsedSeconds;
return lastUnix;
}
+27
View File
@@ -0,0 +1,27 @@
#include "RTClib.h"
/**************************************************************************/
/*!
@brief Set the current date/time of the RTC_Millis clock.
@param dt DateTime object with the desired date and time
*/
/**************************************************************************/
void RTC_Millis::adjust(const DateTime &dt) {
lastMillis = millis();
lastUnix = dt.unixtime();
}
/**************************************************************************/
/*!
@brief Return a DateTime object containing the current date/time.
Note that computing (millis() - lastMillis) is rollover-safe as long
as this method is called at least once every 49.7 days.
@return DateTime object containing current time
*/
/**************************************************************************/
DateTime RTC_Millis::now() {
uint32_t elapsedSeconds = (millis() - lastMillis) / 1000;
lastMillis += elapsedSeconds * 1000;
lastUnix += elapsedSeconds;
return lastUnix;
}
+292
View File
@@ -0,0 +1,292 @@
#include "RTClib.h"
#define PCF8523_ADDRESS 0x68 ///< I2C address for PCF8523
#define PCF8523_CLKOUTCONTROL 0x0F ///< Timer and CLKOUT control register
#define PCF8523_CONTROL_1 0x00 ///< Control and status register 1
#define PCF8523_CONTROL_2 0x01 ///< Control and status register 2
#define PCF8523_CONTROL_3 0x02 ///< Control and status register 3
#define PCF8523_TIMER_B_FRCTL 0x12 ///< Timer B source clock frequency control
#define PCF8523_TIMER_B_VALUE 0x13 ///< Timer B value (number clock periods)
#define PCF8523_OFFSET 0x0E ///< Offset register
#define PCF8523_STATUSREG 0x03 ///< Status register
/**************************************************************************/
/*!
@brief Start I2C for the PCF8523 and test succesful connection
@param wireInstance pointer to the I2C bus
@return True if Wire can find PCF8523 or false otherwise.
*/
/**************************************************************************/
bool RTC_PCF8523::begin(TwoWire *wireInstance) {
if (i2c_dev)
delete i2c_dev;
i2c_dev = new Adafruit_I2CDevice(PCF8523_ADDRESS, wireInstance);
if (!i2c_dev->begin())
return false;
return true;
}
/**************************************************************************/
/*!
@brief Check the status register Oscillator Stop flag to see if the PCF8523
stopped due to power loss
@details When battery or external power is first applied, the PCF8523's
crystal oscillator takes up to 2s to stabilize. During this time adjust()
cannot clear the 'OS' flag. See datasheet OS flag section for details.
@return True if the bit is set (oscillator is or has stopped) and false only
after the bit is cleared, for instance with adjust()
*/
/**************************************************************************/
bool RTC_PCF8523::lostPower(void) {
return read_register(PCF8523_STATUSREG) >> 7;
}
/**************************************************************************/
/*!
@brief Check control register 3 to see if we've run adjust() yet (setting
the date/time and battery switchover mode)
@return True if the PCF8523 has been set up, false if not
*/
/**************************************************************************/
bool RTC_PCF8523::initialized(void) {
return (read_register(PCF8523_CONTROL_3) & 0xE0) != 0xE0;
}
/**************************************************************************/
/*!
@brief Set the date and time, set battery switchover mode
@param dt DateTime to set
*/
/**************************************************************************/
void RTC_PCF8523::adjust(const DateTime &dt) {
uint8_t buffer[8] = {3, // start at location 3
bin2bcd(dt.second()),
bin2bcd(dt.minute()),
bin2bcd(dt.hour()),
bin2bcd(dt.day()),
bin2bcd(0), // skip weekdays
bin2bcd(dt.month()),
bin2bcd(dt.year() - 2000U)};
i2c_dev->write(buffer, 8);
// set to battery switchover mode
write_register(PCF8523_CONTROL_3, 0x00);
}
/**************************************************************************/
/*!
@brief Get the current date/time
@return DateTime object containing the current date/time
*/
/**************************************************************************/
DateTime RTC_PCF8523::now() {
uint8_t buffer[7];
buffer[0] = 3;
i2c_dev->write_then_read(buffer, 1, buffer, 7);
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5]),
bcd2bin(buffer[3]), bcd2bin(buffer[2]), bcd2bin(buffer[1]),
bcd2bin(buffer[0] & 0x7F));
}
/**************************************************************************/
/*!
@brief Resets the STOP bit in register Control_1
*/
/**************************************************************************/
void RTC_PCF8523::start(void) {
uint8_t ctlreg = read_register(PCF8523_CONTROL_1);
if (ctlreg & (1 << 5))
write_register(PCF8523_CONTROL_1, ctlreg & ~(1 << 5));
}
/**************************************************************************/
/*!
@brief Sets the STOP bit in register Control_1
*/
/**************************************************************************/
void RTC_PCF8523::stop(void) {
write_register(PCF8523_CONTROL_1,
read_register(PCF8523_CONTROL_1) | (1 << 5));
}
/**************************************************************************/
/*!
@brief Is the PCF8523 running? Check the STOP bit in register Control_1
@return 1 if the RTC is running, 0 if not
*/
/**************************************************************************/
uint8_t RTC_PCF8523::isrunning() {
return !((read_register(PCF8523_CONTROL_1) >> 5) & 1);
}
/**************************************************************************/
/*!
@brief Read the mode of the INT/SQW pin on the PCF8523
@return SQW pin mode as a #Pcf8523SqwPinMode enum
*/
/**************************************************************************/
Pcf8523SqwPinMode RTC_PCF8523::readSqwPinMode() {
int mode = read_register(PCF8523_CLKOUTCONTROL);
mode >>= 3;
mode &= 0x7;
return static_cast<Pcf8523SqwPinMode>(mode);
}
/**************************************************************************/
/*!
@brief Set the INT/SQW pin mode on the PCF8523
@param mode The mode to set, see the #Pcf8523SqwPinMode enum for options
*/
/**************************************************************************/
void RTC_PCF8523::writeSqwPinMode(Pcf8523SqwPinMode mode) {
write_register(PCF8523_CLKOUTCONTROL, mode << 3);
}
/**************************************************************************/
/*!
@brief Enable the Second Timer (1Hz) Interrupt on the PCF8523.
@details The INT/SQW pin will pull low for a brief pulse once per second.
*/
/**************************************************************************/
void RTC_PCF8523::enableSecondTimer() {
uint8_t ctlreg = read_register(PCF8523_CONTROL_1);
uint8_t clkreg = read_register(PCF8523_CLKOUTCONTROL);
// TAM pulse int. mode (shared with Timer A), CLKOUT (aka SQW) disabled
write_register(PCF8523_CLKOUTCONTROL, clkreg | 0xB8);
// SIE Second timer int. enable
write_register(PCF8523_CONTROL_1, ctlreg | (1 << 2));
}
/**************************************************************************/
/*!
@brief Disable the Second Timer (1Hz) Interrupt on the PCF8523.
*/
/**************************************************************************/
void RTC_PCF8523::disableSecondTimer() {
write_register(PCF8523_CONTROL_1,
read_register(PCF8523_CONTROL_1) & ~(1 << 2));
}
/**************************************************************************/
/*!
@brief Enable the Countdown Timer Interrupt on the PCF8523.
@details The INT/SQW pin will be pulled low at the end of a specified
countdown period ranging from 244 microseconds to 10.625 days.
Uses PCF8523 Timer B. Any existing CLKOUT square wave, configured with
writeSqwPinMode(), will halt. The interrupt low pulse width is adjustable
from 3/64ths (default) to 14/64ths of a second.
@param clkFreq One of the PCF8523's Timer Source Clock Frequencies.
See the #PCF8523TimerClockFreq enum for options and associated time ranges.
@param numPeriods The number of clkFreq periods (1-255) to count down.
@param lowPulseWidth Optional: the length of time for the interrupt pin
low pulse. See the #PCF8523TimerIntPulse enum for options.
*/
/**************************************************************************/
void RTC_PCF8523::enableCountdownTimer(PCF8523TimerClockFreq clkFreq,
uint8_t numPeriods,
uint8_t lowPulseWidth) {
// Datasheet cautions against updating countdown value while it's running,
// so disabling allows repeated calls with new values to set new countdowns
disableCountdownTimer();
// Leave compatible settings intact
uint8_t ctlreg = read_register(PCF8523_CONTROL_2);
uint8_t clkreg = read_register(PCF8523_CLKOUTCONTROL);
// CTBIE Countdown Timer B Interrupt Enabled
write_register(PCF8523_CONTROL_2, ctlreg |= 0x01);
// Timer B source clock frequency, optionally int. low pulse width
write_register(PCF8523_TIMER_B_FRCTL, lowPulseWidth << 4 | clkFreq);
// Timer B value (number of source clock periods)
write_register(PCF8523_TIMER_B_VALUE, numPeriods);
// TBM Timer B pulse int. mode, CLKOUT (aka SQW) disabled, TBC start Timer B
write_register(PCF8523_CLKOUTCONTROL, clkreg | 0x79);
}
/**************************************************************************/
/*!
@overload
@brief Enable Countdown Timer using default interrupt low pulse width.
@param clkFreq One of the PCF8523's Timer Source Clock Frequencies.
See the #PCF8523TimerClockFreq enum for options and associated time ranges.
@param numPeriods The number of clkFreq periods (1-255) to count down.
*/
/**************************************************************************/
void RTC_PCF8523::enableCountdownTimer(PCF8523TimerClockFreq clkFreq,
uint8_t numPeriods) {
enableCountdownTimer(clkFreq, numPeriods, 0);
}
/**************************************************************************/
/*!
@brief Disable the Countdown Timer Interrupt on the PCF8523.
@details For simplicity, this function strictly disables Timer B by setting
TBC to 0. The datasheet describes TBC as the Timer B on/off switch.
Timer B is the only countdown timer implemented at this time.
The following flags have no effect while TBC is off, they are *not* cleared:
- TBM: Timer B will still be set to pulsed mode.
- CTBIE: Timer B interrupt would be triggered if TBC were on.
- CTBF: Timer B flag indicates that interrupt was triggered. Though
typically used for non-pulsed mode, user may wish to query this later.
*/
/**************************************************************************/
void RTC_PCF8523::disableCountdownTimer() {
// TBC disable to stop Timer B clock
write_register(PCF8523_CLKOUTCONTROL,
~1 & read_register(PCF8523_CLKOUTCONTROL));
}
/**************************************************************************/
/*!
@brief Stop all timers, clear their flags and settings on the PCF8523.
@details This includes the Countdown Timer, Second Timer, and any CLKOUT
square wave configured with writeSqwPinMode().
*/
/**************************************************************************/
void RTC_PCF8523::deconfigureAllTimers() {
disableSecondTimer(); // Surgically clears CONTROL_1
write_register(PCF8523_CONTROL_2, 0);
write_register(PCF8523_CLKOUTCONTROL, 0);
write_register(PCF8523_TIMER_B_FRCTL, 0);
write_register(PCF8523_TIMER_B_VALUE, 0);
}
/**************************************************************************/
/*!
@brief Compensate the drift of the RTC.
@details This method sets the "offset" register of the PCF8523,
which can be used to correct a previously measured drift rate.
Two correction modes are available:
- **PCF8523\_TwoHours**: Clock adjustments are performed on
`offset` consecutive minutes every two hours. This is the most
energy-efficient mode.
- **PCF8523\_OneMinute**: Clock adjustments are performed on
`offset` consecutive seconds every minute. Extra adjustments are
performed on the last second of the minute is `abs(offset)>60`.
The `offset` parameter sets the correction amount in units of
roughly 4&nbsp;ppm. The exact unit depends on the selected mode:
| mode | offset unit |
|---------------------|----------------------------------------|
| `PCF8523_TwoHours` | 4.340 ppm = 0.375 s/day = 2.625 s/week |
| `PCF8523_OneMinute` | 4.069 ppm = 0.352 s/day = 2.461 s/week |
See the accompanying sketch pcf8523.ino for an example on how to
use this method.
@param mode Correction mode, either `PCF8523_TwoHours` or
`PCF8523_OneMinute`.
@param offset Correction amount, from -64 to +63. A positive offset
makes the clock slower.
*/
/**************************************************************************/
void RTC_PCF8523::calibrate(Pcf8523OffsetMode mode, int8_t offset) {
write_register(PCF8523_OFFSET, ((uint8_t)offset & 0x7F) | mode);
}
+123
View File
@@ -0,0 +1,123 @@
#include "RTClib.h"
#define PCF8563_ADDRESS 0x51 ///< I2C address for PCF8563
#define PCF8563_CLKOUTCONTROL 0x0D ///< CLKOUT control register
#define PCF8563_CONTROL_1 0x00 ///< Control and status register 1
#define PCF8563_CONTROL_2 0x01 ///< Control and status register 2
#define PCF8563_VL_SECONDS 0x02 ///< register address for VL_SECONDS
#define PCF8563_CLKOUT_MASK 0x83 ///< bitmask for SqwPinMode on CLKOUT pin
/**************************************************************************/
/*!
@brief Start I2C for the PCF8563 and test succesful connection
@param wireInstance pointer to the I2C bus
@return True if Wire can find PCF8563 or false otherwise.
*/
/**************************************************************************/
bool RTC_PCF8563::begin(TwoWire *wireInstance) {
if (i2c_dev)
delete i2c_dev;
i2c_dev = new Adafruit_I2CDevice(PCF8563_ADDRESS, wireInstance);
if (!i2c_dev->begin())
return false;
return true;
}
/**************************************************************************/
/*!
@brief Check the status of the VL bit in the VL_SECONDS register.
@details The PCF8563 has an on-chip voltage-low detector. When VDD drops
below Vlow, bit VL in the VL_seconds register is set to indicate that
the integrity of the clock information is no longer guaranteed.
@return True if the bit is set (VDD droped below Vlow) indicating that
the clock integrity is not guaranteed and false only after the bit is
cleared using adjust()
*/
/**************************************************************************/
bool RTC_PCF8563::lostPower(void) {
return read_register(PCF8563_VL_SECONDS) >> 7;
}
/**************************************************************************/
/*!
@brief Set the date and time
@param dt DateTime to set
*/
/**************************************************************************/
void RTC_PCF8563::adjust(const DateTime &dt) {
uint8_t buffer[8] = {PCF8563_VL_SECONDS, // start at location 2, VL_SECONDS
bin2bcd(dt.second()), bin2bcd(dt.minute()),
bin2bcd(dt.hour()), bin2bcd(dt.day()),
bin2bcd(0), // skip weekdays
bin2bcd(dt.month()), bin2bcd(dt.year() - 2000U)};
i2c_dev->write(buffer, 8);
}
/**************************************************************************/
/*!
@brief Get the current date/time
@return DateTime object containing the current date/time
*/
/**************************************************************************/
DateTime RTC_PCF8563::now() {
uint8_t buffer[7];
buffer[0] = PCF8563_VL_SECONDS; // start at location 2, VL_SECONDS
i2c_dev->write_then_read(buffer, 1, buffer, 7);
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x1F),
bcd2bin(buffer[3] & 0x3F), bcd2bin(buffer[2] & 0x3F),
bcd2bin(buffer[1] & 0x7F), bcd2bin(buffer[0] & 0x7F));
}
/**************************************************************************/
/*!
@brief Resets the STOP bit in register Control_1
*/
/**************************************************************************/
void RTC_PCF8563::start(void) {
uint8_t ctlreg = read_register(PCF8563_CONTROL_1);
if (ctlreg & (1 << 5))
write_register(PCF8563_CONTROL_1, ctlreg & ~(1 << 5));
}
/**************************************************************************/
/*!
@brief Sets the STOP bit in register Control_1
*/
/**************************************************************************/
void RTC_PCF8563::stop(void) {
uint8_t ctlreg = read_register(PCF8563_CONTROL_1);
if (!(ctlreg & (1 << 5)))
write_register(PCF8563_CONTROL_1, ctlreg | (1 << 5));
}
/**************************************************************************/
/*!
@brief Is the PCF8563 running? Check the STOP bit in register Control_1
@return 1 if the RTC is running, 0 if not
*/
/**************************************************************************/
uint8_t RTC_PCF8563::isrunning() {
return !((read_register(PCF8563_CONTROL_1) >> 5) & 1);
}
/**************************************************************************/
/*!
@brief Read the mode of the CLKOUT pin on the PCF8563
@return CLKOUT pin mode as a #Pcf8563SqwPinMode enum
*/
/**************************************************************************/
Pcf8563SqwPinMode RTC_PCF8563::readSqwPinMode() {
int mode = read_register(PCF8563_CLKOUTCONTROL);
return static_cast<Pcf8563SqwPinMode>(mode & PCF8563_CLKOUT_MASK);
}
/**************************************************************************/
/*!
@brief Set the CLKOUT pin mode on the PCF8563
@param mode The mode to set, see the #Pcf8563SqwPinMode enum for options
*/
/**************************************************************************/
void RTC_PCF8563::writeSqwPinMode(Pcf8563SqwPinMode mode) {
write_register(PCF8563_CLKOUTCONTROL, mode);
}
+764
View File
@@ -0,0 +1,764 @@
/**************************************************************************/
/*!
@file RTClib.cpp
@mainpage Adafruit RTClib
@section intro Introduction
This is a fork of JeeLab's fantastic real time clock library for Arduino.
For details on using this library with an RTC module like the DS1307, PCF8523,
or DS3231, see the guide at:
https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
@section classes Available classes
This library provides the following classes:
- Classes for manipulating dates, times and durations:
- DateTime represents a specific point in time; this is the data
type used for setting and reading the supported RTCs
- TimeSpan represents the length of a time interval
- Interfacing specific RTC chips:
- RTC_DS1307
- RTC_DS3231
- RTC_PCF8523
- RTC_PCF8563
- RTC emulated in software; do not expect much accuracy out of these:
- RTC_Millis is based on `millis()`
- RTC_Micros is based on `micros()`; its drift rate can be tuned by
the user
@section license License
Original library by JeeLabs https://jeelabs.org/pub/docs/rtclib/, released to
the public domain.
This version: MIT (see LICENSE)
*/
/**************************************************************************/
#include "RTClib.h"
#ifdef __AVR__
#include <avr/pgmspace.h>
#elif defined(ESP8266)
#include <pgmspace.h>
#elif defined(ARDUINO_ARCH_SAMD)
// nothing special needed
#elif defined(ARDUINO_SAM_DUE)
#define PROGMEM
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
/**************************************************************************/
/*!
@brief Write value to register.
@param reg register address
@param val value to write
*/
/**************************************************************************/
void RTC_I2C::write_register(uint8_t reg, uint8_t val) {
uint8_t buffer[2] = {reg, val};
i2c_dev->write(buffer, 2);
}
/**************************************************************************/
/*!
@brief Read value from register.
@param reg register address
@return value of register
*/
/**************************************************************************/
uint8_t RTC_I2C::read_register(uint8_t reg) {
uint8_t buffer[1];
i2c_dev->write(&reg, 1);
i2c_dev->read(buffer, 1);
return buffer[0];
}
/**************************************************************************/
// utility code, some of this could be exposed in the DateTime API if needed
/**************************************************************************/
/**
Number of days in each month, from January to November. December is not
needed. Omitting it avoids an incompatibility with Paul Stoffregen's Time
library. C.f. https://github.com/adafruit/RTClib/issues/114
*/
const uint8_t daysInMonth[] PROGMEM = {31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30};
/**************************************************************************/
/*!
@brief Given a date, return number of days since 2000/01/01,
valid for 2000--2099
@param y Year
@param m Month
@param d Day
@return Number of days
*/
/**************************************************************************/
static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) {
if (y >= 2000U)
y -= 2000U;
uint16_t days = d;
for (uint8_t i = 1; i < m; ++i)
days += pgm_read_byte(daysInMonth + i - 1);
if (m > 2 && y % 4 == 0)
++days;
return days + 365 * y + (y + 3) / 4 - 1;
}
/**************************************************************************/
/*!
@brief Given a number of days, hours, minutes, and seconds, return the
total seconds
@param days Days
@param h Hours
@param m Minutes
@param s Seconds
@return Number of seconds total
*/
/**************************************************************************/
static uint32_t time2ulong(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
return ((days * 24UL + h) * 60 + m) * 60 + s;
}
/**************************************************************************/
/*!
@brief Constructor from
[Unix time](https://en.wikipedia.org/wiki/Unix_time).
This builds a DateTime from an integer specifying the number of seconds
elapsed since the epoch: 1970-01-01 00:00:00. This number is analogous
to Unix time, with two small differences:
- The Unix epoch is specified to be at 00:00:00
[UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time),
whereas this class has no notion of time zones. The epoch used in
this class is then at 00:00:00 on whatever time zone the user chooses
to use, ignoring changes in DST.
- Unix time is conventionally represented with signed numbers, whereas
this constructor takes an unsigned argument. Because of this, it does
_not_ suffer from the
[year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem).
If called without argument, it returns the earliest time representable
by this class: 2000-01-01 00:00:00.
@see The `unixtime()` method is the converse of this constructor.
@param t Time elapsed in seconds since 1970-01-01 00:00:00.
*/
/**************************************************************************/
DateTime::DateTime(uint32_t t) {
t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970
ss = t % 60;
t /= 60;
mm = t % 60;
t /= 60;
hh = t % 24;
uint16_t days = t / 24;
uint8_t leap;
for (yOff = 0;; ++yOff) {
leap = yOff % 4 == 0;
if (days < 365U + leap)
break;
days -= 365 + leap;
}
for (m = 1; m < 12; ++m) {
uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
if (leap && m == 2)
++daysPerMonth;
if (days < daysPerMonth)
break;
days -= daysPerMonth;
}
d = days + 1;
}
/**************************************************************************/
/*!
@brief Constructor from (year, month, day, hour, minute, second).
@warning If the provided parameters are not valid (e.g. 31 February),
the constructed DateTime will be invalid.
@see The `isValid()` method can be used to test whether the
constructed DateTime is valid.
@param year Either the full year (range: 2000--2099) or the offset from
year 2000 (range: 0--99).
@param month Month number (1--12).
@param day Day of the month (1--31).
@param hour,min,sec Hour (0--23), minute (0--59) and second (0--59).
*/
/**************************************************************************/
DateTime::DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
uint8_t min, uint8_t sec) {
if (year >= 2000U)
year -= 2000U;
yOff = year;
m = month;
d = day;
hh = hour;
mm = min;
ss = sec;
}
/**************************************************************************/
/*!
@brief Copy constructor.
@param copy DateTime to copy.
*/
/**************************************************************************/
DateTime::DateTime(const DateTime &copy)
: yOff(copy.yOff), m(copy.m), d(copy.d), hh(copy.hh), mm(copy.mm),
ss(copy.ss) {}
/**************************************************************************/
/*!
@brief Convert a string containing two digits to uint8_t, e.g. "09" returns
9
@param p Pointer to a string containing two digits
*/
/**************************************************************************/
static uint8_t conv2d(const char *p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
/**************************************************************************/
/*!
@brief Constructor for generating the build time.
This constructor expects its parameters to be strings in the format
generated by the compiler's preprocessor macros `__DATE__` and
`__TIME__`. Usage:
```
DateTime buildTime(__DATE__, __TIME__);
```
@note The `F()` macro can be used to reduce the RAM footprint, see
the next constructor.
@param date Date string, e.g. "Apr 16 2020".
@param time Time string, e.g. "18:34:56".
*/
/**************************************************************************/
DateTime::DateTime(const char *date, const char *time) {
yOff = conv2d(date + 9);
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
switch (date[0]) {
case 'J':
m = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7);
break;
case 'F':
m = 2;
break;
case 'A':
m = date[2] == 'r' ? 4 : 8;
break;
case 'M':
m = date[2] == 'r' ? 3 : 5;
break;
case 'S':
m = 9;
break;
case 'O':
m = 10;
break;
case 'N':
m = 11;
break;
case 'D':
m = 12;
break;
}
d = conv2d(date + 4);
hh = conv2d(time);
mm = conv2d(time + 3);
ss = conv2d(time + 6);
}
/**************************************************************************/
/*!
@brief Memory friendly constructor for generating the build time.
This version is intended to save RAM by keeping the date and time
strings in program memory. Use it with the `F()` macro:
```
DateTime buildTime(F(__DATE__), F(__TIME__));
```
@param date Date PROGMEM string, e.g. F("Apr 16 2020").
@param time Time PROGMEM string, e.g. F("18:34:56").
*/
/**************************************************************************/
DateTime::DateTime(const __FlashStringHelper *date,
const __FlashStringHelper *time) {
char buff[11];
memcpy_P(buff, date, 11);
yOff = conv2d(buff + 9);
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
switch (buff[0]) {
case 'J':
m = (buff[1] == 'a') ? 1 : ((buff[2] == 'n') ? 6 : 7);
break;
case 'F':
m = 2;
break;
case 'A':
m = buff[2] == 'r' ? 4 : 8;
break;
case 'M':
m = buff[2] == 'r' ? 3 : 5;
break;
case 'S':
m = 9;
break;
case 'O':
m = 10;
break;
case 'N':
m = 11;
break;
case 'D':
m = 12;
break;
}
d = conv2d(buff + 4);
memcpy_P(buff, time, 8);
hh = conv2d(buff);
mm = conv2d(buff + 3);
ss = conv2d(buff + 6);
}
/**************************************************************************/
/*!
@brief Constructor for creating a DateTime from an ISO8601 date string.
This constructor expects its parameters to be a string in the
https://en.wikipedia.org/wiki/ISO_8601 format, e.g:
"2020-06-25T15:29:37"
Usage:
```
DateTime dt("2020-06-25T15:29:37");
```
@note The year must be > 2000, as only the yOff is considered.
@param iso8601dateTime
A dateTime string in iso8601 format,
e.g. "2020-06-25T15:29:37".
*/
/**************************************************************************/
DateTime::DateTime(const char *iso8601dateTime) {
char ref[] = "2000-01-01T00:00:00";
memcpy(ref, iso8601dateTime, min(strlen(ref), strlen(iso8601dateTime)));
yOff = conv2d(ref + 2);
m = conv2d(ref + 5);
d = conv2d(ref + 8);
hh = conv2d(ref + 11);
mm = conv2d(ref + 14);
ss = conv2d(ref + 17);
}
/**************************************************************************/
/*!
@brief Check whether this DateTime is valid.
@return true if valid, false if not.
*/
/**************************************************************************/
bool DateTime::isValid() const {
if (yOff >= 100)
return false;
DateTime other(unixtime());
return yOff == other.yOff && m == other.m && d == other.d && hh == other.hh &&
mm == other.mm && ss == other.ss;
}
/**************************************************************************/
/*!
@brief Writes the DateTime as a string in a user-defined format.
The _buffer_ parameter should be initialized by the caller with a string
specifying the requested format. This format string may contain any of
the following specifiers:
| specifier | output |
|-----------|--------------------------------------------------------|
| YYYY | the year as a 4-digit number (2000--2099) |
| YY | the year as a 2-digit number (00--99) |
| MM | the month as a 2-digit number (01--12) |
| MMM | the abbreviated English month name ("Jan"--"Dec") |
| DD | the day as a 2-digit number (01--31) |
| DDD | the abbreviated English day of the week ("Mon"--"Sun") |
| AP | either "AM" or "PM" |
| ap | either "am" or "pm" |
| hh | the hour as a 2-digit number (00--23 or 01--12) |
| mm | the minute as a 2-digit number (00--59) |
| ss | the second as a 2-digit number (00--59) |
If either "AP" or "ap" is used, the "hh" specifier uses 12-hour mode
(range: 01--12). Otherwise it works in 24-hour mode (range: 00--23).
The specifiers within _buffer_ will be overwritten with the appropriate
values from the DateTime. Any characters not belonging to one of the
above specifiers are left as-is.
__Example__: The format "DDD, DD MMM YYYY hh:mm:ss" generates an output
of the form "Thu, 16 Apr 2020 18:34:56.
@see The `timestamp()` method provides similar functionnality, but it
returns a `String` object and supports a limited choice of
predefined formats.
@param[in,out] buffer Array of `char` for holding the format description
and the formatted DateTime. Before calling this method, the buffer
should be initialized by the user with the format string. The method
will overwrite the buffer with the formatted date and/or time.
@return A pointer to the provided buffer. This is returned for
convenience, in order to enable idioms such as
`Serial.println(now.toString(buffer));`
*/
/**************************************************************************/
char *DateTime::toString(char *buffer) const {
uint8_t apTag =
(strstr(buffer, "ap") != nullptr) || (strstr(buffer, "AP") != nullptr);
uint8_t hourReformatted = 0, isPM = false;
if (apTag) { // 12 Hour Mode
if (hh == 0) { // midnight
isPM = false;
hourReformatted = 12;
} else if (hh == 12) { // noon
isPM = true;
hourReformatted = 12;
} else if (hh < 12) { // morning
isPM = false;
hourReformatted = hh;
} else { // 1 o'clock or after
isPM = true;
hourReformatted = hh - 12;
}
}
for (size_t i = 0; i < strlen(buffer) - 1; i++) {
if (buffer[i] == 'h' && buffer[i + 1] == 'h') {
if (!apTag) { // 24 Hour Mode
buffer[i] = '0' + hh / 10;
buffer[i + 1] = '0' + hh % 10;
} else { // 12 Hour Mode
buffer[i] = '0' + hourReformatted / 10;
buffer[i + 1] = '0' + hourReformatted % 10;
}
}
if (buffer[i] == 'm' && buffer[i + 1] == 'm') {
buffer[i] = '0' + mm / 10;
buffer[i + 1] = '0' + mm % 10;
}
if (buffer[i] == 's' && buffer[i + 1] == 's') {
buffer[i] = '0' + ss / 10;
buffer[i + 1] = '0' + ss % 10;
}
if (buffer[i] == 'D' && buffer[i + 1] == 'D' && buffer[i + 2] == 'D') {
static PROGMEM const char day_names[] = "SunMonTueWedThuFriSat";
const char *p = &day_names[3 * dayOfTheWeek()];
buffer[i] = pgm_read_byte(p);
buffer[i + 1] = pgm_read_byte(p + 1);
buffer[i + 2] = pgm_read_byte(p + 2);
} else if (buffer[i] == 'D' && buffer[i + 1] == 'D') {
buffer[i] = '0' + d / 10;
buffer[i + 1] = '0' + d % 10;
}
if (buffer[i] == 'M' && buffer[i + 1] == 'M' && buffer[i + 2] == 'M') {
static PROGMEM const char month_names[] =
"JanFebMarAprMayJunJulAugSepOctNovDec";
const char *p = &month_names[3 * (m - 1)];
buffer[i] = pgm_read_byte(p);
buffer[i + 1] = pgm_read_byte(p + 1);
buffer[i + 2] = pgm_read_byte(p + 2);
} else if (buffer[i] == 'M' && buffer[i + 1] == 'M') {
buffer[i] = '0' + m / 10;
buffer[i + 1] = '0' + m % 10;
}
if (buffer[i] == 'Y' && buffer[i + 1] == 'Y' && buffer[i + 2] == 'Y' &&
buffer[i + 3] == 'Y') {
buffer[i] = '2';
buffer[i + 1] = '0';
buffer[i + 2] = '0' + (yOff / 10) % 10;
buffer[i + 3] = '0' + yOff % 10;
} else if (buffer[i] == 'Y' && buffer[i + 1] == 'Y') {
buffer[i] = '0' + (yOff / 10) % 10;
buffer[i + 1] = '0' + yOff % 10;
}
if (buffer[i] == 'A' && buffer[i + 1] == 'P') {
if (isPM) {
buffer[i] = 'P';
buffer[i + 1] = 'M';
} else {
buffer[i] = 'A';
buffer[i + 1] = 'M';
}
} else if (buffer[i] == 'a' && buffer[i + 1] == 'p') {
if (isPM) {
buffer[i] = 'p';
buffer[i + 1] = 'm';
} else {
buffer[i] = 'a';
buffer[i + 1] = 'm';
}
}
}
return buffer;
}
/**************************************************************************/
/*!
@brief Return the hour in 12-hour format.
@return Hour (1--12).
*/
/**************************************************************************/
uint8_t DateTime::twelveHour() const {
if (hh == 0 || hh == 12) { // midnight or noon
return 12;
} else if (hh > 12) { // 1 o'clock or later
return hh - 12;
} else { // morning
return hh;
}
}
/**************************************************************************/
/*!
@brief Return the day of the week.
@return Day of week as an integer from 0 (Sunday) to 6 (Saturday).
*/
/**************************************************************************/
uint8_t DateTime::dayOfTheWeek() const {
uint16_t day = date2days(yOff, m, d);
return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
}
/**************************************************************************/
/*!
@brief Return Unix time: seconds since 1 Jan 1970.
@see The `DateTime::DateTime(uint32_t)` constructor is the converse of
this method.
@return Number of seconds since 1970-01-01 00:00:00.
*/
/**************************************************************************/
uint32_t DateTime::unixtime(void) const {
uint32_t t;
uint16_t days = date2days(yOff, m, d);
t = time2ulong(days, hh, mm, ss);
t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000
return t;
}
/**************************************************************************/
/*!
@brief Convert the DateTime to seconds since 1 Jan 2000
The result can be converted back to a DateTime with:
```cpp
DateTime(SECONDS_FROM_1970_TO_2000 + value)
```
@return Number of seconds since 2000-01-01 00:00:00.
*/
/**************************************************************************/
uint32_t DateTime::secondstime(void) const {
uint32_t t;
uint16_t days = date2days(yOff, m, d);
t = time2ulong(days, hh, mm, ss);
return t;
}
/**************************************************************************/
/*!
@brief Add a TimeSpan to the DateTime object
@param span TimeSpan object
@return New DateTime object with span added to it.
*/
/**************************************************************************/
DateTime DateTime::operator+(const TimeSpan &span) const {
return DateTime(unixtime() + span.totalseconds());
}
/**************************************************************************/
/*!
@brief Subtract a TimeSpan from the DateTime object
@param span TimeSpan object
@return New DateTime object with span subtracted from it.
*/
/**************************************************************************/
DateTime DateTime::operator-(const TimeSpan &span) const {
return DateTime(unixtime() - span.totalseconds());
}
/**************************************************************************/
/*!
@brief Subtract one DateTime from another
@note Since a TimeSpan cannot be negative, the subtracted DateTime
should be less (earlier) than or equal to the one it is
subtracted from.
@param right The DateTime object to subtract from self (the left object)
@return TimeSpan of the difference between DateTimes.
*/
/**************************************************************************/
TimeSpan DateTime::operator-(const DateTime &right) const {
return TimeSpan(unixtime() - right.unixtime());
}
/**************************************************************************/
/*!
@author Anton Rieutskyi
@brief Test if one DateTime is less (earlier) than another.
@warning if one or both DateTime objects are invalid, returned value is
meaningless
@see use `isValid()` method to check if DateTime object is valid
@param right Comparison DateTime object
@return True if the left DateTime is earlier than the right one,
false otherwise.
*/
/**************************************************************************/
bool DateTime::operator<(const DateTime &right) const {
return (yOff + 2000U < right.year() ||
(yOff + 2000U == right.year() &&
(m < right.month() ||
(m == right.month() &&
(d < right.day() ||
(d == right.day() &&
(hh < right.hour() ||
(hh == right.hour() &&
(mm < right.minute() ||
(mm == right.minute() && ss < right.second()))))))))));
}
/**************************************************************************/
/*!
@author Anton Rieutskyi
@brief Test if two DateTime objects are equal.
@warning if one or both DateTime objects are invalid, returned value is
meaningless
@see use `isValid()` method to check if DateTime object is valid
@param right Comparison DateTime object
@return True if both DateTime objects are the same, false otherwise.
*/
/**************************************************************************/
bool DateTime::operator==(const DateTime &right) const {
return (right.year() == yOff + 2000U && right.month() == m &&
right.day() == d && right.hour() == hh && right.minute() == mm &&
right.second() == ss);
}
/**************************************************************************/
/*!
@brief Return a ISO 8601 timestamp as a `String` object.
The generated timestamp conforms to one of the predefined, ISO
8601-compatible formats for representing the date (if _opt_ is
`TIMESTAMP_DATE`), the time (`TIMESTAMP_TIME`), or both
(`TIMESTAMP_FULL`).
@see The `toString()` method provides more general string formatting.
@param opt Format of the timestamp
@return Timestamp string, e.g. "2020-04-16T18:34:56".
*/
/**************************************************************************/
String DateTime::timestamp(timestampOpt opt) const {
char buffer[25]; // large enough for any DateTime, including invalid ones
// Generate timestamp according to opt
switch (opt) {
case TIMESTAMP_TIME:
// Only time
sprintf(buffer, "%02d:%02d:%02d", hh, mm, ss);
break;
case TIMESTAMP_DATE:
// Only date
sprintf(buffer, "%u-%02d-%02d", 2000U + yOff, m, d);
break;
default:
// Full
sprintf(buffer, "%u-%02d-%02dT%02d:%02d:%02d", 2000U + yOff, m, d, hh, mm,
ss);
}
return String(buffer);
}
/**************************************************************************/
/*!
@brief Create a new TimeSpan object in seconds
@param seconds Number of seconds
*/
/**************************************************************************/
TimeSpan::TimeSpan(int32_t seconds) : _seconds(seconds) {}
/**************************************************************************/
/*!
@brief Create a new TimeSpan object using a number of
days/hours/minutes/seconds e.g. Make a TimeSpan of 3 hours and 45 minutes:
new TimeSpan(0, 3, 45, 0);
@param days Number of days
@param hours Number of hours
@param minutes Number of minutes
@param seconds Number of seconds
*/
/**************************************************************************/
TimeSpan::TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds)
: _seconds((int32_t)days * 86400L + (int32_t)hours * 3600 +
(int32_t)minutes * 60 + seconds) {}
/**************************************************************************/
/*!
@brief Copy constructor, make a new TimeSpan using an existing one
@param copy The TimeSpan to copy
*/
/**************************************************************************/
TimeSpan::TimeSpan(const TimeSpan &copy) : _seconds(copy._seconds) {}
/**************************************************************************/
/*!
@brief Add two TimeSpans
@param right TimeSpan to add
@return New TimeSpan object, sum of left and right
*/
/**************************************************************************/
TimeSpan TimeSpan::operator+(const TimeSpan &right) const {
return TimeSpan(_seconds + right._seconds);
}
/**************************************************************************/
/*!
@brief Subtract a TimeSpan
@param right TimeSpan to subtract
@return New TimeSpan object, right subtracted from left
*/
/**************************************************************************/
TimeSpan TimeSpan::operator-(const TimeSpan &right) const {
return TimeSpan(_seconds - right._seconds);
}
+519
View File
@@ -0,0 +1,519 @@
/**************************************************************************/
/*!
@file RTClib.h
Original library by JeeLabs http://news.jeelabs.org/code/, released to the
public domain
License: MIT (see LICENSE)
This is a fork of JeeLab's fantastic real time clock library for Arduino.
For details on using this library with an RTC module like the DS1307, PCF8523,
or DS3231, see the guide at:
https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
*/
/**************************************************************************/
#ifndef _RTCLIB_H_
#define _RTCLIB_H_
#include <Adafruit_I2CDevice.h>
#include <Arduino.h>
class TimeSpan;
/** Constants */
#define SECONDS_PER_DAY 86400L ///< 60 * 60 * 24
#define SECONDS_FROM_1970_TO_2000 \
946684800 ///< Unixtime for 2000-01-01 00:00:00, useful for initialization
/** DS1307 SQW pin mode settings */
enum Ds1307SqwPinMode {
DS1307_OFF = 0x00, // Low
DS1307_ON = 0x80, // High
DS1307_SquareWave1HZ = 0x10, // 1Hz square wave
DS1307_SquareWave4kHz = 0x11, // 4kHz square wave
DS1307_SquareWave8kHz = 0x12, // 8kHz square wave
DS1307_SquareWave32kHz = 0x13 // 32kHz square wave
};
/** DS3231 SQW pin mode settings */
enum Ds3231SqwPinMode {
DS3231_OFF = 0x1C, /**< Off */
DS3231_SquareWave1Hz = 0x00, /**< 1Hz square wave */
DS3231_SquareWave1kHz = 0x08, /**< 1kHz square wave */
DS3231_SquareWave4kHz = 0x10, /**< 4kHz square wave */
DS3231_SquareWave8kHz = 0x18 /**< 8kHz square wave */
};
/** DS3231 Alarm modes for alarm 1 */
enum Ds3231Alarm1Mode {
DS3231_A1_PerSecond = 0x0F, /**< Alarm once per second */
DS3231_A1_Second = 0x0E, /**< Alarm when seconds match */
DS3231_A1_Minute = 0x0C, /**< Alarm when minutes and seconds match */
DS3231_A1_Hour = 0x08, /**< Alarm when hours, minutes
and seconds match */
DS3231_A1_Date = 0x00, /**< Alarm when date (day of month), hours,
minutes and seconds match */
DS3231_A1_Day = 0x10 /**< Alarm when day (day of week), hours,
minutes and seconds match */
};
/** DS3231 Alarm modes for alarm 2 */
enum Ds3231Alarm2Mode {
DS3231_A2_PerMinute = 0x7, /**< Alarm once per minute
(whenever seconds are 0) */
DS3231_A2_Minute = 0x6, /**< Alarm when minutes match */
DS3231_A2_Hour = 0x4, /**< Alarm when hours and minutes match */
DS3231_A2_Date = 0x0, /**< Alarm when date (day of month), hours
and minutes match */
DS3231_A2_Day = 0x8 /**< Alarm when day (day of week), hours
and minutes match */
};
/** PCF8523 INT/SQW pin mode settings */
enum Pcf8523SqwPinMode {
PCF8523_OFF = 7, /**< Off */
PCF8523_SquareWave1HZ = 6, /**< 1Hz square wave */
PCF8523_SquareWave32HZ = 5, /**< 32Hz square wave */
PCF8523_SquareWave1kHz = 4, /**< 1kHz square wave */
PCF8523_SquareWave4kHz = 3, /**< 4kHz square wave */
PCF8523_SquareWave8kHz = 2, /**< 8kHz square wave */
PCF8523_SquareWave16kHz = 1, /**< 16kHz square wave */
PCF8523_SquareWave32kHz = 0 /**< 32kHz square wave */
};
/** PCF8523 Timer Source Clock Frequencies for Timers A and B */
enum PCF8523TimerClockFreq {
PCF8523_Frequency4kHz = 0, /**< 1/4096th second = 244 microseconds,
max 62.256 milliseconds */
PCF8523_Frequency64Hz = 1, /**< 1/64th second = 15.625 milliseconds,
max 3.984375 seconds */
PCF8523_FrequencySecond = 2, /**< 1 second, max 255 seconds = 4.25 minutes */
PCF8523_FrequencyMinute = 3, /**< 1 minute, max 255 minutes = 4.25 hours */
PCF8523_FrequencyHour = 4, /**< 1 hour, max 255 hours = 10.625 days */
};
/** PCF8523 Timer Interrupt Low Pulse Width options for Timer B only */
enum PCF8523TimerIntPulse {
PCF8523_LowPulse3x64Hz = 0, /**< 46.875 ms 3/64ths second */
PCF8523_LowPulse4x64Hz = 1, /**< 62.500 ms 4/64ths second */
PCF8523_LowPulse5x64Hz = 2, /**< 78.125 ms 5/64ths second */
PCF8523_LowPulse6x64Hz = 3, /**< 93.750 ms 6/64ths second */
PCF8523_LowPulse8x64Hz = 4, /**< 125.000 ms 8/64ths second */
PCF8523_LowPulse10x64Hz = 5, /**< 156.250 ms 10/64ths second */
PCF8523_LowPulse12x64Hz = 6, /**< 187.500 ms 12/64ths second */
PCF8523_LowPulse14x64Hz = 7 /**< 218.750 ms 14/64ths second */
};
/** PCF8523 Offset modes for making temperature/aging/accuracy adjustments */
enum Pcf8523OffsetMode {
PCF8523_TwoHours = 0x00, /**< Offset made every two hours */
PCF8523_OneMinute = 0x80 /**< Offset made every minute */
};
/** PCF8563 CLKOUT pin mode settings */
enum Pcf8563SqwPinMode {
PCF8563_SquareWaveOFF = 0x00, /**< Off */
PCF8563_SquareWave1Hz = 0x83, /**< 1Hz square wave */
PCF8563_SquareWave32Hz = 0x82, /**< 32Hz square wave */
PCF8563_SquareWave1kHz = 0x81, /**< 1kHz square wave */
PCF8563_SquareWave32kHz = 0x80 /**< 32kHz square wave */
};
/**************************************************************************/
/*!
@brief Simple general-purpose date/time class (no TZ / DST / leap
seconds).
This class stores date and time information in a broken-down form, as a
tuple (year, month, day, hour, minute, second). The day of the week is
not stored, but computed on request. The class has no notion of time
zones, daylight saving time, or
[leap seconds](http://en.wikipedia.org/wiki/Leap_second): time is stored
in whatever time zone the user chooses to use.
The class supports dates in the range from 1 Jan 2000 to 31 Dec 2099
inclusive.
*/
/**************************************************************************/
class DateTime {
public:
DateTime(uint32_t t = SECONDS_FROM_1970_TO_2000);
DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour = 0,
uint8_t min = 0, uint8_t sec = 0);
DateTime(const DateTime &copy);
DateTime(const char *date, const char *time);
DateTime(const __FlashStringHelper *date, const __FlashStringHelper *time);
DateTime(const char *iso8601date);
bool isValid() const;
char *toString(char *buffer) const;
/*!
@brief Return the year.
@return Year (range: 2000--2099).
*/
uint16_t year() const { return 2000U + yOff; }
/*!
@brief Return the month.
@return Month number (1--12).
*/
uint8_t month() const { return m; }
/*!
@brief Return the day of the month.
@return Day of the month (1--31).
*/
uint8_t day() const { return d; }
/*!
@brief Return the hour
@return Hour (0--23).
*/
uint8_t hour() const { return hh; }
uint8_t twelveHour() const;
/*!
@brief Return whether the time is PM.
@return 0 if the time is AM, 1 if it's PM.
*/
uint8_t isPM() const { return hh >= 12; }
/*!
@brief Return the minute.
@return Minute (0--59).
*/
uint8_t minute() const { return mm; }
/*!
@brief Return the second.
@return Second (0--59).
*/
uint8_t second() const { return ss; }
uint8_t dayOfTheWeek() const;
/* 32-bit times as seconds since 2000-01-01. */
uint32_t secondstime() const;
/* 32-bit times as seconds since 1970-01-01. */
uint32_t unixtime(void) const;
/*!
Format of the ISO 8601 timestamp generated by `timestamp()`. Each
option corresponds to a `toString()` format as follows:
*/
enum timestampOpt {
TIMESTAMP_FULL, //!< `YYYY-MM-DDThh:mm:ss`
TIMESTAMP_TIME, //!< `hh:mm:ss`
TIMESTAMP_DATE //!< `YYYY-MM-DD`
};
String timestamp(timestampOpt opt = TIMESTAMP_FULL) const;
DateTime operator+(const TimeSpan &span) const;
DateTime operator-(const TimeSpan &span) const;
TimeSpan operator-(const DateTime &right) const;
bool operator<(const DateTime &right) const;
/*!
@brief Test if one DateTime is greater (later) than another.
@warning if one or both DateTime objects are invalid, returned value is
meaningless
@see use `isValid()` method to check if DateTime object is valid
@param right DateTime object to compare
@return True if the left DateTime is later than the right one,
false otherwise
*/
bool operator>(const DateTime &right) const { return right < *this; }
/*!
@brief Test if one DateTime is less (earlier) than or equal to another
@warning if one or both DateTime objects are invalid, returned value is
meaningless
@see use `isValid()` method to check if DateTime object is valid
@param right DateTime object to compare
@return True if the left DateTime is earlier than or equal to the
right one, false otherwise
*/
bool operator<=(const DateTime &right) const { return !(*this > right); }
/*!
@brief Test if one DateTime is greater (later) than or equal to another
@warning if one or both DateTime objects are invalid, returned value is
meaningless
@see use `isValid()` method to check if DateTime object is valid
@param right DateTime object to compare
@return True if the left DateTime is later than or equal to the right
one, false otherwise
*/
bool operator>=(const DateTime &right) const { return !(*this < right); }
bool operator==(const DateTime &right) const;
/*!
@brief Test if two DateTime objects are not equal.
@warning if one or both DateTime objects are invalid, returned value is
meaningless
@see use `isValid()` method to check if DateTime object is valid
@param right DateTime object to compare
@return True if the two objects are not equal, false if they are
*/
bool operator!=(const DateTime &right) const { return !(*this == right); }
protected:
uint8_t yOff; ///< Year offset from 2000
uint8_t m; ///< Month 1-12
uint8_t d; ///< Day 1-31
uint8_t hh; ///< Hours 0-23
uint8_t mm; ///< Minutes 0-59
uint8_t ss; ///< Seconds 0-59
};
/**************************************************************************/
/*!
@brief Timespan which can represent changes in time with seconds accuracy.
*/
/**************************************************************************/
class TimeSpan {
public:
TimeSpan(int32_t seconds = 0);
TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds);
TimeSpan(const TimeSpan &copy);
/*!
@brief Number of days in the TimeSpan
e.g. 4
@return int16_t days
*/
int16_t days() const { return _seconds / 86400L; }
/*!
@brief Number of hours in the TimeSpan
This is not the total hours, it includes the days
e.g. 4 days, 3 hours - NOT 99 hours
@return int8_t hours
*/
int8_t hours() const { return _seconds / 3600 % 24; }
/*!
@brief Number of minutes in the TimeSpan
This is not the total minutes, it includes days/hours
e.g. 4 days, 3 hours, 27 minutes
@return int8_t minutes
*/
int8_t minutes() const { return _seconds / 60 % 60; }
/*!
@brief Number of seconds in the TimeSpan
This is not the total seconds, it includes the days/hours/minutes
e.g. 4 days, 3 hours, 27 minutes, 7 seconds
@return int8_t seconds
*/
int8_t seconds() const { return _seconds % 60; }
/*!
@brief Total number of seconds in the TimeSpan, e.g. 358027
@return int32_t seconds
*/
int32_t totalseconds() const { return _seconds; }
TimeSpan operator+(const TimeSpan &right) const;
TimeSpan operator-(const TimeSpan &right) const;
protected:
int32_t _seconds; ///< Actual TimeSpan value is stored as seconds
};
/**************************************************************************/
/*!
@brief A generic I2C RTC base class. DO NOT USE DIRECTLY
*/
/**************************************************************************/
class RTC_I2C {
protected:
/*!
@brief Convert a binary coded decimal value to binary. RTC stores
time/date values as BCD.
@param val BCD value
@return Binary value
*/
static uint8_t bcd2bin(uint8_t val) { return val - 6 * (val >> 4); }
/*!
@brief Convert a binary value to BCD format for the RTC registers
@param val Binary value
@return BCD value
*/
static uint8_t bin2bcd(uint8_t val) { return val + 6 * (val / 10); }
Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface
uint8_t read_register(uint8_t reg);
void write_register(uint8_t reg, uint8_t val);
};
/**************************************************************************/
/*!
@brief RTC based on the DS1307 chip connected via I2C and the Wire library
*/
/**************************************************************************/
class RTC_DS1307 : RTC_I2C {
public:
bool begin(TwoWire *wireInstance = &Wire);
void adjust(const DateTime &dt);
uint8_t isrunning(void);
DateTime now();
Ds1307SqwPinMode readSqwPinMode();
void writeSqwPinMode(Ds1307SqwPinMode mode);
uint8_t readnvram(uint8_t address);
void readnvram(uint8_t *buf, uint8_t size, uint8_t address);
void writenvram(uint8_t address, uint8_t data);
void writenvram(uint8_t address, const uint8_t *buf, uint8_t size);
};
/**************************************************************************/
/*!
@brief RTC based on the DS3231 chip connected via I2C and the Wire library
*/
/**************************************************************************/
class RTC_DS3231 : RTC_I2C {
public:
bool begin(TwoWire *wireInstance = &Wire);
void adjust(const DateTime &dt);
bool lostPower(void);
DateTime now();
Ds3231SqwPinMode readSqwPinMode();
void writeSqwPinMode(Ds3231SqwPinMode mode);
bool setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode);
bool setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode);
DateTime getAlarm1();
DateTime getAlarm2();
Ds3231Alarm1Mode getAlarm1Mode();
Ds3231Alarm2Mode getAlarm2Mode();
void disableAlarm(uint8_t alarm_num);
void clearAlarm(uint8_t alarm_num);
bool alarmFired(uint8_t alarm_num);
void enable32K(void);
void disable32K(void);
bool isEnabled32K(void);
float getTemperature(); // in Celsius degree
/*!
@brief Convert the day of the week to a representation suitable for
storing in the DS3231: from 1 (Monday) to 7 (Sunday).
@param d Day of the week as represented by the library:
from 0 (Sunday) to 6 (Saturday).
@return the converted value
*/
static uint8_t dowToDS3231(uint8_t d) { return d == 0 ? 7 : d; }
};
/**************************************************************************/
/*!
@brief RTC based on the PCF8523 chip connected via I2C and the Wire library
*/
/**************************************************************************/
class RTC_PCF8523 : RTC_I2C {
public:
bool begin(TwoWire *wireInstance = &Wire);
void adjust(const DateTime &dt);
bool lostPower(void);
bool initialized(void);
DateTime now();
void start(void);
void stop(void);
uint8_t isrunning();
Pcf8523SqwPinMode readSqwPinMode();
void writeSqwPinMode(Pcf8523SqwPinMode mode);
void enableSecondTimer(void);
void disableSecondTimer(void);
void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods,
uint8_t lowPulseWidth);
void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods);
void disableCountdownTimer(void);
void deconfigureAllTimers(void);
void calibrate(Pcf8523OffsetMode mode, int8_t offset);
};
/**************************************************************************/
/*!
@brief RTC based on the PCF8563 chip connected via I2C and the Wire library
*/
/**************************************************************************/
class RTC_PCF8563 : RTC_I2C {
public:
bool begin(TwoWire *wireInstance = &Wire);
bool lostPower(void);
void adjust(const DateTime &dt);
DateTime now();
void start(void);
void stop(void);
uint8_t isrunning();
Pcf8563SqwPinMode readSqwPinMode();
void writeSqwPinMode(Pcf8563SqwPinMode mode);
};
/**************************************************************************/
/*!
@brief RTC using the internal millis() clock, has to be initialized before
use. NOTE: this is immune to millis() rollover events.
*/
/**************************************************************************/
class RTC_Millis {
public:
/*!
@brief Start the RTC
@param dt DateTime object with the date/time to set
*/
void begin(const DateTime &dt) { adjust(dt); }
void adjust(const DateTime &dt);
DateTime now();
protected:
/*!
Unix time from the previous call to now().
This, together with `lastMillis`, defines the alignment between
the `millis()` timescale and the Unix timescale. Both variables
are updated on each call to now(), which prevents rollover issues.
*/
uint32_t lastUnix;
/*!
`millis()` value corresponding `lastUnix`.
Note that this is **not** the `millis()` value of the last call to
now(): it's the `millis()` value corresponding to the last **full
second** of Unix time preceding the last call to now().
*/
uint32_t lastMillis;
};
/**************************************************************************/
/*!
@brief RTC using the internal micros() clock, has to be initialized before
use. Unlike RTC_Millis, this can be tuned in order to compensate for
the natural drift of the system clock. Note that now() has to be
called more frequently than the micros() rollover period, which is
approximately 71.6 minutes.
*/
/**************************************************************************/
class RTC_Micros {
public:
/*!
@brief Start the RTC
@param dt DateTime object with the date/time to set
*/
void begin(const DateTime &dt) { adjust(dt); }
void adjust(const DateTime &dt);
void adjustDrift(int ppm);
DateTime now();
protected:
/*!
Number of microseconds reported by `micros()` per "true"
(calibrated) second.
*/
uint32_t microsPerSecond = 1000000;
/*!
Unix time from the previous call to now().
The timing logic is identical to RTC_Millis.
*/
uint32_t lastUnix;
/*!
`micros()` value corresponding to `lastUnix`.
*/
uint32_t lastMicros;
};
#endif // _RTCLIB_H_