-
Notifications
You must be signed in to change notification settings - Fork 0
Initial Library Release #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| name: Test | ||
|
|
||
| on: ["pull_request", "push"] | ||
|
|
||
| jobs: | ||
| Test: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Cache pip | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ~/.cache/pip | ||
| key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-pip- | ||
| - name: Cache PlatformIO | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ~/.platformio | ||
| key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} | ||
| - name: Set up Python | ||
| uses: actions/setup-python@v5 | ||
| - name: Install PlatformIO | ||
| run: | | ||
| python -m pip install --upgrade pip | ||
| pip install --upgrade platformio | ||
| - name: Run PlatformIO | ||
| run: platformio ci --lib="." --board=uno --board=megaatmega2560 examples/TMP119_Example/*.ino |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # Compiled Object files | ||
| *.slo | ||
| *.lo | ||
| *.o | ||
| *.obj | ||
|
|
||
| # Precompiled Headers | ||
| *.gch | ||
| *.pch | ||
|
|
||
| # Compiled Dynamic libraries | ||
| *.so | ||
| *.dylib | ||
| *.dll | ||
|
|
||
| # Fortran module files | ||
| *.mod | ||
|
|
||
| # Compiled Static libraries | ||
| *.lai | ||
| *.la | ||
| *.a | ||
| *.lib | ||
|
|
||
| # Executables | ||
| *.exe | ||
| *.out | ||
| *.app |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| The MIT License (MIT) | ||
|
|
||
| Copyright (c) 2026 Blue Robotics | ||
|
|
||
| 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. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,77 @@ | ||
| # BlueRobotics TMP119 Temperature Sensor Library | ||
|
|
||
| Arduino library for the TMP119 temperature sensor. The TMP119 is an ultra-high-accuracy, low-power digital temperature sensor from Texas Instruments with an I2C-compatible interface. | ||
|
|
||
| # Documentation | ||
|
|
||
| Please see the examples for normal operation. Below are the available functions used in the library. | ||
|
|
||
| ``` cpp | ||
| /** Construct an instance of the sensor manager. The TMP119 supports up to four | ||
| * I2C addresses (0x48 - 0x4B), selected by the ADD0 pin; the default address | ||
| * (ADD0 to GND) is 0x48. Uses the default Wire bus if left unspecified. | ||
| * (e.g. "TMP119 mySensor;" is equivilent to "TMP119 mySensor(0x48, &Wire);") | ||
| */ | ||
| TMP119(uint8_t address = 0x48, TwoWire *wire = &Wire); | ||
|
|
||
| /** Initialize the sensor connection - return false if not detected. | ||
| * Configures the sensor for the fastest update rate (no averaging, shortest | ||
| * standby delay); call setAveraging()/setReadDelay() afterwards to override. | ||
| */ | ||
| bool init(); | ||
|
|
||
| /** Reads the latest temperature conversion from the sensor. | ||
| */ | ||
| void read(); | ||
|
|
||
| /** Temperature returned in deg C. | ||
| */ | ||
| float temperature(); | ||
|
|
||
| /** Sets the conversion averaging mode (TMP119_AVERAGE_1X, _8X, _32X, _64X). | ||
| * More averaging reduces noise but takes longer per result (1X=15.5ms, | ||
| * 8X=125ms, 32X=500ms, 64X=1s). Returns false if the I2C write fails. | ||
| */ | ||
| bool setAveraging(tmp119_average_count_t avg); | ||
|
|
||
| /** Sets the minimum standby delay between conversions in continuous-conversion | ||
| * mode (TMP119_DELAY_NONE, TMP119_DELAY_125_MS, _250_MS, _500_MS, _1000_MS, | ||
| * _4000_MS, _8000_MS, _16000_MS). Returns false if the I2C write fails. | ||
| */ | ||
| bool setReadDelay(tmp119_delay_t delay); | ||
|
|
||
| /** Reads / writes the raw 16-bit configuration register (address 0x01) | ||
| * for advanced use. | ||
| */ | ||
| uint16_t getConfig(); | ||
| bool setConfig(uint16_t config); | ||
|
|
||
| ``` | ||
|
|
||
| The TMP119 runs in continuous-conversion mode, so `read()` always returns the | ||
| latest result. `init()` configures the sensor for the fastest update rate (no | ||
| averaging, no added standby delay, ~15.5 ms cycle). To trade speed for lower | ||
| noise, call `setAveraging()` and `setReadDelay()` after `init()`. | ||
|
|
||
| `setReadDelay()` sets only the *minimum* standby delay. The actual time between | ||
| readings is the greater of the averaging time and that standby delay (datasheet | ||
| Table 8-6). For example, `TMP119_AVERAGE_64X` always yields at least a ~1 s | ||
| cycle because the averaging alone takes 1 s, regardless of the delay setting. | ||
|
|
||
| ``` cpp | ||
| TMP119 sensor; | ||
| sensor.init(); // fastest rate by default | ||
| sensor.setAveraging(TMP119_AVERAGE_64X); // 64-sample averaging | ||
| sensor.setReadDelay(TMP119_DELAY_1000_MS); // ~1 s standby between reads | ||
| ``` | ||
|
|
||
| See `examples/TMP119_Example` for a complete sketch that reads the sensor | ||
| and configures averaging and the read delay (with all options listed). | ||
|
|
||
| # Versions | ||
|
|
||
| - `1.0.0` - initial release | ||
|
|
||
| # Reference | ||
|
|
||
| You can find the [TMP119 datasheet here](https://www.ti.com/lit/ds/symlink/tmp119.pdf). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| // Copyright (c) 2026 Blue Robotics Inc. | ||
|
|
||
| #include "TMP119.h" | ||
|
|
||
| #define TMP119_TEMP_REG 0x00 | ||
| #define TMP119_CONFIG_REG 0x01 | ||
| #define TMP119_DEVICE_ID_REG 0x0F | ||
| #define TMP119_DEVICE_ID 0x2117 | ||
|
|
||
| #define TMP119_CONV_SHIFT 7 | ||
| #define TMP119_CONV_MASK 0x0380 // CONV[2:0], bits 9:7 | ||
| #define TMP119_AVG_SHIFT 5 | ||
| #define TMP119_AVG_MASK 0x0060 // AVG[1:0], bits 6:5 | ||
|
|
||
| TMP119::TMP119(uint8_t address, TwoWire *wire) { | ||
| _address = address; | ||
| _wire = wire; | ||
| } | ||
|
|
||
| bool TMP119::init() { | ||
| // Verify the device by reading its ID register | ||
| _wire->beginTransmission(_address); | ||
| _wire->write(TMP119_DEVICE_ID_REG); | ||
| _wire->endTransmission(); | ||
|
|
||
| if ( _wire->requestFrom(_address, (uint8_t)2) != 2 ) { | ||
| return false; | ||
| } | ||
|
|
||
| uint16_t id = (_wire->read() << 8) | _wire->read(); | ||
| if ( id != TMP119_DEVICE_ID ) { | ||
| return false; | ||
| } | ||
|
|
||
| // Configure for the fastest update rate: no averaging and no added standby | ||
| // delay, giving a ~15.5 ms conversion cycle (datasheet Table 8-6) | ||
| uint16_t config = getConfig(); | ||
| // Cute trick to set all the values to zero to acheive AVG = 1X, delay = none | ||
| config &= ~(TMP119_AVG_MASK | TMP119_CONV_MASK); | ||
| return setConfig(config); | ||
| } | ||
|
|
||
| void TMP119::read() { | ||
| // The TMP119 powers up in continuous-conversion mode, so the | ||
| // temperature register always holds the most recent conversion. | ||
| _wire->beginTransmission(_address); | ||
| _wire->write(TMP119_TEMP_REG); | ||
| _wire->endTransmission(); | ||
|
|
||
| _wire->requestFrom(_address, (uint8_t)2); | ||
| int16_t raw = (_wire->read() << 8) | _wire->read(); | ||
|
|
||
| // Each LSB represents 0.0078125 deg C, data is in 2's complement format | ||
| TEMP = raw * 0.0078125f; | ||
| } | ||
|
|
||
| float TMP119::temperature() { | ||
| return TEMP; | ||
| } | ||
|
|
||
| uint16_t TMP119::getConfig() { | ||
| _wire->beginTransmission(_address); | ||
| _wire->write(TMP119_CONFIG_REG); | ||
| _wire->endTransmission(); | ||
|
|
||
| _wire->requestFrom(_address, (uint8_t)2); | ||
| return (_wire->read() << 8) | _wire->read(); | ||
| } | ||
|
|
||
| bool TMP119::setConfig(uint16_t config) { | ||
| _wire->beginTransmission(_address); | ||
| _wire->write(TMP119_CONFIG_REG); | ||
| _wire->write(config >> 8); // MSB first | ||
| _wire->write(config & 0xFF); // LSB | ||
| return _wire->endTransmission() == 0; | ||
| } | ||
|
|
||
| bool TMP119::setAveraging(tmp119_average_count_t avg) { | ||
| uint16_t config = getConfig(); | ||
| config = (config & ~TMP119_AVG_MASK) | ((uint16_t)avg << TMP119_AVG_SHIFT); | ||
| return setConfig(config); | ||
| } | ||
|
|
||
| bool TMP119::setReadDelay(tmp119_delay_t delay) { | ||
| uint16_t config = getConfig(); | ||
| config = (config & ~TMP119_CONV_MASK) | ((uint16_t)delay << TMP119_CONV_SHIFT); | ||
| return setConfig(config); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| /* Blue Robotics Arduino TMP119 Temperature Sensor Library | ||
| * | ||
| * This library provides utilities to communicate with and read data from the | ||
| * Texas Instruments TMP119 high-accuracy temperature sensor. | ||
| * | ||
| * Author: Zachariah Mears, Blue Robotics Inc. | ||
| * | ||
| * SPDX-License-Identifier: MIT | ||
| * Copyright (c) 2026 Blue Robotics Inc. | ||
| */ | ||
|
|
||
| #ifndef TMP119_H_BLUEROBOTICS | ||
| #define TMP119_H_BLUEROBOTICS | ||
|
|
||
| #include "Arduino.h" | ||
| #include <Wire.h> | ||
|
|
||
| /** Conversion averaging mode (AVG[1:0], configuration register bits 6:5). | ||
| * Determines how many conversions are accumulated and averaged before the | ||
| * temperature register updates. More averaging reduces noise but takes longer | ||
| * to produce each result. The time to compute one averaged result is the | ||
| * per-mode minimum conversion time shown below (datasheet Table 8-6). | ||
| * Power-on default: TMP119_AVERAGE_8X. | ||
| */ | ||
| typedef enum { | ||
| TMP119_AVERAGE_1X, // No averaging (min conversion time 15.5 ms) | ||
| TMP119_AVERAGE_8X, // 8 conversions (min conversion time 125 ms, default) | ||
| TMP119_AVERAGE_32X, // 32 conversions (min conversion time 500 ms) | ||
| TMP119_AVERAGE_64X, // 64 conversions (min conversion time 1 s) | ||
| } tmp119_average_count_t; | ||
|
|
||
| /** Minimum standby delay inserted between conversions in continuous-conversion | ||
| * mode (CONV[2:0], configuration register bits 9:7). | ||
| * | ||
| * This is not the actual time between readings on its own. The actual | ||
| * conversion cycle time is the greater of this standby delay and the time | ||
| * needed by the selected averaging mode (see tmp119_average_count_t). For | ||
| * example, TMP119_DELAY_NONE with TMP119_AVERAGE_64X still produces a ~1 s | ||
| * cycle because the 64x average alone takes 1 s. See datasheet Table 8-6. | ||
| * | ||
| * Power-on default: TMP119_DELAY_1000_MS. | ||
| */ | ||
| typedef enum { | ||
| TMP119_DELAY_NONE, // no added standby delay | ||
| TMP119_DELAY_125_MS, | ||
| TMP119_DELAY_250_MS, | ||
| TMP119_DELAY_500_MS, | ||
| TMP119_DELAY_1000_MS, // power-on default | ||
| TMP119_DELAY_4000_MS, | ||
| TMP119_DELAY_8000_MS, | ||
| TMP119_DELAY_16000_MS, | ||
| } tmp119_delay_t; | ||
|
Comment on lines
+43
to
+52
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As the comment says. And in the datasheet:
With the default register value of:
It's possible to validate the 1s as the default value indeed, but.. There are two possible options IMO, one is to keep the current approach and having a different name for tmp119_delay_t values, maybe.. TMP119_DELAY_000
TMP119_DELAY_001
...This is not clear for the user sadly.. but at least is clear the values, and the user can use it based in the table in the datasheet... The second approach is better I believe, it requires as to read the AVG and set the delay based in desired time. typedef enum {
TMP119_DELAY_15_5_MS, // <-- Note this new name, that follows CONV 0b000 and AVG 0b00
TMP119_DELAY_125_MS,
TMP119_DELAY_250_MS,
TMP119_DELAY_500_MS,
TMP119_DELAY_1000_MS, // power-on default
TMP119_DELAY_4000_MS,
TMP119_DELAY_8000_MS,
TMP119_DELAY_16000_MS,
} tmp119_delay_t;
...
bool TMP119::setReadDelay(tmp119_delay_t delay) {
uint16_t config = getConfig();
uint8_t avg = (config & TMP119_AVG_MASK) >> TMP119_AVG_SHIFT;
switch(avg) {
case 0b00:
// Accept all delays
break;
case 0b01:
if(delay < TMP119_DELAY_125_MS) {
return false;
}
break;
case 0b10:
if(delay < TMP119_DELAY_500_MS) {
return false;
}
break;
case 0b11:
if(delay < TMP119_DELAY_1000_MS) {
return false;
}
break;
};
config = (config & ~TMP119_CONV_MASK) | ((uint16_t)delay << TMP119_CONV_SHIFT);
return setConfig(config);
}As you can see, the
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a great point, personally I prefer that the function directly sets the register (since this proposed function would cause issues if you try to set the delay before setting the averaging) but I've re-named some things and added a bunch more comments that make it more clear how this timing actually works without needing to read the datasheet. |
||
|
|
||
| class TMP119 { | ||
| public: | ||
|
|
||
| /** The TMP119 supports up to four I2C addresses (0x48 - 0x4B), selected | ||
| * by the ADD0 pin. The default address (ADD0 to GND) is 0x48. | ||
| */ | ||
| TMP119(uint8_t address = 0x48, TwoWire *wire = &Wire); | ||
|
|
||
| /** Initialize the sensor connection - returns false if not detected. | ||
| * Configures the sensor for the fastest update rate (no averaging and | ||
| * the shortest standby delay). Call setAveraging() / setReadDelay() | ||
| * afterwards to override. | ||
| */ | ||
| bool init(); | ||
|
|
||
| /** Reads the latest temperature conversion from the sensor. | ||
| */ | ||
| void read(); | ||
|
|
||
| /** Temperature returned in deg C. | ||
| */ | ||
| float temperature(); | ||
|
|
||
| /** Sets the conversion averaging mode. Returns false if the I2C write | ||
| * fails. Other configuration bits are preserved. | ||
| */ | ||
| bool setAveraging(tmp119_average_count_t avg); | ||
|
|
||
| /** Sets the minimum standby delay between conversions in | ||
| * continuous-conversion mode. Returns false if the I2C write fails. | ||
| * Other configuration bits are preserved. | ||
| */ | ||
| bool setReadDelay(tmp119_delay_t delay); | ||
|
|
||
| /** Reads the raw 16-bit configuration register (address 0x01). | ||
| */ | ||
| uint16_t getConfig(); | ||
|
|
||
| /** Writes the raw 16-bit configuration register (address 0x01). Returns | ||
| * false if the I2C write fails. Read-only bits are ignored by the device. | ||
| */ | ||
| bool setConfig(uint16_t config); | ||
|
|
||
| private: | ||
| TwoWire* _wire; | ||
| uint8_t _address; | ||
| float TEMP; | ||
|
|
||
| }; | ||
|
|
||
| #endif | ||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Over having the user to call
readandtemperatureevery time that he wants a temperature value, you can just create a single function calledgetTemperature.The reason behind the
getprefix is to follow the other functions of the class that already start withget/set.This will also make the code simpler, since you can remove a function and also a private variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking I might leave this one as-is. It's more consistent with the old library, and some other sensor libraries I've seen. I'm torn because the simplicity of one function is nice but I do like that currently tmp119.temperature(); doesn't require an I2C call and you can re-use it a bunch of times in place of needing to declare your own temperature variable.