4-CH 16-Bit ADS1115 ADC Module SKU: CQRADC001

From CQRobot-Wiki
Revision as of 08:15, 27 January 2026 by Chenqi (talk | contribs) (Arduino Example and Test Code)
Jump to: navigation, search
4-CH 16-Bit ADS1115 ADC Module

Description

The 4-channel 16-bit ADS1115 ADC Module is a high-precision analog-to-digital conversion solution based on the TI ADS1115IDGSR chip. This module provides four 16-bit precision analog input channels, supports both 3.3V and 5V operation, and features a hardware-configurable I2C address. The module also integrates an NTC temperature measurement interface, enabling multi-channel signal acquisition and temperature monitoring.


Features

  • High-Precision 16-bit ADC Chip: Based on the TI ADS1115IDGSR chip, it provides four 16-bit resolution analog input channels, enabling high-precision signal acquisition.
  • Flexible Input Modes: Supports 4 single-ended inputs or 2 differential inputs, suitable for various sensor signal measurement scenarios.
  • Configurable I2C Address: Configurable via the ADDR pin, supporting 4 I2C addresses to facilitate multi-device networking.
  • Wide Sampling Rate Range: Supports programmable sampling rates from 8 SPS to 860 SPS, meeting the requirements of different applications.
  • Integrated NTC Temperature Measurement Interface: Onboard MF52AT 10KΩ NTC temperature sensor interface with a B value of 3950K, ideal for temperature monitoring applications.
  • Dual-Voltage Compatible Design: Supports 3.3V/5V dual-voltage operation, with a built-in LP5907 LDO providing stable 3.3V power.
  • Automatic Level Conversion: I2C signals are automatically converted to 3.3V levels when powered by 5V, allowing direct connection to 3.3V microcontrollers.
  • Standard Interface Design: Equipped with HY2.0mm 4P connectors and 2.54mm pin headers for easy connection to various development boards.

Certification Documents

Media:CQRADC001-CE-Certification.rar

Media:CQRADC001-FCC-SDOC-Certification.rar

Pin Description and Size

CQRobot.jpg
CQRADC001-1.jpg
CQRADC001-2.jpg

Specification

CQRADC001-3.jpg
CQRADC001-8.jpg

Working Principle

CQRADC001-4-1.jpg

Power Supply and Sensor Compatibility

This module supports dual-voltage operation at 3.3V/5V. When powered at 3.3V, all I/Os are at 3.3V level; when powered at 5V, the I2C signals are automatically converted to 3.3V for communication with the host, while also allowing measurement of 5V sensor signals. The module includes built-in protection circuits to prevent damage from overvoltage and provides a 3.3V LDO output to power external sensors.

Important: When measuring 5V sensors, the module must be powered at 5V. In this case, the I2C signals remain at 3.3V level and can be directly connected to 3.3V host GPIO. Note that the SDA and SCL pins on this module are limited to 3.3V.


Connections and Examples

  • Configuration Method:

Use a jumper cap to connect the ADDR pin to the corresponding voltage level point. After configuration, restart the power for the changes to take effect.

  • Using an I2C Address Conversion Module for Configuration:

When using an I2C address conversion module, all ADS1115 modules can be set to the same hardware address. Address differentiation is achieved by selecting channels on the conversion module, eliminating the need to modify hardware jumper configurations.

CQRADC001-5.jpg

Arduino Example and Test Code

CQRADC001-72.jpg

#include <Wire.h>
#include <Adafruit_ADS1X15.h>

Adafruit_ADS1115 ads;

void setup() {
  Serial.begin(9600);
  ads.begin(0x48);
  ads.setGain(GAIN_ONE);
}

void loop() {
  int16_t adc = ads.readADC_SingleEnded(0);
  float voltage = adc * 0.125 / 1000.0;
  float ntc_r = (3.3 * 10000.0 / voltage) - 20000.0;
  float temp = 1.0 / (log(ntc_r / 10000.0) / 3950.0 + 1.0 / 298.15) - 273.15;
  
  Serial.print("Temp: ");
  Serial.print(temp, 1);
  Serial.println("C");
  
  delay(1000);
}

Example Results Explanation:

CQRADC001-711.jpg

  • Temporarily set the I2C address to 0x48. You can modify this line of code as needed: ads.begin(0x48).
  • Temporarily set the input channel to AIN0. You can modify this line of code as needed: int16_t adc = ads.readADC_SingleEnded(0).
  • To use the 5V measurement device, replace the conversion formula with the following:
float ntc_r = (5.0 * 10000.0 / voltage) - 20000.0;  // Modify to 5V
float temp = 1.0 / (log(ntc_r / 10000.0) / 3950.0 + 1.0 / 298.15) - 273.15;

Raspberry Pi Example and Test Code

CQRADC001-76.jpg

CQRADC001-73.jpg

Raspberry Pi 4B Pinout Diagram

CQRADC001-75.jpg

CQRADC001-77.jpg

  • Create a folder and a .c file, write the code into it, and then you can directly add it to the compressed archive: Media: ADS1115.rar


CQRADC001-78.jpg

gcc -Wall -g -o ADS1115 ADS1115.c -lm

./ADS1115
  • Navigate to the created folder in the terminal, use GCC for cross-compilation, and then run the file.
  • Example Code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <math.h>

#define ADS1115_ADDR 0x48

int main() {
    int fd = open("/dev/i2c-1", O_RDWR);
    if (fd < 0) return 1;
    if (ioctl(fd, I2C_SLAVE, ADS1115_ADDR) < 0) return 1;
    
    while(1) {
        unsigned char config[3] = {0x01, 0xC2, 0x83};
        unsigned char result[2];
        
        write(fd, config, 3);
        usleep(8000);
        
        unsigned char reg[1] = {0x00};
        write(fd, reg, 1);
        read(fd, result, 2);
        
        int16_t adc = (result[0] << 8) | result[1];
        float voltage = adc * 0.125 / 1000.0;
        float ntc_r = (3.3 * 10000.0 / voltage) - 20000.0;
        float temp = 1.0 / (log(ntc_r / 10000.0) / 3950.0 + 1.0 / 298.15) - 273.15;
        
        printf("Temp: %.1fC\n", temp);
        sleep(1);
    }
    
    return 0;
}
  • Example Results Explanation:

CQRADC001-79.jpg

  • The I2C address is temporarily set to 0x48. You can change this line of code as needed: `#define ADS1115_ADDR 0x48`.
  • The input channel is temporarily set to AIN0. You can replace it with the following codes according to your actual needs:

AIN0: 0xC2

AIN1: 0xD2

AIN2: 0E2

AIN3: 0xF2


Used in Conjunction with the TDS Meter Sensor (SKU: CQRSENTDS01 / ASIN: B08KXRHK7H)

CQRADC001-7.jpg
  • Example Program

CQRADC001-80.jpg

  • Create a folder and a .c file, write the code into it, and then you can directly add it to the compressed archive: Media: ADSTDS.rar

CQRADC001-81.jpg

gcc -o ADSTDS ADSTDS.c -lwiringPi

./ADSTDS
  • Example Code
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <math.h>
#include <time.h>


#define VREF 5.0f           
#define SCOUNT 30           // number of sampling points
#define TEMPERATURE 25.0f   // water temperature (degrees celsius)


int analogBuffer[SCOUNT];        
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0;
float averageVoltage = 0, tdsValue = 0;

int ads1115_fd;

// function declaration
int getMedianNum(int bArray[], int iFilterLen);
int readADS1115();
unsigned long my_millis();  


unsigned long my_millis() {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}


int getMedianNum(int bArray[], int iFilterLen) {
    int bTab[iFilterLen];
    for (int i = 0; i < iFilterLen; i++) {
        bTab[i] = bArray[i];
    }
    
    int i, j, bTemp;
    for (j = 0; j < iFilterLen - 1; j++) {
        for (i = 0; i < iFilterLen - j - 1; i++) {
            if (bTab[i] > bTab[i + 1]) {
                bTemp = bTab[i];
                bTab[i] = bTab[i + 1];
                bTab[i + 1] = bTemp;
            }
        }
    }
    
    if ((iFilterLen & 1) > 0) {
        bTemp = bTab[(iFilterLen - 1) / 2];
    } else {
        bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
    }
    return bTemp;
}


int readADS1115() {
    // configuration ADS1115: aisle 0
    uint16_t config = 0xC283;  
    wiringPiI2CWriteReg16(ads1115_fd, 0x01, (config >> 8) | (config << 8));
    usleep(8000);  
    
    uint16_t result = wiringPiI2CReadReg16(ads1115_fd, 0x00);
    int16_t adc = ((result >> 8) & 0xFF) | ((result & 0xFF) << 8);
    
 
    static int debug_count = 0;
    if (debug_count++ % 20 == 0) {
        printf("[original ADC: %d] ", adc);
    }
    

    int adc_abs = abs(adc);
    
    // convert to estimated value (0-1023)
    int arduino_value = (adc_abs * 1024) / 30000;
    
    // limited to 0-1023 scope
    if (arduino_value > 1023) arduino_value = 1023;
    if (arduino_value < 0) arduino_value = 0;
    
    return arduino_value;
}

int main() {
    printf("=== Raspberry Pi TDS measurement ===\n");
    printf("TDS = 133.42*V^3 - 255.86*V^2 + 857.39*V * 0.5\n\n");
    
    // initialization wiringPi
    if (wiringPiSetup() < 0) {
        printf("wiringPi initialization failed\n");
        return 1;
    }
    
    // initialization ADS1115
    ads1115_fd = wiringPiI2CSetup(0x48);
    if (ads1115_fd < 0) {
        printf("ADS1115 initialization failed (address 0x48)\n");
        printf("check, please: sudo i2cdetect -y 1\n");
        return 1;
    }
    
    printf("✓ hardware initialization complete\n");
    printf("start measuring...\n");
    printf("----------------------------------------\n");
    
    // time point variable (using custom my_millis)
    unsigned long analogSampleTimepoint = my_millis();
    unsigned long printTimepoint = my_millis();
    
    while (1) {
        unsigned long currentMillis = my_millis();
        
    
        if (currentMillis - analogSampleTimepoint > 40U) {
            analogSampleTimepoint = currentMillis;
            
            int arduinoValue = readADS1115();
            
            analogBuffer[analogBufferIndex] = arduinoValue;
            analogBufferIndex++;
            if (analogBufferIndex == SCOUNT) {
                analogBufferIndex = 0;
            }
        }
        
       
        if (currentMillis - printTimepoint > 800U) {
            printTimepoint = currentMillis;
           
            for (int copyIndex = 0; copyIndex < SCOUNT; copyIndex++) {
                analogBufferTemp[copyIndex] = analogBuffer[copyIndex];
            }
            
            
            int medianValue = getMedianNum(analogBufferTemp, SCOUNT);
            
            averageVoltage = medianValue * VREF / 1024.0;
            
         
            float compensationCoefficient = 1.0 + 0.02 * (TEMPERATURE - 25.0);
            float compensationVoltage = averageVoltage / compensationCoefficient;
            
            
            tdsValue = (133.42 * compensationVoltage * compensationVoltage * compensationVoltage 
                       - 255.86 * compensationVoltage * compensationVoltage 
                       + 857.39 * compensationVoltage) * 0.5;
            
           
            printf("TDS Value: %.0fppm", tdsValue);
           
            printf(" (ADC:%d, Volt:%.3fV)\n", medianValue, averageVoltage);
            
            fflush(stdout);
        }
        
        usleep(1000);  
    }
    
    return 0;
}
  • Test Results Explanation:

CQRADC001-82.jpg

The raw ADC value is the raw 16-bit analog-to-digital conversion data from the ADS1115; the ADC value is the stable value after median filtering; the voltage value is the calculated corresponding voltage value; and the TDS value represents the total dissolved solids content of the water. The I2C address is 0x48; the analog port is AIN0.