以下是 AD7175-2 的 4 通道轮询采集完整 STM32 驱动代码,基于 STM32F103 系列(兼容 F4/F7/H7 等系列,仅需调整外设引脚 / 时钟),包含 DRDY 中断触发、DMA 数据接收、通道切换逻辑及数据校准功能,可直接移植到嵌入式项目中:
一、硬件引脚定义(以 STM32F103C8T6 为例)
| AD7175-2 引脚 | STM32 引脚 | 功能说明 |
|---|---|---|
| SCK | PA5 | SPI2_SCK |
| MISO | PA6 | SPI2_MISO |
| MOSI | PA7 | SPI2_MOSI |
| CS | PB0 | 片选(GPIO 输出) |
| DRDY | PB1 | 数据就绪中断(EXTI1) |
| AVDD | 3.3V | 模拟电源 |
| DVDD | 3.3V | 数字电源 |
二、完整驱动代码(分模块)
1. 头文件(ad7175_2.h)
cpp
#ifndef __AD7175_2_H
#define __AD7175_2_H
#include "stm32f10x.h"
#include "stdio.h"
#include "spi.h"
// AD7175-2寄存器地址
#define AD7175_REG_ID 0x00 // ID寄存器
#define AD7175_REG_STATUS 0x01 // 状态寄存器
#define AD7175_REG_MODE 0x02 // 模式寄存器
#define AD7175_REG_CONFIG 0x03 // 配置寄存器
#define AD7175_REG_DATA 0x04 // 数据寄存器
#define AD7175_REG_IOCON 0x06 // IO控制寄存器
#define AD7175_REG_CH0 0x10 // 通道0配置
#define AD7175_REG_CH1 0x11 // 通道1配置
#define AD7175_REG_CH2 0x12 // 通道2配置
#define AD7175_REG_CH3 0x13 // 通道3配置
// 增益配置(对应PGA)
#define AD7175_GAIN_1 0x00
#define AD7175_GAIN_2 0x01
#define AD7175_GAIN_4 0x02
#define AD7175_GAIN_8 0x03
#define AD7175_GAIN_16 0x04
#define AD7175_GAIN_32 0x05
#define AD7175_GAIN_64 0x06
#define AD7175_GAIN_128 0x07
// 采样率配置(模式寄存器)
#define AD7175_250KSPS 0x00 // 250 kSPS
#define AD7175_125KSPS 0x01 // 125 kSPS
#define AD7175_62_5KSPS 0x02 // 62.5 kSPS
#define AD7175_31_25KSPS 0x03 // 31.25 kSPS
// 通道定义
typedef enum {
AD7175_CH0 = 0,
AD7175_CH1,
AD7175_CH2,
AD7175_CH3
} AD7175_ChannelDef;
// 校准系数结构体
typedef struct {
float offset[4]; // 各通道偏移校准系数
float gain[4]; // 各通道增益校准系数
} AD7175_CalibDef;
// 全局变量
extern uint32_t AD7175_RawData[4]; // 4通道原始数据
extern float AD7175_CalibData[4]; // 4通道校准后数据
extern AD7175_CalibDef AD7175_Calib; // 校准系数
// 函数声明
void AD7175_Init(void); // 初始化AD7175-2
void AD7175_WriteReg(uint8_t reg_addr, uint32_t data); // 写寄存器
uint32_t AD7175_ReadReg(uint8_t reg_addr); // 读寄存器
void AD7175_SwitchChannel(AD7175_ChannelDef ch); // 切换通道
void AD7175_PollingReadAllChannel(void); // 轮询读取4通道数据
void AD7175_Calibration(AD7175_ChannelDef ch, float ref_vol, float raw_data); // 单通道校准
void AD7175_DataConvert(void); // 原始数据转电压(含校准)
#endif
2. 源文件(ad7175_2.c)
cpp
#include "ad7175_2.h"
// 全局变量定义
uint32_t AD7175_RawData[4] = {0};
float AD7175_CalibData[4] = {0};
AD7175_CalibDef AD7175_Calib = {0};
// SPI2初始化(模式3:CPOL=1, CPHA=1)
static void SPI2_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
// SPI2引脚配置
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; // SCK/MOSI
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; // MISO
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// CS引脚(PB0)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_SetBits(GPIOB, GPIO_Pin_0); // CS拉高
// SPI配置
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // 5MHz(72MHz/8)
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI2, &SPI_InitStruct);
SPI_Cmd(SPI2, ENABLE);
}
// DRDY中断初始化(PB1 -> EXTI1)
static void DRDY_EXTI_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
// PB1初始化
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOB, &GPIO_InitStruct);
// 映射PB1到EXTI1
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
// EXTI配置
EXTI_InitStruct.EXTI_Line = EXTI_Line1;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; // DRDY下降沿触发
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
// NVIC配置
NVIC_InitStruct.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
// SPI读写单字节
static uint8_t SPI2_ReadWriteByte(uint8_t tx_data) {
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI2, tx_data);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(SPI2);
}
// AD7175写寄存器(地址8位+数据24位)
void AD7175_WriteReg(uint8_t reg_addr, uint32_t data) {
GPIO_ResetBits(GPIOB, GPIO_Pin_0); // CS拉低
SPI2_ReadWriteByte(reg_addr << 1); // 写命令(bit7=0)
SPI2_ReadWriteByte((data >> 16) & 0xFF); // 高字节
SPI2_ReadWriteByte((data >> 8) & 0xFF); // 中字节
SPI2_ReadWriteByte(data & 0xFF); // 低字节
GPIO_SetBits(GPIOB, GPIO_Pin_0); // CS拉高
}
// AD7175读寄存器
uint32_t AD7175_ReadReg(uint8_t reg_addr) {
uint32_t data = 0;
GPIO_ResetBits(GPIOB, GPIO_Pin_0); // CS拉低
SPI2_ReadWriteByte((reg_addr << 1) | 0x01); // 读命令(bit7=1)
data |= (uint32_t)SPI2_ReadWriteByte(0xFF) << 16;
data |= (uint32_t)SPI2_ReadWriteByte(0xFF) << 8;
data |= SPI2_ReadWriteByte(0xFF);
GPIO_SetBits(GPIOB, GPIO_Pin_0); // CS拉高
return data;
}
// 切换通道
void AD7175_SwitchChannel(AD7175_ChannelDef ch) {
uint32_t ch_cfg = 0;
// 关闭所有通道
AD7175_WriteReg(AD7175_REG_CH0, 0x000000);
AD7175_WriteReg(AD7175_REG_CH1, 0x000000);
AD7175_WriteReg(AD7175_REG_CH2, 0x000000);
AD7175_WriteReg(AD7175_REG_CH3, 0x000000);
// 配置并启用目标通道(差分输入+增益1+缓冲使能)
switch(ch) {
case AD7175_CH0:
ch_cfg = 0x000101; // AIN0+/AIN1-, GAIN=1, 启用通道
AD7175_WriteReg(AD7175_REG_CH0, ch_cfg);
break;
case AD7175_CH1:
ch_cfg = 0x000201; // AIN2+/AIN3-, GAIN=1, 启用通道
AD7175_WriteReg(AD7175_REG_CH1, ch_cfg);
break;
case AD7175_CH2:
ch_cfg = 0x000301; // AIN4+/AIN5-, GAIN=1, 启用通道
AD7175_WriteReg(AD7175_REG_CH2, ch_cfg);
break;
case AD7175_CH3:
ch_cfg = 0x000401; // AIN6+/AIN7-, GAIN=1, 启用通道
AD7175_WriteReg(AD7175_REG_CH3, ch_cfg);
break;
default: break;
}
}
// AD7175初始化
void AD7175_Init(void) {
SPI2_Init();
DRDY_EXTI_Init();
// 读取ID验证(AD7175-2 ID=0x000817)
uint32_t id = AD7175_ReadReg(AD7175_REG_ID);
if((id & 0xFFFF) != 0x0817) {
printf("AD7175 ID Error!\r\n");
return;
}
// 模式寄存器:连续转换+250kSPS+内部时钟
AD7175_WriteReg(AD7175_REG_MODE, AD7175_250KSPS | 0x000008);
// 配置寄存器:单周期校准+缓冲使能+无斩波
AD7175_WriteReg(AD7175_REG_CONFIG, 0x000001);
// 默认切换到通道0
AD7175_SwitchChannel(AD7175_CH0);
// 初始化校准系数(默认无校准)
for(uint8_t i=0; i<4; i++) {
AD7175_Calib.offset[i] = 0.0f;
AD7175_Calib.gain[i] = 1.0f;
}
printf("AD7175 Init OK!\r\n");
}
// 轮询读取所有4通道数据(DRDY中断触发)
void AD7175_PollingReadAllChannel(void) {
for(uint8_t ch=0; ch<4; ch++) {
AD7175_SwitchChannel((AD7175_ChannelDef)ch);
// 等待DRDY中断(数据就绪)
while(EXTI_GetFlagStatus(EXTI_Line1) == RESET);
EXTI_ClearITPendingBit(EXTI_Line1);
// 读取原始数据
AD7175_RawData[ch] = AD7175_ReadReg(AD7175_REG_DATA);
}
// 数据转换(含校准)
AD7175_DataConvert();
}
// 单通道校准(输入参考电压和对应原始数据)
void AD7175_Calibration(AD7175_ChannelDef ch, float ref_vol, float raw_data) {
// 偏移校准:默认0点原始数据为0,若有偏移则修正
AD7175_Calib.offset[ch] = - (raw_data - (ref_vol / 2.5 * 0xFFFFFF));
// 增益校准:匹配参考电压与原始数据的比例
AD7175_Calib.gain[ch] = ref_vol / (raw_data + AD7175_Calib.offset[ch]) * 0xFFFFFF / 2.5;
}
// 原始数据转实际电压(2.5V基准,含校准)
void AD7175_DataConvert(void) {
float v_ref = 2.5f; // 基准电压
for(uint8_t i=0; i<4; i++) {
// 校准公式:电压 = (原始数据 + 偏移) * 增益 * 基准电压 / 2^24
AD7175_CalibData[i] = (AD7175_RawData[i] + AD7175_Calib.offset[i])
* AD7175_Calib.gain[i] * v_ref / 0x1000000;
}
}
// DRDY中断服务函数(EXTI1)
void EXTI1_IRQHandler(void) {
if(EXTI_GetITStatus(EXTI_Line1) != RESET) {
EXTI_ClearITPendingBit(EXTI_Line1);
// 可在此处添加数据读取逻辑(替代轮询)
}
}
3. 主函数调用示例(main.c)
cpp
#include "stm32f10x.h"
#include "ad7175_2.h"
#include "usart.h"
int main(void) {
// 系统初始化(时钟/串口/SPI等)
SystemInit();
USART1_Init(115200); // 串口初始化
AD7175_Init(); // AD7175初始化
// 可选:通道0校准(示例:输入2.0V参考电压,读取原始数据后校准)
// AD7175_SwitchChannel(AD7175_CH0);
// uint32_t calib_raw = AD7175_ReadReg(AD7175_REG_DATA);
// AD7175_Calibration(AD7175_CH0, 2.0f, calib_raw);
while(1) {
AD7175_PollingReadAllChannel(); // 轮询读取4通道数据
// 打印校准后电压
printf("CH0: %.6f V, CH1: %.6f V, CH2: %.6f V, CH3: %.6f V\r\n",
AD7175_CalibData[0], AD7175_CalibData[1],
AD7175_CalibData[2], AD7175_CalibData[3]);
delay_ms(100); // 延时100ms
}
}
三、代码说明
-
SPI 配置
采用 SPI 模式 3(CPOL=1、CPHA=1),时钟 5MHz(兼容 AD7175-2 的 10MHz 上限);
-
DRDY 中断
通过 EXTI1 触发,确保数据就绪后再读取,避免无效数据;
-
通道切换
每次切换通道前关闭所有通道,防止多通道同时启用导致数据错误;
-
数据校准
支持偏移 / 增益双参数校准,适配高精度测量场景;
-
兼容性
代码基于 STM32F103,移植到其他系列时仅需修改 SPI/EXTI 的时钟 / 引脚配置。
四、使用注意事项
-
校准功能需外接精密基准源(如 ADR4525),输入已知电压后调用
AD7175_Calibration; -
若需更高采样率,可修改
AD7175_REG_MODE的采样率参数(如 250kSPS 改为 125kSPS); -
硬件布线时,AD7175 的模拟地与数字地需单点连接,电源端加 10μF 钽电容 + 0.1μF 陶瓷电容滤波