关于 51 单片机驱动 ADS1115 进行 AD 模拟信号采集,下面是完整的原理讲解、通信流程、驱动代码示例与注意事项,适用于 C51 系列(如 STC89C52、AT89S52 等) 单片机配合 ADS1115(I²C 接口 16 位 ADC)模块进行高精度电压采集。


🧩 51 驱动 ADS1115 进行 AD 采集全指南


📦 一、ADS1115 模块简介

参数
分辨率16位(15位有效 + 符号位)
通道数4通道单端 / 2通道差分
通信接口I²C
内置PGA支持 ±6.144V ~ ±0.256V 可编程增益
电压范围2.0V ~ 5.5V
采样率8~860 SPS(Samples Per Second)

🔌 二、硬件连接方式

假设你使用 ADS1115 模块(默认地址 0x48),连接如下:

ADS1115 引脚51 单片机引脚
SDA(数据)P2.0(或任意IO口)
SCL(时钟)P2.1
VCC5V
GNDGND
ADDR悬空或接地(决定I2C地址)

🧠 三、I²C 通信基本流程

51 单片机通过软件模拟 I²C 通信(位操作),与 ADS1115 交互:

  1. 启动条件 → 发送器件地址(0x48)+ 写命令
  2. 写配置寄存器(设置通道、采样率等)
  3. 启动转换或读取转换结果寄存器
  4. 读取两个字节的转换数据

🧾 四、配置说明(关键寄存器)

  • 配置寄存器地址:0x01
  • 数据寄存器地址:0x00

配置寄存器 16 位格式(简略):

15     14-12   11    10-9     8   7-5   4-0
OS | MUX   | PGA | MODE | DR | COMP_MODE 等

示例配置值:

  • MUX = 100:通道 AIN0 单端输入
  • PGA = 010:±2.048V 量程
  • MODE = 1:单次转换模式
  • DR = 100:128 SPS

组合配置字(16位)示例:0xC283(高字节 0xC2,低字节 0x83)


🧰 五、驱动代码(C51 示例)

以下为 51 单片机模拟 I²C + 读取 ADS1115 AIN0 的简单示例:

#include <reg52.h>

sbit SDA = P2^0;
sbit SCL = P2^1;

void I2C_Start(void);
void I2C_Stop(void);
bit I2C_WriteByte(unsigned char dat);
unsigned char I2C_ReadByte(bit ack);

// 延时函数略(需10us级)

#define ADS1115_ADDR 0x90  // 0x48 << 1 | Write

void ADS1115_Init(void)
{
    I2C_Start();
    I2C_WriteByte(ADS1115_ADDR);     // 器件地址 + 写
    I2C_WriteByte(0x01);             // 配置寄存器地址
    I2C_WriteByte(0xC2);             // 高字节:单端AIN0, ±2.048V, 单次模式
    I2C_WriteByte(0x83);             // 低字节:128SPS,无比较器
    I2C_Stop();
}

int ADS1115_Read(void)
{
    unsigned char dataH, dataL;
    int result;

    // 再次指向寄存器0x00(转换结果)
    I2C_Start();
    I2C_WriteByte(ADS1115_ADDR);
    I2C_WriteByte(0x00);
    I2C_Stop();

    // 读取数据
    I2C_Start();
    I2C_WriteByte(ADS1115_ADDR | 0x01);  // 读
    dataH = I2C_ReadByte(1);
    dataL = I2C_ReadByte(0);
    I2C_Stop();

    result = (dataH << 8) | dataL;
    if(result > 0x7FFF) result -= 65536; // 转换为有符号值

    return result;  // 原始ADC值(范围 -32768~+32767)
}

🧮 六、电压换算

float voltage = adc_val * 2.048 / 32768.0;

假设设置量程为 ±2.048V,则对应:

  • 原始值 0x7FFF ≈ +2.048V
  • 原始值 0x0000 ≈ 0V
  • 原始值 0x8000 ≈ -2.048V

⚠️ 七、注意事项

项目说明
地址默认地址为 0x48(写 0x90,读 0x91),通过 ADDR 引脚可改
参考电压与 VCC 一致,设置 PGA 需匹配输入电压范围
转换模式支持连续和单次模式,单次需每次触发
I²C 总线建议加 4.7kΩ 上拉电阻
电平兼容3.3V 与 5V 都支持,注意与 51 单片机电平匹配

📚 资料与链接


如果你使用的是 STC 系列、想扩展多通道读取、或将数据通过串口输出给上位机,我可以继续帮你写完整采集程序和串口调试助手脚本。是否继续?

好的,下面给你一个基于51单片机(STC89C52)驱动ADS1115的多通道采集完整示例程序,并包含通过串口将采集数据发送给上位机的代码。方便你做多路模拟量采集与调试。


51单片机驱动ADS1115多通道采集 + 串口发送完整代码示例

#include <reg52.h>

sbit SDA = P2^0;
sbit SCL = P2^1;

#define ADS1115_ADDR_W 0x90  // 写地址 (0x48 << 1)
#define ADS1115_ADDR_R 0x91  // 读地址

// 延时函数,约10us,视晶振调整
void delay_us(unsigned int us)
{
    unsigned int i,j;
    for(i=us; i>0; i--)
        for(j=10; j>0; j--);
}

// I2C启动条件
void I2C_Start(void)
{
    SDA = 1; SCL = 1; delay_us(5);
    SDA = 0; delay_us(5);
    SCL = 0; delay_us(5);
}

// I2C停止条件
void I2C_Stop(void)
{
    SDA = 0; SCL = 1; delay_us(5);
    SDA = 1; delay_us(5);
}

// I2C发送字节,返回ACK(0:应答,1:无应答)
bit I2C_WriteByte(unsigned char dat)
{
    unsigned char i;
    bit ack;

    for(i=0; i<8; i++)
    {
        SDA = (dat & 0x80) ? 1 : 0;
        dat <<= 1;
        SCL = 1; delay_us(5);
        SCL = 0; delay_us(5);
    }

    SDA = 1;  // 释放总线,等待ACK
    SCL = 1; delay_us(5);
    ack = SDA; // 读取ACK
    SCL = 0; delay_us(5);

    return ack;
}

// I2C读取字节,参数 ack=1表示发送ACK,0表示NACK
unsigned char I2C_ReadByte(bit ack)
{
    unsigned char i, dat=0;
    SDA = 1; // 释放数据线

    for(i=0; i<8; i++)
    {
        dat <<= 1;
        SCL = 1; delay_us(5);
        if(SDA) dat |= 0x01;
        SCL = 0; delay_us(5);
    }

    SDA = (ack) ? 0 : 1; // 发送ACK或NACK
    SCL = 1; delay_us(5);
    SCL = 0; delay_us(5);
    SDA = 1; // 释放数据线

    return dat;
}

// 发送配置命令启动ADS1115单次采样(指定通道)
void ADS1115_ConfigChannel(unsigned char channel)
{
    unsigned int config = 0;

    // 参考TI手册配置:
    // OS=1 (启动单次转换)
    // MUX: 100 + channel (AIN0:100, AIN1:101, AIN2:110, AIN3:111)
    // PGA: 010 (±2.048V)
    // MODE: 1 (单次)
    // DR: 100 (128SPS)
    // COMP: 0000 (关闭比较器)

    config = 0x8000 | ((0x04 + channel) << 12) | (0x02 << 9) | (1 << 8) | (0x04 << 5);

    I2C_Start();
    I2C_WriteByte(ADS1115_ADDR_W);
    I2C_WriteByte(0x01);               // 配置寄存器地址
    I2C_WriteByte((config >> 8) & 0xFF);
    I2C_WriteByte(config & 0xFF);
    I2C_Stop();
}

// 读取转换结果(16位有符号数)
int ADS1115_ReadResult(void)
{
    unsigned char high, low;
    int val;

    I2C_Start();
    I2C_WriteByte(ADS1115_ADDR_W);
    I2C_WriteByte(0x00);   // 指向转换寄存器
    I2C_Stop();

    I2C_Start();
    I2C_WriteByte(ADS1115_ADDR_R);
    high = I2C_ReadByte(1);
    low = I2C_ReadByte(0);
    I2C_Stop();

    val = (high << 8) | low;
    if(val & 0x8000) val -= 0x10000; // 转换成带符号数
    return val;
}

// 串口初始化 9600bps@11.0592MHz
void UART_Init(void)
{
    SCON = 0x50;   // 8位可变波特率,允许接收
    TMOD = 0x20;   // 定时器1模式2,8位自动重装载
    TH1 = 0xFD;    // 9600bps
    TL1 = 0xFD;
    TR1 = 1;       // 启动定时器1
    EA = 1;        // 开总中断
    ES = 1;        // 允许串口中断
}

// 串口发送一个字节
void UART_SendByte(unsigned char dat)
{
    SBUF = dat;
    while(!TI);
    TI = 0;
}

// 发送整型数字(-32768~32767)字符串到串口
void UART_SendInt(int val)
{
    char buf[7]; // 负号+5位+结束符足够
    unsigned char i = 0;
    unsigned char sign = 0;
    unsigned int v;

    if(val < 0)
    {
        sign = 1;
        v = -val;
    }
    else
    {
        v = val;
    }

    do
    {
        buf[i++] = v % 10 + '0';
        v /= 10;
    }while(v > 0);

    if(sign) buf[i++] = '-';

    // 反转字符串
    while(i > 0)
    {
        UART_SendByte(buf[--i]);
    }
}

// 延时ms函数(粗略)
void delay_ms(unsigned int ms)
{
    unsigned int i,j;
    for(i=ms; i>0; i--)
        for(j=120; j>0; j--);
}

void main(void)
{
    int adc_val;
    unsigned char ch;

    UART_Init();

    while(1)
    {
        for(ch=0; ch<4; ch++) // 四通道采集
        {
            ADS1115_ConfigChannel(ch);  // 配置指定通道启动单次转换
            delay_ms(10);               // 等待采样完成(大于1/128s)

            adc_val = ADS1115_ReadResult();

            // 发送格式:CHx:数值\n
            UART_SendByte('C');
            UART_SendByte('H');
            UART_SendByte(ch + '0');
            UART_SendByte(':');
            UART_SendInt(adc_val);
            UART_SendByte('\r');
            UART_SendByte('\n');

            delay_ms(100);
        }
    }
}

说明

  • 通过 软件I2C 实现对 ADS1115 的配置和读取
  • 支持 4个单端通道 轮流采样
  • 采样后数据通过 串口 9600 波特率 发送到上位机
  • 上位机串口助手(如 SecureCRT、PuTTY、或者自行开发的软件)可接收数据,格式为:CH0:1234 每通道一行
  • 采样延时保证转换完成,约10ms(128SPS对应约7.8ms)

上位机接收建议

  • 任何串口调试软件均可,例如:
  • 设置串口波特率9600,8数据位,无校验,1停止位
  • 可在上位机做数据解析绘图或存储

明白!下面给你一个简单的 Python 上位机串口接收和实时绘图示例,基于 pyserial 和 matplotlib,适合接收上面51单片机发送的 ADS1115 多通道数据并实时显示:


Python 串口接收 + 实时绘图示例(支持4通道)

import serial
import threading
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import re
from collections import deque

# 串口参数
PORT = 'COM3'       # 请根据实际改成你的串口号
BAUDRATE = 9600

# 创建串口对象
ser = serial.Serial(PORT, BAUDRATE, timeout=1)

# 每个通道保存最近100个采样点
data_ch0 = deque(maxlen=100)
data_ch1 = deque(maxlen=100)
data_ch2 = deque(maxlen=100)
data_ch3 = deque(maxlen=100)

# 初始化全部通道数据为0
for _ in range(100):
    data_ch0.append(0)
    data_ch1.append(0)
    data_ch2.append(0)
    data_ch3.append(0)

# 正则匹配数据格式,如 CH0:1234
pattern = re.compile(r'CH(\d):(-?\d+)')

def read_serial():
    while True:
        line = ser.readline().decode('utf-8', errors='ignore').strip()
        match = pattern.match(line)
        if match:
            ch = int(match.group(1))
            val = int(match.group(2))
            if ch == 0:
                data_ch0.append(val)
            elif ch == 1:
                data_ch1.append(val)
            elif ch == 2:
                data_ch2.append(val)
            elif ch == 3:
                data_ch3.append(val)

# 启动串口读取线程
threading.Thread(target=read_serial, daemon=True).start()

# 绘图初始化
fig, ax = plt.subplots()
line0, = ax.plot(range(100), data_ch0, label='CH0')
line1, = ax.plot(range(100), data_ch1, label='CH1')
line2, = ax.plot(range(100), data_ch2, label='CH2')
line3, = ax.plot(range(100), data_ch3, label='CH3')

ax.set_ylim(-35000, 35000)  # 根据16位有符号范围调整
ax.set_title("ADS1115 4通道 ADC 实时采样")
ax.set_xlabel("采样点")
ax.set_ylabel("ADC值")
ax.legend()

def update(frame):
    line0.set_ydata(data_ch0)
    line1.set_ydata(data_ch1)
    line2.set_ydata(data_ch2)
    line3.set_ydata(data_ch3)
    return line0, line1, line2, line3

ani = animation.FuncAnimation(fig, update, interval=100)

plt.show()

使用说明

  1. 安装依赖
pip install pyserial matplotlib
  1. 修改串口号

把代码中 PORT = 'COM3' 替换成你实际串口号,比如 Linux/Mac 可能是 /dev/ttyUSB0

  1. 运行脚本

运行该脚本后,会弹出一个窗口,实时显示4个通道的ADC数值曲线。

  1. 数据格式要求

确保单片机发送数据格式为:

CH0:1234
CH1:-123
CH2:2345
CH3:-3456

每行一个通道数据,数字为带符号的16位ADC值。