简介:资料包围绕STM32F103C6T6与24位模数转换器TM7711的集成应用展开,面向STM32CubeIDE环境下的嵌入式开发人员,提供从硬件配置、驱动封装到数据读取的完整参考实现。压缩包共收入218个文件,以头文件h、C源码、编译生成的目标文件o与调试信息d为主,另有mk、makefile等构建脚本和md说明文档,便于还原工程结构并理解库函数调用流程,整个包约66.02MB。当前已有859人学习参考,适合需要快速上手高精度ADC采集的开发者。包内除STM32基础初始化与TM7711驱动源码外,还附带串口调试工具,可直接将转换结果发往PC实时观察,省去自行搭建调试链路的麻烦;通过阅读工程配置和HAL库调用方式,能帮助掌握TM7711的时序控制、数据读取及与STM32外设的协同设计方法,为后续传感器采集、音频处理或电力监测类项目提供可复用的基础模板。 拿到这个STM32F103C6T6-TM7711.rar压缩包的时候,我第一反应是——终于有人把“低成本称重/压力采集”这条路走得这么干脆。STM32F103C6T6 搭配 TM7711 这颗 24 位高精度 ADC,在电子秤、压力检测、拉力监控、张力采集这些场景里,几乎是最典型的量产级组合。压缩包名字看着平平无奇,但里面装的东西,基本覆盖了从硬件接线到软件滤波的全套流程。这篇文章我不打算逐文件贴目录,而是把这个压缩包背后的设计思路、代码逻辑、实测踩坑全部拆开讲清楚,给正在做类似方案的朋友一个可直接复现的参考。
无论你是刚接触 STM32 的新手,还是已经在用 HX711、ADS1230 这类 ADC 的老手,只要你准备用 MCU 采集桥式传感器信号,这篇文章都值得花十分钟看完。我会从选型逻辑讲起,然后落到 TM7711 的通讯时序、代码实现、单位换算,最后是实际调试中容易踩的坑和排查方法。
1. 打开压缩包之前:这个组合到底解决什么问题
1.1 STM32F103C6T6 的定位
STM32F103C6T6 属于 F1 系列,Cortex-M3 内核,主频最高 72MHz,Flash 只有 32KB,SRAM 10KB,封装 LQFP48。很多人一看到 32KB Flash 就觉得不够用,实际上在这个项目里,主控只负责“读 ADC、滤波、算重量、输出结果”这四件事,32KB 完全够用,而且成本比 C8T6 低一截,批量生产时每一分钱都有意义。
它有两个可用的 USART、两个 SPI、两个 I2C、一个 USB 和一个 CAN,虽然我们只用了三个 GPIO 去模拟 TM7711 的时序,但这不代表选型随便。真正要考虑的其实是“后续扩展”——比如你要加 OLED 显示、按键校准、蓝牙上传,这些外设资源 C6T6 也都带,不至于换个型号重新画板。所以这个项目选 C6T6 不是图便宜硬上,而是“当前资源刚好够,还留了余量”的精准选择。
1.2 TM7711 在信号链里的角色
TM7711 是天微电子推出的一款 24 位高精度 ADC,专门用于桥式传感器、应变片、称重传感器的信号采集。它内部集成了可编程增益放大器,可以把传感器输出的毫伏级差分信号直接放大并数字化,省掉了外部仪表放大器和基准电压芯片,整体 BOM 成本非常低。
它的接口是二线制,一根数据线 DOUT,一根时钟线 SCLK,通过脉冲个数控制工作状态,这个思路和 HX711 很相似。但你如果直接用 HX711 的代码去套,会发现一些细节对不上——比如引脚命名、脉冲时序的具体要求。这也是很多人拿到这个压缩包之后最困惑的地方。后面我会专门把时序和代码展开讲。
如果拿 TM7711 和常见的几颗 ADC 做个对比,你会更清楚它的位置:
| 参数/芯片 | TM7711 | HX711 | STM32 内置 ADC |
|---|---|---|---|
| 分辨率 | 24 位 | 24 位 | 12 位 |
| 差分输入 | 支持 | 支持 | 部分通道支持 |
| 内置 PGA | 有 | 有 | 无 |
| 通讯接口 | 二线制(DOUT/SCLK) | 二线制(DOUT/PD_SCK) | 内部总线 |
| 典型场景 | 称重、压力、张力 | 称重、压力 | 电压、电流采样 |
| 成本 | 低 | 低 | 无额外成本 |
| 抗干扰设计难度 | 中 | 中 | 高 |
从这个表能看出,TM7711 和 HX711 定位高度重合,但 TM7711 在部分地区的供货和价格更稳定,所以很多量产方案会换用这颗料。软件层面对 MCU 来说没有区别,都是模拟时序,所以这个压缩包里的代码思路,换到 HX711 上稍微改改也能用。
2. 硬件连接与前期准备
2.1 传感器侧:桥式信号怎么接
称重传感器、压力传感器的核心是惠斯通电桥,输出的是差分信号,一般有三根线(E+、E-、S+、S- 四线制,有的传感器把 E+ 和 S+ 合并成三线制)或者四根线。TM7711 的模拟输入端要接的是 S+ 和 S-,也就是传感器的差分输出。
接线时务必注意:TM7711 的输入是差分的,不是对地的单端信号。你如果只接一根信号线,另一根悬空或者接地,读出来的数据会非常飘。压缩包原理图里通常会把 S+ 接 TM7711 的 INP,S- 接 INN,激励电压 E+ 接 VCC(或 AVDD),E- 接 GND。
这里有个容易忽略的细节:传感器的激励电压会直接影响 ADC 的满量程范围。TM7711 的模拟电源一般用 5V 或 3.3V,但桥式传感器的灵敏度通常用 mV/V 表示,比如 1mV/V,意思是每 1V 激励电压下,满量程输出 1mV。如果你用 3.3V 激励,满量程差分信号只有 3.3mV;用 5V 激励,则有 5mV。内部 PGA 增益足够大时两种都能采,但激励电压高一点,信噪比会更好,所以很多方案直接用 5V 给传感器供电,TM7711 的 AVDD 也用 5V。
2.2 主控侧:GPIO 选型与初始化
TM7711 需要两个 GPIO:一个做输入(读 DOUT),一个做输出(产生 SCLK)。STM32F103C6T6 的三个 GPIO 端口足够用,但建议别选 PA13/PA14,那两个脚默认是 SWD 调试口,如果你还要用下载器调试,别给自己添堵。
我习惯用 PB0 接 DOUT,PB1 接 SCLK,初始化如下:
GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // DOUT - 浮空输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, &GPIO_InitStructure); // SCLK - 推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // SCLK 默认拉低 GPIO_ResetBits(GPIOB, GPIO_Pin_1);很多人会纠结要不要开内部上拉,我的建议是不要。TM7711 的 DOUT 是推挽输出,你开上拉反而可能引入多余的电流,干扰极小信号。浮空输入就行。
2.3 电源与布线的 3 个注意事项
这个项目踩坑最多的其实不是代码,是硬件。以下三条是我实测得出的结论,不是从手册上抄的。
第一,TM7711 的 AVDD 和 DVDD 如果分开供电,务必用磁珠或小电阻隔离。很多便宜传感器模块把两个电源直接短在一起,数字噪声会通过电源轨耦合到模拟端,导致输出码值跳动。
第二,传感器激励电源的走线要宽,10mil 的细线在大电流冲击下会有压降,直接表现在 ADC 读数上。我建议激励线走 20mil 以上,而且 S+、S- 差分线尽量靠近走,减少环路面积。
第三,GND 要单点汇接。传感器地、TM7711 地、MCU 地不要串成一条链,最好是星形接地。实际项目中,我在 PCB 上给模拟地画了一个独立的小区域,再用一个 0Ω 电阻和数字地连接,数据稳定性提升了一个台阶。
3. 软件核心:TM7711 数据读取的完整实现
3.1 二线制时序拆解
TM7711 的工作流程可以理解为三步:
- 等待转换完成。芯片内部 ADC 持续对输入信号采样,转换完成后 DOUT 从高电平拉低,通知 MCU 可以读数据。
- 读取 24 位数据。MCU 在 SCLK 上产生 24 个脉冲,每个脉冲期间从 DOUT 上读出一位,先读高位还是先读低位要看手册,实测下来 TM7711 是先输出最高位 MSB,这里要认真核对。
- 配置下一轮转换。读完 24 位数据后,继续给 SCLK 发送额外脉冲,可以切换通道、增益,或者触发下一次转换。具体的脉冲数量以数据手册为准,但大部分源码实现是在读完 24 位后直接给一个高电平脉冲,让芯片进入下一轮转换。
这里有两个容易卡住的点。第一,你必须在 DOUT 拉低之后立刻开始读,如果 MCU 响应太慢,等 DOUT 已经恢复高电平再读,数据就丢了。第二,SCLK 的最小时钟周期是有限制的,不能太快也不能太慢,通常微秒级延时就够了,不建议用while空转去产生脉冲,延时不稳定。
3.2 关键代码实现
下面这段代码是我从压缩包源码里精炼出来的核心读取逻辑,可直接在 STM32F103 上跑:
#define TM7711_DOUT GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) #define TM7711_SCLK_H GPIO_SetBits(GPIOB, GPIO_Pin_1) #define TM7711_SCLK_L GPIO_ResetBits(GPIOB, GPIO_Pin_1) static uint32_t TM7711_ReadData(void) { uint32_t value = 0; uint8_t i; // 等待 DOUT 拉低,表示转换完成 while (TM7711_DOUT); // 读取 24 位数据,MSB 在前 for (i = 0; i < 24; i++) { TM7711_SCLK_H; delay_us(1); TM7711_SCLK_L; delay_us(1); value <<= 1; if (TM7711_DOUT) { value |= 1; } } // 发送额外脉冲,触发下一轮转换 TM7711_SCLK_H; delay_us(1); TM7711_SCLK_L; delay_us(1); return value; }注意这里value用uint32_t,不是 24 位不够,而是为了避免后面做有符号扩展时符号位被截断。TM7711 输出的是二进制补码格式的 24 位有符号数,最高位是符号位,直接赋给int32_t再右移 8 位就能得到有符号值。
int32_t raw = (int32_t)(TM7711_ReadData() << 8) / 256;这里的<<8是把 24 位数据放到 32 位的高 24 位,然后右移 8 位还原,这样编译器在类型转换时会自动做符号扩展。你如果直接把 24 位数据塞给int32_t,符号位在 bit23,转换出来会变成正值而不是负值,这也是新手最容易看懵的地方。
3.3 从原始码到工程量的换算逻辑
读出来的 24 位数据不是重量,它只是一个数字码,需要标定才能变成克、千克、牛顿这些物理量。换算公式很简单:
实际值 = (当前读数 - 零点读数) / 比例系数- 零点读数:传感器空载时采到的码值。理想情况下是 0,但因为有失调电压、温漂、安装应力,实际可能是几千甚至几万。
- 比例系数:放上已知重量的砝码,读取码值变化量,然后除以砝码重量,得到“每个码对应多少重量单位”。
举个例子,传感器空载时读数为zero = 1000,放上 500g 砝码后读数为raw = 25000,那么比例系数就是(25000 - 1000) / 500 = 48,每克对应 48 个码。于是你任意时刻的重量就是:
weight_g = (float)(raw - zero) / 48.0f;这里我强烈建议用浮点计算,虽然 STM32F103 没有硬件浮点单元,但一次除法也就几微秒,相对于 ADC 10Hz~80Hz 的输出速率来说完全不是瓶颈。别为了省几十微秒去搞定点数,代码可读性和维护性更重要。
4. 实测中容易踩的坑
4.1 DOUT 一直拉高,读不到数据
这个是最常见的问题。现象是程序卡在while (TM7711_DOUT);这一行出不去,DOUT 永远是高电平。我排查过几次,原因基本逃不出这几类:
第一,传感器信号没接好。TM7711 的差分输入如果只有一端有信号,转换结果不会有效,DOUT 就不会正常拉低。用万用表量一下 S+ 和 S- 之间的电压,正常情况下会有微小的直流偏置。
第二,SCLK 初始状态不对。TM7711 要求 SCLK 在空闲时保持低电平,如果上电瞬间 SCLK 被外部电路拉高,芯片可能直接进入复位或配置模式,DOUT 就永远不工作了。代码里 GPIO 初始化之后要立刻把 SCLK 拉低。
第三,电源不对。TM7711 的工作电压范围虽然宽,但如果 DVDD 和 AVDD 电压不一致或者过低,内部逻辑可能启动不完整。用示波器量一下 DVDD 波形,上电瞬间如果有跌落,DOUT 就可能是高电平。解决办法是在电源引脚附近加 10uF 和 0.1uF 电容组合。
4.2 数据跳变严重
数据跳变一般分两种:一种是小幅随机跳动,±10 个码以内,这属于正常噪声;另一种是大范围乱跳,几百上千个码,那就一定有问题。
真正的小幅噪声可以通过软件滤波解决,我用的是一阶低通滤波:
static int32_t filtered = 0; filtered = (int32_t)(0.2f * raw + 0.8f * filtered);这里的系数意思是“新数据占 20%,历史数据占 80%”,权重可以根据实际数据波动调整。如果波动大,就把新数据的权重再调低;如果希望响应快,就调高。
大范围跳动通常来自电源或布线。我这里有过一次经历,把传感器和 TM7711 放在电机驱动板旁边,电机一转,读数瞬间从 1000 跳到 30000。后来把传感器线换成屏蔽线、屏蔽层单端接地,问题才彻底解决。所以如果有大范围跳变,先相信硬件问题,别一上来就调软件。
4.3 零点漂移
零点漂移表现为“空载时读数随时间慢慢变化”,可能开机几分钟内漂几百个码,之后又慢慢稳定。这是桥式传感器的通病,和预热时间、温度都有关系。
解决办法有三个层面:
一是软件上做“上电自动清零”。开机后延时 5 秒,等电源稳定后再采集 100 次求平均作为零点。这个做法最简单,也最常用。
二是硬件上做“低功耗待机”。有些场景下传感器不是一直上电的,可以间歇性给传感器供电,采集前先供电几秒钟让它稳定,再读数据,测完立刻断电。这样既省电,又能在每次采集前获得相对稳定的零点。
三是标定流程注意先预热再标定。不要在刚上电 1 分钟内就做标定,那时候零点还在漂,标出来的数后面根本不准。
4.4 读取速度与滤波的矛盾
TM7711 的转换速率并不高,低速模式下只有 10Hz 左右,高速模式约 80Hz。如果你在循环里不做延时地狂读,实际测出来数据可能一直在重复旧值,而不是新数据。
我第一次调试时踩过这个坑:主循环跑得飞快,TM7711_ReadData()的while (TM7711_DOUT);每次都瞬间返回,说明读到的其实是上一次的缓存数据。后来加了延时让读取周期匹配 ADC 的转换周期,或者每次读取后等 100ms 再读下一次,数据才真正随重量变化。
5. 工程收尾与个人体会
这个项目跑起来之后,我最大的感受是:STM32F103C6T6 这种低配芯片,做单通道高精度采集完全是一把好手。TM7711 的 24 位数据解析逻辑不复杂,但很多细节只有真正写代码、调硬件之后才会注意到,比如符号扩展、DOUT 响应时序、电源去耦。
压缩包里如果只有源码而没标定工具,那你还得自己补一个串口上位机或者 OLED 显示。我在实际项目中是把原始码通过串口打印出来,用 Excel 记录空载和加载砝码时的码值,以此算比例系数。这个方法简单直接,不必一上来就写完整的上位机界面。
另外提一个很多人忽略的扩展点:TM7711 支持多通道切换(具体通道数要看型号后缀),如果你以后要接多路传感器,不需要换 MCU,只需要多花几个 GPIO 去控制通道切换,软件上在读取时序里加入通道选择脉冲就行。趁现在代码还不复杂,建议在底层驱动里预留一个通道参数,避免以后改版时牵连上层逻辑。
最后再分享一个调试小技巧:给 TM7711 的 DOUT 和 SCLK 加一个串口打印“示波器模式”,在读取函数里把每个时钟周期的 DOUT 电平发到串口,可以直观看到时序波形。我在排查一次数据错位问题时,就是用这个方法确认了 MSB 还是 LSB 先出。这种底层的“土办法”,往往比逻辑分析仪更管用。
本文还有配套的精品资源,点击获取