
简介这份资源是 TI 官方提供的 MSP430 与 LMP90100 传感器 AFE 接口代码库面向使用 MSP430 单片机进行传感器信号采集与调理的嵌入式开发者尤其适合需要快速搭建 LMP90100 原型验证环境的中高级 C/C 工程师。压缩包共 37 个文件以 23 个 .c 源文件和 12 个 .h 头文件为主体构成可直接调用的函数库覆盖 LMP90100 的寄存器配置、通道切换与数据读取等操作另附 2 份 PDF 说明文档分别讲解器件接口方式与库函数用法整体约 5.79MB。已有 277 人学习下载。读者可从中获得官方示例工程与演示程序借助现成函数库缩短传感器 AFE 初始化与控制代码的编写周期并通过文档理解硬件连接与软件调用之间的对应关系为后续项目移植和调试提供参考。1. 拿到一份 MSP430 与 LMP90100 的接口代码库先别急着编译去年帮一个做工业称重的朋友看板子他手里有一份 TI 的 MSP430 接口 LMP90100 的代码库解压之后一堆 .c 和 .h 文件Keil 工程、IAR 工程、CCS 工程混在一起他第一反应是“这玩意儿到底从哪开始看”。这其实是很多做嵌入式的人拿到官方代码库时的真实状态代码能跑但不知道跑在哪、改了会不会崩。这份代码库解决的就是 MSP430 单片机通过 SPI 去配置和读取 LMP90100 这颗 24 位多通道 ADC 的问题典型场景是称重传感器、压力变送器、热电偶采集这类需要高精度、低噪声模拟前端的设备。适合谁适合手上已经有 MSP430 板子、需要接 LMP90100 做数据采集又不想从寄存器手册第一页啃起的开发者。C 在这里主要体现为工程里的封装层和示例应用底层驱动仍然是 C 风格。2. 代码库结构拆解从工程目录到 SPI 驱动分层2.1 目录里到底有什么拿到压缩包解压后常见结构大致是这样不同版本文件名略有差异但分层逻辑一致LMP90100_MSP430_Library/ ├── driver/ │ ├── lmp90100.c # ADC 寄存器读写、通道配置、转换启动 │ ├── lmp90100.h # 寄存器地址宏、通道枚举、返回码 │ ├── spi_msp430.c # MSP430 侧 SPI 主机收发 │ └── spi_msp430.h ├── application/ │ ├── main.c # 初始化、主循环、串口打印 │ └── app_config.h # 采样率、增益、通道数等业务参数 ├── platform/ │ ├── msp430_port.c # 引脚映射、时钟、延时 │ └── msp430_port.h └── project/ ├── ccs/ # Code Composer Studio 工程 ├── iar/ # IAR Embedded Workbench 工程 └── keil/ # Keil MDK 工程部分版本提供这个分层不是摆设。driver层只关心 LMP90100 的寄存器语义和 SPI 时序platform层只关心 MSP430 的引脚和时钟application层才是业务逻辑。二次开发时最忌讳的就是把业务参数写进lmp90100.c那样换一块板子就得重来。2.2 三层架构的职责边界用一张表把职责说清楚层级文件职责改动频率驱动层lmp90100.c/h寄存器读写、通道切换、转换等待低平台层msp430_port.c、spi_msp430.cSPI 引脚、时钟、片选、延时中换板必改应用层main.c、app_config.h采样率、增益、数据上报高驱动层里最核心的是两个函数一个写寄存器一个读寄存器。LMP90100 的 SPI 帧格式是“命令字节 数据字节”命令字节最高位区分读写低 7 位是寄存器地址。代码里通常这样封装/* lmp90100.c 片段寄存器写操作 */ uint8_t LMP90100_WriteReg(uint8_t regAddr, uint8_t data) { uint8_t txBuf[2]; uint8_t rxBuf[2]; txBuf[0] regAddr 0x7F; /* bit70 表示写 */ txBuf[1] data; LMP90100_CS_LOW(); /* 片选拉低SPI 事务开始 */ SPI_MSP430_Transfer(txBuf, rxBuf, 2); LMP90100_CS_HIGH(); /* 片选拉高锁存数据 */ return rxBuf[0]; /* 返回状态字节供上层判断 */ }逻辑说明regAddr 0x7F保证写方向位为 0片选必须在完整两字节传输期间保持低电平这是 LMP90100 的时序要求中途拉高会导致寄存器写入失败。参数说明regAddr是 7 位寄存器地址data是要写入的 8 位值返回值是 ADC 回传的状态字节常见做法是上层检查 bit0 判断是否出错。读操作对称只是命令字节 bit7 置 1并且需要多发一个 dummy 字节把数据时钟出来/* lmp90100.c 片段寄存器读操作 */ uint8_t LMP90100_ReadReg(uint8_t regAddr, uint8_t *pData) { uint8_t txBuf[2] { regAddr | 0x80, 0x00 }; /* bit71 读第二字节 dummy */ uint8_t rxBuf[2]; LMP90100_CS_LOW(); SPI_MSP430_Transfer(txBuf, rxBuf, 2); LMP90100_CS_HIGH(); *pData rxBuf[1]; /* 第二个字节才是寄存器值 */ return rxBuf[0]; }这里有个容易翻车的点很多新手以为读的时候第一个回传字节就是数据实际上第一个字节是状态第二个才是寄存器内容。这个坑我在早期调试时踩过读出来的增益配置永远是 0查了半天才发现偏移了一位。2.3 平台层SPI 和引脚映射怎么改msp430_port.h里通常是一堆宏把 LMP90100 的片选、复位、数据就绪引脚映射到 MSP430 的具体端口。换板子时只改这个文件/* msp430_port.h 片段引脚映射 */ #define LMP90100_CS_PORT P3OUT #define LMP90100_CS_PIN BIT0 #define LMP90100_CS_LOW() (LMP90100_CS_PORT ~LMP90100_CS_PIN) #define LMP90100_CS_HIGH() (LMP90100_CS_PORT | LMP90100_CS_PIN) #define LMP90100_DRDY_PORT P1IN #define LMP90100_DRDY_PIN BIT2 #define LMP90100_DRDY_READ() ((LMP90100_DRDY_PORT LMP90100_DRDY_PIN) ? 1 : 0)SPI 初始化部分要关注时钟极性和相位。LMP90100 支持 SPI 模式 1CPOL0CPHA1代码里spi_msp430.c会配置 UCB0 或 USCI 模块/* spi_msp430.c 片段SPI 主机初始化 */ void SPI_MSP430_Init(void) { UCB0CTL1 | UCSWRST; /* 先复位 USCI 模块 */ UCB0CTL0 UCMST | UCMODE_0 | UCSYNC | UCMSB | UCCKPH; /* UCMST 主机模式UCSYNC 同步 SPIUCMSB 高位先发 UCCKPH 对应 CPHA1配合 CPOL0 即 SPI 模式 1 */ UCB0CTL1 UCSSEL_2 | UCSWRST; /* SMCLK 作为时钟源保持复位 */ UCB0BR0 0x02; /* 分频实际速率 SMCLK/2 */ UCB0BR1 0x00; UCB0CTL1 ~UCSWRST; /* 释放复位SPI 就绪 */ }参数说明UCMSB决定高位先发LMP90100 要求 MSB firstUCCKPH置位表示数据在第一个时钟沿采样这是模式 1 的关键。如果 SPI 模式配错现象是读出来的寄存器值全是 0xFF 或随机跳变这时候先查UCB0CTL0这一行别急着怀疑 ADC 坏了。3. 跑起来从工程导入到第一帧数据3.1 选工程、配时钟、编译下载代码库通常提供 CCS 和 IAR 两套工程。以 CCS 为例导入project/ccs下的工程后第一件事是确认目标芯片型号和时钟配置。MSP430 的 DCO 默认频率不一定满足 SPI 速率要求main.c里一般会调用BCSCTL1、DCOCTL或UCS相关寄存器把主频拉到 8MHz 或 16MHz。编译前检查三个地方芯片型号是否和板子一致、链接文件是否匹配、app_config.h里的采样率是否在 LMP90100 支持范围内。下载运行后如果串口没有输出先别改代码用示波器或逻辑分析仪看两个信号片选有没有拉低、SPI 时钟有没有出来。片选不动说明程序卡在初始化之前时钟不动说明 SPI 模块没使能。这个排查顺序能省掉大量瞎猜。3.2 初始化序列LMP90100 上电后必须做的事LMP90100 上电后不能直接读数据要先走一遍配置流程。代码库里LMP90100_Init()通常包含这些步骤/* lmp90100.c 片段初始化序列 */ uint8_t LMP90100_Init(void) { uint8_t status; LMP90100_Reset(); /* 硬件或软件复位 */ Delay_ms(10); /* 等内部基准稳定 */ status LMP90100_WriteReg(REG_ADC_EN, 0x01); /* 使能 ADC */ if (status 0x01) return ERR_ADC_EN; status LMP90100_WriteReg(REG_CH0_CONFIG, CH0_GAIN_128 | CH0_BUFFER_ON); if (status 0x01) return ERR_CH_CFG; /* 通道 0增益 128缓冲开 */ status LMP90100_WriteReg(REG_SAMPLE_RATE, SR_10SPS); if (status 0x01) return ERR_SR; /* 10 SPS低噪声场景 */ return OK; }逻辑说明复位后必须留出基准稳定时间常见做法是 10ms 起步要求高的场景给到 50ms。增益和采样率是业务强相关参数称重场景常用增益 128 配 10SPS因为称重传感器输出信号小、对噪声敏感。参数说明CH0_GAIN_128这类宏在lmp90100.h里定义改增益就是换宏SR_10SPS同理。返回值用位判断而不是等值判断是因为状态字节可能同时置多个标志位。3.3 主循环里怎么取一帧数据数据就绪有两种方式轮询 DRDY 引脚或者用中断。代码库示例一般用轮询简单直观/* main.c 片段主循环采样 */ int main(void) { int32_t adcValue; uint8_t ch; WDTCTL WDTPW | WDTHOLD; /* 关看门狗 */ Platform_Init(); /* 时钟、引脚、串口 */ SPI_MSP430_Init(); LMP90100_Init(); while (1) { for (ch 0; ch LMP90100_CH_NUM; ch) { LMP90100_SelectChannel(ch); LMP90100_StartConversion(); if (LMP90100_WaitDRDY(100) OK) { /* 超时 100ms */ adcValue LMP90100_ReadData24(); UART_SendInt32(adcValue); /* 串口上报 */ } } } }逻辑说明LMP90100_ReadData24()要连续读三个字节拼成 24 位有符号数注意符号扩展否则负电压读出来会变成很大的正数。WaitDRDY带超时是血泪经验没有超时的轮询在传感器断线时会死等整个采集卡住。参数说明100是超时毫秒数按采样率调整10SPS 时一帧 100ms超时给 200ms 更稳。4. 避坑与排查调试 LMP90100 时最容易翻车的五件事4.1 读出来全是 0 或 0xFF现象串口打印的 ADC 值恒定不变要么全 0 要么全 0xFF。原因通常是 SPI 模式不对或片选时序错误。先确认UCB0CTL0里UCCKPH是否置位模式 1再用逻辑分析仪看片选拉低到第一个时钟沿之间有没有足够建立时间。解决把 SPI 速率降一半试如果数据开始跳变说明原速率下时序余量不够。4.2 通道切换后第一帧数据是上一通道的现象切到通道 1 读出来的值跟通道 0 一样。原因LMP90100 切换通道后需要丢弃第一帧内部 PGA 和调制器还没稳定。解决SelectChannel之后先启动一次转换并丢弃结果再启动第二次取有效值。代码里加一行LMP90100_StartConversion(); LMP90100_WaitDRDY(200);丢弃即可。4.3 增益改了但读数没变化现象把增益从 1 改成 128读数几乎不变。原因增益寄存器写错了地址或者写完之后没有重新触发转换。LMP90100 的增益配置在通道配置寄存器里写完后必须重新 start conversion 才生效。解决确认REG_CH0_CONFIG地址正确写完后加一次转换启动。4.4 24 位数据符号扩展错误现象接负电压信号时读数异常大。原因三个字节拼成 24 位后没有做符号扩展直接赋给 int32_t 导致高 8 位为 0。解决判断 bit23为 1 时高 8 位补 0xFFint32_t raw ((int32_t)buf[0] 16) | ((int32_t)buf[1] 8) | buf[2]; if (raw 0x800000) { raw | 0xFF000000; /* 符号扩展 */ }4.5 串口打印正常但数据跳变严重现象读数在几十个 LSB 范围内乱跳。原因模拟地和数字地没处理好或者采样率配太高。LMP90100 在 10SPS 下噪声最低配到 1000SPS 以上跳变会明显增大。解决先降采样率验证如果跳变减小说明是速率问题如果还跳查 PCB 上 ADC 的 REF 引脚滤波电容和模拟地走线。5. 二次开发把示例代码改成自己的采集固件5.1 参数配置集中化示例代码里增益、采样率散落在main.c和lmp90100.c里二次开发第一步是把它们收进app_config.h/* app_config.h 片段业务参数集中管理 */ #define APP_SAMPLE_RATE SR_10SPS #define APP_CH0_GAIN CH0_GAIN_128 #define APP_CH1_GAIN CH1_GAIN_64 #define APP_CH_NUM 2 #define APP_DRDY_TIMEOUT_MS 200这样换项目只改一个文件驱动层不动。我一般还会在app_config.h里加一个APP_DEBUG_UART开关调试时打开串口打印量产时关掉省功耗。5.2 把轮询改成中断驱动轮询在单通道低速场景够用多通道高速采集时 CPU 空转浪费。改造思路是把 DRDY 引脚配成下降沿中断中断里置标志位主循环只处理数据/* 中断方式改造片段 */ #pragma vectorPORT1_VECTOR __interrupt void Port1_ISR(void) { if (P1IFG LMP90100_DRDY_PIN) { P1IFG ~LMP90100_DRDY_PIN; /* 清中断标志 */ g_drdyFlag 1; /* 只置标志不做耗时操作 */ } }主循环里判断g_drdyFlag再读数据。注意中断里绝对不能调 SPI 读寄存器耗时太长会丢中断。这个改造我建议在验证完轮询版本之后再动先保证数据对再优化结构。5.3 验证方法用已知信号对一遍改完代码怎么确认没改坏最直接的办法是给 ADC 输入一个已知电压比如用基准分压出一个 1.25V看读数换算回来是不是 1.25V 附近。换算公式是电压 读数 × VREF / (增益 × 2^23)。如果偏差超过几个 LSB先查增益配置再查基准电压实际值。我习惯在main.c里留一个APP_SELFTEST宏打开后循环打印原始码值和换算电压量产前关掉。5.4 一个具体技巧寄存器回读校验LMP90100 写寄存器后回读一遍确认写入生效这个习惯能挡掉一半的配置类 buguint8_t cfg; LMP90100_WriteReg(REG_CH0_CONFIG, CH0_GAIN_128 | CH0_BUFFER_ON); LMP90100_ReadReg(REG_CH0_CONFIG, cfg); if (cfg ! (CH0_GAIN_128 | CH0_BUFFER_ON)) { return ERR_CFG_VERIFY; /* 配置没写进去直接报错 */ }多花几行代码换来的是上电自检时就能发现配置失败而不是等到现场数据不对再回头查。从那以后我每次接新的 ADC 芯片初始化里都强制走一遍写后回读哪怕手册说不用。希望这份拆解能帮你把这块板子先跑通再改成自己项目里能用的采集固件。本文还有配套的精品资源点击获取