零知IDE——STM32F407VET6与ADS1115模数转换器实现多通道数据采集显示系统

✔零知IDE 是一个真正属于国人自己的开源软件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!

✔访问零知实验室,获取更多实战项目和教程资源吧!

www.lingzhilab.com

目录

一、硬件连接部分

[1.1 硬件清单](#1.1 硬件清单)

[1.2 接线方案](#1.2 接线方案)

[1.3 具体接线图](#1.3 具体接线图)

[1.4 连接实物图](#1.4 连接实物图)

二、代码讲解部分

[2.1 数据结构与定义](#2.1 数据结构与定义)

[2.2 核心数据采集](#2.2 核心数据采集)

[2.3 实时数据显示](#2.3 实时数据显示)

[2.4 结果排序和显示](#2.4 结果排序和显示)

[2.5 完整代码](#2.5 完整代码)

三、项目结果演示

[3.1 操作流程](#3.1 操作流程)

[3.2 数据记录](#3.2 数据记录)

[3.3 视频演示](#3.3 视频演示)

四、ADS1115工作原理详解

[4.1 内部架构与功能](#4.1 内部架构与功能)

[4.2 I2C通信协议](#4.2 I2C通信协议)

[4.3 寄存器映射](#4.3 寄存器映射)

五、常见问题解答

[Q1: ADS1115读取数据不稳定怎么办?](#Q1: ADS1115读取数据不稳定怎么办?)

[Q2: 显示屏出现闪烁如何解决?](#Q2: 显示屏出现闪烁如何解决?)

[Q3: 如何提高ADC采集精度?](#Q3: 如何提高ADC采集精度?)


(1)项目概述

本项目基于STM32F407VET6微控制器和ADS1115 16位高精度模数转换器,设计了一个多功能数据采集与显示系统。系统通过STM32F407VET6控制ADS1115采集四路模拟信号,并将采集到的数据实时显示在240×240的ST7789彩色LCD显示屏上。项目展示了高精度ADC数据采集、实时数据显示、多通道信号处理等关键技术。

(2)项目难点及解决方案

问题描述:多任务实时处理

解决方案:优化程序结构,采用状态机模式管理不同显示界面

一、硬件连接部分

1.1 硬件清单

组件 型号 数量 备注
主控板 STM32F407VET6 1 零知增强板
ADC模块 ADS1115 1 16位精度
显示屏 ST7789 1 240×240分辨率
电位器 10kΩ 1 模拟信号输入
连接线 杜邦线 若干 信号连接

1.2 接线方案

STM32F407引脚 ADS1115引脚 ST7789引脚 功能描述
3.3V VDD VCC 电源正极
GND GND GND 电源地
52 SCL SCL I2C时钟
51 SDA SDA I2C数据
/ A0 / 模拟输入0
/ A1 / 模拟输入1
/ A2 / 模拟输入2
/ A3 / 模拟输入3
4 / DC 数据/命令
2 / RST 复位
53 / CS 片选

注意:本项目ADS1117模数转换器的引脚连接如下,A0和A2连接到3.3V电源、A1连接电位器调节ADC值、A3接到零知增强板任一模拟引脚观察悬空引脚模拟值变化

1.3 具体接线图

1.4 连接实物图

二、代码讲解部分

2.1 数据结构与定义

cpp 复制代码
// 定义ST7789显示屏引脚
#define TFT_CS    53
#define TFT_RST   2
#define TFT_DC    4

// 创建ADS1115和ST7789对象
Adafruit_ADS1115 ads;
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

// 游戏相关变量
struct Car {
  int16_t x;           // 赛车x坐标
  int16_t y;           // 赛车y坐标
  uint16_t color;      // 赛车颜色
  int16_t lastADC;     // 上一次ADC值
  int16_t speed;       // 当前速度
  bool finished;       // 是否完成比赛
  uint32_t finishTime; // 完成时间
};

Car cars[4];  // 四辆赛车
bool gameStarted = false;
bool gameFinished = false;
uint32_t startTime = 0;
const int16_t FINISH_LINE = 200;  // 终点线位置

// A1和A3通道数据显示变量
int16_t lastA1ADC = -1;
float lastA1Voltage = -1;
int16_t lastA3ADC = -1;
float lastA3Voltage = -1;

// 颜色定义
#define CAR1_COLOR ST77XX_RED
#define CAR2_COLOR ST77XX_GREEN
#define CAR3_COLOR ST77XX_BLUE
#define CAR4_COLOR ST77XX_YELLOW
#define TRACK_COLOR 0x7453
#define BACKGROUND_COLOR ST77XX_BLACK
#define DATA_BG_COLOR 0x1082
#define DATA_TEXT_COLOR ST77XX_WHITE

ST7789显示屏引脚定义到零知增强板的硬件SPI接口、Car结构体封装了每个通道的显示属性和状态、每个通道对应特定颜色

2.2 核心数据采集

cpp 复制代码
void updateGame() {
  bool allFinished = true;
  float ret;
  
  // 读取A1和A3通道数据并更新显示
  updateChannelDataDisplay();
  
  for (int i = 0; i < 4; i++) {
    if (!cars[i].finished) {
      // 读取ADC值并转换为速度
      int16_t adc = ads.readADC_SingleEnded(i);
      cars[i].speed = map(adc, 0, 26000, 1, 10);
      
      // 更新赛车位置
      cars[i].x += cars[i].speed;
      
      // 检查是否到达终点
      if (cars[i].x >= FINISH_LINE) {
        cars[i].finished = true;
        cars[i].finishTime = millis() - startTime;
        cars[i].x = FINISH_LINE;
      } else {
        allFinished = false;
      }
      
      updateCarDisplay(i);
      
      // 串口调试信息(仅显示A1通道)
      if (i == 1) {
        Serial.print("ADC");
        Serial.print(i);
        Serial.print(": ");
        Serial.print(adc);
        Serial.print(" | Voltage:");
        ret = adc * 0.0001875; 
        Serial.print(ret); 
        Serial.print(" | Speed: ");
        Serial.print(cars[i].speed);
        Serial.print(" | Position: ");
        Serial.println(cars[i].x);
      }
    }
  }
  
  if (allFinished && !gameFinished) {
    gameFinished = true;
    showResults();
  }
}

电压计算公式采用:adc * 0.0001875基于6.144V量程的分辨率

2.3 实时数据显示

cpp 复制代码
void updateChannelDataDisplay() {
  // 读取A1和A3通道数据
  int16_t a1ADC = ads.readADC_SingleEnded(1);
  float a1Voltage = a1ADC * 0.0001875;
  int16_t a3ADC = ads.readADC_SingleEnded(3);
  float a3Voltage = a3ADC * 0.0001875;
  
  // 只在新数据与旧数据不同时更新显示,避免闪烁
  if (a1ADC != lastA1ADC) {
    displayChannelData(1, a1ADC, a1Voltage, 210);
    lastA1ADC = a1ADC;
    lastA1Voltage = a1Voltage;
  }
  
  if (a3ADC != lastA3ADC) {
    displayChannelData(3, a3ADC, a3Voltage, 225);
    lastA3ADC = a3ADC;
    lastA3Voltage = a3Voltage;
  }
}

仅当ADC值变化时更新显示,避免不必要的屏幕刷新

2.4 结果排序和显示

cpp 复制代码
void showResults() {
  // ... 显示标题等代码 ...
  
  // 确定名次
  int rankings[4] = {0, 1, 2, 3};
  
  // 冒泡排序按完成时间排序
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3 - i; j++) {
      if (cars[rankings[j]].finishTime > cars[rankings[j + 1]].finishTime) {
        int temp = rankings[j];
        rankings[j] = rankings[j + 1];
        rankings[j + 1] = temp;
      }
    }
  }
  
  // 显示排序结果
  int yPos = 60;
  for (int i = 0; i < 4; i++) {
    int carIndex = rankings[i];
    tft.setCursor(30, yPos);
    tft.print("Channel ");
    tft.print(carIndex);
    tft.print(": ");
    
    tft.fillRect(90, yPos, 10, 10, cars[carIndex].color);
    
    tft.setCursor(105, yPos);
    tft.print("Time: ");
    tft.print(cars[carIndex].finishTime / 1000.0, 2);
    tft.print("s");
    
    yPos += 30;
  }
}

相邻元素比较交换,最大元素"冒泡"到末尾。时间复杂度为O(n²),适合小数据量排序

2.5 完整代码

cpp 复制代码
// 文件名:STM32F407_ADS1115_DataDisplay.ino

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

// 定义ST7789显示屏引脚
#define TFT_CS    53
#define TFT_RST   2
#define TFT_DC    4

// 创建ADS1115和ST7789对象
Adafruit_ADS1115 ads;
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

// 游戏相关变量
struct Car {
  int16_t x;           // 赛车x坐标
  int16_t y;           // 赛车y坐标
  uint16_t color;      // 赛车颜色
  int16_t lastADC;     // 上一次ADC值
  int16_t speed;       // 当前速度
  bool finished;       // 是否完成比赛
  uint32_t finishTime; // 完成时间
};

Car cars[4];  // 四辆赛车
bool gameStarted = false;
bool gameFinished = false;
uint32_t startTime = 0;
const int16_t FINISH_LINE = 200;  // 终点线位置

// A1和A3通道数据显示变量
int16_t lastA1ADC = -1;
float lastA1Voltage = -1;
int16_t lastA3ADC = -1;
float lastA3Voltage = -1;

// 颜色定义
#define CAR1_COLOR ST77XX_RED
#define CAR2_COLOR ST77XX_GREEN
#define CAR3_COLOR ST77XX_BLUE
#define CAR4_COLOR ST77XX_YELLOW
#define TRACK_COLOR 0x7453
#define BACKGROUND_COLOR ST77XX_BLACK
#define DATA_BG_COLOR 0x1082
#define DATA_TEXT_COLOR ST77XX_WHITE

void setup(void) {
  Serial.begin(115200);
  Serial.println("STM32F407 ADS1115数据采集系统启动!");
  
  // 初始化ADS1115
  Wire.begin();
  if (!ads.begin()) {
    Serial.println("ADS1115初始化失败!");
    while (1);
  }
  ads.setGain(GAIN_TWOTHIRDS);
  
  // 初始化ST7789显示屏
  tft.init(240, 240);
  tft.setRotation(1);  // 重要:设置屏幕方向
  tft.fillScreen(BACKGROUND_COLOR);
  
  // 初始化赛车
  initializeCars();
  
  // 显示开始界面
  showStartScreen();
}

void loop(void) {
  if (!gameStarted) {
    // 等待开始信号(任意通道电压超过1V)
    if (checkStartCondition()) {
      startGame();
    }
    return;
  }
  
  if (gameFinished) {
    // 游戏结束,显示结果
    if (checkRestartCondition()) {
      resetGame();
    }
    return;
  }
  
  // 主游戏循环
  updateGame();
  delay(50);  // 控制游戏速度
}

void initializeCars() {
  // 初始化四辆赛车的属性
  int16_t startY[] = {40, 80, 120, 160};
  uint16_t colors[] = {CAR1_COLOR, CAR2_COLOR, CAR3_COLOR, CAR4_COLOR};
  
  for (int i = 0; i < 4; i++) {
    cars[i].x = 20;
    cars[i].y = startY[i];
    cars[i].color = colors[i];
    cars[i].lastADC = 0;
    cars[i].speed = 0;
    cars[i].finished = false;
    cars[i].finishTime = 0;
  }
}

bool checkStartCondition() {
  // 检查任意通道电压是否超过1V作为开始信号
  for (int i = 0; i < 4; i++) {
    int16_t adc = ads.readADC_SingleEnded(i);
    float voltage = adc * 0.0001875;
    if (voltage > 1.0) {
      return true;
    }
  }
  return false;
}

bool checkRestartCondition() {
  // 检查所有通道电压是否都低于0.5V作为重新开始信号
  for (int i = 0; i < 4; i++) {
    int16_t adc = ads.readADC_SingleEnded(i);
    float voltage = adc * 0.0001875;
    if (voltage > 0.5) {
      return false;
    }
  }
  return true;
}

void startGame() {
  gameStarted = true;
  startTime = millis();
  drawGameScreen();
}

void resetGame() {
  gameStarted = false;
  gameFinished = false;
  initializeCars();
  tft.fillScreen(BACKGROUND_COLOR);
  showStartScreen();
}

void updateGame() {
  bool allFinished = true;
  float ret;
  
  // 读取A1和A3通道数据并更新显示
  updateChannelDataDisplay();
  
  for (int i = 0; i < 4; i++) {
    if (!cars[i].finished) {
      // 读取ADC值并转换为速度
      int16_t adc = ads.readADC_SingleEnded(i);
      cars[i].speed = map(adc, 0, 26000, 1, 10);  // 映射ADC值到速度
      
      // 更新赛车位置
      cars[i].x += cars[i].speed;
      
      // 检查是否到达终点
      if (cars[i].x >= FINISH_LINE) {
        cars[i].finished = true;
        cars[i].finishTime = millis() - startTime;
        cars[i].x = FINISH_LINE;  // 确保不会超出终点
      } else {
        allFinished = false;
      }
      
      // 更新显示
      updateCarDisplay(i);
      
      // 在串口显示调试信息
      if (i == 1) {  // 显示A1通道的信息
        Serial.print("ADC");
        Serial.print(i);
        Serial.print(": ");
        Serial.print(adc);
        Serial.print(" | Voltage:");
        ret = adc * 0.0001875; 
        Serial.print(ret); 
        Serial.print(" | Speed: ");
        Serial.print(cars[i].speed);
        Serial.print(" | Position: ");
        Serial.println(cars[i].x);
      }
    }
  }
  
  // 检查游戏是否结束
  if (allFinished && !gameFinished) {
    gameFinished = true;
    showResults();
  }
}

void updateChannelDataDisplay() {
  // 读取A1和A3通道数据
  int16_t a1ADC = ads.readADC_SingleEnded(1);
  float a1Voltage = a1ADC * 0.0001875;
  int16_t a3ADC = ads.readADC_SingleEnded(3);
  float a3Voltage = a3ADC * 0.0001875;
  
  // 只在新数据与旧数据不同时更新显示,避免闪烁
  if (a1ADC != lastA1ADC) {
    displayChannelData(1, a1ADC, a1Voltage, 210);
    lastA1ADC = a1ADC;
    lastA1Voltage = a1Voltage;
  }
  
  if (a3ADC != lastA3ADC) {
    displayChannelData(3, a3ADC, a3Voltage, 225);
    lastA3ADC = a3ADC;
    lastA3Voltage = a3Voltage;
  }
}

void displayChannelData(int channel, int16_t adc, float voltage, int yPos) {
  // 设置文本颜色和大小
  tft.setTextColor(DATA_TEXT_COLOR);
  tft.setTextSize(1);
  
  // 清除旧数据区域(局部刷新)
  tft.fillRect(55, yPos, 180, 10, DATA_BG_COLOR);
  
  // 显示通道数据
  tft.setCursor(5, yPos);
  tft.print("A");
  tft.print(channel);
  tft.print(": ADC= ");
  tft.print(adc);
  tft.print(" | V=");
  tft.print(voltage, 3);
  tft.print("V");
}

void updateCarDisplay(int carIndex) {
  // 清除旧的赛车位置(绘制背景色矩形)
  tft.fillRect(cars[carIndex].x - cars[carIndex].speed - 2, cars[carIndex].y - 8, 
               cars[carIndex].speed + 4, 16, TRACK_COLOR);
  
  // 绘制新位置的赛车
  drawCar(carIndex);
}

void drawCar(int carIndex) {
  // 绘制赛车(简单的矩形表示)
  tft.fillRoundRect(cars[carIndex].x, cars[carIndex].y - 6, 12, 12, 3, cars[carIndex].color);
  tft.fillRoundRect(cars[carIndex].x + 10, cars[carIndex].y - 4, 6, 8, 2, ST77XX_WHITE);
}

void showStartScreen() {
  tft.setTextSize(3);
  tft.setTextColor(ST77XX_GREEN);
  tft.setCursor(20, 50);
  tft.println("Data Display");
  
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(1);
  tft.setCursor(20, 80);
  tft.println("Connect sensors to ADS1115:");
  tft.setCursor(40, 100);
  tft.println("Channel 0 - Red indicator");
  tft.setCursor(40, 115);
  tft.println("Channel 1 - Potentiometer");
  tft.setCursor(40, 130);
  tft.println("Channel 2 - Blue indicator");
  tft.setCursor(40, 145);
  tft.println("Channel 3 - Analog input");
  
  tft.setCursor(30, 170);
  tft.println("Adjust any channel voltage");
  tft.setCursor(50, 185);
  tft.println("to start data display!");

  delay(500);
}

void drawGameScreen() {
  tft.fillScreen(BACKGROUND_COLOR);
  
  // 绘制赛道背景
  tft.fillRect(0, 30, 240, 160, TRACK_COLOR);
  
  // 绘制起点线
  for (int y = 30; y < 190; y += 10) {
    tft.drawFastVLine(20, y, 5, ST77XX_WHITE);
  }
  
  // 绘制终点线
  for (int y = 30; y < 190; y += 10) {
    tft.drawFastVLine(FINISH_LINE, y, 5, ST77XX_WHITE);
  }
  
  // 绘制数据背景区域
  tft.fillRect(0, 200, 240, 40, DATA_BG_COLOR);
  
  // 绘制数据标题
  tft.setTextColor(DATA_TEXT_COLOR);
  tft.setTextSize(1);
  
  // 初始化A1和A3数据显示
  tft.setCursor(5, 210);
  tft.print("A1: ADC= --- =---V");
  tft.setCursor(5, 225);
  tft.print("A3: ADC= --- =---V");
  
  // 绘制赛车初始位置
  for (int i = 0; i < 4; i++) {
    drawCar(i);
  }
  
  // 显示游戏状态
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(1);
  tft.setCursor(5, 5);
  tft.print("Data Acquisition Active...");
}

void showResults() {
  tft.fillScreen(BACKGROUND_COLOR);
  tft.setTextColor(ST77XX_WHITE);
  tft.fillRect(0, 0, 240, 40, ST77XX_RED);
  tft.setTextSize(2);
  tft.setCursor(40, 20);
  tft.println("Test Complete");
  
  tft.setTextSize(1);
  
  // 确定名次
  int rankings[4] = {0, 1, 2, 3};
  
  // 简单的冒泡排序按完成时间排序
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3 - i; j++) {
      if (cars[rankings[j]].finishTime > cars[rankings[j + 1]].finishTime) {
        int temp = rankings[j];
        rankings[j] = rankings[j + 1];
        rankings[j + 1] = temp;
      }
    }
  }
  
  // 显示测试结果
  int yPos = 60;
  for (int i = 0; i < 4; i++) {
    int carIndex = rankings[i];
    tft.setCursor(30, yPos);
    tft.print("Channel ");
    tft.print(carIndex);
    tft.print(": ");
    
    // 显示通道颜色方块
    tft.fillRect(90, yPos, 10, 10, cars[carIndex].color);
    
    tft.setCursor(105, yPos);
    tft.print("Time: ");
    tft.print(cars[carIndex].finishTime / 1000.0, 2);
    tft.print("s");
    
    yPos += 30;
  }

  // 显示最终数据
  tft.setCursor(30, 180);
  tft.print("Final A1 Voltage: ");
  tft.print(lastA1Voltage, 3);
  tft.print("V");
  
  tft.setCursor(30, 195);
  tft.print("Final A3 Voltage: ");
  tft.print(lastA3Voltage, 3);
  tft.print("V");
  
  tft.setTextSize(1);  
  tft.setCursor(40, 215);
  tft.println("Reset all channels to restart");
}

// 辅助函数:绘制带边框的矩形
void drawBorderedRect(int16_t x, int16_t y, int16_t w, int16_t h, 
                     uint16_t color, uint16_t borderColor) {
  tft.fillRect(x, y, w, h, borderColor);
  tft.fillRect(x + 1, y + 1, w - 2, h - 2, color);
}

冒泡排序算法原理:

冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成

算法步骤分解:

**①外层循环(i循环):**控制排序的轮数

对于4个元素,需要3轮比较(n-1轮)、i < 3 因为4个元素需要3轮比较

**②内层循环(j循环):**进行相邻元素的比较和交换

j < 3 - i 每完成一轮,最大的元素就会"冒泡"到末尾,因此后续比较次数减少

③比较和交换:

cars[rankings[j]].finishTime > cars[rankings[j + 1]].finishTime

如果前一个元素的完成时间大于后一个元素,则交换它们在排名数组中的位置

三、项目结果演示

3.1 操作流程

(1)系统上电,将A0和A2连接到GND(后接3.3V)、A1连接5V电位器、A3连接零知增强板A0引脚

(2)旋转电位器(大于1V时)系统启动,观察模拟值和电压值变化

将ADC值map映射到物体的移动速度,通过小车移动速度的快慢直观的感受到A1通道模拟值变化

底部显示旋转电位器的A1通道和零知增强板A0模拟引脚的A3通道具体ADC值和GAIN_TWOTHIRDS分辨率的电压值

(3)同时打开串口监视器观察通道1的ADC值和波形

3.2 数据记录

时间点 A0电压 A1电压 A2电压 A3电压 备注
初始 0V 0V 0V 0V 系统启动
测试1 3.3V 2.5V 3.3V 0.4V 正常采集
测试2 3.3V 4.8V 3.3V 0.4V 电位器调节

对模拟值的大小进行冒泡排序,观察ADC值的变化过程

3.3 视频演示

ADS1115模数转换器实现多通道数据采集

系统启动和数据采集显示、电位器调节效果以及不同ADC值大小变化过程

四、ADS1115工作原理详解

ADS1115 具有 一个输入多路复用器 (MUX),可实现双路差分输入或 四路单端输入测量。兼容 I 2C 的 16 位低功耗精密模数转换器 (ADC)

4.1 内部架构与功能

(1)Δ-Σ调制器

以远高于奈奎斯特频率的速率采样、将量化噪声推向高频区域、将模拟信号转换为位流

(2)Multiplexer 复用器

ADS1115包含一个输入多路器,四个单电压输入或者两个差分输入。AIN0和AIN1可以与AIN3进行差分测量,多路复用器由配置寄存器中的位MUX [2:0]配置。

测量单端信号时,ADC的负输入通过多路器内的开关内部连接到GND

(3)噪声表现

采样速率不宜过高,由表格看出当采样速率大于128SPS时,分辨率在不同量程下均有所下降

(4)满量程范围

由配置寄存器中的 PGA [2:0] 位配置,可设置为 ±6.144 V、±4.096 V、±2.048 V、±1.024 V、±0.512 V、±0.256 V

4.2 I2C通信协议

(1)I2C 地址选择

ADS1115有一个地址引脚 ADDR,用于配置器件的 I2C 地址。该引脚可连接至 GND、VDD、SDA 或 SCL,通过一个引脚即可选择四种不同的地址

(2)向寄存器写入数据

要访问 ADS111x 中的特定寄存器,主机必须首先向地址指针寄存器中的寄存器地址指针位 P [1:0] 写入适当的值。

地址指针寄存器是在从机地址字节、低电平的读 / 写位以及从机成功应答之后直接写入,从机进行应答,主机发出停止条件或重复起始条件

(3)从寄存器读取数据

从 ADS111x 读取数据时,先前写入位 P [1:0] 的值决定了要读取的寄存器。要更改读取的寄存器,必须向 P [1:0] 写入新值

(4)数据格式

以二进制补码格式提供 16 位数据。正满量程(+FS)输入产生的输出代码为 7FFFh,负满量程(--FS)输入产生的输出代码为 8000h

对于超过满量程的信号,输出会钳位在这些代码上

电压计算原理

ADS1115的输出代码与输入电压的关系为:电压 = (ADC读数 × 满量程电压) / (2¹⁵ - 1)

在GAIN_TWOTHIRDS模式下:满量程电压 = 6.144V、分辨率 = 6.144V / 32767 ≈ 0.1875mV

4.3 寄存器映射

ADS1115有四个寄存器,可通过I2C接口和地址指针寄存器访问。转换寄存器存上次转换结果,配置寄存器用于更改工作模式和查询设备状态,另两个寄存器(Lo_thresh和Hi_thresh)则设定比较器功能的阈值。

(1)地址指针寄存器

地址指针寄存器的2-7位保留全部置0,最低两位写入地址指针访问对应寄存器

(2)转换寄存器(P [1:0] = 0h)

16 位转换寄存器以二进制补码格式存储最后一次转换的结果。上电后,转换寄存器被清零,并且在第一次转换完成前一直保持为 0

(3)配置寄存器(P [1:0] = 1h)

16位配置寄存器用于控制工作模式、输入选择、数据速率、满量程范围和比较器模式

eg:设置DR[2:0]位为100,控制数据速率默认的128SPS

五、常见问题解答

Q1: ADS1115读取数据不稳定怎么办?

A: 检查电源稳定性,添加滤波电容,确保I2C上拉电阻正确连接。

Q2: 显示屏出现闪烁如何解决?

A: 使用局部刷新技术,避免全屏刷新,优化刷新频率。

Q3: 如何提高ADC采集精度?

A: 使用外部基准电压,降低采样速率,添加硬件滤波。

项目资源整合:

ADS1115库文件:Adafruit_ADS1X15

ADS1115数据手册:ADS111x datasheet

相关推荐
xxy.c5 小时前
基于IMX6ULL的时钟,定时器(EPIT,GPT)
单片机·嵌入式硬件·fpga开发
happygrilclh6 小时前
stm32L496 flash 分配
stm32·单片机·嵌入式硬件
古译汉书7 小时前
嵌入式铁头山羊STM32-各章节详细笔记-查阅传送门
数据结构·笔记·stm32·单片机·嵌入式硬件·个人开发
小和尚同志10 小时前
使用 Certimate 实现自动续签 SSL 证书
开源·github·自动化运维
一枚码农~10 小时前
STM32红外与LED控制实战
单片机·嵌入式硬件
Heavy sea11 小时前
STM32定时器(寄存器与HAL库实现)
stm32·单片机
路过羊圈的狼12 小时前
STM32的HAL库驱动ADS124S08进行PT100温度采集
stm32·嵌入式硬件·mongodb
proud121212 小时前
开源的 CSS 动画库
前端·css·开源
李永奉13 小时前
51单片机-实现红外遥控模块教程
单片机·嵌入式硬件·51单片机