利用 STM32 和 ADS1256 进行高精度数据采集

一、系统架构设计

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    ADS1256 数据采集系统                   │
├─────────────────────────────────────────────────────────────┤
│  STM32主控     │  ADS1256 ADC    │  信号调理      │  应用层    │
│                │                 │                │           │
│  • SPI通信    │  • 24位分辨率    │  • 电压跟随器  │  • 数据显示 │
│  • 时钟配置    │  • 8通道差分输入 │  • RC滤波      │  • 数据存储 │
│  • DMA传输    │  • 可编程增益    │  • 过压保护    │  • 通信上传 │
│  • 中断处理    │  • 30kSPS速率    │  • 屏蔽设计   │  • 报警控制 │
└─────────────────────────────────────────────────────────────┘

二、硬件连接设计

2.1 引脚连接表

复制代码
STM32F103C8T6          ADS1256
─────────────────────────────────────
PA5 (SPI1_SCK)  ──────> SCLK
PA6 (SPI1_MISO) ──────> DOUT
PA7 (SPI1_MOSI) ──────> DIN
PA4 (SPI1_NSS)  ──────> CS
PB0             ──────> DRDY (数据就绪中断)
3.3V            ──────> DVDD (数字电源)
5V              ──────> AVDD (模拟电源)
GND             ──────> DGND/AGND

2.2 模拟输入电路

复制代码
差分输入配置(以通道0为例):
        
        R1 (100Ω)     C1 (100nF)
Vin+ ────╱╱╱───────┬───────┐
                     │       │
                    ╱╱╱     ╱╱╱
                    R2      R3 (匹配电阻)
                     │       │
Vin- ────╱╱╱───────┼───────┘
        R3 (100Ω)     C2 (100nF)
                     │
                    AGND

三、完整源码实现

3.1 ADS1256 驱动头文件 (ads1256.h)

c 复制代码
#ifndef __ADS1256_H
#define __ADS1256_H

#include "stm32f10x.h"
#include <stdint.h>
#include <stdbool.h>

// ADS1256 寄存器地址
#define ADS1256_STATUS      0x00
#define ADS1256_MUX         0x01
#define ADS1256_ADCON       0x02
#define ADS1256_DRATE       0x03
#define ADS1256_IO         0x04
#define ADS1256_OFC0        0x05
#define ADS1256_OFC1        0x06
#define ADS1256_OFC2        0x07
#define ADS1256_FSC0        0x08
#define ADS1256_FSC1        0x09
#define ADS1256_FSC2        0x0A

// 命令定义
#define ADS1256_CMD_WAKEUP  0x00
#define ADS1256_CMD_RDATA   0x01
#define ADS1256_CMD_RDATAC  0x03
#define ADS1256_CMD_SDATAC  0x0F
#define ADS1256_CMD_RREG    0x10
#define ADS1256_CMD_WREG    0x50
#define ADS1256_CMD_SELFCAL 0xF0
#define ADS1256_CMD_SELFOCAL 0xF1
#define ADS1256_CMD_SELFGCAL 0xF2
#define ADS1256_CMD_SYSOCAL 0xF3
#define ADS1256_CMD_SYSGCAL 0xF4
#define ADS1256_CMD_SYNC    0xFC
#define ADS1256_CMD_STANDBY 0xFD
#define ADS1256_CMD_RESET  0xFE

// 输入通道定义
typedef enum {
    ADS1256_CH0 = 0x00,
    ADS1256_CH1 = 0x10,
    ADS1256_CH2 = 0x20,
    ADS1256_CH3 = 0x30,
    ADS1256_CH4 = 0x40,
    ADS1256_CH5 = 0x50,
    ADS1256_CH6 = 0x60,
    ADS1256_CH7 = 0x70,
    ADS1256_CH0_CH1 = 0x01,  // AIN0 vs AIN1
    ADS1256_CH2_CH3 = 0x23,  // AIN2 vs AIN3
    ADS1256_CH4_CH5 = 0x45,  // AIN4 vs AIN5
    ADS1256_CH6_CH7 = 0x67   // AIN6 vs AIN7
} ADS1256_Channel_t;

// 增益定义
typedef enum {
    ADS1256_GAIN_1 = 0x00,
    ADS1256_GAIN_2 = 0x01,
    ADS1256_GAIN_4 = 0x02,
    ADS1256_GAIN_8 = 0x03,
    ADS1256_GAIN_16 = 0x04,
    ADS1256_GAIN_32 = 0x05,
    ADS1256_GAIN_64 = 0x06
} ADS1256_Gain_t;

// 数据速率定义
typedef enum {
    ADS1256_DR_30000 = 0xF0,  // 30k SPS
    ADS1256_DR_15000 = 0xE0,  // 15k SPS
    ADS1256_DR_7500  = 0xD0,  // 7.5k SPS
    ADS1256_DR_3750  = 0xC0,  // 3.75k SPS
    ADS1256_DR_2000  = 0xB0,  // 2k SPS
    ADS1256_DR_1000  = 0xA1,  // 1k SPS
    ADS1256_DR_500   = 0x92,  // 500 SPS
    ADS1256_DR_100   = 0x82,  // 100 SPS
    ADS1256_DR_60    = 0x72,  // 60 SPS
    ADS1256_DR_50    = 0x63,  // 50 SPS
    ADS1256_DR_30    = 0x53,  // 30 SPS
    ADS1256_DR_25    = 0x43,  // 25 SPS
    ADS1256_DR_15    = 0x33,  // 15 SPS
    ADS1256_DR_10    = 0x23,  // 10 SPS
    ADS1256_DR_5     = 0x13,  // 5 SPS
    ADS1256_DR_2_5   = 0x03   // 2.5 SPS
} ADS1256_DataRate_t;

// 采集数据结构体
typedef struct {
    int32_t raw_data;         // 原始24位数据
    float voltage;            // 转换后的电压值
    uint8_t channel;          // 通道号
    uint32_t timestamp;       // 时间戳
    bool valid;               // 数据有效性
} ADS1256_Data_t;

// 系统配置结构体
typedef struct {
    ADS1256_Gain_t gain;      // 增益设置
    ADS1256_DataRate_t rate;  // 采样率设置
    bool buffer_enable;       // 输入缓冲使能
    bool auto_calibration;    // 自动校准使能
    float vref;               // 参考电压
} ADS1256_Config_t;

// 函数声明
bool ADS1256_Init(void);
void ADS1256_Reset(void);
void ADS1256_Config(ADS1256_Config_t *config);
void ADS1256_SetChannel(ADS1256_Channel_t channel);
void ADS1256_SetGain(ADS1256_Gain_t gain);
void ADS1256_SetDataRate(ADS1256_DataRate_t rate);
bool ADS1256_ReadData(ADS1256_Data_t *data);
bool ADS1256_ReadChannel(uint8_t channel, float *voltage);
void ADS1256_SelfCalibration(void);
void ADS1256_SystemCalibration(void);
float ADS1256_GetVoltage(int32_t raw_data);
void ADS1256_WaitDRDY(void);
void ADS1256_StartConversion(void);
void ADS1256_StopConversion(void);

#endif /* __ADS1256_H */

3.2 SPI 底层驱动 (spi.c)

c 复制代码
#include "spi.h"
#include "stm32f10x_spi.h"

// SPI初始化
void SPI_InitConfig(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;
    
    // 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
    
    // 配置SPI引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;  // SCK, MOSI
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;  // MISO
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;  // CS
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置SPI参数
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;      // CPOL=0
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;    // CPHA=1
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; // 2.25MHz
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStructure);
    
    // 使能SPI
    SPI_Cmd(SPI1, ENABLE);
}

// SPI发送接收字节
uint8_t SPI_ReadWriteByte(uint8_t data) {
    // 等待发送缓冲区空
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    
    // 发送数据
    SPI_I2S_SendData(SPI1, data);
    
    // 等待接收完成
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    
    // 返回接收的数据
    return SPI_I2S_ReceiveData(SPI1);
}

// 片选控制
void SPI_CS_Select(void) {
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);
}

void SPI_CS_Deselect(void) {
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

3.3 ADS1256 核心驱动 (ads1256.c)

c 复制代码
#include "ads1256.h"
#include "spi.h"
#include "delay.h"

// 全局变量
static ADS1256_Config_t ads_config = {
    .gain = ADS1256_GAIN_1,
    .rate = ADS1256_DR_1000,
    .buffer_enable = true,
    .auto_calibration = true,
    .vref = 5.0f
};

// 写寄存器
static void ADS1256_WriteReg(uint8_t reg, uint8_t value) {
    SPI_CS_Select();
    SPI_ReadWriteByte(ADS1256_CMD_WREG | reg);
    SPI_ReadWriteByte(0x00);  // 写1个寄存器
    SPI_ReadWriteByte(value);
    SPI_CS_Deselect();
    Delay_us(10);
}

// 读寄存器
static uint8_t ADS1256_ReadReg(uint8_t reg) {
    uint8_t value;
    
    SPI_CS_Select();
    SPI_ReadWriteByte(ADS1256_CMD_RREG | reg);
    SPI_ReadWriteByte(0x00);  // 读1个寄存器
    Delay_us(10);
    value = SPI_ReadWriteByte(0xFF);
    SPI_CS_Deselect();
    
    return value;
}

// 发送命令
static void ADS1256_SendCmd(uint8_t cmd) {
    SPI_CS_Select();
    SPI_ReadWriteByte(cmd);
    SPI_CS_Deselect();
    Delay_us(10);
}

// 等待DRDY信号
void ADS1256_WaitDRDY(void) {
    while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 1) {
        // 等待DRDY变低
    }
}

// 初始化ADS1256
bool ADS1256_Init(void) {
    uint8_t id;
    
    // 复位ADS1256
    ADS1256_Reset();
    Delay_ms(100);
    
    // 读取ID寄存器
    id = ADS1256_ReadReg(ADS1256_STATUS);
    if ((id & 0x70) != 0x30) {  // 检查ID位
        return false;
    }
    
    // 配置默认参数
    ADS1256_Config(&ads_config);
    
    // 执行自校准
    if (ads_config.auto_calibration) {
        ADS1256_SelfCalibration();
    }
    
    return true;
}

// 复位ADS1256
void ADS1256_Reset(void) {
    ADS1256_SendCmd(ADS1256_CMD_RESET);
    Delay_ms(10);
}

// 配置ADS1256
void ADS1256_Config(ADS1256_Config_t *config) {
    uint8_t status_reg;
    
    if (config == NULL) return;
    
    // 配置状态寄存器
    status_reg = 0x00;
    if (config->buffer_enable) {
        status_reg |= 0x02;  // 使能输入缓冲
    }
    ADS1256_WriteReg(ADS1256_STATUS, status_reg);
    
    // 配置MUX寄存器(默认通道0)
    ADS1256_WriteReg(ADS1256_MUX, ADS1256_CH0);
    
    // 配置ADCON寄存器(增益设置)
    ADS1256_WriteReg(ADS1256_ADCON, config->gain);
    
    // 配置数据速率
    ADS1256_WriteReg(ADS1256_DRATE, config->rate);
    
    // 保存配置
    ads_config = *config;
}

// 设置通道
void ADS1256_SetChannel(ADS1256_Channel_t channel) {
    ADS1256_WriteReg(ADS1256_MUX, channel);
    Delay_us(50);  // 通道切换后需要稳定时间
}

// 设置增益
void ADS1256_SetGain(ADS1256_Gain_t gain) {
    uint8_t adcon = ADS1256_ReadReg(ADS1256_ADCON);
    adcon = (adcon & 0xF8) | gain;  // 清除低3位,设置增益
    ADS1256_WriteReg(ADS1256_ADCON, adcon);
}

// 设置数据速率
void ADS1256_SetDataRate(ADS1256_DataRate_t rate) {
    ADS1256_WriteReg(ADS1256_DRATE, rate);
}

// 读取转换数据
bool ADS1256_ReadData(ADS1256_Data_t *data) {
    uint8_t buffer[3];
    int32_t raw_value;
    
    if (data == NULL) return false;
    
    // 等待数据就绪
    ADS1256_WaitDRDY();
    
    // 发送读取数据命令
    SPI_CS_Select();
    SPI_ReadWriteByte(ADS1256_CMD_RDATA);
    Delay_us(10);  // t6等待时间
    
    // 读取24位数据
    buffer[0] = SPI_ReadWriteByte(0xFF);
    buffer[1] = SPI_ReadWriteByte(0xFF);
    buffer[2] = SPI_ReadWriteByte(0xFF);
    SPI_CS_Deselect();
    
    // 转换为32位有符号整数
    raw_value = ((int32_t)buffer[0] << 16) |
                ((int32_t)buffer[1] << 8)  |
                (int32_t)buffer[2];
    
    // 符号扩展(24位补码转32位)
    if (raw_value & 0x800000) {
        raw_value |= 0xFF000000;
    }
    
    data->raw_data = raw_value;
    data->voltage = ADS1256_GetVoltage(raw_value);
    data->timestamp = Get_SystemTick();
    data->valid = true;
    
    return true;
}

// 读取指定通道电压
bool ADS1256_ReadChannel(uint8_t channel, float *voltage) {
    ADS1256_Channel_t ch;
    ADS1256_Data_t data;
    
    if (channel > 7 || voltage == NULL) return false;
    
    // 设置通道
    ch = (ADS1256_Channel_t)(channel << 4);
    ADS1256_SetChannel(ch);
    
    // 启动转换
    ADS1256_SendCmd(ADS1256_CMD_SYNC);
    ADS1256_SendCmd(ADS1256_CMD_WAKEUP);
    
    // 读取数据
    if (ADS1256_ReadData(&data)) {
        *voltage = data.voltage;
        return true;
    }
    
    return false;
}

// 将原始数据转换为电压值
float ADS1256_GetVoltage(int32_t raw_data) {
    float voltage;
    float gain_factor;
    
    // 根据增益计算系数
    switch (ads_config.gain) {
        case ADS1256_GAIN_1:  gain_factor = 1.0f; break;
        case ADS1256_GAIN_2:  gain_factor = 2.0f; break;
        case ADS1256_GAIN_4:  gain_factor = 4.0f; break;
        case ADS1256_GAIN_8:  gain_factor = 8.0f; break;
        case ADS1256_GAIN_16: gain_factor = 16.0f; break;
        case ADS1256_GAIN_32: gain_factor = 32.0f; break;
        case ADS1256_GAIN_64: gain_factor = 64.0f; break;
        default: gain_factor = 1.0f; break;
    }
    
    // 计算电压:V = (RawData / 2^23) * VREF / Gain
    voltage = ((float)raw_data / 8388608.0f) * ads_config.vref / gain_factor;
    
    return voltage;
}

// 自校准
void ADS1256_SelfCalibration(void) {
    printf("Starting Self-Calibration...\n");
    ADS1256_SendCmd(ADS1256_CMD_SELFCAL);
    ADS1256_WaitDRDY();
    printf("Self-Calibration Complete.\n");
}

// 系统偏移校准
void ADS1256_SystemCalibration(void) {
    printf("Starting System Offset Calibration...\n");
    ADS1256_SendCmd(ADS1256_CMD_SYSOCAL);
    ADS1256_WaitDRDY();
    printf("System Calibration Complete.\n");
}

3.4 主程序 (main.c)

c 复制代码
#include "stm32f10x.h"
#include "ads1256.h"
#include "spi.h"
#include "usart.h"
#include "delay.h"
#include "led.h"

// 全局变量
ADS1256_Data_t adc_data[8];
uint8_t current_channel = 0;
uint32_t sample_count = 0;

// 系统初始化
void System_Init(void) {
    SystemClock_Init();
    Delay_Init();
    USART_Init(115200);
    LED_Init();
    SPI_InitConfig();
    
    printf("ADS1256 High Precision Data Acquisition System\r\n");
    printf("================================================\r\n");
    
    // 初始化ADS1256
    if (ADS1256_Init()) {
        printf("ADS1256 Initialized Successfully!\r\n");
        LED_On(LED_GREEN);
    } else {
        printf("ADS1256 Initialization Failed!\r\n");
        LED_On(LED_RED);
        while(1);
    }
    
    // 配置采集参数
    ADS1256_Config_t config = {
        .gain = ADS1256_GAIN_1,
        .rate = ADS1256_DR_1000,  // 1kSPS
        .buffer_enable = true,
        .auto_calibration = true,
        .vref = 5.0f
    };
    ADS1256_Config(&config);
    
    printf("Configuration Complete.\r\n");
    printf("Gain: 1x, Sample Rate: 1kSPS\r\n");
}

// 多通道扫描
void Scan_AllChannels(void) {
    for (uint8_t ch = 0; ch < 8; ch++) {
        if (ADS1256_ReadChannel(ch, &adc_data[ch].voltage)) {
            adc_data[ch].raw_data = (int32_t)(adc_data[ch].voltage * 8388608.0f / 5.0f);
            adc_data[ch].channel = ch;
            adc_data[ch].valid = true;
        }
        Delay_ms(1);  // 通道切换延时
    }
}

// 显示采集结果
void Display_Results(void) {
    static uint32_t last_display = 0;
    
    if (Get_SystemTick() - last_display >= 1000) {  // 每秒显示一次
        printf("Sample Count: %lu\r\n", sample_count);
        printf("Channel Voltages (V):\r\n");
        
        for (uint8_t i = 0; i < 8; i++) {
            printf("CH%d: %+8.6f  ", i, adc_data[i].voltage);
            if ((i + 1) % 4 == 0) printf("\r\n");
        }
        printf("==========================================\r\n");
        
        last_display = Get_SystemTick();
    }
}

int main(void) {
    // 系统初始化
    System_Init();
    
    printf("Starting Data Acquisition...\r\n");
    
    while(1) {
        // 扫描所有通道
        Scan_AllChannels();
        sample_count++;
        
        // 显示结果
        Display_Results();
        
        // LED指示采样状态
        if (sample_count % 100 == 0) {
            LED_Toggle(LED_BLUE);
        }
        
        Delay_ms(10);  // 控制采样间隔
    }
}

参考代码 利用STM32和ADS1256进行数据采集 www.youwenfan.com/contentcsu/60828.html

四、工程配置与优化

4.1 编译配置

复制代码
Keil MDK-ARM 工程配置:
• Target: STM32F103C8
• Code Generation: ARM Compiler 6
• Optimization: Level 2 (-O2)
• Include Paths: 
  - ./Inc
  - ./Drivers/STM32F10x_StdPeriph_Driver/inc
  - ./ADS1256

4.2 性能优化建议

优化项目 建议方案
采样精度 使用外部基准电压源,避免电源噪声
抗干扰 模拟地与数字地单点连接,使用磁珠隔离
采样速度 根据需求选择合适的采样率,避免过高
温度漂移 定期执行系统校准,考虑温度补偿
数据稳定 增加软件滤波(中值滤波、均值滤波)

4.3 常见问题解决

问题 原因 解决方案
数据跳动大 电源噪声干扰 增加电源滤波,使用线性稳压器
通道间串扰 输入阻抗不匹配 添加电压跟随器,降低输出阻抗
采样值偏低 增益设置错误 检查增益配置,重新校准
通信失败 SPI时序问题 降低SPI时钟频率,检查CPOL/CPHA
温度漂移 基准电压温漂 使用低温漂基准源,如REF5025
相关推荐
黑白园1 小时前
ADC读取XY二轴操纵杆数据通过I2C_GPIO模拟 控制0.96寸OLED显示
stm32·单片机·嵌入式硬件
一个平凡而乐于分享的小比特2 小时前
还在手动挡写单片机?MicroPython 一脚油门踩进 Python 硬件世界
单片机·嵌入式硬件·micropython
FreakStudio3 小时前
WIZnet-EVB-Pico2开始,用MicroPython玩转以太网开发
python·单片机·嵌入式·大学生·面向对象·技术栈·并行计算·电子diy·电子计算机
LCG元3 小时前
STM32实战:基于STM32F103的工业仪表数据采集(多路ADC)
stm32·单片机·嵌入式硬件
BT-BOX4 小时前
Stm32CubeMX+Proteus仿真--STM32外部中断
stm32·单片机·proteus
Wallystech-Linda5 小时前
DR9574 vs DR9574S — Choosing the Right IPQ9574 WiFi 7 Platform for Your Network
嵌入式硬件
森利威尔电子-5 小时前
森利威尔SL8700 降压型大功率 LED 恒流驱动器:5A/95%效率,支持 PWM/模拟调光
单片机·嵌入式硬件·集成电路·芯片·电源芯片
三佛科技-187366133975 小时前
GP8892SEH贴片SOP7省外围5V2A隔离型原边反馈芯片直接替代MT3723
单片机·嵌入式硬件
Quinn275 小时前
正点原子 STM32MP257 修复异核 FreeRTOS 例程 osDelay() 函数比 HAL_Delay() 延时快的问题
stm32·单片机·嵌入式硬件