You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

12位ADC SPI驱动代码读取应变传感器数据始终返回0问题排查

LTC1296CCN ADC采样全0故障排查

系统配置与故障现象

  • 信号链路:INA128P仪表放大器 + LTC1296CCN 12位ADC,采集额定输出2mV/V的应变式称重传感器信号
  • ADC通信规则:拉低CS片选引脚后,先向Din引脚发送8位配置字,随后Dout引脚依次输出1个无效空比特、12位有效采样数据,后续持续输出低电平,直到CS引脚拉高结束通信;器件支持半双工模式,官方推荐3线双向连接架构
  • 故障表现:分别尝试全双工、半双工SPI通信实现,读取结果始终为全0,无有效采样值
  • 硬件实现:面包板搭建电路,采用STM32作为主控

现有实现代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c  
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_SPI1_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

 /**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
    char uart_buf[100];
    char boofer[100];
    uint8_t ADC_buf[2];
    uint8_t input_word[2];
    int uart_buf_len;
    int length;
    uint16_t testdata[100];
    uint8_t i = 0;
    uint16_t sample;
   /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */

  // CS pin should default high
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);

    uart_buf_len = sprintf(uart_buf, "SPI test\r\n");
    HAL_UART_Transmit(&huart2, (uint8_t *)uart_buf, uart_buf_len, 100);
    //input word is 10100110
    input_word[0] = 167;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
        //HAL_SPI_Transmit(&hspi1, input_word, 1, 100);
        //HAL_SPI_Receive(&hspi1, ADC_buf, 2, 100);
        HAL_SPI_TransmitReceive(&hspi1, input_word, ADC_buf, 2, 100);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
        sample = (((uint16_t) ADC_buf[0] << 9)|(((uint16_t)ADC_buf[1] << 1))) >> 4;
        testdata[i] = sample;
        length =sprintf(boofer,"%d\n",testdata[i])  + 1;
        HAL_UART_Transmit(&huart2, boofer, length, 100);
        i++;
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
   }
   /* USER CODE END 3 */


}

故障点定位

代码逻辑硬错误

  • 配置字数值错误:注释标注配置字应为10100110,换算十进制为166(十六进制0xA6),但代码中input_word[0]赋值为167(二进制10100111),最后一位配置位错误会导致ADC无法识别启动指令,直接输出低电平。
  • SPI传输长度不足:按照时序要求,拉低CS后总共需要21个SCK时钟周期(8个发配置字 + 1个空比特 +12个读有效数据)才能完成一次采样,对应3字节传输。现有代码一次仅传输2字节共16个时钟,还未等ADC输出完有效数据就结束传输,之后拉高CS直接终止通信,自然读不到有效数据。
  • 数据移位拼接逻辑完全错位:8个配置字发送周期内ADC的Dout为高阻态,接收到的第一个字节全为无效值;空比特出现在第9个时钟周期,12位有效数据分布在第10-21个时钟周期,现有移位逻辑从无效的第一个字节取数,拼出的结果必然是错误的0值。
  • 数组越界风险:定义uint8_t i作为testdata数组(长度100)的索引,循环中i持续自增无归零逻辑,i溢出后会篡改其他内存数据,导致程序运行异常。

SPI配置必查项(现有代码未贴SPI初始化部分,以下为高频错误点)

  • 模式不匹配:LTC1296要求SPI空闲时SCK为低电平,数据在SCK上升沿锁存,对应SPI模式0(CPOL=0,CPHA=0),如果配置为其他模式,通信时序完全错位。
  • 波特率过高:LTC1296最高支持SPI时钟为8MHz,面包板接线寄生电容大,调试阶段需将SPI波特率降到1MHz以下,时钟过高会导致采样边沿错位。
  • 半双工接线错误:采用3线半双工模式时,必须将STM32的MISO、MOSI引脚短接后再连接ADC的双向DATA引脚;如果用全双工模式,需将MOSI接ADC的Din、MISO接ADC的Dout,两种模式接线不能混淆,否则会出现引脚电平冲突,读不到数据。
  • CS引脚配置错误:采用软件控制CS时,需将SPI硬件NSS功能关闭,对应PB6引脚配置为推挽输出模式。

硬件连接排查项

  • 电源与基准电压异常:LTC1296需要稳定5V单电源供电,Vref参考电压引脚必须接独立高精度基准源,不能直接接电源Vcc,否则电源纹波会导致ADC不工作;用万用表实测Vcc、Vref引脚电压,确认AGND、DGND可靠共地。
  • 前端放大器输出异常:断开ADC输入,实测INA128的输出电压,确认传感器受压时输出电压在0~Vref范围内,无负电压、超量程输出情况。
  • 接触不良:检查面包板接线,确认SCK、DATA、CS引脚无虚接、错接,CS拉低/拉高时引脚电平符合0V/5V要求。

修正后核心采样逻辑参考

uint8_t tx_buf[3] = {0xA6, 0x00, 0x00}; // 正确配置字10100110
uint8_t rx_buf[3] = {0};
uint16_t adc_val = 0;

// 采样循环逻辑
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
HAL_Delay(1); // 等待CS电平稳定
HAL_SPI_TransmitReceive(&hspi1, tx_buf, rx_buf, 3, 100);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);

// 按实际时序拼接12位有效数据
adc_val = ((uint16_t)(rx_buf[1] & 0x7F) << 5) | (rx_buf[2] >> 3);

内容的提问来源于stack exchange,提问作者Νίκος Χαλκιάς

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 02:31:06