STM32使用SPI接口AD7175芯片ADC采集的驱动

以下是 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
    }
}

三、代码说明

  1. SPI 配置

    采用 SPI 模式 3(CPOL=1、CPHA=1),时钟 5MHz(兼容 AD7175-2 的 10MHz 上限);

  2. DRDY 中断

    通过 EXTI1 触发,确保数据就绪后再读取,避免无效数据;

  3. 通道切换

    每次切换通道前关闭所有通道,防止多通道同时启用导致数据错误;

  4. 数据校准

    支持偏移 / 增益双参数校准,适配高精度测量场景;

  5. 兼容性

    代码基于 STM32F103,移植到其他系列时仅需修改 SPI/EXTI 的时钟 / 引脚配置。

四、使用注意事项

  1. 校准功能需外接精密基准源(如 ADR4525),输入已知电压后调用AD7175_Calibration

  2. 若需更高采样率,可修改AD7175_REG_MODE的采样率参数(如 250kSPS 改为 125kSPS);

  3. 硬件布线时,AD7175 的模拟地与数字地需单点连接,电源端加 10μF 钽电容 + 0.1μF 陶瓷电容滤波

相关推荐
qq_401700414 小时前
合宙4G模块Air724UG
嵌入式硬件
yugi9878384 小时前
基于51单片机的篮球计分器设计
单片机·嵌入式硬件·51单片机
编程之升级打怪4 小时前
什么是PWM
嵌入式硬件
zmj3203245 小时前
单片机内存在C 语言编译后的 “逻辑分区”
c语言·单片机·内存分区
魈学习ing6 小时前
IO口无法外部上拉到3.3V以上,或被钳位到3.8V左右
stm32
小柯博客6 小时前
STM32MP2 Secure Boot实战
stm32·单片机·嵌入式硬件
Ww.xh6 小时前
STM32调用AI接口完整教程
stm32·单片机·嵌入式硬件
ZYNQRFSOC6 小时前
基于安路PH2A系列FPGA的JESD204B接口测试
嵌入式硬件·fpga开发
LCG元7 小时前
STM32实战:基于STM32F407的LWIP以太网通信(TCP Server)
stm32·嵌入式硬件·tcp/ip
Wave8457 小时前
嵌入式底层核心架构详解 (Cortex-M3)
stm32·架构