云计算百科
云计算领域专业知识百科平台

STC8G1K08A+HX711高精度体重秤设计与实现

1. 项目背景与硬件选型

大家好,今天我想分享一个自己动手做高精度体重秤的项目。这个项目用的是STC8G1K08A单片机和HX711模数转换芯片,再加上TM1637驱动数码管显示,整体成本不高,但精度相当不错,适合家用或者一些小型的健康监测场景。

先说说为什么选STC8G1K08A这款单片机。STC8系列是深圳英科微电子出的高性能8位单片机,基于经典的8051架构,但运行频率能到30MHz,比传统的51单片机快不少。我选它的主要原因有几个:一是功耗低,适合电池供电的设备,比如体重秤这种需要长时间待机的东西;二是外设丰富,有足够的IO口和定时器,还能支持SPI、I2C这些通信协议,方便扩展;三是开发工具成熟,用Keil或者STC官方提供的ISP工具就能轻松写程序调试,对新手挺友好的。

HX711是专门用于称重传感器的高精度ADC芯片,24位的分辨率,能读到非常细微的重量变化。市面上很多电子秤都在用这个芯片,性价比高,而且资料多,容易上手。TM1637是数码管驱动芯片,能直接驱动4位数码管,显示体重数值,不需要单片机再去管数码管的段选和位选,节省IO口,程序也简单。

硬件连接上,HX711和TM1637都是通过简单的串行通信和单片机交互,接线不复杂,但有些细节要注意,比如电源要稳定,地线要共地,不然读数会跳。后面我会详细说怎么布线。

2. 电路设计与连接

电路设计这块,我画了一个简单的示意图,核心就是STC8G1K08A单片机作为主控,HX711接称重传感器,TM1637接数码管。称重传感器一般是4根线:E+、E-接激励电压,A+、A-接信号输出。HX711的VCC和GND接5V电源,DOUT和SCK分别接单片机的两个IO口,我用的是P3.2和P3.3,你也可以用其他口,但程序里要对应改一下。

TM1637的接线更简单,CLK和DIO接单片机的任意两个IO口,VCC和GND接电源。数码管我用的是共阳极的,因为TM1637驱动共阳数码管更常见,程序里预定义的段码表也是按共阳设计的。如果你手头是共阴的,段码表要反过来,或者硬件上加反向电路。

电源部分,我建议用线性稳压芯片比如AMS1117-5.0,把输入电压稳到5V,因为HX711和单片机都对电压波动敏感,电压不稳会导致读数漂移。如果是用电池供电,可以加一个低压差稳压器,延长电池寿命。

在实际焊接的时候,有几点容易出错:一是HX711的DOUT和SCK线不要接反,接反了读不到数据;二是称重传感器的线序,E+、E-和A+、A-如果接反了,读数会是负的或者不变化。我第一次做的时候就因为线接错了,调试了半天,最后用万用表量了一遍才发现问题。

地线的处理也很重要,单片机的GND、HX711的GND、TM1637的GND和传感器的GND一定要接在一起,最好用星型连接,减少干扰。如果布线长了,可以加个0.1uF的电容滤波,效果会好很多。

3. 程序框架与初始化

程序的大框架比较简单,主循环里不断读HX711的数据,处理一下,然后显示到数码管上。初始化部分要先设置好IO口模式,TM1637的显示初始化,还有HX711的启动时序。

STC8G1K08A的IO口可以配置成准双向、推挽、开漏等模式,我一般用在准双向模式,驱动能力足够,而且省电。TM1637的初始化就是发送一些命令字,设置显示模式和亮度,这部分有现成的库函数,直接调用就行。

HX711的初始化稍微复杂点,一上电要先等待DOUT变低,表示芯片准备好了,然后发时钟脉冲启动转换。如果DOUT一直高电平,可能是接线问题或者芯片坏了。我遇到过因为电源电压不够,HX711不工作的情况,后来换了个稳压芯片就好了。

主程序里,我用了个简单的状态机,平时在低功耗模式,有重量变化时才唤醒显示,这样省电。STC8G1K08A支持多种低功耗模式,比如空闲模式和掉电模式,通过定时器中断或者外部中断唤醒,适合电池供电的场景。

#include "STC8G.H"
#include "hx711.h"
#include "tm1637.h"

void main() {
IO_Init(); // IO口初始化
TM1637_Init(); // 数码管初始化
HX711_Init(); // HX711初始化

while(1) {
long weight = Read_HX711(); // 读HX711数据
weight = Process_Weight(weight); // 数据处理
Display_Weight(weight); // 显示重量
Delay_ms(500); // 延时一下,避免刷新太快
}
}

4. HX711数据读取详解

HX711的数据读取是靠串行通信实现的,DOUT输出数据,SCK发时钟脉冲。当DOUT从高变低后,就可以开始发脉冲了,发24个脉冲,每个脉冲的上升沿读取一位数据,从最高位到最低位。

这里有个细节:第25到27个脉冲是用来选择下次转换的通道和增益的,比如通道A增益128,或者通道B增益64。我的项目里只用通道A,增益128,适合称重传感器。

读数据的代码要注意时序,延时要准确。STC8G1K08A的频率高,我用的是1微秒的延时,实测下来很稳。如果延时太长或太短,可能会读错数据。

unsigned long Read_HX711(void) {
unsigned long count = 0;
unsigned char i;

HX711_CLK = 0; // 先拉低SCK
while(HX711_DATA); // 等待DOUT变低

for (i = 0; i < 24; i++) {
Delay_us(1);
HX711_CLK = 1; // 上升沿准备读数
Delay_us(1);
count = count << 1; // 左移一位
if (HX711_DATA)
count++;
HX711_CLK = 0; // 拉低SCK
}

// 发第25个脉冲,设置下次增益
HX711_CLK = 1;
Delay_us(1);
HX711_CLK = 0;

return count;
}

读出来的数据是24位二进制补码,有可能是负数,比如空载的时候可能是0xFF8E这样的值。这时候要处理一下,转换成有符号数。我一开始直接用unsigned long,发现重量变化不对,后来改成了 signed long,就好了。

5. 数据处理与校准算法

raw数据读出来之后,不能直接当重量用,要先校准。校准一般分两步:去皮和标定。去皮就是先把空载时的读数记下来,以后每次读数减去这个值。标定是用已知重量的砝码,比如1kg,读出来对应的AD值,然后算斜率。

我的做法是:先读空载时的值,记作offset;然后放个标准重量,比如1kg,读AD值,记作cal_value。斜率k就是标准重量除以(cal_value – offset)。实际重量 = (AD值 – offset) * k。

这里有个坑:STC8G是16位单片机,int是16位的,但AD值是24位的,所以变量要用long,不然会溢出。我一开始用int,重量大到一定程度就循环了,后来改long就好了。

long Get_Weight() {
long ad_value = Read_HX711();
long weight = (ad_value – offset) * scale_factor;
return weight;
}

为了减少跳动,我加了软件滤波,比如取10次读数平均,或者用中值滤波。实测下来,平均滤波效果不错,而且计算简单。如果要求更高,可以用卡尔曼滤波,但单片机资源有限,可能跑不动。

显示部分,我设了个阈值,重量小于100克时不显示,避免误触发。还有,只有当重量变化超过0.5kg时才更新显示,这样看起来稳定些。

6. TM1637数码管显示驱动

TM1637驱动数码管挺简单的,主要是发命令和数据。命令包括设置显示模式、地址、亮度等。数据是按字节发送,每个字节对应数码管的一段。

TM1637的数据传输是串行的,时钟线CLK下降沿的时候数据变化,上升沿的时候采样。每个字节传完后,TM1637会回一个ACK信号,但实际用的时候,我们可以不检查ACK,因为硬件没问题的话一般都能成功。

我写了个显示函数,可以显示4位数,还能控制中间的小数点。比如显示"12.34",就是第一第二位数显示数字,第三位显示带小数点的3,第四位显示4。

void TM1637_DisplayNumber(int number) {
unsigned char digits[4];
digits[0] = number / 1000; // 千位
digits[1] = (number / 100) % 10; // 百位
digits[2] = (number / 10) % 10; // 十位
digits[3] = number % 10; // 个位

TM1637_Start();
TM1637_Write(0x40); // 写数据模式
TM1637_Stop();

TM1637_Start();
TM1637_Write(0xC0); // 设置地址从0开始
for (int i = 0; i < 4; i++) {
TM1637_Write(DigitToSegment(digits[i])); // 转换数字到段码
}
TM1637_Stop();

TM1637_Start();
TM1637_Write(0x8F); // 开显示,设置亮度
TM1637_Stop();
}

段码表要根据数码管的类型来定义,共阳和共阴的是反的。我用的共阳数码管,0显示是0xC0,1显示是0xF9,等等。如果数码管显示乱码,多半是段码表不对。

7. 实际调试与问题解决

调试的时候,我遇到了几个坑。第一个是接线问题:HX711的DOUT和SCK接反了,读出来的数据全是0。后来用示波器看了一下波形,才发现问题。所以如果读不到数据,先检查接线,再用示波器看SCK和DOUT的波形对不对。

第二个问题是数据溢出:因为AD值是24位的,但单片机是16位的,处理的时候要用long类型。我一开始没注意,重量显示到一定程度就回零了,后来把变量都改成long就好了。

第三个问题是负数处理:HX711输出的是二进制补码,空载的时候可能是负数。我一开始直接用unsigned long,负数变成了很大的正数,处理错了。后来加了判断,如果最高位是1,就是负数,要转换一下。

long ConvertToSigned(long value) {
if (value & 0x800000) {
value = ~value + 1; // 取补码
value = -value;
}
return value;
}

第四个问题是电源噪声:如果电源不稳,读数会跳。我加了滤波电容,效果好了很多。称重传感器本身也有温漂,长时间使用后可能会有偏差,定期校准一下就好。

最后,分享一个小技巧:如果读数老是跳,可以试试软件滤波,比如移动平均或者中值滤波。我用了10次平均,效果不错,跳动明显小了。

8. 优化与扩展建议

这个体重秤基本功能已经实现了,但还有很多可以优化的地方。比如功耗,STC8G1K08A支持休眠模式,可以在没有重量变化的时候进入休眠,有变化时通过中断唤醒,这样更省电。我实测下来,电池供电可以用好几个月。

显示部分,可以增加背光,或者用OLED屏显示更多信息,比如历史记录、趋势图等。但OLED耗电大,适合插电的设备。

如果需要联网,可以加个蓝牙模块,把数据传到手机APP上。STC8G1K08A有UART口,接个HC-05之类的模块就能实现。不过代码会复杂些,要考虑数据传输和协议。

精度方面,可以尝试更高的采样率或者更复杂的滤波算法。但STC8G1K08A资源有限,如果不够用,可以考虑换STC32位单片机,或者ESP32这类带无线功能的芯片。

结构上,秤盘要平整,传感器要安装牢固,不然会影响精度。我用的铝合金材料,比较轻便,而且不容易变形。

最后,如果大家想自己做,建议先从小负载开始试,比如5kg以内,调试好了再慢慢加大范围。

赞(0)
未经允许不得转载:网硕互联帮助中心 » STC8G1K08A+HX711高精度体重秤设计与实现
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!