STM32F103 + ADS1255 双通道连续读取方案
ADS1255驱动程序,实现双通道自动切换、连续读取、数据滤波、SPI通信
一、ADS1255特性
| 参数 | 值 | 说明 |
|---|---|---|
| 分辨率 | 24位 | 无失码 |
| 采样率 | 30kSPS | 最大 |
| 通道 | 4路差分/8路单端 | |
| 接口 | SPI | 模式1 |
| 基准电压 | 2.5V | 内部/外部 |
| 输入范围 | ±Vref | 可编程增益 |
| 功耗 | 7.5mW | 正常工作 |
推荐配置:
- 采样率:1000SPS
- 增益:1
- 模式:连续转换
- 通道切换:自动轮流
- SPI时钟:2MHz
二、硬件连接
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+ (基准)
注意事项:
- DRDY需要中断模式
- 基准电压要稳定
- 模拟电源要干净
- SPI线要短
三、程序架构
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");
}