简介面向需要驱动ADS1118的嵌入式开发者这套资料提供基于STM32F103与STM32F407两款单片机的完整驱动覆盖4路单端输入、2路双差分输入以及温度传感器读取的全部程序并附带实测数据与ADS1118相关文档适合从入门到进阶快速搞透这颗16位ADC。压缩包为RAR格式大小约11.82MB页面暂未列出具体文件构成不过从标题和描述看内容以C语言工程源码、测试数据表格和芯片资料为主。资源已有321人学习对于工业自动化、精密测量、传感器采集等场景下的开发具有直接参考价值。拿到手后可对照实验测试数据验证程序配置理解采样率、增益、单端与差分通道切换等关键设置并借助配套手册排查通信与配置问题缩短开发周期。1. 基于 STM32F103、STM32F407 驱动 ADS1118一套能跑单端、差分与温度的完整驱动接手一个多路数据采集需求的时候8 路模拟信号要分时采集又要做温度补偿成本还压得紧。选了一圈最后落在 ADS1118 这颗 16 位 ADC 上SPI 接口省引脚内置可编程增益放大器和温度传感器一颗芯片能当 4 路单端或者 2 路双差分用内部温度还能拿来校正传感器漂移。但网上现成例程多半只演示单个通道读电压真要在 STM32F103 和 STM32F407 两套平台上把四路单端、两路双差分、温度测量都跑通还是得自己把驱动从头捋一遍。这篇笔记就把这套完整驱动拆开讲从寄存器配置、SPI 时序到每路通道的换算公式和移植要点照着抄就能在你的板子上跑起来。2. 硬件接口与寄存器驱动 ADS1118 之前需要先吃透的四件事2.1 SPI 通信帧16 位命令下去16 位数据回来ADS1118 走的是标准 4 线 SPICS、SCLK、DIN、DOUT。和普通 SPI 从机不太一样的地方是它的每次事务固定是 16 位命令字和 16 位数据结果两个方向同时发生。你往 DIN 上发一个配置字的同时DOUT 上会把上一次转换结果移出来。实际驱动里通常这样做先把 CS 拉低发送 16 位配置字带启动转换位然后把 CS 拉高等转换完成之后再把 CS 拉低发送一个 16 位空操作帧同时把转换结果从 DOUT 读回来。需要注意的是每次 CS 低电平期间送出的数据位顺序固定是 MSB 在前时序图里 SCLK 空闲为低DOUT 在 SCLK 下降沿更新数据MCU 在上升沿采样。这个相位关系对应 SPI 模式 1CPOL0CPHA1。提示如果 DOUT 引脚没有接到 MCU 上无法靠 DRDY 中断判断转换完成那就按数据速率对应的最长时间做固定延时这是最省事的方案。这套驱动两种方式都支持默认走固定延时。片选拉低 → 发配置字(SS1) → 片选拉高 → 等待转换完成 片选拉低 → 发NOP帧(0x0007) → 读回16位结果 → 片选拉高2.2 配置寄存器逐位拆解MUX、PGA、DR 与温度模式ADS1118 只有一个 16 位配置寄存器所有通道选择、增益、数据速率和模式都在这一帧里设置。它的内部基准电压是固定的不需要外接基准源这点对布线很友好。位段字段名功能说明bit15SS写1启动单次转换连续模式下读该位表示转换完成状态bit14:11MUX[3:0]输入多路开关选择决定单端或差分通道bit10:9PGA[1:0]增益档位决定满量程电压范围bit8MODE0连续转换1单次转换驱动里推荐用单次bit7:5DR[2:0]数据速率8~860 SPS 共 8 档bit4TS_MODE0ADC 模式1温度传感器模式bit3PULL_UP_ENDOUT 内部上拉使能长线传输时建议打开bit2NOP置1表示本帧命令只读数据、不更新配置bit1:0RESERVED这两个位必须写 1否则配置可能不生效MUX 字段是驱动里最常用的部分。标题里说的 4 路单端和 2 路双差分对应编码如下MUX[3:0]输入选择用途0100AIN0 - GND单端通道 00101AIN1 - GND单端通道 10110AIN2 - GND单端通道 20111AIN3 - GND单端通道 30000AIN0 - AIN1差分对 10011AIN2 - AIN3差分对 2PGA 字段只有 2 位对应 4 档满量程±6.144V、±4.096V、±2.048V、±1.024V。数据速率 8 档分别是 8、16、32、64、128、250、475、860 SPS。速率越低单次转换时间越长比如 8SPS 时一次转换约 125ms而 860SPS 时只需要 1.2ms 左右。驱动里把换算系数和增益档位绑定避免误用。2.3 F103 与 F407 平台差异SPI 外设、引脚复用与分频F103 和 F407 的 SPI 外设寄存器结构大体相同但时钟树差别很大。F103 的 APB2 最高 36MHzSPI1 挂在这条总线上F407 的 APB2 最高 84MHz。如果两套工程共用一份 SPI 初始化代码F407 上不调整分频系数SCLK 很容易超出 ADS1118 数据手册建议的时钟上限。我在这套驱动里用条件编译区分两个平台核心是把分频系数分开设置#if defined(STM32F103) #define ADS1118_SPI SPI1 #define ADS1118_SPI_RCC RCC_APB2Periph_SPI1 #define ADS1118_SCLK_DIV SPI_BaudRatePrescaler_16 /* 36MHz / 16 2.25MHz */ #elif defined(STM32F407) #define ADS1118_SPI SPI1 #define ADS1118_SPI_RCC RCC_APB2Periph_SPI1 #define ADS1118_SCLK_DIV SPI_BaudRatePrescaler_32 /* 84MHz / 32 2.625MHz */ #endif分频之后两边的 SCLK 都落在 2~3MHz 区间远离芯片手册的上限值长线连接时也有余量。引脚方面F103 和 F407 的 SPI1 都默认在 PA5SCK、PA6MISO、PA7MOSI上片选我习惯用软件控制选一个空闲 GPIO 即可不占用硬件 NSS。注意把 MISO 配成浮空输入或上拉输入MOSI 和 SCK 配成复用推挽输出片选配成推挽输出初始化顺序错了读回来的数据经常是 0。3. 驱动代码拆解从单端四通道到双差分与温度读取3.1 驱动文件组织底层传输、平台适配与通道封装三层结构这套完整驱动按三层拆分目的是让你换平台时只改一层不用动上层逻辑ads1118/ ├── ads1118.h 寄存器宏定义、通道枚举、API 声明 ├── ads1118.c 上层驱动通道封装、电压换算、温度读取 ├── ads1118_port.h 平台抽象接口SPI 收发、片选、延时 └── ads1118_port.c F103 / F407 的 SPI 初始化和底层实现底层接口我只保留了四个函数上层所有代码都只依赖这四个函数/* ads1118_port.h */ void ads1118_cs_low(void); void ads1118_cs_high(void); uint16_t ads1118_spi_xfer16(uint16_t tx); void ads1118_delay_ms(uint32_t ms);这样做的好处很直接如果某天你要把这套驱动挪到别的单片机比如从 F103 换到 GD32 或者 NXP 平台只需要重写 ads1118_port.c 这一个文件甚至只需要替换里面 SPI 收发函数的实现上层通道逻辑完全不用动。3.2 单端 4 通道采集MUX 切换与电压换算单端采集的逻辑是一轮一轮循环切通道、启动转换、等转换完成、读结果。下面是去掉平台细节后的核心代码/* ads1118.c —— 单端通道读取 */ static void ads1118_start_conversion(uint16_t cfg) { cfg | (1u 15); /* bit15 SS1启动一次单次转换 */ cfg | (1u 1) | (1u 0); /* 保留位必须写 1 */ ads1118_cs_low(); ads1118_spi_xfer16(cfg); ads1118_cs_high(); } static uint16_t ads1118_read_result_raw(void) { uint16_t cmd 0x0007; /* bit2 NOP1保留位补 1只读数据 */ ads1118_cs_low(); uint16_t raw ads1118_spi_xfer16(cmd); ads1118_cs_high(); return raw; } float ads1118_read_single_ended(uint8_t ch) { uint16_t cfg ADS1118_MODE_SINGLE | ADS1118_PGA_FSR_4096 | ADS1118_DR_128SPS; switch (ch) { case 0: cfg | ADS1118_MUX_AIN0_GND; break; case 1: cfg | ADS1118_MUX_AIN1_GND; break; case 2: cfg | ADS1118_MUX_AIN2_GND; break; case 3: cfg | ADS1118_MUX_AIN3_GND; break; default: return 0.0f; } ads1118_start_conversion(cfg); ads1118_delay_ms(ads1118_conv_time_ms(ADS1118_DR_128SPS)); uint16_t raw ads1118_read_result_raw(); /* 16 位有符号数乘以满量程再除以 32768 */ return (float)(int16_t)raw * 4.096f / 32768.0f; }这段代码把 ADS1118 的配置字构建放在了函数开头MUX、增益、速率都是宏定义改起来很直观。ads1118_start_conversion发送配置字后立即拉高片选芯片在后台完成采样和转换。ads1118_read_result_raw发的是空操作帧目的只是提供移位时钟把 DOUT 上的 16 位结果同步读回来。电压换算那一行的关键是先把raw转成int16_t。单端模式下电压都是正的读到的值最大是 0x7FFF但差分模式下会出现负数统一按有符号数处理就不会踩坑。满量程 4.096V 是 PGA 档位决定的如果你把配置改成了 ±2.048V这里的系数要同步改成 2.048f否则数据显示会翻一倍。3.3 双差分采集正负电压与有符号换算双差分模式和单端模式唯一的差别在 MUX 编码以及换算时对负数的理解。两个差分对的读取函数如下float ads1118_read_diff(uint8_t pair) { uint16_t cfg ADS1118_MODE_SINGLE | ADS1118_PGA_FSR_4096 | ADS1118_DR_128SPS; if (pair 0) cfg | ADS1118_MUX_AIN0_AIN1; else cfg | ADS1118_MUX_AIN2_AIN3; ads1118_start_conversion(cfg); ads1118_delay_ms(ads1118_conv_time_ms(ADS1118_DR_128SPS)); uint16_t raw ads1118_read_result_raw(); return (float)(int16_t)raw * 4.096f / 32768.0f; }差分输入时 ADC 测量的是两个引脚之间的电位差所以结果可能是正值也可能是负值。比如 AIN0 比 AIN1 高 1V读回的正码对应 1.0V反过来 AIN1 比 AIN0 高读回的就是补码形式的负数。把原始值强转int16_t之后负电压的换算自然成立不需要额外判断符号。需要注意差分输入下满量程电压是 ±4.096V也就是说两脚之间最大只能测 4.096V 的压差。如果输入超过满量程读数会饱和在 0x7FFF 或者 0x8000 附近不会继续增长。做工业采集时如果传感器输出范围不确定先把 PGA 调到最大档等确认实际信号幅度后再降增益避免数据截断。3.4 内部温度读取TS_MODE、符号扩展与 0.03125 系数ADS1118 内部温度传感器的用法和 ADC 通道略有不同配置字里把 TS_MODE 置 1转换结果就不再是电压码而是 14 位有效的温度数据。读取代码如下float ads1118_read_temperature(void) { uint16_t cfg ADS1118_MODE_SINGLE | ADS1118_DR_8SPS | ADS1118_TS_MODE; ads1118_start_conversion(cfg); ads1118_delay_ms(200); /* 8SPS 下留足单次转换时间 */ uint16_t raw ads1118_read_result_raw(); int16_t t (int16_t)(raw 2); /* 高 14 位有效先算术右移 */ return (float)t * 0.03125f; /* 1 LSB 0.03125°C */ }这里最容易写错的一步是右移 2 位之前必须先把raw转成有符号int16_t这样右移才是算术右移符号位会跟着扩展。如果先把raw当成无符号数右移再转int16_t负温度值就会算错直接差出几十度。0.03125 的来源很简单14 位有效数据温度分辨率就是 2^(-5)即 0.03125°C 每 LSB。芯片内部温度传感器主要用来做冷端补偿或芯片过热保护精度在 ±0.5°C 量级不能当成精密温度计用但判断 PCB 温漂趋势足够了。4. 常见问题排查读回全 0、数值偏差 4 倍、温度乱跳的根源4.1 读回全是 0xFFFF 或 0x0000现象SPI 收发函数执行正常但读回来的数据永远是同一个值要么全 1 要么全 0。原因基本出在三个地方。第一MISO 引脚模式配置错误比如被初始化成推挽输出数据根本进不了 SPI 外设。第二SPI 极性和相位和芯片对不上ADS1118 要求数据在上升沿被锁存按 CPOL0、CPHA1 配置。第三片选信号没真正拉低或者片选 GPIO 配的是开漏输出但没有外部上拉导致 CS 一直处于无效电平。解决先把 MISO 配成浮空输入用逻辑分析仪抓 SCLK 和 CS 波形确认电平翻转正常再检查 SPI 外设寄存器里的 CPOL/CPHA 位。我一般会写一个最简单的查询函数循环读 10 次状态寄存器看 RXNE 标志和 DR 寄存器是否在变化快速定位是硬件还是软件问题。4.2 电压数值稳定但偏大或偏小现象采集到的电压值稳定且线性但和万用表实测对不上要么正好翻倍要么正好减半。原因PGA 增益档位和电压换算系数没对应上。比如配置寄存器写的是 PGA10满量程 ±2.048V但换算代码里还在用 4.096V 做分母结果所有读数都偏大一倍。这类问题在复制代码时特别容易发生因为配置宏和换算函数往往分散在文件各处。解决把满量程系数做成一个查找表和 PGA 编码一一对应不要在每个读取函数里各自写死。调试时用精密电阻分压出一个固定电压比如用两个千分之一精度电阻把 3.3V 分到 1.65V接在 AIN0 上验证读数误差应该在几个毫伏以内。4.3 温度读数比室温高好几倍现象读取温度得到的数值稳定但明显不合理比如室温 25°C 读出来却是 100°C。原因没有对原始值做右移处理直接把 16 位整数值乘了 0.03125。温度数据只有高 14 位有效低 2 位是无效填充位如果不右移等效于把有效值放大了 4 倍算出来的温度自然变成了 25 × 4 100。解决按 3.4 节的写法把raw转成int16_t后先右移 2 位再乘 0.03125。验证方法很简单上电稳定后读一次温度数值接近环境温度代表正确如果差出好几倍优先检查右移和符号扩展这一步。查看原始十六进制值也有帮助比如 0x0320 约等于 25°C。4.4 F407 上同样的代码通信不稳定现象F103 上跑得好好的代码烧到 F407 后偶尔读回乱码或者某个通道数据跳动明显变大。原因F407 的 APB2 总线和 CPU 主频比 F103 高很多如果 SPI 分频系数照搬实际 SCLK 频率成倍上升超过了 ADS1118 的接口时序上限数据在长线上出现建立时间不足。信号完整性在高速时变得敏感加上杜邦线连接问题更明显。解决F407 上的 SPI 分频从大往小调先保证通信稳定再追求速度。我在 F407 上习惯从 32 分频起跳确认 1000 次连续读取无错码后再逐档提高。另外把 ADS1118 的 DOUT 上拉使能位打开长线时波形边缘会干净很多。注意SPI 通信速率不是越快越好ADC 转换时间是瓶颈所在SCLK 跑再快也没用。稳定优先速率够用就行。5. 二次开发如何把这套驱动移植到自己的板上5.1 软件模拟 SPI 作为兜底验证手段硬件 SPI 在某些板子上会遇到引脚复用冲突比如 SPI1 的引脚已经被以太网或者 LCD 占用。这时候最稳的兜底方案是软件模拟 SPI只需要四个 GPIO 就能完成通信代价是 CPU 占用高一些但 ADS1118 本身速率上限不高模拟完全够用。/* ads1118_port.c —— 软件模拟 SPI 收发 */ static uint16_t ads1118_spi_xfer16_soft(uint16_t tx) { uint16_t rx 0; for (int i 15; i 0; i--) { /* MSB 先发出 */ HAL_GPIO_WritePin(MOSI_PORT, MOSI_PIN, (tx i) 1); HAL_GPIO_WritePin(SCK_PORT, SCK_PIN, GPIO_PIN_SET); HAL_Delay(1); /* 延时拉长先保证时序正确 */ if (HAL_GPIO_ReadPin(MISO_PORT, MISO_PIN)) rx | (1u i); HAL_GPIO_WritePin(SCK_PORT, SCK_PIN, GPIO_PIN_RESET); HAL_Delay(1); } return rx; }软件模拟的实现思路就是按位翻转 SCLK 和 DIN同时采样 DOUT。延时先给足确定逻辑正确后再把延时缩短到微秒级。这个方法最大的价值不是替代硬件 SPI而是帮你判断问题出在芯片还是外设配置上硬件 SPI 读不到数据时用软件模拟绕过去就能定位责任方。5.2 多片 ADS1118 级联与外部通道扩展如果你的项目通道数超过 4 路单端有两种扩展思路。第一种是直接并联多片 ADS1118每片独立片选引脚共享 SCLK、MOSI、MISO 三条线通过不同的 CS 选中目标芯片。驱动层只需要增加一个设备编号参数所有命令字不用改是最干净的扩展方式。第二种是在前端加模拟多路复用器比如用 CD4051 这类 8 选 1 芯片把 8 个传感器轮流切换到 ADS1118 的同一个 AIN 输入上。切换后需要留出足够的建立时间再启动转换驱动里加一段固定延时即可。MUX 通道选择用普通 GPIO 控制代价是牺牲一点采样率换来的是单颗 ADC 成本不变的情况下通道数翻倍。移植到自己的工程时我建议先做三件事验证 SPI 通信能读到稳定数据、用固定电压源标定每个增益档位的换算系数、最后再接入真实传感器闭环测试。我早前在某个项目里返工过一次就是因为拿到驱动后没有重新校验 PGA 换算直接把配置抄过来结果一路传感器读数都偏了 30%。从那以后我每换一套平台或者改一次增益都会强制走一遍固定电压标定流程再上真传感器。希望这篇笔记能帮你在自己的板子上少走两步弯路。本文还有配套的精品资源点击获取