恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
MSP430与LMP90100接口代码库:24位SPI多通道采集驱动解析
首页
资讯中心
/
MSP430与LMP90100接口代码库:24位SPI多通道采集驱动解析
MSP430与LMP90100接口代码库:24位SPI多通道采集驱动解析
发布时间:2026/10/15 17:06:28
简介这是一份TI官方提供的MSP430与LMP90100传感器模拟前端接口代码库面向嵌入式开发、工业传感采集及物联网设备设计者帮助解决MSP430快速配置和控制LMP90100多通道高精度ADC的问题。代码以C/C编写自带函数库与演示应用示例覆盖寄存器读写、通道配置、数据采集等常用操作配套的PDF文档包含芯片数据手册及应用报告便于查阅寄存器细节与接口时序。资源包以RAR格式压缩共37个文件其中23个C源文件、12个头文件、2个PDF文档整体大小约5.79MB结构紧凑、便于直接导入工程。目前已有277人学习下载适合需要基于MSP430快速搭建传感器AFE原型的中高级嵌入式开发者可直接复用官方驱动缩短开发调试周期。1. MSP430 与 LMP90100 的接口代码库24 位多通道采集驱动拿来就能省掉一个月调时序做嵌入式采集的工程流程里主控和 ADC 之间的驱动层是最磨人的而这套 MSP430 与 LMP90100 的接口代码库把 24 位多通道采集链路上的 SPI 通信、寄存器配置和 C 封装全给铺好了。LMP90100 是带 PGA 和多通道输入的 Δ-Σ ADC和 MSP430 的配合点集中在时序和配置细节上代码库把这些细节转成可直接调用的驱动函数和示例流程省掉的是翻数据手册、调 SPI 相位、反复试寄存器组合的时间。做称重、流量积算、高精度温压采集的开发者拿到手改引脚、调增益就能跑新手和熟手都吃得下这一套。2. 代码库的架构与选型先摸清 LMP90100 的通信脾气再决定怎么接线LMP90100 作为 24 位 Δ-Σ ADC和主控之间只走 SPI 这一条数据通道。它的不少行为是由协议细节决定的CS 片选需要在整个帧期间保持有效DRDY 引脚在每次转换完成后拉低寄存器访问带读写命令位。如果把这些细节当普通 SPI Flash 来写多半要翻车——你读回来的寄存器值永远是同一个或者设备 ID 直接是 0xFF。所以拿到代码库的第一件事不是急着编译而是把它的通信模型理顺。2.1 LMP90100 的 SPI 帧格式与 MSP430 USCI_B 模块LMP90100 的 SPI 帧由命令地址字节和数据字节组成读和写的高 4 位命令码不同低 4 位是寄存器地址。支持连续读CS 不被拉高的前提下持续供时钟就能把连续地址的数据依次送出这对多通道结果批量读取特别关键。代码库的寄存器定义头文件里一般用宏把这几个命令码列出来改动余地很小。MSP430 的 USCI_B 做 SPI 主机足够顺手。下面是初始化最小配置// MSP430 USCI_B0 初始化为 SPI 主机模式 // 先进入软件复位状态再改配置最后退出复位 UCB0CTLW0 | UCSWRST; // 进入复位态 UCB0CTLW0 UCMST | UCMODE_0 | UCSYNC // 主机、三线 SPI、同步模式 | UCSSEL_2 | UCMSB // 时钟源 SMCLK、高位先出 | UCCKPH; // 相位按数据手册要求 UCB0BRW 0x0002; // SMCLK / 2得到 SPI 时钟 UCB0CTLW0 ~UCSWRST; // 退出复位模块生效这段代码的核心有两处。第一UCSWRST 必须在改动配置前置位否则寄存器写入直接被锁存到错误状态第二UCCKPH 和 UCCKPL 的组合决定了采样沿具体组合要以 LMP90100 手册的时序图为准代码库里默认给的是 UCCKPL0、UCCKPH1。如果后面发现读寄存器永远是固定值把这四个组合各试一遍是最快的排查方法。引脚复用也是常见隐患。MSP430 的 USCI 功能需要把对应引脚切到第二功能很多人 SPI 配置写了一大堆P1SEL0/P1SEL1 没动SDO/SDI/SCLK 全都没接上。做硬件抽象时把引脚复用函数和 SPI 初始化剥离开但调用顺序上必须确保复用配置在前。SPI 帧的结构可以用下面这张表来理解帧段位宽说明命令/地址字节8 bit高 4 位读写命令低 4 位寄存器地址数据字节8 bit写操作时为要写入的值读操作时主控发 0x00CRC 字节可选 8 bit开启 CRC 后追加在数据字节之后代码库的驱动层把帧拼装封装好了应用层看不到这些字节的细节。但知道这个结构对排查问题很有用——当你在逻辑分析仪上看到一帧数据能立刻判断出命令、地址、数据分别对应哪一段而不是对着波形发懵。2.2 代码库目录驱动层、硬件抽象与示例工程的分工这种官方类型的接口代码库目录结构有规律通常分三层。最底层是寄存器驱动文件里是寄存器地址、位定义、读寄存器和写寄存器的实现中间是硬件抽象层把 USCI_B 的收发细节包成 spi_read 和 spi_write 两个函数再往上就是示例工程演示多通道配置和连续采样主流程。分层的好处是换板子只改中间一层。文件角色可以用这张表来对应目录/文件职责移植时要改吗寄存器定义头文件地址、命令码、位字段宏一般不改寄存器读写实现拼装 SPI 帧解析返回值一般不改硬件抽象层调用 USCI_B 的收发和 GPIO 片选必须改示例主程序初始化序列、采样循环按应用需求改代码库里最容易让人改坏的正是那个「看起来不变」的头文件。有人为了适配自己的板子把寄存器地址宏改了结果后面所有人的代码都对不齐。正确做法是寄存器地址一个字节都不能动要动的是硬件抽象层里引脚的映射和时钟分频。把这一点想清楚后面移植才不会越改越乱。2.3 为什么用 C 写驱动、用 C 做封装从题目标注的 C 可以看出这份代码库是分了层次的驱动层用 C 保证编译器和硬件无关性应用层用 C 把设备抽象成对象。MSP430 的编译器对 C 的支持最成熟驱动层用 C 写能最大程度减少移植摩擦而 C 封装则让上层调用更接近「操作一个 ADC 设备」的直觉。C 封装层最常见的设计是把 LMP90100 变成一个类构造函数里完成引脚初始化和 SPI 初始化成员方法暴露通道配置和数据读取class LMP90100 { public: int init(); int set_channel(uint8_t ch, uint8_t gain); int read_sample(); private: uint8_t read_reg(uint8_t addr); void write_reg(uint8_t addr, uint8_t val); }; int LMP90100::read_sample() { // 先从 C 驱动层读取一个完整的 SPI 数据帧 // 再做 24 位符号扩展返回真实采样值 return parse_24bit(spi_read_word()); }封装之后业务代码里不用再关心寄存器地址和位操作只调用 set_channel 和 read_sample。还有一点容易被忽略C 的全局对象构造顺序在单片机上不受保证所以类实例通常放在 main 函数里显式构造或者用指针加手动 new避免静态初始化顺序带出来的断电重启后初始化失败问题。这点放到后面避坑章节会详细说。2.4 换 MCU 时的移植边界代码库也不可能永远只跑在 MSP430 上。如果以后要移到别的单片机记住一个原则寄存器驱动层可以整目录带走硬件抽象层重新写。跨平台移植时最大的坑是 SPI 极性和相位的命名映射每家的外设寄存器对 CPOL/CPHA 的叫法都不一样光看名字容易对错。把 LMP90100 手册里的时序图打印出来对照新平台 SPI 外设的时序描述一项一项核对比对着寄存器位猜可靠得多。片选信号也要二次确认。新平台如果支持硬件 CS看起来省事但有些硬件 CS 会在帧间自动释放而 LMP90100 要求 CS 行为精确可控这对连续读和 CRC 帧很不友好。实战里我一般把 CS 做成软件 GPIO 控制哪怕新平台有硬件 CS 也只在测试高速模式时用。到这里通信模型、目录结构和封装思路已经清楚了下面进入实操环节把 SPI 初始化和寄存器配置讲透。3. 把驱动跑起来SPI 初始化、设备 ID 校验与通道配置三步走上一章把通信模型理清了这一步开始接触实际的初始化流程。整个初始化可以拆成三个动作配好 SPI 模块、读设备 ID 确认链路通、写通道配置寄存器。任何一步没做扎实后面采到的数据都没有参考意义。3.1 补齐 SPI 初始化把固定分频改成自适应参数2.1 里的最小初始化是演示用的实际工程里系统主频可能是 8MHz、16MHz 甚至更高写死分频系数容易把 SPI 时钟推到超出 LMP90100 规格。更稳的写法是把期望波特率作为参数传进来在函数里算分频void spi_init(uint32_t clk_hz, uint32_t spi_hz) { uint16_t brw clk_hz / spi_hz; // 整数分频注意下限 UCB0CTLW0 | UCSWRST; UCB0CTLW0 UCMST | UCMODE_0 | UCSYNC | UCSSEL_2 | UCMSB | UCCKPH; UCB0BRW brw; P1SEL0 | BIT0 | BIT1 | BIT2; // CLK/DI/DO 切到第二功能 P1SEL1 ~(BIT0 | BIT1 | BIT2); UCB0CTLW0 ~UCSWRST; }参数说明clk_hz 传系统主时钟频率spi_hz 传你想跑的 SPI 时钟频率两者相除结果写到 UCBRW 里。注意 brw 算出来最小是 2分频系数 0 和 1 在 USCI 里是特殊含义如果 clk_hz / spi_hz 小于 2说明目标波特率超出硬件能力要降 spi_hz 或者降主频。P1SEL0 和 P1SEL1 这两行的引脚编号要按你实际板子的原理图来改USCI_B0 和 USCI_B1 的引脚位置不一样。通过这两行代码SPI 模块就从「能发」变成了「知道按多快发」。但波特率不是想多快就多快LMP90100 手册里给了一个 SPI 时钟上限工程实践建议留 30%50% 裕量。如果发现读寄存器偶尔错位第一件事就是把 spi_hz 对半砍这是成本最低的降噪方案。3.2 上电复位与设备 ID 校验把链路问题拦在最前面LMP90100 上电后有一段内部复位时间这段时间内访问总线设备可能不应答。稳妥的初始化序列是上电延时几百微秒然后读设备 ID 寄存器确认值和预期一致再继续。代码库里的初始化入口一般是这样的uint8_t id lmp90100_read_reg(REG_DEVICE_ID); if (id ! LMP90100_EXPECTED_ID) { // 每个错误值都指向一种具体的原因 error_handler(ERR_SPI_LINK); return -1; }读设备 ID 的价值不在于「确认型号」而在于把通信链路的各种问题当场暴露出来。读到 0xFF 说明 SDO 一直保持高电平CS 大概率没真正按到低读到 0x00 说明时钟相位或极性不对数据被锁存到了错误边沿读到一个随机跳动的值多半是电源还没稳定或者复位时间不够。代码库一般会把 ERR_SPI_LINK 这个错误码预留在错误处理模块里实际使用时把读到的原始 ID 也带上排查效率会高很多。3.3 通道配置从寄存器参数表到实际写入代码LMP90100 的通道选择、PGA 增益和采样率分散在几个配置寄存器里。手工往 main 函数里填寄存器魔法数维护两天就会想骂人。代码库的做法是定义一个配置结构体把通道相关的参数集中起来再交给一个统一的配置函数去拆解、写入typedef struct { uint8_t channel; // 通道号0 起始单端模式最多 8 个 uint8_t gain; // PGA 增益按数据手册的档位取值 uint16_t samp_rate; // 采样率单位 SPS } lmp90100_ch_cfg; int lmp90100_config_channel(lmp90100_ch_cfg *cfg) { uint8_t reg_val (cfg-gain 4) | (cfg-channel 0x0F); lmp90100_write_reg(REG_CH_CFG, reg_val); // 采样率是 16 位寄存器拆成两个字节写 lmp90100_write_reg(REG_RATE_H, (cfg-samp_rate 8) 0xFF); lmp90100_write_reg(REG_RATE_L, cfg-samp_rate 0xFF); return 0; }这个结构体里的 gain 字段在写入时要左移四位是因为 LMP90100 的增益字段在位域的高四位通道号占低四位。如果你只记住「把 gain 塞进寄存器」而忘了移位配置会静默错位采出来的数据放大倍数完全不对这还是那种不报错的故障最坑人。采样率寄存器拆成高字节低字节两次写入写完之后最好养成回读校验的习惯可以在配置函数最后加一行uint8_t chk lmp90100_read_reg(REG_CH_CFG); if (chk ! reg_val) { return -2; // 回读不一致说明 SPI 写被干扰或降速不够 }回读校验看起来多花一次 SPI 传输但对排查问题价值巨大。只要回读失败立刻能定位到「写入环节」而不是「配置语义」出了问题。实际跑的时候配置失败大概率是 SPI 时钟频率偏高把 3.1 里的 spi_hz 降一档再试。配置完成之后main 函数里的调用顺序是固定的void main(void) { WDTCTL WDTPW | WDTHOLD; // 关看门狗避免复位打断配置 spi_init(8000000UL, 1000000UL); // 主频 8MHzSPI 1MHz lmp90100_ch_cfg ch {0, 1, 3200}; lmp90100_config_channel(ch); lmp90100_start_conversion(); __bis_SR_register(LPM0_bits); // 进低功耗等 DRDY 中断 }这段代码里LPM0_bits 让主核休眠配合下一章要讲的 DRDY 中断实现真正意义上的事件驱动采集。如果你不想用低功耗模式也可以写成主循环轮询。到这里SPI 通了、ID 验了、通道配了下一步就该处理数据读取了。4. 数据读取与中断配合连续转换模式下的时序控制LMP90100 每个转换周期结束都会拉低 DRDY 引脚这是它与主控打交道的「门铃」。数据读取的核心问题不是「怎么读 SPI」而是「怎么知道什么时候该读」。这一章把三种取数方式、24 位数据重组和与主循环的配合一次讲透。4.1 轮询、DRDY 中断还是 DMA三种取数方式的选择取数方式取决于你对实时性和 CPU 占用的要求。三种方式各有适用边界方式实时性CPU 占用复杂度适用场景轮询 DRDY中高低低采样率、逻辑简单中断 标志位高低中大多数应用的首选DMA 自动搬运最高极低高高采样率、需持续采集轮询方式最直接主循环里死等 DRDY 引脚拉低再读缺点是等待期间 CPU 干不了别的事。DMA 方式最省心数据搬完了才通知 CPU但缓冲区的环形管理和 DMA 与 SPI 接收中断的协调很容易出隐蔽 bug。我一般在绝大多数工程里用中断加标志位的方式兼顾实时性和可控性。中断方式的代码骨架如下volatile uint8_t drdy_flag 0; // 中断里只置位 #pragma vectorPORT1_VECTOR __interrupt void P1_ISR(void) { if (P1IFG BIT3) { // 确认触发源是 DRDY drdy_flag 1; P1IFG ~BIT3; } }中断函数里千万不要调用 lmp90100_read_reg。第一个原因是带参函数调用在 MSP430 上会引入额外的出入栈开销拉长中断响应第二个原因是如果这个中断被打断SPI 读操作可能停在半帧状态。正确姿势是置标志位返回主循环检测到标志后再搬数据。4.2 24 位数据重组拼字节、符号扩展与通道对齐LMP90100 的转换结果由三个字节组成多通道模式下每次 SPI 读取返回的不仅是数据还包含通道信息。把三字节拼成有符号数这件事看着简单翻车率其实不低int32_t parse_24bit(uint8_t b2, uint8_t b1, uint8_t b0) { int32_t val ((int32_t)b2 16) | ((int32_t)b1 8) | b0; if (b2 0x80) { val - (1 24); // 手动符号扩展 } return val; }第一移位前要先把 uint8_t 提升成 int32_t不然 b2 左移 16 位会被编译器当成 int 运算高位符号位处理会出问题。第二负数的符号扩展不要依赖隐式转换显式减掉 1 24 更可靠。第三多通道数据在数组里存放时必须确定通道号的对应关系否则通道 3 的传感器读数会被当成通道 0 送进算法这种错误在波形上几乎看不出来。做传感器采集时我一般会在结构体里同时保存通道号和原始值而不是只存一个拼接好的数值。多加 4 个字节换来的是后期排查时能直接打印通道号确认来源这笔开销值得。4.3 环形缓冲区让主循环和中断各有各的节奏中断里置了标志主循环读数据如果读得慢而采样率高数据会被覆盖。给数据加一层环形缓冲区是让生产者和消费者解耦的常用手法#define BUF_SIZE 128 static volatile int32_t sample_buf[BUF_SIZE]; static volatile uint16_t buf_head, buf_tail, buf_count; void buf_push(int32_t v) { if (buf_count BUF_SIZE) { sample_buf[buf_head % BUF_SIZE] v; buf_head; buf_count; } } int32_t buf_pop(void) { int32_t v 0; if (buf_count 0) { v sample_buf[buf_tail % BUF_SIZE]; buf_tail; buf_count--; } return v; }这里的三个 buf 变量全部声明成 volatile 是对的但还不够。buf_head、buf_tail 用 16 位是因为 8 位变量在连续采集几万次后会溢出到时候索引错乱数据全乱套。buf_count 在中断 push 和主循环 pop 同时发生时存在竞态严格做法是 push 前关中断pop 后开中断或者在中断里只用一种方式更新 count。MSP430 上关中断的开销很小工程上不必为了省那几条指令去冒数据错乱的风险。缓冲区还有一个细节如果 buf_count 达到 BUF_SIZE这段实现是直接丢弃新数据。对于连续采集丢掉一部分样本比覆盖旧数据更安全因为后者会让数据出现「回退」的时间错觉。如果你需要的是不丢点就得把 BUF_SIZE 撑大或者改为 DMA 双缓冲方案。5. 避坑与排查SPI 通信失败、数据漂移与配置丢失的五条血泪记录驱动写出来能编译过距离能稳定跑还差得远。以下是实际调试 LMP90100 驱动时反复踩过的几类问题每一条都按「现象、原因、解决」来拆可以直接对照你自己的板子排查。5.1 设备 ID 读出来永远是 0xFF现象程序烧进去第一句读 ID 就返回 0xFF后续寄存器读写全部失败。用示波器测 SCLK 有波形但 SDO 引脚一直保持高电平SPI 看起来像在「单机模式」自说自话。原因最常见的片选逻辑问题。CS 信号如果在硬件上经过反相器或者被其他外设占用软件拉低片选时 ADC 实际看到的可能是释放状态它自然就不会把数据放到 SDO 上。第二个原因是 CS 拉低到 SCLK 第一个沿之间的建立时间不足器件还没来得及响应时钟就被喂了数据。解决先用万用表量 CS 引脚在软件拉低后的实际电平确认极性没被板子的反相电路翻转过。然后在拉低 CS 后加一段延时常见做法是 10 微秒左右的空循环代价可以忽略但对建立时间短的器件帮助很大。再不行就把 SPI 时钟频率降一半排除时序裕量问题。这三板斧下来0xFF 基本都能解决。5.2 前几个通道数值异常跳变后面的通道正常现象多通道扫描模式下第 0、1 通道的采样值明显偏大甚至直接打满后面的通道倒是正常。把通道顺序换一下异常跟着第一轮的通道走说明不是硬件接线问题。原因LMP90100 的输入多路复用器切换后前端采样电容需要时间建立尤其是 PGA 增益开得高的时候建立时间会拉长。配置刚写完就开始采数转换结果自然是乱的。这属于 Δ-Σ ADC 的共性行为不算芯片缺陷。解决在通道配置之后加入建立等待或者更简单粗暴——配置完丢弃前 N 个转换结果。N 的取值按采样率反推比如采样率 3.2kSPS每个样本周期 312us丢弃 8 个样本相当于等待 2.5ms足够大部分增益档位完成建立。代码库的示例里通常会留一个 settle_wait 参数换算成循环次数不要图省事写成固定 0 或者 1。5.3 配置写进去回读正常断电重启后全部丢失现象板子正常跑配置写入后立即回读数值正确。但只要断电再上电LMP90100 好像失忆了一样所有寄存器回到默认值采集结果完全不对。原因LMP90100 的配置寄存器是易失性的没有内部非易失存储区来保存配置。上电后芯片只能按复位默认值工作需要主控每次开机重新灌一遍配置。这个特性在数据手册里有写但很容易被忽略尤其是之前用惯了带非易失配置的 ADC 的人。解决把初始化配置做成一个独立的幂等函数每次上电完整执行。注意不要因为「上次已经跑过初始化」就跳过更不要在看门狗复位后跳过初始化流程。看门狗复位不触发 LMP90100 的复位但主控重新启动会重新拉低 CS、重跑 SPI此时 ADC 内部状态和配置寄存器的对应关系可能已经错位最稳妥的做法是复位后先软复位 ADC再从设备 ID 校验开始完整走一遍。5.4 C 封装后中断回调只触发一次或者干脆不触发现象把驱动封装成 C 类之后DRDY 中断在第一次转换时正常后面就再也不进了。单步调试发现中断标志位确实置位了但进不了中断服务函数。原因C 类实例被放在了某个函数的栈上函数返回后对象被析构中断回调指向的成员函数地址已经失效。另一个常见原因是编译器把中断服务函数里的静态成员调用优化了或者全局对象的构造顺序在启动代码里还没轮到中断就已经开启了。解决类实例用全局 static 对象避免栈上生命周期问题。中断服务函数保持 C 风格在 ISR 里调用一个静态成员函数来操作对象不要直接在中断向量表里挂成员函数指针。初始化顺序上先构造对象再做外设配置最后才开中断顺序反了会出现「中断来时对象还没准备好」的现场。5.5 采样数据低频漂移像持续的低频正弦叠加在真实值上现象数据整体趋势正确但在零点附近能看到明显的缓慢漂移周期从几秒到几十秒不等。用手触摸线缆或者更换电源漂移幅度会变化。原因参考电压不稳定是主要嫌疑。LMP90100 对参考源的纹波抑制有限内部参考需要足够的建立时间外部参考如果带载能力弱负载波动就会直接进结果。再一个是数字噪声耦合SPI 时钟频率偏高时数字走线的振铃会耦合到模拟前端体现在 24 位结果的最低位上。解决先把采样率降到最低如果漂移明显改善说明数字噪声占大头优先处理 SPI 走线和去耦。给参考引脚和 AVDD 加上 100nF 加 10uF 的双级去耦电容这是低成本见效快的方案。传感器信号线如果长用屏蔽线并把屏蔽层单端接地。最后注意接地平面完整模拟地和数字地单点连接。这一条往往是最难查的因为它不报错只是数据难看。排查时建议先把差分信号和单端信号分别测一遍确认漂移是来自前端输入还是转换链路本身。5.6 排查工具与手段别让故障靠猜上面五条如果靠眼睛看寄存器猜效率太低。实际排查时我通常先接逻辑分析仪抓 CS、SCLK、MISO、MOSI 四根线一次传输就能看出 CS 极性、数据沿和帧格式对不对。逻辑分析仪没有足够的通道也不怕SPI 就四根线入门级的 8 通道型号完全够用。第二步是写一段寄存器回读的测试代码把所有配置过的寄存器逐个读回来在串口上打印成表格和写入值逐字节比对。这一步能筛出 80% 的通信问题。最后才轮到上信号源验证转换精度。6. 进阶用法用 CRC 校验和数据就绪标志把采集链路做到可靠6.1 开启 LMP90100 的 SPI CRC 校验寄存器级别的通信在实验室里没问题放到工控现场就扛不住线缆干扰了。LMP90100 支持在 SPI 帧尾追加一个 CRC 字节让主控确认每一帧数据在过去传输中没有被动过手脚。代码库里通常带一个查表法 CRC 函数多项式以数据手册附录为准uint8_t crc8(uint8_t *data, uint8_t len) { uint8_t crc 0x00; while (len--) { crc ^ *data; for (uint8_t i 0; i 8; i) { crc (crc 0x80) ? (crc 1) ^ POLY : (crc 1); } } return crc; }POLY 的取值在代码库头文件里已经按数据手册定义好直接用即可。开启 CRC 后要注意两点。第一CRC 计算范围包含命令地址字节和数据字节不包括 CS 释放期间的填充第二读操作的最后一个字节是主机算好的 CRC发给 ADC 做校验ADC 校验失败会把 SDO 拉高表示错误。这个功能平时可以不开但做主从距离远、线缆经过接插件的项目建议强制开启省下的现场维护时间远超那一点协议开销。6.2 三步验证法把「自认为能跑」变成「确定能跑」驱动改完不要直接接传感器先做三个层次的验证。第一步把 SDI 和 SDO 短接CS 拉死让 SPI 自发自收验证主控侧时序自身是闭环的。第二步把所有配置寄存器回读一遍和写入值做逐字节比对这一步抓得住绝大多数 SPI 配置问题。第三步在 ADC 输入端接一个精密电压源输出已知电压读取转换结果换算成毫伏后与理论值对比偏差在预期范围内才能上真实的传感器。从那次在项目现场被漂移问题折腾了一整天之后我养成了一个习惯每移植一次 ADC 驱动这三步验证就强制走一遍相关测试代码直接留在工程里作为自检用例。换板子、换芯片版本、换编译器优化等级都跑一遍再进业务开发。这套 MSP430 与 LMP90100 的接口代码库本身已经把驱动、封装和示例铺好了路真正决定项目差别的往往就是验证这一步有没有做到位。希望帮到你。本文还有配套的精品资源点击获取