{"id":13894184,"url":"https://github.com/RobTillaart/ADS1X15","last_synced_at":"2025-07-17T09:31:10.995Z","repository":{"id":37412333,"uuid":"283840909","full_name":"RobTillaart/ADS1X15","owner":"RobTillaart","description":"Arduino library for ADS1015 = I2C 12 bit ADC and ADS1115 = I2C 16 bit ADC","archived":false,"fork":false,"pushed_at":"2025-07-07T14:29:43.000Z","size":241,"stargazers_count":187,"open_issues_count":4,"forks_count":39,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-07-07T14:52:52.353Z","etag":null,"topics":["adc","comparator-mode","differential-measurements"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RobTillaart.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"RobTillaart","custom":"https://www.paypal.me/robtillaart"}},"created_at":"2020-07-30T17:49:28.000Z","updated_at":"2025-06-19T11:35:43.000Z","dependencies_parsed_at":"2024-06-29T09:44:43.910Z","dependency_job_id":"5924443f-7bd6-4f2f-b703-aad2d2998ed4","html_url":"https://github.com/RobTillaart/ADS1X15","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/RobTillaart/ADS1X15","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FADS1X15","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FADS1X15/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FADS1X15/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FADS1X15/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RobTillaart","download_url":"https://codeload.github.com/RobTillaart/ADS1X15/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FADS1X15/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265589087,"owners_count":23793465,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adc","comparator-mode","differential-measurements"],"created_at":"2024-08-06T18:01:26.005Z","updated_at":"2025-07-17T09:31:10.981Z","avatar_url":"https://github.com/RobTillaart.png","language":"C++","funding_links":["https://github.com/sponsors/RobTillaart","https://www.paypal.me/robtillaart"],"categories":["C++"],"sub_categories":[],"readme":"\n[![Arduino CI](https://github.com/RobTillaart/ADS1X15/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)\n[![Arduino-lint](https://github.com/RobTillaart/ADS1X15/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/ADS1X15/actions/workflows/arduino-lint.yml)\n[![JSON check](https://github.com/RobTillaart/ADS1X15/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/ADS1X15/actions/workflows/jsoncheck.yml)\n[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/ADS1X15.svg)](https://github.com/RobTillaart/ADS1X15/issues)\n\n[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/ADS1X15/blob/master/LICENSE)\n[![GitHub release](https://img.shields.io/github/release/RobTillaart/ADS1X15.svg?maxAge=3600)](https://github.com/RobTillaart/ADS1X15/releases)\n[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/ADS1X15.svg)](https://registry.platformio.org/libraries/robtillaart/ADS1X15)\n\n\n# ADS1X15\n\nArduino library for I2C ADC ADS1015, ADS1115, and similar.\n\nFor using I2C ADC with Raspberry pi or other SBC with Linux OS,\nyou can check similar library [here](https://github.com/chandrawi/ADS1x15-ADC).\n\n\n## Description\n\nThis library should work for the devices mentioned below,\nalthough not all sensors support all functionality.\n\n|  Device   |  Channels  |  Resolution  |  Max SPS  |  Comparator  |  Interrupts  |  ProgGainAMP  |  Notes   |\n|:---------:|:----------:|:------------:|:---------:|:------------:|:------------:|:-------------:|:---------|\n|  ADS1013  |      1     |       12     |    3300   |       N      |       N      |        N      |          |\n|  ADS1014  |      1     |       12     |    3300   |       Y      |       Y      |        Y      |          |\n|  ADS1015  |      4     |       12     |    3300   |       Y      |       Y      |        Y      |          |\n|  ADS1113  |      1     |       16     |    860    |       N      |       N      |        N      |          |\n|  ADS1114  |      1     |       16     |    860    |       Y      |       Y      |        Y      |          |\n|  ADS1115  |      4     |       16     |    860    |       Y      |       Y      |        Y      |  Tested  |\n\n\nAs the **ADS1015** and the **ADS1115** are both 4 channels these are the most\ninteresting from functionality point of view as these can do\ndifferential measurements.\n\n\n### Interrupts\n\nBesides polling the **ADS1x14** and **ADS1x15** support interrupts to maximize throughput\nwith minimal latency. For this these device has an ALERT/RDY pin.\nThis pin can be used both for interrupts or polling, see table of examples below.\n\n|   example                         |  Interrupts  |  notes  |\n|:---------------------------------:|:------------:|:-------:|\n|  ADS_1114_two_continuous.ino      |      Y       |\n|  ADS_continuous_3_channel.ino     |      Y       |\n|  ADS_continuous_4_channel.ino     |      Y       |\n|  ADS_continuous_8_channel.ino     |      Y       |\n|  ADS_continuous_differential.ino  |      Y       |\n|  ADS_high_speed_differential.ino  |      Y       |\n|  ADS_read_async_rdy.ino           |   polling    |\n|  ADS_read_RDY.ino                 |   polling    |\n\n\nThe examples of this library all use the **RISING** edge for the interrupt detection\nof the **ALERT / RDY** pin.\nIn https://github.com/RobTillaart/ADS1X15/issues/87 it is observed that the **FALLING**\nedge gave far more stable results for the application used (determine True RMS).\nThis effect can not be explained as the edges are only 8 us apart.\nThus changing the edge to **FALLING** might improve your measurements too.\n\nDatasheet section 7.3.8 Conversion ready pin, figure 7-8 indicates using\nthe **FALLING** edge as the moment the conversion is ready.\n\n\nejdp62 explained the detailed behaviour of the ALERT / RDY pin\nSee https://github.com/RobTillaart/ADS1X15/issues/87#issuecomment-2988617290\n\n_As the **ALERT/RDY** pin is open collector, the rising edges of the output signal \nand the falling edges of the output signal are quite different! \nAll the scope pictures show this difference. \n**The falling edges are much more clearly defined, because the signal \nis actively pulled low**, whereas it is only passively pulled high. \nAnd that is true regardless of the polarity chosen, as it is a consequence \nof the output cell in the chip (open collector driver), and not of the signal \nthat the I/O cell is passing to the ready pin. I think this does explain all \nobservations made._\n\n_Now that the data sheet has been updated to explicitly show that the conversion \nis ready on the second slope of the pulse, it is clear what to do best: \nset the polarity such that that second slope is falling (as that is the superior direction), \nand use that one to trigger the interrupt. \nIt may be appropriate to adapt the code in the library to implement only that choice, \nas it will indeed give the best results._\n\n\n### 0.5.0 Breaking change\n\nFixed #80, setComparatorPolarity() and setComparatorLatch() as these inverted\nthe setting.\n\n\n### 0.4.0 Breaking change\n\nVersion 0.4.0 introduced a breaking change.\nYou cannot set the pins in **begin()** any more.\nThis reduces the dependency of processor dependent Wire / I2C implementations.\nThe user has to call **Wire.begin()** and can optionally set the I2C pins\nbefore calling **begin()**.\n\n\n### Related\n\n- https://github.com/RobTillaart/AD7367 2 channel simultaneous 14 bit ADC.\n- https://github.com/RobTillaart/ADC081S 10-12 bit, single channel ADC\n- https://github.com/RobTillaart/ADC08XS 10-12 bit, 2 + 4 channel ADC\n- https://gammon.com.au/adc tutorial about ADC's (UNO specific)\n- https://github.com/RobTillaart/MCP_ADC 10-12 bit, 1,2,4,8 channel ADC\n- https://github.com/RobTillaart/ADS1x15\n- https://github.com/RobTillaart/PCF8591 8 bit single ADC (+ 1 bit DAC)\n- https://github.com/RobTillaart/AD5593R 8 channel ADC / DAC / GPIO device.\n\n\n## I2C Address\n\nThe I2C address of the ADS1113 /14 /15 is determined by to which pin\nthe **ADDR** is connected to:\n\n|  ADDR pin connected to  |  Address  |  Notes    |\n|:-----------------------:|:---------:|:---------:|\n|        GND              |   0x48    |  default  |\n|        VDD              |   0x49    |           |\n|        SDA              |   0x4A    |           |\n|        SCL              |   0x4B    |           |\n\n\n### I2C multiplexing\n\nSometimes you need to control more devices than possible with the default\naddress range the device provides.\nThis is possible with an I2C multiplexer e.g. TCA9548 which creates up\nto eight channels (think of it as I2C subnets) which can use the complete\naddress range of the device.\n\nDrawback of using a multiplexer is that it takes more administration in\nyour code e.g. which device is on which channel.\nThis will slow down the access, which must be taken into account when\ndeciding which devices are on which channel.\nAlso note that switching between channels will slow down other devices\ntoo if they are behind the multiplexer.\n\n- https://github.com/RobTillaart/TCA9548\n\n\n## Interface\n\n```cpp\n#include \"ADS1X15.h\"\n```\n\n### Initializing\n\nTo initialize the library you must call a constructor as described below.\n\n- **ADS1x15()** base constructor, should not be used.\n- **ADS1013(uint8_t address, TwoWire \\*wire = \u0026Wire)** Constructor with device address,\nand optional the Wire interface as parameter.\n- **ADS1014(uint8_t address, TwoWire \\*wire = \u0026Wire)** Constructor with device address,\nand optional the Wire interface as parameter.\n- **ADS1015(uint8_t address, TwoWire \\*wire = \u0026Wire)** Constructor with device address,\nand optional the Wire interface as parameter.\n- **ADS1113(uint8_t address, TwoWire \\*wire = \u0026Wire)** Constructor with device address,\nand optional the Wire interface as parameter.\n- **ADS1114(uint8_t address, TwoWire \\*wire = \u0026Wire)** Constructor with device address,\nand optional the Wire interface as parameter.\n- **ADS1115(uint8_t address, TwoWire \\*wire = \u0026Wire)** Constructor with device address,\nand optional the Wire interface as parameter.\n\n\nAfter construction the **ADS.begin()** must be called, typical in **setup()**.\n\n- **bool begin()** Returns false if an invalid address is used.\n- **bool isConnected()** is used to check if the device address is visible on I2C.\n- **void reset()** sets the internal parameters to their initial value as\nin the constructor.\n\nFor example.\n\n```cpp\n  #include \"ADS1X15.h\"\n\n  //  initialize ADS1115 on I2C bus 1 with default address 0x48\n  ADS1115 ADS(0x48);\n\n  void setup()\n  {\n    if (!ADS.begin())\n    {\n      //  invalid address ADS1115 or 0x48 not found\n    }\n    if (!ADS.isConnected())\n    {\n      //  address 0x48 not found\n    }\n  }\n```\n\n\n### I2C clock speed\n\nThe function **void setWireClock(uint32_t speed = 100000)** is used to set the clock speed\nin Hz of the used I2C interface. Typical value is 100 KHz.\n\nThe function **uint32_t getWireClock()** is a prototype.\nIt returns the value set by setWireClock().\nThis is not necessary the actual value.\nWhen no value is set **getWireClock()** returns 0.\nNeed to implement a read / calculate from low level I2C code (e.g. TWBR on AVR),\nbetter the Arduino Wire lib should support this call (ESP32 does).\n\nSee - https://github.com/arduino/Arduino/issues/11457\n\nQuestion: Should this functionality be in this library?\n\n\n### Programmable Gain\n\n- **void setGain(uint8_t gain)** set the gain value, indicating the maxVoltage that can be measured\nAdjusting the gain allowing to make more precise measurements.\nNote: the gain is not set in the device until an explicit read/request of the ADC (any read call will do).\nSee table below.\n- **uint8_t getGain()** returns the gain value (index).\n\n|  define               |  PGA value  |  Max Voltage  |   Notes   |\n|:---------------------:|:-----------:|:-------------:|:---------:|\n|  ADS1X15_GAIN_6144MV  |      0      |    ±6.144V    |  default  |\n|  ADS1X15_GAIN_4096MV  |      1      |    ±4.096V    |           |\n|  ADS1X15_GAIN_2048MV  |      2      |    ±2.048V    |           |\n|  ADS1X15_GAIN_1024MV  |      4      |    ±1.024V    |           |\n|  ADS1X15_GAIN_0512MV  |      8      |    ±0.512V    |           |\n|  ADS1X15_GAIN_0256MV  |      16     |    ±0.256V    |           |\n\n\n- **float getMaxVoltage()** returns the max voltage with the current gain.\n- **float toVoltage(float raw = 1)** converts a raw measurement to a voltage.\nCan be used for normal and differential measurements.\nThe default value of 1 returns the conversion factor for any raw number.\nThe parameter is made float to allow the average of multiple raw measurements\nto be converted.\n\nThe voltage factor can also be used to set HIGH and LOW threshold registers\nwith a voltage in the comparator mode.\nCheck the [examples](https://github.com/RobTillaart/ADS1X15/blob/master/examples/ADS_read_comparator_1/ADS_read_comparator_1.ino).\n\n```cpp\n  float f = ADS.toVoltage();\n  ADS.setComparatorThresholdLow( 3.0 / f );\n  ADS.setComparatorThresholdHigh( 4.3 / f );\n```\n\n\n### Operational mode\n\nThe ADS sensor can operate in single shot or continuous mode.\nDepending on how often conversions needed you can tune the mode.\n\n- **void setMode(uint8_t mode)** 0 = CONTINUOUS, 1 = SINGLE (default)\nNote: the mode is not set in the device until an explicit read/request of the ADC\n(any successful read() call will do).\n- **uint8_t getMode()** returns current mode 0 or 1, or ADS1X15_INVALID_MODE = 0xFE.\n\n|  define                   |  value  |   Notes   |\n|:-------------------------:|:-------:|:---------:|\n|  ADS1X15_MODE_CONTINUOUS  |    0    |           |\n|  ADS1X15_MODE_SINGLE      |    1    |  default  |\n\n\n### Data rate\n\n- **void setDataRate(uint8_t dataRate)** Data rate depends on type of device.\nFor all devices the index 0..7 can be used, see table below.\nValues above 7 ==\u003e will be set to the default 4.\nNote: the data rate is not set in the device until an explicit read/request of the ADC (any read call will do).\n- **uint8_t getDataRate()** returns the current data rate (index).\n\nThe library has no means to convert this index to the actual numbers\nas that would take 32 bytes.\n\nData rate in samples per second, based on datasheet is described on table below.\n\n|  define              |  data rate  |  ADS101x  |  ADS111x  |   Notes   |\n|:--------------------:|:-----------:|----------:|----------:|:---------:|\n|  ADS1X15_DATARATE_0  |     0       |   128     |    8      |  slowest  |\n|  ADS1X15_DATARATE_1  |     1       |   250     |    16     |           |\n|  ADS1X15_DATARATE_2  |     2       |   490     |    32     |           |\n|  ADS1X15_DATARATE_3  |     3       |   920     |    64     |           |\n|  ADS1X15_DATARATE_4  |     4       |   1600    |    128    |  default  |\n|  ADS1X15_DATARATE_5  |     5       |   2400    |    250    |           |\n|  ADS1X15_DATARATE_6  |     6       |   3300    |    475    |           |\n|  ADS1X15_DATARATE_7  |     7       |   3300    |    860    |  fastest  |\n\n\n### ReadADC Single mode\n\nReading the ADC is very straightforward, the **readADC()** function handles all in one call.\nUnder the hood it uses the asynchronous calls.\n\n- **int16_t readADC(uint8_t pin = 0)** normal ADC functionality, pin = 0..3.\nIf the pin number is out of range, this function will return 0 (seems safest).\nDefault pin = 0 as this is convenient for the single channel devices.\n\n```cpp\n  //  read ADC in pin 2\n  ADS.readADC(2);\n\n  //  read ADC in pin 0 - two ways\n  ADS.readADC();\n  ADS.readADC(0);\n```\n\n\nSee [examples](https://github.com/RobTillaart/ADS1X15/blob/master/examples/ADS_minimum/ADS_minimum.ino).\n\nThe **readADC()** can return **ADS1X15_ERROR_TIMEOUT (-101)** which is an errorcode.\nThis may conflict with a possible actual value of -101.\nTherefore the user should check with **getError()** if an error has occurred after reading the ADC.\n\n```cpp\n   Value = ADS.readADC()\n   if (ADS.getError() == ADS1X15_OK)\n      //  Use value\n   else\n      //  handle error\n```\n\nThe error handling within the library need to be improved, see also issue #84.\n\n\n### Read the ADC in asynchronous way\n\nTo read the ADC in an asynchronous way (e.g. to minimize blocking) you need call three functions:\n\n- **void requestADC(uint8_t pin = 0)**  Start the conversion. pin = 0..3.\nDefault pin = 0 as this is convenient for 1 channel devices.\n- **bool isBusy()** Is the conversion not ready yet? Works only in SINGLE mode!\n- **bool isReady()** Is the conversion ready? Works only in SINGLE mode!  (= wrapper around **isBusy()** )\n- **int16_t getValue()** Read the result of the conversion.\n\n\nin terms of code:\n\n```cpp\n  void setup()\n  {\n    //  other setup things here\n    ADS.setMode(ADS1X15_MODE_SINGLE);\n    ADS.requestADC(pin);\n  }\n\n  void loop()\n  {\n    if (ADS.isReady())\n    {\n      value = ADS.getValue();\n      ADS.requestADC(pin);       //  request new conversion\n    }\n    //  do other things here\n  }\n```\nSee [examples](https://github.com/RobTillaart/ADS1X15/blob/master/examples/ADS_read_async/ADS_read_async.ino).\n\n\n### ReadADC Differential\n\nFor reading the ADC in a differential way there are 4 calls possible.\n\n- **int16_t readADC_Differential_0_1()** returns the difference between 2 ADC pins.\n- **int16_t readADC_Differential_0_3()** ADS1x15 only\n- **int16_t readADC_Differential_1_3()** ADS1x15 only\n- **int16_t readADC_Differential_2_3()** ADS1x15 only\n- **int16_t readADC_Differential_0_2()** ADS1x15 only - in software (no async equivalent)\n- **int16_t readADC_Differential_1_2()** ADS1x15 only - in software (no async equivalent)\n\n```cpp\n  //  read differential ADC between pin 0 and 1\n  ADS.readADC_Differential_0_1(0);\n```\n\nThe differential reading of the ADC can also be done with asynchronous calls.\n\n- **void requestADC_Differential_0_1()** starts conversion for differential reading\n- **void requestADC_Differential_0_3()** ADS1x15 only\n- **void requestADC_Differential_1_3()** ADS1x15 only\n- **void requestADC_Differential_2_3()** ADS1x15 only\n\nAfter one of these calls you need to call\n- **int16_t getValue()** Read the result of the last conversion.\n\nSee [examples](https://github.com/RobTillaart/ADS1X15/blob/master/examples/ADS_differential/ADS_differential.ino).\n\n\n### lastRequestMode\n\nSince 0.3.12 the library tracks the last request mode, single pin or differential.\nThis variable is set at the moment of request, and keeps its value until a new\nrequest is made. This implies that the value / request can be quite old.\n\nValues \u003e= 0x10 are differential, values \u003c 0x10 are single pin.\n\n- **uint8_t lastRequest()** returns one of the values below.\n\n|  Value  |  Description                 |  Notes  |\n|:-------:|:-----------------------------|:--------|\n|  0xFF   |  no (invalid) request made   |  after call constructor.\n|  0x00   |  single pin 0                |\n|  0x01   |  single pin 1                |\n|  0x02   |  single pin 2                |\n|  0x03   |  single pin 3                |\n|  0x10   |  differential pin 1 0        |\n|  0x30   |  differential pin 3 0        |\n|  0x31   |  differential pin 3 1        |\n|  0x32   |  differential pin 3 2        |\n\n\nPlease note that (for now) the function does not support a descriptive return value\nfor the following two requests:\n- **readADC_Differential_0_2()** ADS1x15 only - in software (no async equivalent)\n- **readADC_Differential_1_2()** ADS1x15 only - in software (no async equivalent)\n\nAs these are emulated in software by two single pin calls, the state would be\none of the two single pin values.\n\n\n### ReadADC continuous mode\n\nTo use the continuous mode you need call three functions:\n\n- **void setMode(0)** 0 = CONTINUOUS, 1 = SINGLE (default).\nNote: the mode is not set in the device until an explicit read/request of the ADC (any read call will do).\n- **int16_t readADC(uint8_t pin)** or **void requestADC(uint8_t pin)** to get the continuous mode started.\n- **int16_t getValue()** to return the last value read by the device.\nNote this can be a different pin, so be warned.\nCalling this over and over again can give the same value multiple times.\n\n```cpp\n  void setup()\n  {\n    //  configuration things here\n    ADS.setMode(ADS1X15_MODE_CONTINUOUS);\n    //  request on pin 0\n    ADS.requestADC(0);\n  }\n\n  void loop()\n  {\n    value = ADS.getValue()\n    sleep(1)\n  }\n```\n\nSee [examples](https://github.com/RobTillaart/ADS1X15/blob/master/examples/ADS_continuous/ADS_continuous.ino)\n.\nBy using **bool isBusy()** or **bool isReady()** one can wait until new data is available.\nNote this only works in the SINGLE_SHOT modus.\n\nIn continuous mode, you can't use **isBusy()** or **isReady()** functions to wait until new data available.\nInstead you can configure the threshold registers to allow the **ALERT/RDY**\npin to trigger an interrupt signal when conversion data ready.\n\n\n### Switching mode or channel during continuous mode\n\nWhen switching the operating mode or the ADC channel in continuous mode, be aware that\nthe device will always finish the running conversion.\nThis implies that after switching the mode or channel the first sample you get is probably\nthe last sample with the previous settings, e.g. channel.\nThis might be a problem for your project as this value can be in an \"unexpected\" range (outlier).\n\nThe robust way to change mode or channel therefore seems to be:\n\n1. stop continuous mode,\n1. wait for running conversion to be ready,\n1. reject the last conversion or process it \"under old settings\",\n1. change the settings,\n1. restart (continuous mode) with the new settings.\n\nThis explicit stop takes extra time, however it should prevent \"incorrect\" readings.\n\n(need to be verified with different models)\n\n\n### Threshold registers\n\n(datasheet 9.3.8)  \n_Conversion Ready Pin (ADS1114 and ADS1115 Only)\nThe ALERT/RDY pin can also be configured as a conversion ready pin. Set the most-significant bit of the\nHi_thresh register to 1 and the most-significant bit of Lo_thresh register to 0 to enable the pin as a conversion\nready pin._\n\n\nIf the thresholdHigh is set to 0x8000 and the thresholdLow to 0x0000\nthe **ALERT/RDY** pin is triggered when a conversion is ready.\n\n- **void setComparatorThresholdLow(int16_t lo)** writes value to device directly.\n- **void setComparatorThresholdHigh(int16_t hi)** writes value to device directly.\n- **int16_t getComparatorThresholdLow()** reads value from device.\n- **int16_t getComparatorThresholdHigh()** reads value from device.\n\nSee [examples](https://github.com/RobTillaart/ADS1X15/blob/master/examples/ADS_read_RDY/ADS_read_RDY.ino).\n\n\n### Comparator\n\nPlease read Page 15 of the datasheet as the behaviour of the\ncomparator is not trivial.\n\nNOTE: all comparator settings are copied to the device only after calling\n**readADC()** or **requestADC()** functions.\n\n\n### Comparator Mode\n\nWhen configured as a **TRADITIONAL** comparator, the **ALERT/RDY** pin asserts\n(active low by default) when conversion data exceed the limit set in the\nhigh threshold register. The comparator then de-asserts when the input\nsignal falls below the low threshold register value.\n\n- **void setComparatorMode(uint8_t mode)** value 0 = TRADITIONAL 1 = WINDOW,\n- **uint8_t getComparatorMode()** returns value set.\n\n|  define                         |  value  |   Notes   |\n|:-------------------------------:|:-------:|:---------:|\n|  ADS1x15_COMP_MODE_TRADITIONAL  |    0    |           |\n|  ADS1x15_COMP_MODE_WINDOW       |    1    |           |\n\n\nIf the comparator **LATCH** is set, the **ALERT/RDY** pin asserts and it will be\nreset after reading the sensor (conversion register) again.\n*An SMB alert command (00011001) on the I2C bus will also reset the alert state.*\n*Not implemented in the library (yet)*\n\nIn **WINDOW** comparator mode, the **ALERT/RDY** pin asserts if conversion data exceeds\nthe high threshold register or falls below the low threshold register.\nIn this mode the alert is held if the **LATCH** is set. This is similar as above.\n\n\n### Polarity\n\nDefault state of the **ALERT/RDY** pin is **LOW**, which can be to set **HIGH**.\n\n- **void setComparatorPolarity(uint8_t pol)**\nFlag is only explicitly set after a **readADC()** or a **requestADC()**\n- **uint8_t getComparatorPolarity()** returns value set.\n\n|  define                         |  value  |   Notes   |\n|:-------------------------------:|:-------:|:---------:|\n|  ADS1x15_COMP_POL_FALLING_EDGE  |    0    |           |\n|  ADS1x15_COMP_POL_RISING_EDGE   |    1    |           |\n\n\nFrom tests (see #76) it became clear that the behaviour of the **ALERT/RDY** pin\nlooks ambiguous. Further investigation eventually showed that the behaviour is\nlogical but one should not think in \"pulses\", more in levels and edges.\n\nIn the continuous mode it looks like an 8us pulse, however this \"pulse\" is\nactual a short time (8 us) of IDLE followed by a long time pulse of converting.\n\nIn the single shot mode it looks like the converting time is the pulse\nas that is the only single change visible. This is IMHO the correct view.\n\n\n#### ALERT RDY table\n\n|  MODE          |  COMP_POL  |  CONVERT  |  COMPLETING  |   READY   |\n|:---------------|:-----------|:----------|:-------------|:----------|\n| 0 = continuous |  0 = LOW   |  LOW      |   RISING     |  FALLING  |\n| 0 = continuous |  1 = HIGH  |  HIGH     |   FALLING    |  RISING   |\n| 1 = single     |  0 = LOW   |  LOW      |   RISING     |  FALLING  |\n| 1 = single     |  1 = HIGH  |  HIGH     |   FALLING    |  RISING   |\n\n\nSee issue #76 and #87 for some screenshots with an oscilloscope.\nFurthermore #87 gives an explanation why to prefer the FALLING edges (from ejdp62).\nSee also above in description section.\n\nSee also [Rev. D data sheet, Page 17 Figure 7-8 Conversion Ready Pulse in Continuous-Conversion Mode](https://www.ti.com/lit/ds/symlink/ads1115.pdf)\n\n\n#### Converting time by Data Rate\n\n|  data rate  |  convert time  |  Notes  |\n|:-----------:|:--------------:|:-------:|\n|      0      |     125 ms     |\n|      1      |      62 ms     |\n|      2      |      32 ms     |\n|      3      |      16 ms     |\n|      4      |       8 ms     |  default, see in table above.\n|      5      |     4.4 ms     |\n|      6      |     2.4 ms     |\n|      7      |     1.2 ms     |\n\nTimes are estimates from scope.\n\n\n#### Conclusions\n\n- Conversion generates a conversion pulse with length depending on the data rate.\n- In continuous mode it looks like there is a short pulse, but actual the long\n  period is the conversion pulse.\n\nIn short:\n\n- if COMP_POL == 0,\n  - a LOW level indicates converting.\n  - a RISING edge indicates conversion completing.\n  - a FALLING edge indicates conversion ready.\n\n- if COMP_POL == 1,\n  - a HIGH level indicates converting.\n  - a FALLING edge indicates conversion completing.\n  - a RISING edge indicates conversion ready.\n\nThis interpretation is in line with all tests done in #76 and #87.\n\nSee also [Rev. D data sheet, Page 17 Figure 7-8 Conversion Ready Pulse in Continuous-Conversion Mode](https://www.ti.com/lit/ds/symlink/ads1115.pdf)\n\n\n### Latch\n\nHolds the **ALERT/RDY** to **HIGH** (or **LOW** depending on polarity) after triggered\neven if actual value has been 'restored to normal' value.\n\n- **void setComparatorLatch(uint8_t latch)** 0 = NO LATCH, not 0 = LATCH\n- **uint8_t getComparatorLatch()** returns value set.\n\n|  define                    |  value  |   Notes   |\n|:--------------------------:|:-------:|:---------:|\n|  ADS1x15_COMP_POL_NOLATCH  |    0    |           |\n|  ADS1x15_COMP_POL_LATCH    |    1    |           |\n\n\nThe (no-)latch is not verified in detail yet.\n\n\n### QueConvert\n\nSet the number of conversions before trigger activates.\n\nThe **void setComparatorQueConvert(uint8_t mode)** is used to set the number of\nconversions that exceed the threshold before the **ALERT/RDY** pin is set **HIGH**.\nA value of 3 (or above) effectively disables the comparator. See table below.\n\nSee [examples](https://github.com/RobTillaart/ADS1X15/blob/master/examples/ADS_continuous_differential/ADS_continuous_differential.ino).\n\n- **void setComparatorQueConvert(uint8_t mode)** See table below.\n- **uint8_t getComparatorQueConvert()**  returns the value set.\n\n|  value  |  meaning                            |  Notes    |\n|:-------:|:------------------------------------|:----------|\n|    0    |  trigger alert after 1 conversion   |           |\n|    1    |  trigger alert after 2 conversions  |           |\n|    2    |  trigger alert after 4 conversions  |           |\n|    3    |  Disable comparator                 |  default  |\n|  other  |  Disable comparator                 |           |\n\nTo enable the conversion-ready function of the **ALERT/RDY** pin,\nit is necessary to set the MSB of the Hi_threshold register to 1 (value 0x8000)\nand the MSB of the Lo_threshold register to 0.\nSee section **Threshold registers** above.\n\n\n### Threshold registers comparator mode\n\nDepending on the comparator mode **TRADITIONAL** or **WINDOW** the thresholds registers\nmean something different see - Comparator Mode above or datasheet.\n\n- **void setComparatorThresholdLow(int16_t lo)** set the low threshold; take care the hi \u003e= lo.\n- **void setComparatorThresholdHigh(int16_t hi)**  set the high threshold; take care the hi \u003e= lo.\n- **int16_t getComparatorThresholdLow()** reads value from device.\n- **int16_t getComparatorThresholdHigh()** reads value from device.\n\n\n## Error codes\n\nThis section has to be elaborated.\n\nSome functions return or set an error value.\nThis is read and reset by **getError()**.\n\n|  Value  |  Define                   |  Description  |\n|:-------:|:-------------------------:|:-------------:|\n|      0  |  ADS1X15_OK               | idem.\n|   -100  |  ADS1X15_INVALID_VOLTAGE  | getMaxVoltage()\n|   -101  |  ADS1X15_ERROR_TIMEOUT    | readADC() device did not respond in time.\n|   -102  |  ADS1X15_ERROR_I2C        | I2C communication failure.\n|   0xFF  |  ADS1X15_INVALID_GAIN     | getGain()\n|   0xFE  |  ADS1X15_INVALID_MODE     | getMode()\n\n\n## Experimental\n\n- **uint16_t getMaxRegValue()** returns 32767 or 2047 depending on ADC bits. (See #91).\n\n\n## Future ideas \u0026 improvements\n\n#### Must\n\n- Improve documentation (always)\n  - split off separate topics?\n\n#### Should\n\n- Investigate ADS1118 library which should be a similar SPI based ADC.\n- improve error handling\n  - refactor values to be more logic.\n- improve API. https://github.com/RobTillaart/ADS1X15/issues/84\n  - (big) breaking change!\n\n#### Could\n\n- SMB alert command (00011001) on I2C bus?\n- Sync code order .h / .cpp\n\n#### Wont (unless requested)\n\n- Type flag?\n- Constructor for ADS1X15? No as all types are supported.\n- Remove **getWireClock()** as this is not an ADC library function\n  but a responsibility of the I2C library. Until fixed in Wire I leave it.\n\n\n## Support\n\nIf you appreciate my libraries, you can support the development and maintenance.\nImprove the quality of the libraries by providing issues and Pull Requests, or\ndonate through PayPal or GitHub sponsors.\n\nThank you,\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRobTillaart%2FADS1X15","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FRobTillaart%2FADS1X15","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRobTillaart%2FADS1X15/lists"}