简介:面向ADS1263/ADS1256等高精度24位ADC开发的驱动源码与中文手册资料包,适合嵌入式工程师、软硬件开发者以及工业仪表、数据采集与测试测量项目人员在模数转换功能设计时参考。资料共87个文件,压缩包约2.39MB,主要包含34个头文件和33个C源程序、8个汇编启动文件、Keil工程配置文件、hex固件及readme说明,目录结构清晰,可在STM32F10x平台直接打开工程,也可按模块提取复用。已有926人学习下载。内容覆盖驱动初始化、SPI通信、采样率/增益/数字滤波器配置、连续与单次转换、中断处理和错误处理等核心环节,并附有ADS1256中文手册,便于对照理解两片ADC的寄存器差异与应用取舍;源码中的寄存器级配置示例和常用功能函数,可直接用于实际项目,帮助开发者减少底层适配工作量、加快高精度采集通道的开发验证。
1. ADS1263驱动源码与ADS1256中文手册:这套STM32工程能让你少走两周弯路
做称重、温度和精密电压采集的工程师,大概率都搜过ADS1263驱动和ADS1256中文手册这两样东西。这两颗ADC经常同时出现在高精度采集项目的选型表里,真正把它们跑通的人,多半是从一套现成的STM32工程起步的。
我拿到这份源码时的第一印象是:它不只是一个.c文件,而是一个能直接编译的Keil工程,驱动层、SPI层、DAC和按键演示代码都分好了。对正在做数据采集板的人来说,这套资源解决三个问题:寄存器配置不用从头啃手册、SPI时序有现成的收发函数、从ADS1263换到ADS1256时有中文手册可对照。
2. 拆解源码包:驱动层、SPI层和工程目录的职责边界
2.1 文件清单与目录结构
把压缩包解开后,目录大致是下面这张表:
| 目录/文件 | 内容 | 职责 |
|---|---|---|
| Project/RVMDK(uv4) | Keil工程文件 | uVision4直接打开编译 |
| Output | Template.hex | 编译好的模板固件 |
| User | main.c、stm32f10x_it.c | 主流程和中断入口 |
| Driver | ADC1263.c/h、spi.c/h、dac1263.c/h、key.c/h、sys_delay.c/h | 全部底层驱动 |
| Libraries | FWlib、CMSIS | 外设库和内核文件 |
| Listing | 编译列表文件 | 编译中间产物 |
| Doc | readme.txt | 使用说明 |
| keilkill.bat | 批处理 | 清理编译中间文件 |
这些文件不是平级堆在一起的,而是按“应用层→驱动层→固件库”分了三层。main.c 只调用 ADC1263_Init、ADC1263_ReadData 这类接口;ADC1263.c 内部再去调用 spi.c 的收发函数;spi.c 只负责 GPIO 配置和字节级交换。这样分层的好处是:如果换一块主控,只需要重写 spi.c 和一个延时函数,驱动逻辑基本不动。
2.2 驱动核心:ADC1263.c 怎么封装寄存器操作
ADC1263.c 里最核心的是写寄存器和读数据两条链路。写寄存器时,驱动会把命令字节、寄存器地址和等待周期一起封装好;读数据时则按芯片手册的时序,分三次 SPI 收发把码值取回来。下面这段是我从这套源码里整理出来的写寄存器写法:
uint8_t ADC1263_WriteReg(uint8_t reg, uint8_t value) { SPI_CS_LOW(); // CS拉低,一次总线事务开始 SPI_RW(WREG | (reg & REG_MASK)); // 拼装写寄存器命令 SPI_RW(0x00); // 写入寄存器个数-1,这里只写一个 SPI_RW(value); // 目标寄存器的新值 SPI_CS_HIGH(); // CS拉高,事务结束 return 0; }WREG 和 REG_MASK 在头文件里定义,具体命令码以手册为准。这套封装的价值在于,把 CS 拉高拉低、命令拼装、字节收发这些容易出错的细节全部收敛在一个函数里,业务代码里永远只看到“写哪个寄存器、写什么值”。
驱动里另一条关键路径是读数据。ADS1263 的转换结果通过 DOUT 引脚按位送出,驱动需要做三次 SPI 交换才能凑齐一个完整的转换码值。很多新手直接把这些 SPI 收发代码写在 main.c 里,一旦通信时序要调,就得满工程翻代码。这套源码的做法是单独提供一个读取函数,内部屏蔽字节顺序和符号位的处理,调用方只拿到一个 int32_t,这个抽象习惯值得照抄。
2.3 Spi.c 和 Sys_delay.c:不是配角
spi.c 的初始化参数直接决定整个驱动能不能工作。参考这套工程里的写法,SPI 模式通常配置为主机模式、CPOL=0、CPHA=1,软件管理 CS 引脚:
void SPI2_Init(void) { SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; SPI_Init(SPI2, &SPI_InitStructure); SPI_Cmd(SPI2, ENABLE); }分频系数从 16 开始是比较稳的调试起点。对于 8MHz 的系统时钟,SCLK 就是 500kHz,先用低速把通信链路验证通,再用逻辑分析仪抓波形逐步提高速率。CPOL 和 CPHA 任何一个配错,读回来的数据都会错位,而且表现得很随机——今天读对明天读错,非常容易误判成硬件问题。
sys_delay.c 提供的毫秒和微秒延时,主要用在复位芯片、写寄存器后等待内部稳定、切换通道后等待建立时间。这些延时看似无关紧要,但很多“配置不生效”的故障其实都出在延时不够上。
2.4 DAC 和按键模块:告诉你怎么扩展这套驱动
dac1263.c 封装的是 ADS1263 内部激励电流源的控制。在称重传感器场景里,这种电流源可以用来做桥臂激励或传感器检测,驱动里单独拆成一个文件,方便在需要时直接打开配置函数修改输出电流档位。
key.c 在这个工程里的作用更像演示:按键触发一次单次转换,验证整个采集链路是否正常。实际产品里按键几乎不会留下,但它的回调式写法值得参考——检测、消抖、调用采集函数,边界很清楚。压缩包里带一个 readme.txt,里面通常会写清楚工程适用的主频和串口波特率,拿到手后第一件事应该是打开它确认编译环境版本,而不是直接双击工程。
3. 把驱动跑在STM32F103上:接线、工程导入与采样率配置
3.1 硬件接线参考
ADS1263 用 SPI 接口和主控通信,如果你用的是 STM32F103 的 SPI2,参考接线如下:
| 信号 | STM32引脚 | ADS1263引脚 |
|---|---|---|
| SCLK | PB13 | SCLK |
| DIN | PB15 | DIN |
| DOUT | PB14 | DOUT |
| CS | PB12 | CS |
| DRDY | 任意普通GPIO | DRDY |
| RESET | 任意普通GPIO | RESET/PWDN |
| VREF | 外部基准输出 | VREF |
模拟电源 AVDD 和数字电源 DVDD 最好分开供电,模拟地和数字地在 ADC 附近单点连接。VREF 不要直接从 STM32 的 3.3V 引出,纹波会直接折合到转换结果上——你用万用表量电压跳动 1mV,读出来的码值就要跳几十个 LSB。常见做法是单独放一颗低噪声基准芯片,输出 2.5V 给 VREF 引脚。
3.2 打开工程与导入驱动
用 Keil uVision4 打开 Project/RVMDK 下的工程文件,如果板子主控确实是 STM32F103,理论上可以直接编译下载。如果是自己的工程想移植,做法是:
- 把 Driver 下的 ADC1263.c、spi.c、dac1263.c、key.c、sys_delay.c 加进工程对应分组。
- 在魔术棒选项卡的 C/C++ Include Paths 里加上 Driver 目录。
- 确认系统主频和延时函数里配置的时钟一致。
- 先编译一遍,把报错集中在“找不到头文件”这一类,解决了就说明路径基本齐了。
Output 目录下的 Template.hex 可以作为一个基准固件:如果自己的改动导致板子跑不起来,先把 Template.hex 烧回去,能恢复现象就说明硬件没问题,问题在自己的代码里。
3.3 主流程与读取数据
main.c 里的流程一般是这样:
int main(void) { Delay_Init(); SPI2_Init(); ADC1263_Init(); while (1) { if (ADC1263_DRDY_Check() == 0) // DRDY拉低表示转换完成 { uint32_t raw = ADC1263_ReadData(); int32_t val = (int32_t)(raw << 8) >> 8; // 24位有符号扩展 float voltage = (float)val * 2.5f / 0x7FFFFF; // 后续做显示、存储或上传 } } }DRDY 是 ADS1263 的转换完成标志引脚,拉低时说明数据寄存器的内容已经更新。不检查 DRDY 就读数据,最常见的结果就是连续读到同一个值或者全 0xFF。24 位数据左移 8 位再右移 8 位是为了把符号位正确扩展到 int32_t,如果不做这一步,负半轴电压换算出来会是一个很大的正数。这里 0x7FFFFF 是对应 VREF 满量程的码值,VREF 换成别的电压时公式里的 2.5f 要同步改。
3.4 采样率、PGA 与输入模式调整
驱动里通常会有类似下面的配置接口:
ADC1263_SetGain(GAIN_8); // PGA增益设置为8倍 ADC1263_SetSampleRate(SPS_1000); // 采样率设为1kSPS Delay_ms(50); // 等待内部数字滤波器稳定PGA 增益决定了满量程范围,计算公式是 ±VREF/Gain。VREF=2.5V、增益 8 时,满量程大约是 ±0.3125V,输入信号只要超过这个范围就会削波。采样率的选择则要看信号类型:
| 应用场景 | 建议采样率 | 滤波器建议 |
|---|---|---|
| 电池电压监测 | 10~100 SPS | SINC3 |
| 称重传感器 | 100~1000 SPS | SINC3 |
| 动态振动信号 | 2000 SPS以上 | SINC1或SINC2 |
采样率设得太高并不总是好事。Σ-Δ ADC 内部数字滤波器需要时间建立,速率越高,单个转换结果里的噪声越多,有效位数会掉。做称重这类慢变信号时,我一般会把速率压在 1kSPS 以内,换取更稳定的读数。
4. 避坑手册:ADS1263驱动调试中六个常见卡点记录
4.1 读出来全是 0xFF 或旧值
现象:SPI 通信看起来正常,但读回的 24 位数据要么全是 0xFF,要么重复上一次的值。最开始会怀疑是芯片坏了,换一片还是一样。
原因:最常见的是没有等 DRDY 拉低就发起了读命令。还有一种情况是 SPI 模式不对,CPOL/CPHA 和芯片要求不一致,导致移位寄存器里的位全部错位。接线松脱时也会出现类似现象,而且偶尔正常偶尔全错。
解决:先在代码里加一个超时等待 DRDY 的过程,确认每次转换完成后才读。然后降 SPI 分频到 128,排除速率太快导致的时序余量不足。最后用逻辑分析仪看 DOUT 上是否有稳定的三个字节输出。代码可以这样写:
for (i = 0; i < 1000; i++) { if (ADC1263_DRDY_Check() == 0) break; Delay_us(10); } if (i >= 1000) { // 超时未就绪,复位SPI或重新初始化ADC }4.2 寄存器写了却像没写
现象:改采样率寄存器后,实际采样间隔完全没变化;改通道配置也不生效。量了 CS 和 SCLK 波形,数据确实发出去了。
原因:很多高精度 ADC 对寄存器写入有时序要求,写完寄存器后需要等待内部操作完成,紧接着去配置下一个寄存器可能被忽略。此外,如果驱动内部用了读改写的方式修改某一位,但读回的时机不对,也会把旧值写回去。
解决:每个寄存器写完以后加 1ms 以上的延时,再读回该寄存器确认数值。我习惯在调试阶段把所有寄存器配置后的读回值通过串口打印出来,连续配置三次做一致性校验,能快速排除“写入被吞”的问题。
4.3 静态读数跳动,有效位数上不去
现象:输入接一个稳定的电压,读数仍然在几十甚至上百个 LSB 之间跳。一开始以为是芯片本身噪声大,换了多片无果。
原因:模拟电源和数字电源共用了一路 LDO,STM32 的 GPIO 翻转和 SPI 通信噪声通过电源耦合进模拟前端。另一种可能是模拟地网络有环路,DOUT 线上的数字信号干扰了相邻的模拟走线。
解决:AVDD 和 DVDD 分开供电,模拟地和数字地在 ADC 的散热焊盘附近单点连接。SPI 的三根信号线各串一个 330Ω 电阻,能明显减少数字边沿对模拟部分的串扰。这个改动做完之后,同样的信号跳动幅度能降一半以上。
4.4 换通道后前几包数据是错的
现象:用多路复用切换输入通道后,前两包数据明显偏大或偏小,后面的数据恢复正常。单通道采集时完全没问题。
原因:多路开关切换后,AIN 引脚上的外部阻抗需要给内部采样电容充电,采样电容建立需要时间。同时数字滤波器还在用切换前的数据进行滤波,产生混合结果。
解决:在通道切换后丢弃前 N 次转换结果。一般丢弃 3~5 次就够,谨慎一点可以丢弃 10 次。实际操作里我用一个变量记录当前通道,通道变了就清掉平均值缓存,避免新旧通道的数据混在一起。
4.5 PGA 增益与量程匹配不当
现象:把 PGA 设成 8 倍增益后,读到的码值长时间停在满量程附近,波形顶部被削平。用万用表量输入电压并不高,为什么还会削波。
原因:满量程范围是 ±VREF/Gain,VREF=2.5V、增益 8 时只有 ±0.3125V。很多传感器输出本身带了直流偏置,没有做偏置扣除,实际进入 ADC 的电压已经超过这个范围。
解决:先用增益 1 测一下输入信号的实际范围,再根据峰值决定增益。如果信号有固定偏置,要么用前端电路把偏置抬到合适位置,要么在软件里先做偏移校准。检查状态寄存器里的 PGA 告警位也能提前发现问题。
4.6 采样率表套用后偏差 20%
现象:从网上拷贝一份采样率配置表,按表设置后测量 DRDY 间隔,实际速率比预期低了或者高了很多。换一块板子又不一样。
原因:采样率表和芯片外部时钟频率强相关。很多例程默认外部晶振是 7.68MHz,如果你的板子用了别的晶振,同样的寄存器数值对应的实际速率就会偏移。
解决:用频率计或者逻辑分析仪直接测 DRDY 引脚的下落沿间隔,得到实际采样率,再回头推寄存器值。有条件的话用示波器看晶振频率是否准确,这个参数错了,后面所有标定都会跟着错。
5. 从源码到ADS1256中文手册:跨芯片迁移的修改清单
5.1 两颗ADC的定位差异
ADS1256 和 ADS1263 经常被放在一起比较,但它们的定位并不相同。ADS1256 是经典的 24 位 Σ-Δ ADC,最高 30kSPS,适合低速高精度测量;ADS1263 定位更高,采样率更快,片内集成了激励电流源和更多诊断功能。源码包里配套的 ADS1256 中文手册,重点不是让你把 ADS1263 的代码改成 ADS1256,而是理解这类 Σ-Δ ADC 的共同工作方式。
| 对比维度 | ADS1256 | ADS1263 |
|---|---|---|
| 分辨率 | 24位 | 高分辨率Σ-Δ架构 |
| 片内DAC/电流源 | 无 | 有 |
| 最高采样率 | 30kSPS | 更高 |
| 适合场景 | 电池监测、温度测量 | 称重、多通道高速采集 |
| 手册价值 | 寄存器映射清晰,适合入门 | 时序和命令更复杂 |
5.2 使用ADS1256中文手册的正确姿势
拿到中文手册后,我一般会先折三页:引脚功能表、寄存器映射表、SPI 时序图。引脚表用来查电源和复位接法,寄存器映射表用来查写配置时的地址,时序图用来核对 CS、SCLK、DRDY 的先后关系。手册最后通常有示例程序流程图,那部分是写初始化代码的骨架。
ADS1256 的寄存器写命令和 ADS1263 不完全一样,迁移时必须逐条核对。典型代码如下:
void ADS1256_WriteReg(uint8_t reg, uint8_t value) { SPI_CS_LOW(); SPI_RW(0x50 | reg); // ADS1256的WREG命令 SPI_RW(0x00); // 寄存器计数-1,表示只写一个 SPI_RW(value); SPI_CS_HIGH(); }注意 ADS1256 在连续读数据模式下,必须先发送 SDATAC 命令退出连续模式,再写寄存器,否则配置会被忽略。很多移植翻车就翻在这里——代码逻辑没错,只是没有退出 RDATAC。
5.3 命令集和寄存器地址的差异
从这套 ADS1263 驱动迁移到 ADS1256,至少要改三个地方。第一是命令字节,写寄存器、读数据、连续读数据的命令码都不同;第二是寄存器地址表,增益、采样率、输入多路复用器对应的地址不一样;第三是数据读取长度,ADS1256 固定读 24 位,而 ADS1263 的部分驱动会按 32 位读。改完寄存器地址表以后,最好在手册上逐个对照一遍,这种机械错误最难查。
5.4 迁移后的自检步骤
迁移完不要直接接传感器,先用一个稳定的直流电压源做基准验证。常见的验证代码是这样:
float Measure_Channel(uint8_t ch) { ADS1256_SetMux(ch); // 设置输入通道 Delay_ms(10); int32_t code = ADS1256_ReadOnce(); return (float)code * 2.5f / 0x7FFFFF; }输入 0V 时读到的电压应在 0 附近;输入一个 1.000V 的已知电压,读数偏差应在几个 mV 以内。如果偏差很大,先怀疑 VREF 实际电压,用万用表量基准输出,再把公式里的 2.5f 换成实测值。完成这一步,基本可以确认迁移成功。
6. 让这套ADS1263驱动更好用:三个工程化打磨技巧
6.1 用 DMA 代替阻塞式读取
原工程里的 SPI 收发是轮询方式,读一次数据要占 CPU 好几个循环。在高采样率场景下,CPU 一直被 SPI 等待消耗,主流程里几乎做不了别的事。常见的做法是改成 DMA 搬运:
void ADC1263_DMA_Config(void) { DMA_DeInit(DMA1_Channel4); // SPI2_RX 对应 DMA1_Channel4 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rx_buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 3; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_Init(DMA1_Channel4, &DMA_InitStructure); }STM32F103 里 SPI1_RX 对应 DMA1_Channel2,SPI2_RX 对应 DMA1_Channel4,通道搞错的现象是 DMA 一直不触发。DMA 每次只搬运三个字节,传输完成中断里再做符号扩展和电压换算,主循环就可以专心处理其他任务。
6.2 均值滤波与粗差剔除
低采样率场景下,简单滑动平均就能显著提升稳定度。要注意累加时用 64 位变量,避免 16 个 24 位值累加后溢出 int32_t:
#define SAMPLE_NUM 16 int32_t avg_value(int32_t *buf) { int64_t sum = 0; for (int i = 0; i < SAMPLE_NUM; i++) sum += buf[i]; return (int32_t)(sum / SAMPLE_NUM); }在信号边缘变化较快的场景里,建议先做中值滤波剔除粗大值再平均,否则一个干扰尖峰会把平均值拉偏很大。称重应用里,均值窗口设 16 点到 32 点之间比较合适,窗口太大系统响应会变得很迟钝。
6.3 逻辑分析仪验证时序
每次移植驱动,我都会在调试初期用逻辑分析仪抓四路信号:CS、SCLK、DIN、DOUT。重点看三个点:CS 拉低后 SCLK 是否连续无毛刺;DOUT 上的数据位是否对齐 24 个时钟;DRDY 拉低到 CS 拉低之间间隔是否足够。先把 SPI 分频降到最低,确认波形干净后再往上提。这个习惯帮我避开了很多“软件看起来对、实际是硬件布线问题”的尴尬。
我自己就吃过一次亏:新板子一上来把采样率拉满,读出的数据时好时坏,查了两天才发现是 SPI 走线太长,高速边沿反射把数据位冲坏了。从那以后,我每移植一套 ADC 驱动,都强制走一遍“低速模式先验证、逻辑分析仪确认时序、再逐步提速”的流程,虽然多花半小时,但省下来的排查时间远远不止这些。希望帮到你。
本文还有配套的精品资源,点击获取