arduino2/libraries/DS1631-master/DS1631.cpp
2020-11-06 13:17:55 +01:00

328 lines
9.3 KiB
C++

//
// DS1631.cpp
// Functions to write and read to the DS1631
// temperature sensor over I2C (two-wire)
// interface. Requires the Wire library.
//
// Created by Luke Miller on 12/30/12.
//
// Modified by Charles Galant on 06/26/15
// Modified by Benoit Debled on 09/05/16
//
// Released into the public domain.
// http://github.com/millerlp/DS1631
#include <Wire.h>
#include <DS1631.h>
// Initialize Class Variables //////////////////////////////////////////////////
int _address;
uint8_t MSByte;
uint8_t LSByte;
// The constructor. Supply the address for the
// DS1631. The base address is 1001 A2 A1 A0
// Available options should be 0 through 7, with
// 0 being the standard option when A2, A1, and A0 are
// tied to ground.
// Call with something like:
// DS1631 TempValue(0); // address 0 = A2,A1,A0 tied to ground
DS1631::DS1631(int Addr){
_address=Addr + 72; // Ground Addr 72 for DS1631
}
//*****************************************************
// Public Methods
// Tell the DS1631 to stop making temperature readings.
void DS1631::stopConversion(){
Wire.beginTransmission(_address);
Wire.write(0x22); // Stop conversion
Wire.endTransmission();
}
// Tell the DS1631 to begin making temperature readings
// If 1SHOT = True, only one temperature reading is taken.
// If 1SHOT = False, the DS1631 is in continuous mode and
// will keep making temperature readings until told to
// stop.
void DS1631::startConversion(){
Wire.beginTransmission(_address);
Wire.write(0x51); // Start conversion
Wire.endTransmission();
}
// Write to the configuration registers
// You'll primarily use this to set the
// conversion resolution (which affects
// the time taken for a reading) and whether
// the DS1631 takes continuous readings or
// goes into a low-power idle state after
// taking 1 reading (1-shot mode).
// 13 = 12 bit, 1-shot mode
// 9 = 11 bit, 1-shot mode
// 5 = 10 bit, 1-shot mode
// 1 = 9 bit, 1-shot mode
// 12 = 12 bit, continuous mode
// 8 = 11 bit, continuous mode
// 4 = 10 bit, continuous mode
// 0 = 9 bit, continuous mode
void DS1631::writeConfig(uint8_t _data){
stopConversion();
Wire.beginTransmission(_address);
Wire.write(0xAC); // AC : Access Config
Wire.write(_data);
Wire.endTransmission();
startConversion();
}
// Read the configuration registers
uint8_t DS1631::readConfig(){
uint8_t _data;
Wire.beginTransmission(_address);
Wire.write(0xAC); // AC : Access Config
Wire.endTransmission();
Wire.requestFrom(_address, 1);
if(Wire.available()) {
_data = Wire.read();
}
return _data;
}
// Set the polarity of the Tout pin
// If b is true, Tout will be active high
// Otherwise, Tout will be avtive low
void DS1631::setActiveHigh(bool b){
uint8_t config = readConfig();
if(b){
writeConfig(config | (1 << 1));
}
else{
writeConfig(config & ~(1 << 1));
}
}
// Set to One-Shot mode or Continuous Conversion Mode
void DS1631::setOneShotMode(bool b){
uint8_t config = readConfig();
if(b){
writeConfig(config | (1 << 0));
}
else{
writeConfig(config & ~(1 << 0));
}
}
// Set resolution between 9 bits and 12 bits
// 9 bits resolution will take a maximum of 93.75 ms to convert
// 10 bits resolution will take a maximum of 187.5 ms to convert
// 11 bits resolution will take a maximum of 375 ms to convert
// 12 bits resolution will take a maximum of 750 ms to convert
void DS1631::setResolution(byte res){
if(res >= 9 && res <=12){
uint8_t config = readConfig();
res = res - 9;
writeConfig(config | (res << 2));
}
}
// Request the TH temperature from the DS1631
float DS1631::readTH(){
readTemperature(0xA1);
return byteToFloat(); // return floating temperature
}
// Request the TL temperature from the DS1631
float DS1631::readTL(){
readTemperature(0xA2);
return byteToFloat();
}
// Request a temperature reading from the DS1631
void DS1631::readT(){
readTemperature(0xAA);
}
// Write the TH temperature to the DS1631
void DS1631::writeTH(float f){
writeTemperature(f, 0xA1);
}
// Write the TL temperature to the DS1631
void DS1631::writeTL(float f){
writeTemperature(f, 0xA2);
}
// Request a temperature reading from the DS1631
// The high and low bytes are saved
void DS1631::readTemperature(byte command){
Wire.beginTransmission(_address);
Wire.write(command);
Wire.endTransmission();
Wire.requestFrom(_address,2); // READ 2 bytes
Wire.available(); // 1st byte
MSByte = Wire.read(); // read a byte
Wire.available(); // 2nd byte
LSByte = Wire.read(); // read a byte
}
// Request a temperature writing to the DS1631
void DS1631::writeTemperature(float f, byte command){
floatToByte(f);
stopConversion();
Wire.beginTransmission(_address);
Wire.write(command);
Wire.write(MSByte);
Wire.write(LSByte);
Wire.endTransmission();
startConversion();
}
// Read the temperature and return a floating point
// temperature value, in degrees Celsius
float DS1631::readTempF(){
readT();
return byteToFloat();
}
// Conversion of a temperature (2 bytes) to a float
float DS1631::byteToFloat(){
double T;
// T° processing. Shift the LSByte right 4 positions
// The resulting binary value, converted to base-10
// and multiplied by 0.0625, is the decimal part of
// the temperature.
LSByte = LSByte>>4;
// The MSByte (8 bits), converted to base-10,
// represents the whole number portion of the
// temperature. When the left-most bit is 1,
// this represents the special case of a
// negative temperature value, so you must
// subtract off 256 to get the whole number
// value.
// Negative temperature fix contributed by Jürgen Thierry
if(MSByte>=0x80)
{ //if sign bit is set
float negMSByte = MSByte - 256;
T = (float)negMSByte + (float)LSByte*0.0625;
return T;
}
// Combine the whole number and fractional
// parts of the temperature
T = (float) MSByte + (float) LSByte*0.0625;
return T;
}
// Conversion of a float temperature to the 2 bytes register
// format (see figure 4 in datasheet)
void DS1631::floatToByte(float f){
MSByte = int(f);
LSByte = int((f - int(f))/0.0625);
LSByte = LSByte<<4;
}
// Read the temperature in 1-shot mode, with a
// wait built in so that the temperature
// has time to update. This isn't necessary when
// using the continuous measuring mode.
float DS1631::readTempOneShot(){
long lastMillis = millis();
float T;
// Send command to start taking temperature reading
startConversion();
// Now wait for the configuration register's
// most significant bit to be returned as 1,
// indicating that the reading is done. A 12-bit
// reading can take up to 750 milliseconds
while ( !conversionDone() ) {
// Wait a little while before checking
// the configuration register again
long elapsed = 0;
while (elapsed < 50) {
elapsed = millis() - lastMillis;
}
if(elapsed > 1000){
// Abort polling if conversion takes more
// than 1000ms. Instead return integer minimum.
return -32768;
}
}
// Once the temperature conversion is done,
// read the value from the DS1631
T = readTempF();
// After reading the temperature, put the
// DS1631 back into low-power idle state.
stopConversion();
return T;
}
// Read the temperature in 1-shot mode and
// return an integer composed of the MSByte
// and LSByte returned from the DS1631, stored
// in two's complement format. The integer
// would be the most compact way of storing the
// temperature data, since it can be stored in
// two bytes.
uint16_t DS1631::readTempOneShotInt(){
long lastMillis = millis();
uint16_t T;
startConversion();
while ( !conversionDone() ){
// Wait a little while before checking
// the configuration register again
long elapsed = 0;
while (elapsed < 50) {
elapsed = millis() - lastMillis;
}
if(elapsed > 1000){
// Abort polling if conversion takes more
// than 1000ms. Instead return integer minimum.
return -32768;
}
}
readT(); // Get MSByte and LSByte
T = word(MSByte,LSByte);
return T;
// If you take the integer and split it
// back into its highByte and lowByte using
// the highByte() and lowByte() functions of
// Arduino, you can quickly calculate the
// temperature using the rules outlined above
// in the readTempF() function.
}
// Read the temperature and return a double value
// If you divide the returned double value by 16,
// you get the temperature value in °C
int32_t DS1631::readTempD(){ // 1/16°C = 12 Bit accuracy 0.0625°C
int T_dec;
int32_t T;
readT();
T=((int32_t)MSByte << 8) + LSByte;
// T° processing
if(T >= 0x8000){ // If sign bit is set, then temp is negative
T = T - 0xFFFF;
}
T = T >>4;
return T;
}
// Check if the temperature reading (Conversion) is
// finished. 12-bit readings take up to 750ms.
bool DS1631::conversionDone(){ // if Conversion Done = Boolean = True
uint8_t _data = readConfig();
// This OR's the _data value with 127 (b01111111)
// If the most significant bit is 1, the result
// is 255 (b11111111)
if ((_data | 127)==255)
return true;
else
return false;
}