STM32F103 + ADS1255 双通道连续读取方案

STM32F103 + ADS1255 双通道连续读取方案

ADS1255驱动程序,实现双通道自动切换、连续读取、数据滤波、SPI通信


一、ADS1255特性

参数 说明
分辨率 24位 无失码
采样率 30kSPS 最大
通道 4路差分/8路单端  
接口 SPI 模式1
基准电压 2.5V 内部/外部
输入范围 ±Vref 可编程增益
功耗 7.5mW 正常工作

推荐配置


二、硬件连接

STM32F103          ADS1255
PA4 (SPI1_CS)  ->  CS
PA5 (SPI1_SCK) ->  SCLK
PA6 (SPI1_MISO) -> DOUT
PA7 (SPI1_MOSI) -> DIN
PB0 (DRDY)     ->  DRDY
PB1 (RESET)    ->  RESET
PB2 (PWDN)     ->  PWDN

电源:
3.3V -> AVDD, DVDD
GND  -> AGND, DGND
2.5V -> REF0+ (基准)

注意事项


三、程序架构

ADS1255_Driver/
├── ads1255.h
├── ads1255.c
├── spi.c
├── interrupt.c
└── main.c

四、ADS1255驱动程序

1、头文件定义

// ads1255.h
#ifndef __ADS1255_H
#define __ADS1255_H

#include "stm32f1xx_hal.h"

// ADS1255寄存器地址
#define ADS1255_REG_STATUS  0x00
#define ADS1255_REG_MUX     0x01
#define ADS1255_REG_ADCON   0x02
#define ADS1255_REG_DRATE   0x03
#define ADS1255_REG_IO      0x04
#define ADS1255_REG_OFC0    0x05
#define ADS1255_REG_OFC1    0x06
#define ADS1255_REG_OFC2    0x07
#define ADS1255_REG_FSC0    0x08
#define ADS1255_REG_FSC1    0x09
#define ADS1255_REG_FSC2    0x0A

// ADS1255命令
#define ADS1255_CMD_WAKEUP  0x00
#define ADS1255_CMD_RDATA   0x01
#define ADS1255_CMD_RDATAC  0x03
#define ADS1255_CMD_SDATAC  0x0F
#define ADS1255_CMD_RREG    0x10
#define ADS1255_CMD_WREG    0x50
#define ADS1255_CMD_SELFCAL 0xF0
#define ADS1255_CMD_SELFOCAL 0xF1
#define ADS1255_CMD_SELFGCAL 0xF2
#define ADS1255_CMD_SYSOCAL 0xF3
#define ADS1255_CMD_SYSGCAL 0xF4
#define ADS1255_CMD_SYNC    0xFC
#define ADS1255_CMD_STANDBY 0xFD
#define ADS1255_CMD_RESET   0xFE
#define ADS1255_CMD_WAKEUP2 0xFF

// 多路复用器配置
#define ADS1255_MUX_AIN0    0x00
#define ADS1255_MUX_AIN1    0x10
#define ADS1255_MUX_AIN2    0x20
#define ADS1255_MUX_AIN3    0x30
#define ADS1255_MUX_AIN4    0x40
#define ADS1255_MUX_AIN5    0x50
#define ADS1255_MUX_AIN6    0x60
#define ADS1255_MUX_AIN7    0x70
#define ADS1255_MUX_AINCOM  0x80

// 增益设置
#define ADS1255_GAIN_1      0x00
#define ADS1255_GAIN_2      0x01
#define ADS1255_GAIN_4      0x02
#define ADS1255_GAIN_8      0x03
#define ADS1255_GAIN_16     0x04
#define ADS1255_GAIN_32     0x05
#define ADS1255_GAIN_64     0x06

// 数据速率
#define ADS1255_DRATE_30000 0xF0
#define ADS1255_DRATE_15000 0xE0
#define ADS1255_DRATE_7500  0xD0
#define ADS1255_DRATE_3750  0xC0
#define ADS1255_DRATE_2000  0xB0
#define ADS1255_DRATE_1000  0xA1
#define ADS1255_DRATE_500   0x92
#define ADS1255_DRATE_100   0x82
#define ADS1255_DRATE_60    0x72
#define ADS1255_DRATE_50    0x63
#define ADS1255_DRATE_30    0x53
#define ADS1255_DRATE_25    0x43
#define ADS1255_DRATE_15    0x33
#define ADS1255_DRATE_10    0x23
#define ADS1255_DRATE_5     0x13
#define ADS1255_DRATE_2_5   0x03

// 通道配置
typedef enum {
    CH_0_1 = 0,  // AIN0-AIN1
    CH_1_2,      // AIN1-AIN2
    CH_2_3,      // AIN2-AIN3
    CH_3_4,      // AIN3-AIN4
    CH_4_5,      // AIN4-AIN5
    CH_5_6,      // AIN5-AIN6
    CH_6_7,      // AIN6-AIN7
    CH_7_0,      // AIN7-AIN0
    CH_NONE = 0xFF
} ADS1255_Channel_t;

// ADS1255配置
typedef struct {
    uint8_t mux_config;     // 多路复用器配置
    uint8_t adcon_config;   // 增益和缓冲
    uint8_t drate_config;   // 数据速率
    uint8_t io_config;      // IO配置
} ADS1255_Config_t;

// 采集数据
typedef struct {
    int32_t raw_data;       // 原始24位数据
    float voltage;         // 转换后的电压
    uint8_t channel;       // 通道号
    uint32_t timestamp;    // 时间戳
} ADS1255_Data_t;

// 双通道采集
typedef struct {
    ADS1255_Data_t ch0_data;  // 通道0数据
    ADS1255_Data_t ch1_data;  // 通道1数据
    uint8_t current_channel;  // 当前通道
    uint8_t ready_flag;      // 数据就绪标志
} DualChannel_Data_t;

// 函数声明
void ADS1255_Init(void);
void ADS1255_Reset(void);
void ADS1255_Config(ADS1255_Config_t *config);
void ADS1255_SetChannel(ADS1255_Channel_t channel);
void ADS1255_StartConversion(void);
void ADS1255_StopConversion(void);
int32_t ADS1255_ReadData(void);
void ADS1255_ReadContinuous(void);
void ADS1255_Calibrate(void);
float ADS1255_ConvertToVoltage(int32_t raw_data, float vref, uint8_t gain);
void ADS1255_DualChannel_Init(void);
void ADS1255_DualChannel_Read(void);
void ADS1255_DRDY_Interrupt_Callback(void);

#endif

2、GPIO初始化

// ads1255_gpio.c
#include "ads1255.h"

// GPIO定义
#define ADS1255_CS_PORT     GPIOA
#define ADS1255_CS_PIN      GPIO_PIN_4
#define ADS1255_DRDY_PORT   GPIOB
#define ADS1255_DRDY_PIN    GPIO_PIN_0
#define ADS1255_RESET_PORT  GPIOB
#define ADS1255_RESET_PIN   GPIO_PIN_1
#define ADS1255_PWDN_PORT   GPIOB
#define ADS1255_PWDN_PIN    GPIO_PIN_2

// GPIO初始化
void ADS1255_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // 使能时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    
    // CS引脚 (输出)
    GPIO_InitStruct.Pin = ADS1255_CS_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(ADS1255_CS_PORT, &GPIO_InitStruct);
    ADS1255_CS_HIGH();  // 默认CS高电平
    
    // DRDY引脚 (输入,中断)
    GPIO_InitStruct.Pin = ADS1255_DRDY_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;  // 下降沿中断
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(ADS1255_DRDY_PORT, &GPIO_InitStruct);
    
    // RESET引脚 (输出)
    GPIO_InitStruct.Pin = ADS1255_RESET_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(ADS1255_RESET_PORT, &GPIO_InitStruct);
    ADS1255_RESET_HIGH();  // 默认不复位
    
    // PWDN引脚 (输出)
    GPIO_InitStruct.Pin = ADS1255_PWDN_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(ADS1255_PWDN_PORT, &GPIO_InitStruct);
    ADS1255_PWDN_LOW();  // 默认不休眠
    
    // 配置中断
    HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

// GPIO控制宏
#define ADS1255_CS_LOW()    HAL_GPIO_WritePin(ADS1255_CS_PORT, ADS1255_CS_PIN, GPIO_PIN_RESET)
#define ADS1255_CS_HIGH()   HAL_GPIO_WritePin(ADS1255_CS_PORT, ADS1255_CS_PIN, GPIO_PIN_SET)
#define ADS1255_RESET_LOW() HAL_GPIO_WritePin(ADS1255_RESET_PORT, ADS1255_RESET_PIN, GPIO_PIN_RESET)
#define ADS1255_RESET_HIGH() HAL_GPIO_WritePin(ADS1255_RESET_PORT, ADS1255_RESET_PIN, GPIO_PIN_SET)
#define ADS1255_PWDN_LOW()  HAL_GPIO_WritePin(ADS1255_PWDN_PORT, ADS1255_PWDN_PIN, GPIO_PIN_RESET)
#define ADS1255_PWDN_HIGH() HAL_GPIO_WritePin(ADS1255_PWDN_PORT, ADS1255_PWDN_PIN, GPIO_PIN_SET)
#define ADS1255_DRDY_READ() HAL_GPIO_ReadPin(ADS1255_DRDY_PORT, ADS1255_DRDY_PIN)

3、SPI驱动

// ads1255_spi.c
#include "ads1255.h"

// SPI句柄
SPI_HandleTypeDef hspi1;

// SPI初始化
void ADS1255_SPI_Init(void)
{
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;      // CPOL=0
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;         // CPHA=0 (模式0)
    hspi1.Init.NSS = SPI_NSS_SOFT;                 // 软件CS
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;  // 9MHz (72/8)
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
    hspi1.Init.CRCPolynomial = 10;
    
    HAL_SPI_Init(&hspi1);
}

// SPI发送一个字节
static uint8_t ADS1255_SPI_SendByte(uint8_t data)
{
    uint8_t rx_data = 0;
    
    HAL_SPI_TransmitReceive(&hspi1, &data, &rx_data, 1, 1000);
    
    return rx_data;
}

// SPI发送命令
static void ADS1255_SPI_SendCmd(uint8_t cmd)
{
    ADS1255_CS_LOW();
    HAL_Delay(1);  // 短暂延时
    ADS1255_SPI_SendByte(cmd);
    HAL_Delay(1);
    ADS1255_CS_HIGH();
}

// SPI读取寄存器
static uint8_t ADS1255_SPI_ReadReg(uint8_t reg)
{
    uint8_t data = 0;
    
    ADS1255_CS_LOW();
    
    // 发送读寄存器命令
    ADS1255_SPI_SendByte(ADS1255_CMD_RREG | reg);
    
    // 发送要读取的寄存器数-1
    ADS1255_SPI_SendByte(0x00);
    
    // 读取寄存器值
    data = ADS1255_SPI_SendByte(0xFF);
    
    ADS1255_CS_HIGH();
    
    return data;
}

// SPI写入寄存器
static void ADS1255_SPI_WriteReg(uint8_t reg, uint8_t data)
{
    ADS1255_CS_LOW();
    
    // 发送写寄存器命令
    ADS1255_SPI_SendByte(ADS1255_CMD_WREG | reg);
    
    // 发送要写入的寄存器数-1
    ADS1255_SPI_SendByte(0x00);
    
    // 写入寄存器值
    ADS1255_SPI_SendByte(data);
    
    ADS1255_CS_HIGH();
}

4、ADS1255核心驱动

// ads1255.c
#include "ads1255.h"
#include <math.h>

// 全局变量
static float vref = 2.5f;  // 基准电压
static uint8_t current_gain = ADS1255_GAIN_1;
static DualChannel_Data_t dual_channel_data = {0};
static uint8_t ads1255_initialized = 0;

// ADS1255初始化
void ADS1255_Init(void)
{
    // 1. 初始化GPIO
    ADS1255_GPIO_Init();
    
    // 2. 初始化SPI
    ADS1255_SPI_Init();
    
    // 3. 复位ADS1255
    ADS1255_Reset();
    
    // 4. 等待上电稳定
    HAL_Delay(100);
    
    // 5. 发送同步命令
    ADS1255_SPI_SendCmd(ADS1255_CMD_SYNC);
    HAL_Delay(1);
    ADS1255_SPI_SendCmd(ADS1255_CMD_WAKEUP);
    HAL_Delay(1);
    
    // 6. 配置寄存器
    ADS1255_Config_t config = {
        .mux_config = ADS1255_MUX_AIN0 | (ADS1255_MUX_AIN1 >> 4),  // AIN0-AIN1
        .adcon_config = (ADS1255_GAIN_1 << 4) | 0x00,  // 增益1,缓冲关闭
        .drate_config = ADS1255_DRATE_1000,  // 1000SPS
        .io_config = 0x00  // GPIO全部为输入
    };
    
    ADS1255_Config(&config);
    
    // 7. 自校准
    ADS1255_Calibrate();
    
    ads1255_initialized = 1;
    
    printf("ADS1255初始化完成\r\n");
}

// ADS1255复位
void ADS1255_Reset(void)
{
    // 硬件复位
    ADS1255_RESET_LOW();
    HAL_Delay(1);
    ADS1255_RESET_HIGH();
    HAL_Delay(1);
    
    // 软件复位
    ADS1255_SPI_SendCmd(ADS1255_CMD_RESET);
    HAL_Delay(2);  // 等待复位完成
}

// ADS1255配置
void ADS1255_Config(ADS1255_Config_t *config)
{
    if (!ads1255_initialized) return;
    
    // 停止连续转换
    ADS1255_StopConversion();
    
    // 写入配置寄存器
    ADS1255_SPI_WriteReg(ADS1255_REG_MUX, config->mux_config);
    ADS1255_SPI_WriteReg(ADS1255_REG_ADCON, config->adcon_config);
    ADS1255_SPI_WriteReg(ADS1255_REG_DRATE, config->drate_config);
    ADS1255_SPI_WriteReg(ADS1255_REG_IO, config->io_config);
    
    // 保存当前增益
    current_gain = (config->adcon_config >> 4) & 0x07;
    
    printf("ADS1255配置完成\r\n");
    printf("  MUX: 0x%02X\r\n", config->mux_config);
    printf("  ADCON: 0x%02X\r\n", config->adcon_config);
    printf("  DRATE: 0x%02X\r\n", config->drate_config);
}

// 设置通道
void ADS1255_SetChannel(ADS1255_Channel_t channel)
{
    if (!ads1255_initialized) return;
    
    uint8_t mux_value = 0;
    
    switch(channel) {
        case CH_0_1: mux_value = ADS1255_MUX_AIN0 | (ADS1255_MUX_AIN1 >> 4); break;
        case CH_1_2: mux_value = ADS1255_MUX_AIN1 | (ADS1255_MUX_AIN2 >> 4); break;
        case CH_2_3: mux_value = ADS1255_MUX_AIN2 | (ADS1255_MUX_AIN3 >> 4); break;
        case CH_3_4: mux_value = ADS1255_MUX_AIN3 | (ADS1255_MUX_AIN4 >> 4); break;
        case CH_4_5: mux_value = ADS1255_MUX_AIN4 | (ADS1255_MUX_AIN5 >> 4); break;
        case CH_5_6: mux_value = ADS1255_MUX_AIN5 | (ADS1255_MUX_AIN6 >> 4); break;
        case CH_6_7: mux_value = ADS1255_MUX_AIN6 | (ADS1255_MUX_AIN7 >> 4); break;
        case CH_7_0: mux_value = ADS1255_MUX_AIN7 | (ADS1255_MUX_AIN0 >> 4); break;
        default: return;
    }
    
    // 写入MUX寄存器
    ADS1255_SPI_WriteReg(ADS1255_REG_MUX, mux_value);
    
    // 发送同步命令
    ADS1255_SPI_SendCmd(ADS1255_CMD_SYNC);
    HAL_Delay(1);
    ADS1255_SPI_SendCmd(ADS1255_CMD_WAKEUP);
    
    printf("设置通道: %d\r\n", channel);
}

// 开始连续转换
void ADS1255_StartConversion(void)
{
    if (!ads1255_initialized) return;
    
    // 发送开始连续转换命令
    ADS1255_SPI_SendCmd(ADS1255_CMD_RDATAC);
    
    printf("开始连续转换\r\n");
}

// 停止连续转换
void ADS1255_StopConversion(void)
{
    if (!ads1255_initialized) return;
    
    // 发送停止连续转换命令
    ADS1255_SPI_SendCmd(ADS1255_CMD_SDATAC);
    
    printf("停止连续转换\r\n");
}

// 读取24位数据
int32_t ADS1255_ReadData(void)
{
    uint8_t data[3] = {0};
    int32_t result = 0;
    
    if (!ads1255_initialized) return 0;
    
    // 等待DRDY变低
    uint32_t timeout = 1000000;
    while (ADS1255_DRDY_READ() == GPIO_PIN_SET) {
        timeout--;
        if (timeout == 0) {
            printf("等待DRDY超时\r\n");
            return 0;
        }
    }
    
    ADS1255_CS_LOW();
    
    // 读取3个字节
    data[0] = ADS1255_SPI_SendByte(0xFF);
    data[1] = ADS1255_SPI_SendByte(0xFF);
    data[2] = ADS1255_SPI_SendByte(0xFF);
    
    ADS1255_CS_HIGH();
    
    // 组合24位数据
    result = ((int32_t)data[0] << 16) | ((int32_t)data[1] << 8) | data[2];
    
    // 处理符号扩展(24位有符号数)
    if (result & 0x00800000) {  // 如果最高位(bit23)为1
        result |= 0xFF000000;    // 扩展为32位有符号数
    }
    
    return result;
}

// 读取数据并转换电压
float ADS1255_ReadVoltage(ADS1255_Channel_t channel)
{
    int32_t raw_data = 0;
    float voltage = 0.0f;
    
    // 设置通道
    ADS1255_SetChannel(channel);
    HAL_Delay(2);  // 等待稳定
    
    // 读取数据
    raw_data = ADS1255_ReadData();
    
    // 转换电压
    voltage = ADS1255_ConvertToVoltage(raw_data, vref, current_gain);
    
    return voltage;
}

// 原始数据转电压
float ADS1255_ConvertToVoltage(int32_t raw_data, float vref, uint8_t gain)
{
    float voltage = 0.0f;
    
    // 计算电压
    // 24位ADC,满量程范围: -Vref/gain 到 +Vref/gain
    // 编码范围: -2^23 到 2^23-1
    voltage = (float)raw_data * vref / (8388608.0f * gain);
    
    return voltage;
}

// 校准
void ADS1255_Calibrate(void)
{
    if (!ads1255_initialized) return;
    
    printf("开始校准...\r\n");
    
    // 自校准
    ADS1255_SPI_SendCmd(ADS1255_CMD_SELFCAL);
    HAL_Delay(100);  // 等待校准完成
    
    printf("校准完成\r\n");
}

5、双通道连续读取

// ads1255_dual_channel.c
#include "ads1255.h"

// 双通道采集缓冲区
#define BUFFER_SIZE 256
static ADS1255_Data_t ch0_buffer[BUFFER_SIZE];
static ADS1255_Data_t ch1_buffer[BUFFER_SIZE];
static uint16_t buffer_index = 0;
static uint8_t is_collecting = 0;

// 双通道初始化
void ADS1255_DualChannel_Init(void)
{
    // 初始化ADS1255
    ADS1255_Init();
    
    // 配置为双通道自动切换
    ADS1255_Config_t config = {
        .mux_config = ADS1255_MUX_AIN0 | (ADS1255_MUX_AIN1 >> 4),  // 初始通道0-1
        .adcon_config = (ADS1255_GAIN_1 << 4) | 0x00,
        .drate_config = ADS1255_DRATE_1000,
        .io_config = 0x00
    };
    
    ADS1255_Config(&config);
    
    // 清空缓冲区
    memset(ch0_buffer, 0, sizeof(ch0_buffer));
    memset(ch1_buffer, 0, sizeof(ch1_buffer));
    buffer_index = 0;
    
    dual_channel_data.current_channel = 0;
    dual_channel_data.ready_flag = 0;
    
    printf("双通道采集初始化完成\r\n");
}

// 双通道连续采集任务
void ADS1255_DualChannel_Collect_Task(void)
{
    static uint32_t last_time = 0;
    static uint8_t current_channel = 0;
    int32_t raw_data = 0;
    float voltage = 0.0f;
    
    if (!is_collecting) return;
    
    // 检查是否超时
    if (HAL_GetTick() - last_time < 1) {  // 1ms间隔
        return;
    }
    
    last_time = HAL_GetTick();
    
    // 切换通道
    if (current_channel == 0) {
        // 切换到通道0
        ADS1255_SetChannel(CH_0_1);
        current_channel = 1;
    } else {
        // 切换到通道1
        ADS1255_SetChannel(CH_1_2);
        current_channel = 0;
    }
    
    // 等待转换完成
    HAL_Delay(1);
    
    // 读取数据
    raw_data = ADS1255_ReadData();
    voltage = ADS1255_ConvertToVoltage(raw_data, vref, current_gain);
    
    // 存储数据
    if (current_channel == 0) {
        // 通道1数据
        dual_channel_data.ch1_data.raw_data = raw_data;
        dual_channel_data.ch1_data.voltage = voltage;
        dual_channel_data.ch1_data.channel = 1;
        dual_channel_data.ch1_data.timestamp = HAL_GetTick();
        
        // 保存到缓冲区
        if (buffer_index < BUFFER_SIZE) {
            ch1_buffer[buffer_index] = dual_channel_data.ch1_data;
        }
    } else {
        // 通道0数据
        dual_channel_data.ch0_data.raw_data = raw_data;
        dual_channel_data.ch0_data.voltage = voltage;
        dual_channel_data.ch0_data.channel = 0;
        dual_channel_data.ch0_data.timestamp = HAL_GetTick();
        
        // 保存到缓冲区
        if (buffer_index < BUFFER_SIZE) {
            ch0_buffer[buffer_index] = dual_channel_data.ch0_data;
        }
        
        // 增加缓冲区索引
        buffer_index++;
        if (buffer_index >= BUFFER_SIZE) {
            buffer_index = 0;  // 循环缓冲区
        }
    }
    
    // 设置数据就绪标志
    dual_channel_data.ready_flag = 1;
    dual_channel_data.current_channel = current_channel;
}

// 开始采集
void ADS1255_StartCollect(void)
{
    is_collecting = 1;
    buffer_index = 0;
    printf("开始双通道采集\r\n");
}

// 停止采集
void ADS1255_StopCollect(void)
{
    is_collecting = 0;
    printf("停止双通道采集\r\n");
}

// 获取双通道数据
DualChannel_Data_t* ADS1255_GetDualChannelData(void)
{
    dual_channel_data.ready_flag = 0;  // 清除标志
    return &dual_channel_data;
}

// 获取缓冲区数据
void ADS1255_GetBufferData(ADS1255_Data_t** ch0_buf, ADS1255_Data_t** ch1_buf, uint16_t* size)
{
    *ch0_buf = ch0_buffer;
    *ch1_buf = ch1_buffer;
    *size = BUFFER_SIZE;
}

6、中断驱动版本(更高效率)

// ads1255_interrupt.c
#include "ads1255.h"

// 中断模式变量
static volatile uint8_t drdy_flag = 0;
static volatile uint8_t data_ready = 0;
static volatile int32_t adc_data = 0;
static volatile uint8_t current_channel_int = 0;
static ADS1255_Channel_t channel_list[2] = {CH_0_1, CH_1_2};
static uint8_t channel_index = 0;

// DRDY中断回调
void ADS1255_DRDY_Interrupt_Callback(void)
{
    if (__HAL_GPIO_EXTI_GET_IT(ADS1255_DRDY_PIN) != RESET) {
        __HAL_GPIO_EXTI_CLEAR_IT(ADS1255_DRDY_PIN);
        drdy_flag = 1;  // 设置标志
    }
}

// 中断模式读取
void ADS1255_Interrupt_Read(void)
{
    uint8_t data[3] = {0};
    
    if (!drdy_flag) return;
    
    drdy_flag = 0;  // 清除标志
    
    ADS1255_CS_LOW();
    
    // 读取3个字节
    data[0] = ADS1255_SPI_SendByte(0xFF);
    data[1] = ADS1255_SPI_SendByte(0xFF);
    data[2] = ADS1255_SPI_SendByte(0xFF);
    
    ADS1255_CS_HIGH();
    
    // 组合数据
    adc_data = ((int32_t)data[0] << 16) | ((int32_t)data[1] << 8) | data[2];
    
    // 处理符号扩展
    if (adc_data & 0x00800000) {
        adc_data |= 0xFF000000;
    }
    
    data_ready = 1;
    
    // 切换通道
    channel_index = (channel_index + 1) % 2;
    ADS1255_SetChannel(channel_list[channel_index]);
    current_channel_int = channel_index;
}

// 中断模式初始化
void ADS1255_Interrupt_Init(void)
{
    // 初始化ADS1255
    ADS1255_Init();
    
    // 配置中断
    EXTI_ConfigTypeDef exti_config = {0};
    
    // 配置GPIO中断
    exti_config.Line = EXTI_LINE_0;
    exti_config.Mode = EXTI_MODE_INTERRUPT;
    exti_config.Trigger = EXTI_TRIGGER_FALLING;
    exti_config.GPIOSel = EXTI_GPIOB;
    HAL_EXTI_SetConfigLine(&hexti0, &exti_config);
    
    // 使能中断
    HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
    
    // 开始连续转换
    ADS1255_StartConversion();
    
    printf("中断模式初始化完成\r\n");
}

// 获取中断模式数据
int ADS1255_GetInterruptData(int32_t* data, uint8_t* channel)
{
    if (data_ready) {
        *data = adc_data;
        *channel = current_channel_int;
        data_ready = 0;
        return 1;
    }
    return 0;
}

7、数据滤波处理

// ads1255_filter.c
#include "ads1255.h"

// 移动平均滤波器
typedef struct {
    float buffer[16];
    uint8_t index;
    float sum;
    uint8_t size;
} MovingAverage_Filter;

// 中值滤波器
typedef struct {
    float buffer[5];
    uint8_t index;
} Median_Filter;

// 初始化移动平均滤波器
void MovingAverage_Init(MovingAverage_Filter* filter, uint8_t size)
{
    memset(filter->buffer, 0, sizeof(filter->buffer));
    filter->index = 0;
    filter->sum = 0.0f;
    filter->size = (size > 16) ? 16 : size;
}

// 移动平均滤波
float MovingAverage_Filter_Update(MovingAverage_Filter* filter, float new_value)
{
    // 减去最旧的值
    filter->sum -= filter->buffer[filter->index];
    
    // 添加新值
    filter->buffer[filter->index] = new_value;
    filter->sum += new_value;
    
    // 更新索引
    filter->index = (filter->index + 1) % filter->size;
    
    // 返回平均值
    return filter->sum / filter->size;
}

// 中值滤波初始化
void Median_Filter_Init(Median_Filter* filter)
{
    memset(filter->buffer, 0, sizeof(filter->buffer));
    filter->index = 0;
}

// 中值滤波
float Median_Filter_Update(Median_Filter* filter, float new_value)
{
    float temp[5];
    uint8_t i, j;
    
    // 更新缓冲区
    filter->buffer[filter->index] = new_value;
    filter->index = (filter->index + 1) % 5;
    
    // 复制到临时数组
    for (i = 0; i < 5; i++) {
        temp[i] = filter->buffer[i];
    }
    
    // 冒泡排序
    for (i = 0; i < 4; i++) {
        for (j = 0; j < 4 - i; j++) {
            if (temp[j] > temp[j + 1]) {
                float swap = temp[j];
                temp[j] = temp[j + 1];
                temp[j + 1] = swap;
            }
        }
    }
    
    // 返回中值
    return temp[2];
}

// 数字低通滤波器
float LowPass_Filter(float input, float* prev_output, float alpha)
{
    float output = alpha * input + (1.0f - alpha) * (*prev_output);
    *prev_output = output;
    return output;
}

8、主程序示例

// main.c
#include "main.h"
#include "ads1255.h"

// 滤波器实例
MovingAverage_Filter ch0_filter;
MovingAverage_Filter ch1_filter;
float ch0_lpf_prev = 0;
float ch1_lpf_prev = 0;

int main(void)
{
    // HAL初始化
    HAL_Init();
    SystemClock_Config();
    
    // 外设初始化
    MX_GPIO_Init();
    MX_SPI1_Init();
    MX_USART1_UART_Init();  // 用于调试输出
    
    printf("STM32F103 + ADS1255 双通道采集系统\r\n");
    printf("==================================\r\n");
    
    // 初始化ADS1255双通道采集
    ADS1255_DualChannel_Init();
    
    // 初始化滤波器
    MovingAverage_Init(&ch0_filter, 8);
    MovingAverage_Init(&ch1_filter, 8);
    
    // 开始采集
    ADS1255_StartCollect();
    
    while (1)
    {
        static uint32_t last_display_time = 0;
        
        // 执行双通道采集
        ADS1255_DualChannel_Collect_Task();
        
        // 获取数据
        DualChannel_Data_t* data = ADS1255_GetDualChannelData();
        
        if (data->ready_flag)
        {
            // 应用滤波
            float ch0_filtered = MovingAverage_Filter_Update(&ch0_filter, 
                                                           data->ch0_data.voltage);
            float ch1_filtered = MovingAverage_Filter_Update(&ch1_filter,
                                                           data->ch1_data.voltage);
            
            // 低通滤波
            ch0_filtered = LowPass_Filter(ch0_filtered, &ch0_lpf_prev, 0.1f);
            ch1_filtered = LowPass_Filter(ch1_filtered, &ch1_lpf_prev, 0.1f);
            
            // 定期显示
            if (HAL_GetTick() - last_display_time > 1000)  // 1秒显示一次
            {
                last_display_time = HAL_GetTick();
                
                printf("通道0: %.6fV (原始: %.6fV)\r\n", 
                       ch0_filtered, data->ch0_data.voltage);
                printf("通道1: %.6fV (原始: %.6fV)\r\n", 
                       ch1_filtered, data->ch1_data.voltage);
                printf("-----\r\n");
                
                // 也可以计算统计数据
                ADS1255_CalculateStatistics();
            }
        }
        
        HAL_Delay(1);  // 1ms延时
    }
}

// 计算统计数据
void ADS1255_CalculateStatistics(void)
{
    ADS1255_Data_t* ch0_buf = NULL;
    ADS1255_Data_t* ch1_buf = NULL;
    uint16_t buf_size = 0;
    
    // 获取缓冲区数据
    ADS1255_GetBufferData(&ch0_buf, &ch1_buf, &buf_size);
    
    if (buf_size > 0)
    {
        float ch0_sum = 0, ch1_sum = 0;
        float ch0_max = -9999, ch0_min = 9999;
        float ch1_max = -9999, ch1_min = 9999;
        
        for (uint16_t i = 0; i < buf_size; i++)
        {
            // 通道0统计
            ch0_sum += ch0_buf[i].voltage;
            if (ch0_buf[i].voltage > ch0_max) ch0_max = ch0_buf[i].voltage;
            if (ch0_buf[i].voltage < ch0_min) ch0_min = ch0_buf[i].voltage;
            
            // 通道1统计
            ch1_sum += ch1_buf[i].voltage;
            if (ch1_buf[i].voltage > ch1_max) ch1_max = ch1_buf[i].voltage;
            if (ch1_buf[i].voltage < ch1_min) ch1_min = ch1_buf[i].voltage;
        }
        
        float ch0_avg = ch0_sum / buf_size;
        float ch1_avg = ch1_sum / buf_size;
        
        printf("统计数据 (%d个样本):\r\n", buf_size);
        printf("通道0: 平均=%.6fV, 最大=%.6fV, 最小=%.6fV\r\n", 
               ch0_avg, ch0_max, ch0_min);
        printf("通道1: 平均=%.6fV, 最大=%.6fV, 最小=%.6fV\r\n", 
               ch1_avg, ch1_max, ch1_min);
    }
}

9、串口调试输出

// debug.c
#include "debug.h"

// 重定向printf到串口
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}

10、CubeMX配置

// SPI配置 (spi.c)
void MX_SPI1_Init(void)
{
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;   // CPOL = 0
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;       // CPHA = 0
    hspi1.Init.NSS = SPI_NSS_SOFT;
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;  // 9MHz
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
    hspi1.Init.CRCPolynomial = 10;
    
    HAL_SPI_Init(&hspi1);
}

参考代码 基于STM32F103单片机实现ADS1255双通道切换连续读取 www.youwenfan.com/contentcnu/70138.html

五、性能优化建议

1. DMA传输

// 使用DMA传输SPI数据
void ADS1255_ReadData_DMA(uint8_t* buffer)
{
    ADS1255_CS_LOW();
    HAL_SPI_Receive_DMA(&hspi1, buffer, 3);
    // 在DMA完成中断中处理数据
}

2. 定时器触发采样

// 使用定时器精确控制采样间隔
void MX_TIM2_Init(void)
{
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 7200 - 1;  // 10kHz
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 10 - 1;       // 1ms触发
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_Base_Init(&htim2);
    
    // 配置定时器中断
    HAL_TIM_Base_Start_IT(&htim2);
}

3. 校准和温度补偿

// 温度补偿
float ADS1255_Temperature_Compensation(float voltage, float temperature)
{
    // 温度系数补偿
    float temp_coeff = 0.5e-6f;  // 0.5ppm/°C
    return voltage * (1.0f + temp_coeff * (temperature - 25.0f));
}

六、常见问题解决

问题 原因 解决
无数据 DRDY无响应 检查DRDY连接,增加上拉电阻
数据跳动 电源噪声 加强电源滤波,使用独立模拟电源
读数不准 基准不稳 使用高精度基准源
SPI通信失败 相位错误 确认CPOL/CPHA配置
通道切换慢 稳定时间不足 增加通道切换后的延时

七、测试程序

// test_ads1255.c
void Test_ADS1255(void)
{
    printf("=== ADS1255测试程序 ===\r\n");
    
    // 1. 初始化测试
    printf("1. 初始化测试...\r\n");
    ADS1255_Init();
    
    // 2. 单次读取测试
    printf("2. 单次读取测试...\r\n");
    for(int i = 0; i < 5; i++) {
        float voltage = ADS1255_ReadVoltage(CH_0_1);
        printf("  通道0-1: %.6fV\r\n", voltage);
        HAL_Delay(100);
    }
    
    // 3. 双通道切换测试
    printf("3. 双通道切换测试...\r\n");
    ADS1255_DualChannel_Init();
    ADS1255_StartCollect();
    
    for(int i = 0; i < 10; i++) {
        ADS1255_DualChannel_Collect_Task();
        DualChannel_Data_t* data = ADS1255_GetDualChannelData();
        
        if(data->ready_flag) {
            printf("  通道0: %.6fV, 通道1: %.6fV\r\n", 
                   data->ch0_data.voltage, data->ch1_data.voltage);
        }
        HAL_Delay(100);
    }
    
    ADS1255_StopCollect();
    
    // 4. 中断模式测试
    printf("4. 中断模式测试...\r\n");
    ADS1255_Interrupt_Init();
    
    for(int i = 0; i < 10; i++) {
        int32_t raw_data;
        uint8_t channel;
        
        if(ADS1255_GetInterruptData(&raw_data, &channel)) {
            float voltage = ADS1255_ConvertToVoltage(raw_data, 2.5f, 1);
            printf("  通道%d: 原始=%ld, 电压=%.6fV\r\n", 
                   channel, raw_data, voltage);
        }
        HAL_Delay(100);
    }
    
    printf("测试完成!\r\n");
}

 

专注于matlab/simulink,电子电路,编程