简介:这是一份面向嵌入式开发者的ADS1263驱动源码与ADS1256中文手册合集,适用于工业、医疗及科研场景中基于24位高精度ADC进行数据采集的项目。资源共87个文件,压缩包大小2.39MB,主要包含C/H源码、汇编启动文件、Keil工程配置文件(uvproj/uvopt)、hex固件、使用说明txt及初始化脚本;源码覆盖SPI通信、ADC初始化、多通道配置、中断处理和错误检测等模块,并提供初始化、配置、读取数据和关闭设备等接口,可直接移植到STM32平台,缩短底层驱动开发周期。目录中区分了源程序、库文件、文档和输出文件,便于按模块检索。配套ADS1256中文手册可用于对比理解相似Σ-Δ型ADC的寄存器与工作模式差异。已有922人学习下载,特别适合正在调试ADS1263/ADS1256驱动、需要可复用工程模板与参考手册的软硬件工程师,可省去从零配置寄存器的工作,快速完成高精度采集系统搭建。
1. 从ADS1256换到ADS1263:STM32驱动源码里藏着的高分辨率ADC取舍
做多通道高精度采集时,ADS1256经常是默认选择,但这颗芯片的局限性在评估ADS1263驱动源码后会更清楚。ADS1263同样定位高分辨率ADC,但把24位有效分辨率、内置PGA、激励电流源和故障诊断集成在一起,称重和RTD测温场景能省掉大量外围电路。源码包基于STM32F103标准外设库,ADC1263.c实现寄存器读写与转换控制,spi.c处理底层时序,main.c串口输出结果,拿到手可以直接套到自己的工程里。
对已经用过ADS1256的人来说,最该警惕的是命令集差异:ADS1256的RREG/WREG命令不能直接用在ADS1263上,数据长度也从3字节变4字节。这篇文章就从源码文件结构开始,重点拆SPI参数、寄存器初始化流程、单次/连续转换代码,最后给出移植到其他平台和验证有效位的可复现步骤。适合正在做高精度仪表、需要把采集精度从16位提升到20位以上的工程师。
2. 驱动源码结构:从STM32标准外设库看ADS1263的SPI接口与初始化分工
2.1 源码包内文件到底做了什么
拿到压缩包先别急着编译,按功能把文件分成三层:SPI底层、设备协议层、应用层。ADC1263.c和ADC1263.h是协议层,负责组SPI命令、拼数据、执行校准;SPI.c和SPI.h是底层,完成STM32的SPI外设初始化与单字节收发;main.c和stm32f10x_it.c是应用层,决定采样时机和数据流向。还有一个dac1263.c,它不是ADC驱动的一部分,而是板载DAC的驱动,用来输出可调电压或电流激励,在电桥测量里会与ADC联动。
| 文件/目录 | 职责 |
|---|---|
| ADC1263.c/h | ADS1263命令封装、寄存器读写、校准、通道切换、数据读取 |
| SPI.c/h | STM32硬件SPI或模拟SPI单字节收发 |
| DAC1263.c/h | 板载DAC控制,输出激励电压/电流 |
| key.c/h | 按键输入,用于手动切换通道或触发校准 |
| sys_delay.c/h | 毫秒/微秒延时,满足复位和DRDY时序 |
| stm32f10x_it.c | 中断服务例程,DRDY下降沿置位 |
| keilkill.bat | 清理Keil编译中间文件 |
我一般会先读main.c,看它调用了哪些ADS1263_开头的函数,再回ADC1263.c里定位具体实现。这个顺序比从头读头文件效率高。源码里的函数命名基本是“模块_动作”风格,比如ADS1263_ReadReg、ADS1263_WriteReg、ADS1263_ReadData,迁移到其他平台时,这些函数签名可以直接保留,只替换SPI层。
2.2 SPI通信层:硬件SPI参数与引脚分配
ADS1263的SPI接口和普通Flash不一样,它的DOUT/DRDY是复用引脚:CS拉低时该引脚输出转换数据,CS拉高时输出数据就绪状态。所以SPI初始化时要特别注意CS控制的时序,不能在读取数据的过程中去检测DRDY。源码里SPI.c完成引脚和SPI外设的配置,典型代码如下:
void SPI1_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); }这段配置把SPI1设为8位主模式、MSB先行、CPOL=High、CPHA=2Edge,对应SPI Mode 3。ADS1263在这组参数下读寄存器最稳定,如果你的板子在GPIO和电源都正常时读ID仍是0xFF,优先检查这里。SPI_BaudRatePrescaler_16在STM32F103的72MHz主频下得到4.5MHz的SCK,对短接排线足够;如果DRDY毛刺频繁,可以降到32分频。
2.3 寄存器访问命令:ADS1263与ADS1256的第一个分岔口
ADS1263写寄存器命令是0x40 | 寄存器地址,读是0x20 | 寄存器地址;ADS1256对应0x50 | 地址和0x10 | 地址。源码里ADC1263.c通常这样封装:
uint8_t ADS1263_ReadReg(uint8_t addr) { uint8_t val; ADS1263_CS_LOW(); SPI_ExchangeByte(0x20 | addr); SPI_ExchangeByte(0x00); // 寄存器数量-1,0表示只读1个 val = SPI_ExchangeByte(0x00); ADS1263_CS_HIGH(); return val; } void ADS1263_WriteReg(uint8_t addr, uint8_t val) { ADS1263_CS_LOW(); SPI_ExchangeByte(0x40 | addr); SPI_ExchangeByte(0x00); // 只写1个寄存器 SPI_ExchangeByte(val); ADS1263_CS_HIGH(); }第二个字节的低5位表示“寄存器数量减一”,0x00表示只操作一个寄存器。这个写法在ADS1263上是固定套路,和ADS1256不通用。拿到数据手册后第一件事就是核对这条命令,因为把ADS1256的老驱动直接改成ADS1263,往往在WriteReg这里就静默失败了。读取器件ID也是用ReadReg,如果读回0xFF,说明SCK极性错或MISO没接好;如果读回0x00,大概率是电源或复位问题。
提示:不同版本的源码可能把复位命令定义成
ADS1263_CMD_RESET,移到新工程时保持头文件里的宏名一致,不要自己重新造常量。
3. 核心驱动实现:初始化、采样率/增益设置与转换数据读取
3.1 初始化流程:复位、读ID、写寄存器
ADS1263上电后不会自动进入可用的采样状态,必须先复位、再确认SPI通信正常,然后按应用需求配置输入通道、PGA增益、滤波器和输出速率。源码里初始化函数的骨架如下:
uint8_t ADS1263_Init(void) { uint8_t id; SPI1_Config(); ADS1263_CS_LOW(); SPI_ExchangeByte(ADS1263_CMD_RESET); ADS1263_CS_HIGH(); delay_ms(5); id = ADS1263_ReadReg(ADS1263_REG_DEVICE_ID); if (id == 0xFF) { return 1; // SPI时序或接线错误 } ADS1263_WriteReg(ADS1263_REG_SPIDIV, ADS1263_SPIDIV_DIV1); ADS1263_WriteReg(ADS1263_REG_SYS_CTRL, ADS1263_SYSCTRL_PGA_EN); ADS1263_WriteReg(ADS1263_REG_MODE0, ADS1263_MODE0_SPS_1000); ADS1263_WriteReg(ADS1263_REG_MODE1, ADS1263_MODE1_FILTER_SINC4); ADS1263_WriteReg(ADS1263_REG_INPMUX, ADS1263_INPMUX_AIN0_AIN1); return 0; }这里宏名以ADC1263.h为准,具体数值请按数据手册核对。复位命令发完后等5ms,让内部振荡器和基准稳定。读ID只排除0xFF这种明显异常,更可靠的做法是把ID值通过UART打印出来,与手册里的DEVICE_ID字段对比。写到SYS_CTRL时,PGA使能位要小心,增益越高对参考电压的要求越严,如果基准纹波大,PGA输出会饱和。
3.2 单次转换与数据读取:32位数据怎么拼才不踩坑
ADS1263每次转换输出4字节,而ADS1256只输出3字节。这是移植时最容易出的延伸错误。源码里单次读取通常长这样:
int32_t ADS1263_ReadSingleConvert(void) { uint8_t buf[4]; uint32_t raw = 0; ADS1263_CS_LOW(); SPI_ExchangeByte(ADS1263_CMD_RDATA1); // 读取主ADC数据 buf[0] = SPI_ExchangeByte(0xFF); buf[1] = SPI_ExchangeByte(0xFF); buf[2] = SPI_ExchangeByte(0xFF); buf[3] = SPI_ExchangeByte(0xFF); ADS1263_CS_HIGH(); raw = ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3]); return (int32_t)raw; // 二进制补码直接转有符号 }逻辑说明:RDATA1命令后连续读4字节,最高字节在前。ADS1263的原始输出是32位二进制补码,所以(int32_t)raw就能保留正负号,不需要像ADS1256那样把24位数据左移8位再右移8位做符号扩展。有的源码会写return raw << 8 >> 8,那是从24位ADC移植过来没改干净,会导致负半段数据错误。SPI_ExchangeByte(0xFF)只是为了产生SCK时钟,发送内容会被ADC忽略。
参数说明:如果使用HAL库,这里对应HAL_SPI_Receive()。单次转换适合间歇采样,每次启动后等DRDY,再读数据。连续转换适合恒定采样率输出,下面看中断如何处理。
3.3 连续转换与DRDY中断:不要在中断里做SPI读
连续转换模式下,每次转换结束,DRDY引脚在CS为高时产生一个低电平脉冲。源码的main.c里通常用外部中断触发:
volatile uint8_t ads1263_data_ready = 0; void EXTI15_10_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line_Drdy) != RESET) { ads1263_data_ready = 1; EXTI_ClearITPendingBit(EXTI_Line_Drdy); } } void MainLoop(void) { if (ads1263_data_ready) { ads1263_data_ready = 0; int32_t val = ADS1263_ReadSingleConvert(); printf("%ld\r\n", val); } }逻辑说明:中断服务程序只置标志位,不在中断里调用SPI读取。因为SPI读数据需要拉低CS、连续发4个字节,如果在中断里做,可能还没读完下一次DRDY又到了,还会跟其他SPI设备抢占总线。正确做法是主循环里消费这个标志,或者配合DMA。对于ADS1263的DOUT/DRDY复用引脚,外部中断要配置在CS为高时采样,否则读到的是数据线上的电平变化。
参数说明:EXTI初始化的触发边沿设为EXTI_Trigger_Falling。启动连续转换用START1命令,停止用STOP1;如果只测主ADC,不要对副ADC发命令,有的源码会把两个ADC都启动,导致DRDY脉冲翻倍。
4. 移植与调试:从STM32F103到其他平台的SPI时序适配与ADS1256/1263差异
4.1 硬件SPI对接时的修正点
从标准外设库换到HAL库,或者从STM32F103换到GD32、ESP32、树莓派,引脚定义和SPI初始化都要重写,但ADS1263的协议层完全可以保留。移植时建议先加一个调试函数,把CS和DRDY状态直接打印出来:
void ADS1263_DebugPins(void) { printf("CS=%d DRDY=%d\r\n", (int)GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4), (int)GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)); }在SPI配置之前调用,确认CS能被拉低、DRDY在转换完成后有电平跳变。很多所谓“驱动不工作”的问题,其实是GPIO在复用模式下把SCK和MOSI方向搞反,或者把MISO设置成了推挽输出。另一个常见点是DOUT/DRDY的复用关系:CS低时它是DOUT,CS高时才是DRDY。如果你的板子把DOUT和DRDY分开引出,那要看原始驱动内部用的是哪个引脚,再改外部中断触发方式。
4.2 模拟SPI移植:不依赖硬件外设
没有硬件SPI时,可以用普通GPIO模拟。ADS1263在低速下对时序并不苛刻,下面这种MSB-first模式对应SPI Mode 3,SCK空闲为高、数据在上升沿被主机采样:
static uint8_t software_spi_xfer(uint8_t dat) { uint8_t i, ret = 0; SCLK_HIGH(); for (i = 0; i < 8; i++) { if (dat & 0x80) MOSI_HIGH(); else MOSI_LOW(); SCLK_LOW(); // 下降沿,ADC在该时刻更新输出 delay_us(1); SCLK_HIGH(); // 上升沿,主机采样MISO delay_us(1); ret <<= 1; if (MISO_READ()) ret |= 0x01; dat <<= 1; } return ret; }这段SCK周期约为2μs,对应500kHz,对ADS1263完全够用。注意:模拟SPI最容易犯的错是边沿选反,表现为读ID稳定返回0xFF。如果遇到,把先拉高再拉低改成先拉低再拉高,或者对照手册里的时序图确认采样沿。模拟方式虽然慢,但好处是SCK速率可调,方便排查长线干扰。
4.3 常见坑与错误定位
| 现象 | 直接原因 | 排查方向 |
|---|---|---|
| 读ID永远是0xFF | SCK极性/相位不对或MISO虚焊 | 用逻辑分析仪抓SCK和MISO,确认第一个位 |
| 数据只有高几位变化 | 数据拼接按24位处理 | 检查RDATA后是否读了4字节,符号扩展是否正确 |
| DRDY中断频繁进入但读不到新数据 | DOUT/DRDY在CS低时被误判 | CS拉高后再检测DRDY,或改用独立DRDY引脚 |
| 连续转换5秒后死掉 | 没有处理SPI超时或CS粘住 | 每次SPI操作前后加超时,CS拉低超时自动释放 |
| 电源纹波大时有效位下降 | 参考电压受数字噪声污染 | 参考引脚加0.1μF+10μF电容,PGA增益调低再验证 |
ADS1263的PGA增益越大,对参考电压和电源纹波越敏感。我一般会先短接输入,把输出码的标准差测出来,再决定要不要加平均滤波。驱动本身用滤波函数压噪声,但治标不治本,先解决电源才是正路。
4.4 ADS1256与ADS1263的命令/寄存器差异
| 项目 | ADS1256 | ADS1263 |
|---|---|---|
| 数据输出 | 3字节,24位 | 4字节,32位原始输出 |
| 最大输出速率 | 30kSPS | 40kSPS |
| RREG命令 | 0x10 | 0x20 |
| WREG命令 | 0x50 | 0x40 |
| 复位命令 | 0xFE | 0x06 |
| 内置激励电流源 | 无 | 有 |
表格里这几项是两片ADC最大的差异。把ADS1256驱动移植到ADS1263,至少要改三处:寄存器命令、数据读取字节数、复位命令。如果ADS1256旧代码里用SPI_ExchangeByte(0x10 | reg),这里会得到完全不同的寄存器内容。标题里的“ads1256中文手册”可以作为参考索引,别把它当ADS1263的寄存器手册用,两边的寄存器地址和位定义都不一样。
5. 基于ADS1263的RTD/电桥测量实战与验证技巧
5.1 用短接输入测ENOB,先判断驱动有没有“虚高”
拿到驱动后,第一步不要急着接传感器,先短接AIN0和AIN1,采集1024个点计算峰峰值噪声。如果这一步过不了,接PT100或电桥都意义不大。短接输入测到的是ADC自身噪声、参考噪声和电源纹波的叠加,最能反映硬件底子。
import statistics import math samples = [int(x) for x in open("adc_data.txt")] v_pp = max(samples) - min(samples) v_rms = statistics.stdev(samples) fsr = 2 * 5.0 # 增益=1、基准=5V时,双极性满量程±5V enob = math.log2(fsr / v_pp) print(f"Vpp={v_pp} LSB, ENOB={enob:.1f} bit")说明:ENOB这里用峰峰值噪声计算,是工程上偏保守的指标;用RMS噪声算会好半位到一位。fsr = 2 * 5.0是示例,实际要按你的基准电压和PGA增益调整,比如PGA=8、基准=2.5V时,满量程是2 * 2.5 / 8。如果ENOB明显低于手册标称值,先查电源纹波,再查模拟输入走线和参考电容。
RTD测量时,可以用ADS1263内置的激励电流源给PT100供电。源码里dac1263.c如果负责控制激励电流,要配合IOMUX寄存器配置。建议的顺序是:先打开激励电流源,延时稳定后再启动转换;不要和ADC采样同时打开,否则第一个读数会偏大。验证完短接噪声之后,再用精密电阻箱代替传感器,分别测0Ω、100Ω、1000Ω,把线性度偏差记下来,这样能区分是驱动问题还是传感器问题。
本文还有配套的精品资源,点击获取