STM32控制AD7685采集方案(基于SPI接口)
一、硬件连接与配置
-
核心电路设计
-
信号线连接:
STM32引脚 AD7685引脚 功能说明 PA5(SCK) SCK SPI时钟线(需上拉) PA6(MISO) SD0 数据接收线 PA4(NSS) CNV 片选/转换信号(主动拉低) PA7(MOSI) SD1 未使用(可悬空或接高电平) -
电源滤波:
- AD7685的VDD接3.3V,AGND与DGND单点连接
- 在VDD与GND间添加10μF电解电容+0.1μF陶瓷电容
-
-
关键参数
- SPI时钟频率:建议≤9MHz(AD7685最大支持40MHz,但STM32 SPI模块需分频)
- 转换时间:t_CONV≥0.7μs(实际延时≥3.2μs)
- 数据格式:16位MSB优先,空闲电平低(CPOL=0,CPHA=1)
二、软件实现流程
1. SPI初始化(HAL库)
// SPI1配置(APB2时钟)
void MX_SPI1_Init(void)
{
SPI_HandleTypeDef hspi1;
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER; // 主模式
hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 全双工
hspi1.Init.DataSize = SPI_DATASIZE_16BIT; // 16位数据
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL=0
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE; // CPHA=1(下降沿采样)
hspi1.Init.NSS = SPI_NSS_SOFT; // 软件控制片选
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 72MHz/4=18MHz
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; // 高位先行
HAL_SPI_Init(&hspi1);
}
// GPIO初始化(CNV引脚)
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
// CNV引脚配置(PA4)
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
2. 数据采集流程
#define CNV_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
#define CNV_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
uint16_t AD7685_Read(void)
{
uint16_t adc_val = 0;
CNV_LOW(); // 拉低CNV启动转换
HAL_Delay(4); // 等待≥3.2μs(实际延时需根据系统时钟调整)
CNV_HIGH(); // 释放CNV进入数据读取
// 读取16位数据(MSB优先)
HAL_SPI_Receive(&hspi1, (uint8_t*)&adc_val, 2, 1000);
return adc_val;
}
3. 数据处理与显示
// 电压转换(假设参考电压3.3V)
float AD7685_Voltage(uint16_t raw)
{
return (raw / 65535.0f * 3.3f);
}
// 主循环
while(1)
{
uint16_t raw = AD7685_Read();
float voltage = AD7685_Voltage(raw);
printf("ADC值:%d, 电压值:%.2fV\n", raw, voltage);
HAL_Delay(1000);
}
三、关键调试技巧
-
时序验证
-
使用逻辑分析仪捕获CNV与SCK信号,确保:
- CNV拉低后至少等待3.2μs再拉高
- SCK时钟频率≤9MHz(通过示波器测量)
-
-
数据校验
-
空载时读取值应在0x8000附近(1.65V中值)
-
接入已知电压(如1V),计算实际增益误差:
float error = (AD7685_Voltage(raw) - 1.0f) / 1.0f * 100%;
-
-
抗干扰措施
-
在SCK/MISO线串联100Ω电阻并并联10pF电容
-
添加软件数字滤波(滑动平均):
#define FILTER_SIZE 8 static uint16_t buffer[FILTER_SIZE] = {0}; static uint8_t idx = 0; buffer[idx++] = raw; if(idx >= FILTER_SIZE) idx = 0; uint32_t sum = 0; for(int i=0; i<FILTER_SIZE; i++) sum += buffer[i]; return sum / FILTER_SIZE;
-
参考代码 STM32控制AD7685采集 www.youwenfan.com/contentcsr/101900.html
四、常见问题解决
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 数据跳变 | 电源噪声/地环路干扰 | 添加LC滤波,优化PCB地平面 |
| 固定值输出 | SPI时序错误 | 检查CPOL/CPHA设置,延长CNV等待时间 |
| 通信失败 | 片选信号未正确控制 | 确认NSS引脚电平状态,添加延时 |
| 负值输出 | 参考电压未接或漂移 | 检查REF引脚连接,校准基准电压 |
五、扩展功能实现
-
多通道采集
-
通过AD7685的通道选择引脚(如CH0-CH7)切换输入通道
-
示例代码:
// 切换到CH1(假设CH0接AIN0) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // CH0选择 HAL_Delay(1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
-
-
DMA传输
// SPI DMA配置(STM32 HAL库) DMA_HandleTypeDef hdma_spi1_rx; void MX_DMA_Init(void) { __HAL_RCC_DMA1_CLK_ENABLE(); hdma_spi1_rx.Instance = DMA1_Stream0; hdma_spi1_rx.Init.Request = DMA_REQUEST_SPI1_RX; hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_spi1_rx.Init.DataSize = DMA_DATASIZE_HALFWORD; HAL_DMA_Init(&hdma_spi1_rx); __HAL_LINKDMA(&hspi1, hdmarx, hdma_spi1_rx); }