STM32驱动ADS1118高精度ADC:从硬件设计到软件实现的完整指南
2026/9/4 7:35:16 网站建设 项目流程

简介:本资源是一套基于STM32F1系列微控制器与ADS1118高精度16位ADC芯片的完整数据采集实现方案,面向嵌入式初学者、传感器应用开发者及工业测控项目工程师,解决高分辨率模拟信号采集、I2C驱动开发与系统级软硬件协同调试等核心问题。压缩包共180个文件,含32个C源码(如stm32f10x_i2c.c、ads1118驱动模块)、32个头文件(定义寄存器、配置宏及接口函数)、31个编译中间文件(.o/.d/.crf)及工程配置文件(uvprojx、uvoptx、sct、axf等),完整覆盖从底层外设初始化、ADS1118配置寄存器写入、差分/单端采样控制、温度传感器读取到主循环数据获取的全流程代码结构,包体大小为6.11MB。已有1623人学习下载,提供可直接编译运行的Keil MDK工程,含清晰目录划分(stm32/ads1118/main等)、关键注释说明及HAL库适配逻辑,是掌握高精度ADC嵌入式驱动开发的典型实践范例。

1. 项目概述与核心价值

最近在做一个工业数据采集的小项目,核心需求是要高精度地测量几路微弱的模拟信号,比如热电偶或者压力传感器的输出。市面上常见的STM32自带的ADC,精度通常在12位,对于mV级别的信号变化,分辨率和噪声表现往往力不从心。这时候,外挂一颗高精度的模数转换器(ADC)就成了刚需。我选用了TI的ADS1118,这是一颗16位精度、带内置PGA和温度传感器的Δ-Σ ADC,通过SPI接口通信,用起来非常灵活。标题里的“stm32-ads1118-20200904”这个日期戳,一看就是某个工程存档的命名,背后很可能是一个已经验证过的、针对特定型号STM32(比如STM32F103)驱动ADS1118进行多通道数据采集的完整程序包。

这个组合在工控、仪器仪表、环境监测等领域非常常见。STM32作为主控,负责逻辑、通信和调度;ADS1118则充当专业的“信号翻译官”,把微弱的模拟世界信号,精准地转换为数字世界能理解的代码。对于开发者而言,核心任务就是打通两者之间的SPI通信,正确配置ADS1118的各种寄存器(增益、采样率、工作模式等),并稳定可靠地读取转换结果。网上能找到的代码片段不少,但往往只解决了“通不通”的问题,关于如何优化SPI时序、处理数据格式、进行温度补偿以及在实际工程中避坑的细节,却很少被系统性地讲述。今天,我就结合这个“20200904”版本可能蕴含的实践,把STM32驱动ADS1118从入门到稳定采集的整个流程,包括那些容易踩坑的细节,给大家掰开揉碎了讲清楚。

2. 硬件平台设计与核心思路拆解

2.1 为什么是STM32 + ADS1118这个组合?

在嵌入式数据采集领域,芯片选型永远是第一步,也是最体现设计思路的一步。STM32系列MCU资源丰富、生态成熟,几乎成了嵌入式开发的事实标准。而选择ADS1118,而不是其他ADC芯片(如ADS1115,I2C接口)或直接用STM32内置ADC,是基于以下几个核心考量:

首先,精度需求。STM32内置ADC通常是12位,理论分辨率为Vref/4096。如果参考电压是3.3V,那么一个LSB(最低有效位)对应的电压大约是0.8mV。对于很多传感器输出的信号,变化范围可能就在几十个mV之内,0.8mV的分辨率显然不够看,会丢失大量细节。ADS1118是16位ADC,在同样的量程下,一个LSB仅约0.05mV,分辨率提升了16倍,能够捕捉到更微小的信号变化。

其次,输入特性与集成度。ADS1118内置了可编程增益放大器(PGA),增益可选1~8倍。这意味着它可以直接测量非常微弱的信号(低至±256mV满量程),而无需外部再搭建运放电路,简化了硬件设计。同时,它集成了一个精度尚可(±0.5°C典型值)的温度传感器,这在需要温度补偿(如热电偶冷端补偿)或同时监测环境温度的场合非常有用,一颗芯片解决两个问题。

再者,接口与速度的权衡。ADS1118采用SPI接口,相比I2C接口的ADS1115,在通信速率和抗干扰能力上通常更有优势。SPI是全双工、主从式接口,由主设备(STM32)完全控制时钟,时序更确定,在有一定噪声的环境下更可靠。虽然最高采样率只有860SPS(每秒采样次数),但对于大多数慢变物理量(温度、压力、应力)的监测,完全足够。

最后,封装与成本。ADS1118采用小巧的MSOP-10封装,节省PCB空间。其成本在需要高精度测量的项目中,通常是可以接受的。综合来看,这个组合在性能、复杂度、成本和可靠性上取得了很好的平衡。

2.2 硬件连接电路设计要点

连接STM32和ADS1118的电路并不复杂,但几个关键点的处理直接影响系统稳定性。

核心SPI引脚连接

  • CS (片选):连接STM32任意一个GPIO口。切记,即使你的STM32 SPI硬件支持NSS(硬件片选)管理,也强烈建议使用一个普通GPIO来软件控制CS。原因在于,ADS1118的SPI时序要求CS在两次读写操作之间必须拉高,而硬件NSS的行为可能不符合此要求,导致通信失败。我通常选用如PA4这样的口。
  • SCLK (时钟):连接STM32 SPI的SCK引脚,例如PA5(SPI1)。
  • DIN (数据输入,主出从入 MOSI):连接STM32 SPI的MOSI引脚,例如PA7(SPI1)。
  • DOUT (数据输出,主入从出 MISO):连接STM32 SPI的MISO引脚,例如PA6(SPI1)。

电源与参考设计

  • 电源去耦:这是高频数字芯片稳定工作的基石。必须在ADS1118的VDD引脚(通常2.0V至5.5V)与地之间,紧贴芯片放置一个0.1μF的陶瓷电容和一个1~10μF的钽电容或陶瓷电容,用于滤除高频和低频噪声。
  • 参考电压:ADS1118使用电源电压VDD作为模拟部分的正参考电压VDD,负参考电压GND。这意味着它的测量范围是0到VDD。因此,一个干净、稳定的电源至关重要。如果VDD是3.3V,那么满量程输入电压就是3.3V(当PGA=1时)。如果需要测量负电压或差分信号,需要将输入信号偏置到0-VDD之间。

模拟输入前端保护

  • 限流与钳位:在ADC的模拟输入引脚(AIN0-AIN3)上,串联一个几百欧姆的电阻(如470Ω),并并联一个肖特基二极管到VDD和GND,构成简单的钳位保护电路。这可以防止意外的高压或静电损坏ADC的精密输入级。
  • 滤波:根据信号频率和采样率,在输入引脚增加RC低通滤波。例如,一个1kΩ电阻和0.1μF电容构成的一阶滤波器,其-3dB截止频率约为1.6kHz,能有效抑制高频噪声。注意电阻会产生热噪声,需要权衡。

注意:ADS1118的输入是多路复用的,可以配置为4个单端输入或2个差分对。在设计电路时,就要想好哪些信号是单端测量(信号对系统地),哪些是差分测量(测量两个引脚间的电压差)。差分测量能有效抑制共模噪声,适合长线传输或噪声环境。

3. STM32 SPI驱动层配置详解

3.1 HAL库SPI初始化关键参数

我以STM32CubeMX配合HAL库为例,这是目前最主流高效的开发方式。在CubeMX中配置SPI外设时,以下几个参数必须与ADS1118的数据手册严格对应:

  1. 时钟极性(CPOL)与时钟相位(CPHA):ADS1118的SPI模式为模式1,即CPOL=0, CPHA=1。在CubeMX中对应“Clock Polarity”为“Low”,“Clock Phase”为“2 Edge”。这个配置错了,数据采样边沿就对不上,永远读不到正确数据。
  2. 数据大小(Data Size):设置为8位。虽然ADS1118一次传输16位数据,但HAL库的SPI收发函数通常以8位为单位进行操作,我们可以通过组合两次8位操作来完成16位数据的读写。
  3. 片选管理(NSS):选择“Software NSS Management”。如前所述,我们将用GPIO软件控制CS引脚。
  4. 波特率预分频器(Baud Rate Prescaler):ADS1118的SPI时钟最高可达4MHz。为了保证可靠通信,特别是在布线较长或有噪声时,建议初始设置一个较低的速率,如FPCLK / 32(如果系统时钟72MHz,则SPI时钟约2.25MHz)。调试稳定后,可以尝试提高。
  5. 位顺序(First Bit):选择“MSB First”。这是大多数SPI设备的默认设置,ADS1118也是如此。

配置完成后生成代码,你会得到SPI_HandleTypeDef hspi1这样的句柄。务必检查生成的MX_SPI1_Init函数里的参数是否符合上述设置。

3.2 软件片选(CS)GPIO的驱动封装

我们需要对连接ADS1118 CS引脚的GPIO进行初始化,并封装两个简洁的函数。

// ads1118.h #define ADS1118_CS_PIN GPIO_PIN_4 #define ADS1118_CS_PORT GPIOA void ADS1118_CS_Low(void) { HAL_GPIO_WritePin(ADS1118_CS_PORT, ADS1118_CS_PIN, GPIO_PIN_RESET); } void ADS1118_CS_High(void) { HAL_GPIO_WritePin(ADS1118_CS_PORT, ADS1118_CS_PIN, GPIO_PIN_SET); }

在SPI传输的整个过程中,必须严格遵循“CS拉低 -> 发送/接收数据 -> CS拉高”的时序。每次完整的读写操作(比如写配置、读转换结果)前后,都需要执行一次CS的拉低和拉高。

4. ADS1118寄存器配置与通信协议解析

4.1 核心寄存器映射与位定义

ADS1118内部主要有两个16位寄存器我们关心:配置寄存器(Config Register)和转换结果寄存器(Conversion Register)。温度传感器读数也通过转换寄存器读取,由配置位决定当前读取的是ADC数据还是温度数据。

配置寄存器(地址:0x01)各位定义如下(从高位到低位):

  • BIT 15: 单次转换/连续转换1= 单次转换(默认),转换完成后自动进入掉电模式,省电;0= 连续转换。
  • BIT 14-12: 输入多路复用器
    • 000:AIN0 - AIN1 (差分)
    • 001:AIN0 - AIN3 (差分)
    • 010:AIN1 - AIN3 (差分)
    • 011:AIN2 - AIN3 (差分)
    • 100:AIN0 - GND (单端)
    • 101:AIN1 - GND (单端)
    • 110:AIN2 - GND (单端)
    • 111:AIN3 - GND (单端)
  • BIT 11-9: 可编程增益放大器
    • 000:FSR = ±6.144V
    • 001:FSR = ±4.096V
    • 010:FSR = ±2.048V(默认)
    • 011:FSR = ±1.024V
    • 100:FSR = ±0.512V
    • 101:FSR = ±0.256V
    • 110:FSR = ±0.256V
    • 111:FSR = ±0.256V
  • BIT 8: 工作模式1= 单次模式(配合BIT15使用);0= 连续模式。
  • BIT 7-5: 数据速率
    • 000:8 SPS
    • 001:16 SPS
    • 010:32 SPS
    • 011:64 SPS
    • 100:128 SPS(默认)
    • 101:250 SPS
    • 110:475 SPS
    • 111:860 SPS
  • BIT 4: 温度传感器模式1= 启用内部温度传感器;0= 禁用(默认)。
  • BIT 3: 上电复位1= 更新配置后不触发复位;0= 更新配置后立即触发一次上电复位(默认)。通常置1。
  • BIT 2: 无效位:应写0。
  • BIT 1-0: 寄存器指针00= 指向转换寄存器(下次读操作读转换结果);01= 指向配置寄存器(下次读操作读配置);10/11:保留。

转换结果寄存器:就是一个16位的二进制补码数,代表最新的ADC转换结果或温度传感器读数。

4.2 SPI读写时序与数据帧解析

ADS1118的SPI通信是“全双工”的,这意味着在主机(STM32)发送数据的同时,从机(ADS1118)也在返回数据。这是一个关键点:当你写入配置字时,同时读回的是上一个转换周期的结果(或之前的配置,取决于指针)。

一次典型的“写配置并读回上次结果”的操作流程如下:

  1. STM32拉低CS。
  2. STM32通过MOSI线发送一个16位的数据帧。这个帧的高8位是命令(其中高2位是寄存器指针,低6位在写操作时无效),低8位是要写入的配置数据的高字节。
  3. 与此同时,ADS1118通过MISO线返回一个16位数据。这个数据是当前寄存器指针所指向的寄存器的内容。在第一次操作时,指针默认是00(指向转换寄存器),但此时可能还没有有效的转换数据,所以常返回0xFFFF或0x0000。
  4. STM32再发送第二个16位数据帧,高8位是配置数据的低字节,低8位任意(通常写0x00)。
  5. 与此同时,ADS1118返回第二个16位数据,这次返回的是你刚刚写入的配置寄存器值的高字节(作为验证)。
  6. STM32拉高CS。

为了简化,我们可以封装一个通用的16位SPI传输函数,并在此基础上构建读写函数。

// ads1118.c static uint16_t ADS1118_SPI_TransmitReceive16(uint16_t txData) { uint16_t rxData = 0; uint8_t txBuf[2], rxBuf[2]; // 将16位数据拆分为两个8位,注意MSB在前 txBuf[0] = (uint8_t)((txData >> 8) & 0xFF); txBuf[1] = (uint8_t)(txData & 0xFF); ADS1118_CS_Low(); HAL_SPI_TransmitReceive(&hspi1, txBuf, rxBuf, 2, HAL_MAX_DELAY); ADS1118_CS_High(); // 将接收到的两个8位数据组合为16位 rxData = (rxBuf[0] << 8) | rxBuf[1]; return rxData; }

5. 采集程序核心实现与数据解析

5.1 初始化与配置函数实现

一个健壮的初始化函数应该完成以下步骤:1) 硬件初始化(由CubeMX完成);2) 发送一个有效的配置字给ADS1118,使其进入已知状态。

// ads1118.c #define ADS1118_CONFIG_REG_ADDR 0x01 #define ADS1118_CONV_REG_ADDR 0x00 void ADS1118_Init(void) { // 1. 延时确保电源稳定(可选) HAL_Delay(10); // 2. 尝试读取设备ID或配置进行探测(非必需,但有助于调试) // 可以先读一次配置寄存器,看返回值是否在预期内(默认值0x8583) // 3. 写入一个确定的配置,例如:单次转换,AIN0单端,PGA=±2.048V,128SPS,禁用温度传感器 uint16_t config = 0; config |= (1 << 15); // 单次转换模式 config |= (0b100 << 12); // 输入多路复用:AIN0单端 config |= (0b010 << 9); // PGA增益:±2.048V config |= (0b100 << 5); // 数据速率:128 SPS config |= (0 << 4); // 禁用温度传感器 config |= (1 << 3); // 无复位 config |= (ADS1118_CONFIG_REG_ADDR << 0); // 指针指向配置寄存器,为后续写配置做准备 // 注意:第一次写入时,读回的数据可能是无效的转换结果,忽略即可 ADS1118_WriteConfig(config); } uint16_t ADS1118_WriteConfig(uint16_t config) { // 构造要发送的16位数据:高8位是命令(指针+无效位),低8位是配置高字节 // 命令:指针指向配置寄存器(01),后6位在写模式忽略,设为0 uint16_t cmd_with_config_high = (ADS1118_CONFIG_REG_ADDR << 14) | ((config >> 8) & 0x3F); uint16_t config_low = (config & 0x00FF) << 8; // 配置低字节左移8位,低8位补0 uint16_t received_data; // 第一次传输:发送命令+配置高字节,同时读回(此时读的是旧数据,忽略或用于调试) received_data = ADS1118_SPI_TransmitReceive16(cmd_with_config_high); // 这里received_data是之前寄存器指针指向的内容,通常忽略 // 第二次传输:发送配置低字节+填充位,同时读回配置高字节(作为验证) received_data = ADS1118_SPI_TransmitReceive16(config_low); // 这里received_data应该是我们刚刚写入的配置字的高字节,可用于验证 // 简单的验证:if ((received_data & 0xFF00) != (cmd_with_config_high & 0xFF00)) { /* 错误处理 */ } return received_data; // 返回读回的配置高字节 }

5.2 启动转换与读取结果流程

在单次转换模式下,每次读取数据都需要:1) 启动一次转换;2) 等待转换完成;3) 读取结果。

// ads1118.c int16_t ADS1118_ReadSingleEnded(uint8_t channel) { uint16_t config = 0; uint16_t adc_value_raw; int16_t adc_value; // 1. 根据通道号设置输入多路复用器位 uint16_t mux_bits; switch(channel) { case 0: mux_bits = 0b100; break; // AIN0 case 1: mux_bits = 0b101; break; // AIN1 case 2: mux_bits = 0b110; break; // AIN2 case 3: mux_bits = 0b111; break; // AIN3 default: return 0x7FFF; // 错误码 } // 2. 构建配置字:单次转换,指定通道,PGA=±2.048V,128SPS,指针指向转换寄存器 config |= (1 << 15); // 单次转换 config |= (mux_bits << 12); // 输入多路选择 config |= (0b010 << 9); // PGA config |= (0b100 << 5); // 128 SPS config |= (0 << 4); // 禁用温度传感器 config |= (1 << 3); // 无复位 config |= (ADS1118_CONV_REG_ADDR << 0); // 指针指向转换寄存器,这样下次读操作直接读结果 // 3. 写入配置,同时启动转换。注意,这次写入后,ADS1118开始转换。 // 写入的配置字中,指针指向转换寄存器(00),所以紧接着的读操作会读取转换结果。 ADS1118_WriteConfig(config); // 4. 等待转换完成。转换时间 = 1 / 数据速率。对于128SPS,约7.8ms。 // 最可靠的方式是延时,可以稍微多加一点余量。 HAL_Delay(10); // 等待10ms,确保转换完成 // 5. 读取转换结果。此时指针已指向转换寄存器,只需发送一个“哑”命令(如0x0000)即可触发读取。 adc_value_raw = ADS1118_SPI_TransmitReceive16(0x0000); // 6. 数据解析:ADS1118返回的是16位二进制补码。 // 对于单端输入(0-VDD),实际返回值是0-32767之间的正数(因为最高位是符号位,单端正电压下为0)。 // 直接转换为有符号16位整数即可。 adc_value = (int16_t)adc_value_raw; return adc_value; }

5.3 原始数据到实际电压的转换

读到的adc_value是一个原始码值,需要根据PGA设置和参考电压换算成实际电压。

// ads1118.c float ADS1118_ConvertToVoltage(int16_t adc_raw, uint8_t pga_setting) { float fsr_voltage; // 满量程电压,单位V float voltage; // 根据PGA配置字确定满量程电压 switch(pga_setting) { case 0b000: fsr_voltage = 6.144f; break; case 0b001: fsr_voltage = 4.096f; break; case 0b010: fsr_voltage = 2.048f; break; case 0b011: fsr_voltage = 1.024f; break; case 0b100: // 0.512V case 0b101: // 0.256V case 0b110: // 0.256V case 0b111: // 0.256V fsr_voltage = 0.256f; break; // 注意:后四种增益的FSR都是±0.256V default: fsr_voltage = 2.048f; // 默认 } // ADS1118是16位ADC,输出码值范围是 -32768 到 +32767。 // 实际电压 = (原始码值 / 32767) * 满量程电压 // 对于单端输入,adc_raw是0到32767的正数。 voltage = ((float)adc_raw / 32767.0f) * fsr_voltage; return voltage; }

5.4 内部温度传感器读取与校准

ADS1118的内部温度传感器精度一般(±2°C典型值),但用于环境温度监测或冷端补偿是足够的。读取温度需要修改配置寄存器的BIT4。

// ads1118.c float ADS1118_ReadTemperature(void) { uint16_t config = 0; uint16_t temp_raw; float temperature; // 1. 构建配置字:启用温度传感器模式,指针指向转换寄存器 config |= (1 << 15); // 单次转换 config |= (0b100 << 12); // 输入多路选择任意(温度传感器模式下被忽略),但必须非111 config |= (0b010 << 9); // PGA任意,但必须设置 config |= (0b100 << 5); // 数据速率:128 SPS config |= (1 << 4); // 启用温度传感器模式!!! config |= (1 << 3); // 无复位 config |= (ADS1118_CONV_REG_ADDR << 0); // 指针指向转换寄存器 // 2. 写入配置,启动温度转换 ADS1118_WriteConfig(config); // 3. 等待转换完成 HAL_Delay(10); // 4. 读取温度原始值 temp_raw = ADS1118_SPI_TransmitReceive16(0x0000); // 5. 数据解析:温度传感器输出也是16位二进制补码。 // 根据数据手册,温度(°C) = (读取的码值 * 0.03125) // 注意:temp_raw 需要先转换为有符号16位整数 temperature = (float)((int16_t)temp_raw) * 0.03125f; return temperature; }

注意:温度传感器的精度有限,且不同芯片个体有差异。如果对温度精度要求高,可以在恒温环境下读取一个已知温度点的值,计算出一个偏移量进行软件校准。

6. 程序优化与高级应用技巧

6.1 多通道轮询采集策略

在实际项目中,往往需要循环采集多个通道。为了避免频繁重写配置寄存器(每次写配置会有一次冗余的SPI传输),可以采用更高效的策略:一次性配置好所有通道共用的参数(如PGA、速率),只切换输入多路复用器位

我们可以设计一个状态机,或者简单地用一个数组记录通道序列,循环采集。

// ads1118.c #define NUM_CHANNELS 4 float channel_voltage[NUM_CHANNELS]; void ADS1118_MultiChannelPolling(void) { static uint8_t current_channel = 0; int16_t raw_adc; float voltage; // 1. 构建基础配置字(共用部分) uint16_t base_config = 0; base_config |= (1 << 15); // 单次转换 base_config |= (0b010 << 9); // PGA = ±2.048V base_config |= (0b100 << 5); // 128 SPS base_config |= (0 << 4); // 禁用温度传感器 base_config |= (1 << 3); // 无复位 base_config |= (ADS1118_CONV_REG_ADDR << 0); // 指针指向转换寄存器 // 2. 为当前通道设置多路复用器位 uint16_t channel_mux[4] = {0b100, 0b101, 0b110, 0b111}; // AIN0-AIN3 单端 uint16_t current_config = base_config | (channel_mux[current_channel] << 12); // 3. 启动当前通道转换并读取 ADS1118_WriteConfig(current_config); HAL_Delay(10); // 等待转换 raw_adc = (int16_t)ADS1118_SPI_TransmitReceive16(0x0000); // 4. 转换并存储电压值 voltage = ADS1118_ConvertToVoltage(raw_adc, 0b010); // PGA=0b010对应±2.048V channel_voltage[current_channel] = voltage; // 5. 切换到下一个通道 current_channel++; if(current_channel >= NUM_CHANNELS) { current_channel = 0; } }

在主循环中定期调用ADS1118_MultiChannelPolling函数,即可实现四通道的轮询采集。为了更精确的定时,可以将这个函数放在一个定时器中断服务程序中。

6.2 利用DMA提升SPI传输效率

当采样率要求较高或系统主频繁忙时,使用DMA进行SPI传输可以解放CPU。HAL库提供了HAL_SPI_TransmitReceive_DMA函数。但需要注意,ADS1118的每次操作(写配置+读数据)包含两次16位传输,且中间CS需要保持低电平。使用DMA时,需要将这两次传输组合成一个32位的缓冲区,并确保CS在整个DMA传输期间保持有效。

这涉及到更底层的SPI和GPIO操作,可能需要直接操作寄存器来精确控制CS引脚在DMA传输开始前拉低,在传输完成中断中拉高。这是一个高级优化技巧,在普通应用中,查询方式的延时(10ms)通常是可以接受的。

6.3 低功耗设计考量

ADS1118在单次转换模式下,转换完成后会自动进入掉电模式,功耗极低(仅几个微安)。这是电池供电设备的福音。我们的驱动代码已经使用了单次转换模式。为了进一步降低STM32的功耗,可以在启动ADS1118转换后,让STM32进入睡眠模式(Sleep或Stop模式),然后通过外部中断(例如,用一个GPIO连接ADS1118的DRDY引脚,但ADS1118没有独立的DRDY,需用定时器)或简单的延时唤醒后读取数据。

7. 常见问题排查与调试心得

调试硬件和SPI通信,逻辑分析仪是神器。没有的话,万用表和示波器也能解决大部分问题。

7.1 通信失败问题排查表

现象可能原因排查步骤与解决方法
始终读回0x0000或0xFFFF1. SPI模式错误
2. CS引脚控制不当
3. 电源或地线问题
4. 芯片损坏
1.首要检查:用逻辑分析仪或示波器抓取SPI四根线的波形。确认SCLK频率是否过高(先降到100kHz试)、CPOL/CPHA是否为0/1、CS是否在数据帧前后有跳变。
2. 确认CS引脚初始化正确,且软件控制拉低/拉高的时机包裹住了整个SPI传输函数。
3. 测量ADS1118的VDD引脚电压是否为预期值(如3.3V),检查所有GND连接是否可靠。
4. 尝试更换芯片。
读回的数据不稳定,跳动大1. 模拟输入噪声大
2. 电源噪声
3. SPI时钟线受到干扰
4. 未等待转换完成就读取
1. 在模拟输入引脚增加RC低通滤波(如1kΩ + 100nF)。
2. 加强电源去耦,靠近ADS1118的VDD引脚并联10μF和0.1μF电容。
3. 降低SPI时钟频率,检查PCB布线,确保SCLK、MOSI、MISO线远离模拟信号线和高频噪声源。
4.确保在启动转换(写配置)后,有足够的延时(> 1/采样率)再读取。这是最常见的原因。
读取的电压值不准,有固定偏移或比例错误1. PGA配置与实际输入电压不匹配
2. 参考电压(VDD)不准
3. 前端电路存在偏移
4. 数据转换公式错误
1. 确认ADS1118_ConvertToVoltage函数中pga_setting参数与实际写入配置寄存器的PGA位一致。
2. 用万用表测量ADS1118的VDD引脚实际电压,并代入公式计算。公式中的满量程电压是±FSR,对于单端输入,实际量程是0~+FSR
3. 输入短路到地(测量0V),看读出的原始码值是否在0附近小范围波动(理想是0)。如果有一个固定的正偏移,可能是前端运放或传感器本身的零点输出。
4. 检查转换公式。单端输入:电压 = (原始码值 / 32767) * FSR。差分输入:电压 = (原始码值 / 32767) * FSR。注意原始码值是有符号的。
温度读数明显错误1. 未正确启用温度传感器模式
2. 温度传感器配置位被意外修改
3. 数据解析公式错误
1. 确认写入的配置字中BIT4(温度传感器使能位)为1。
2. 在读取温度后,如果后续要读ADC,务必记得将配置改回来(BIT4置0),否则ADC读数会是无效的温度传感器数据。
3. 确认温度转换公式:温度 = 有符号16位原始值 * 0.03125

7.2 实操中的坑与技巧

  1. 首次上电的怪现象:有些批次或仿制的ADS1118,第一次上电后SPI通信可能不正常。一个经验是,上电后先延时几十毫秒,然后连续发送几个空字节(如0x00),再开始正式的配置读写,相当于做一个“唤醒”或复位同步操作。
  2. 配置字的“回读验证”:在ADS1118_WriteConfig函数中,第二次SPI传输读回的数据应该是你刚写入的配置高字节。可以增加一个简单的验证,如果不符合,则重试几次。这能有效捕捉偶发的通信错误。
  3. 浮点运算开销:在ADS1118_ConvertToVoltage函数中使用了浮点数除法。如果是在资源紧张的MCU上频繁调用,可以考虑使用定点数运算来优化速度。例如,将/32767的运算转换为移位和乘法。
  4. 通道切换的稳定时间:当ADS1118的输入多路复用器切换通道时,内部电路需要时间建立稳定。数据手册建议在切换通道后等待一个小的延时(几个微秒)再启动转换。在我们的代码中,HAL_Delay(10)已经远大于这个时间,所以没问题。但如果追求极限速度,可以在写配置后、启动转换前加一个__NOP()或短延时。
  5. 软件片选的严格性:务必确保每次ADS1118_SPI_TransmitReceive16函数调用,都被一对CS_LowCS_High包围。不能在一次拉低CS后,进行两次独立的HAL_SPI_TransmitReceive调用(即使它们紧挨着),因为HAL库函数内部可能会操作CS(如果硬件NSS使能),导致时序不符合ADS1118要求。最保险的就是像我们封装的那样,把CS控制放在收发函数内部。

调试时,可以把读到的原始16进制数通过串口打印出来。一个健康的系统,在输入接地时,读到的值应该在0附近小幅波动(比如±10个LSB以内)。输入一个已知的稳定电压(如用基准源或分压电阻产生一个1.000V),对比计算出的电压值与万用表测量值,可以校准整个系统的增益误差。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询