ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于51单片机蓝牙电子秤:从HX711信号链到手机APP

基于51单片机蓝牙电子秤:从HX711信号链到手机APP 简介基于51单片机的蓝牙电子秤设计资料面向电子类课程设计、毕业设计及单片机爱好者解决称重数据采集与手机无线监测的完整实现问题。资源共47个文件约12.95MB涵盖原理图PDF/JPG、Keil工程C/H源程序、APK手机APP、元件清单及说明文档等各类型文件覆盖从硬件设计、固件开发到手机端联调的完整链路。已有2514人学习下载适用于需要快速搭建蓝牙电子秤原型或参考完整设计流程的开发者。包内除核心源程序与原理图外还提供开题报告、文档资料、元件清单及实物图便于对照实物理解结构同时可通过APP源码与单片机程序进行二次功能扩展对入门和进阶均有较高参考价值。1. 基于51单片机蓝牙电子秤从资料包到可用的测量链路如果你拿到一套基于51单片机蓝牙电子秤设计资料里面通常有原理图、源程序、手机APP三样东西那我要先说一个和标题方向不完全一样的结论这套资料最大的学习价值不在蓝牙而在从应变片到HX711再到51单片机这条信号链。重力先变成微伏级电压HX711把电压变成24位数字量51单片机负责滤波、标定和串口输出HC-05再把这些字节透传到手机APP最后解析成“1234.5g”。这套链路适合课程设计、毕业设计也适合想看明白经典蓝牙SPP透传的嵌入式开发者。顺着原理图、源程序、手机APP这条主线下面把每个环节的参数、接线和排错方法过一遍。2. 测量链路与核心选型应变片、HX711与蓝牙透传原理2.1 应变片电桥的输出到底有多弱电阻应变式称重传感器的核心是贴有应变片的弹性体。受力后应变片被拉伸或压缩电阻变化率通常只有千分之几用万用表能测出来但直接送给51单片机肯定不行所以要接成惠斯通电桥把电阻变化转换成差分电压。常见的单点式称重传感器量程5kg灵敏度标称1mV/V到2mV/V意思是激励电压每升高1V满载输出增加1到2mV。给5V激励时满量程信号就是5~10mV。对51单片机来说这个量级相当尴尬。哪怕是外接8位或10位ADC以5V参考电压为例10位ADC每格约4.9mV5mV信号只占一格多根本分辨不出0.1g级别的变化。所以前级必须有一个低噪声放大器这就是HX711在电子秤里近乎标配的原因。很多新手尝试用电位器分压把传感器输出拉进ADC范围最后要么小重量测不出来要么读数跳得没法看本质都是没先算清这5mV的量级。2.2 HX711为什么是51单片机电子秤最常见的选择HX711是专为桥式传感器设计的24位ADC内部集成了可编程增益放大器。A通道增益可设64或128B通道增益32电子秤的常见接法是传感器信号进A通道、增益128。输出数据是24位二进制补码数据更新率10Hz或80Hz可调。两个特点决定了它适合51单片机一是接口只有DOUT和PD_SCK两根线普通GPIO就能模拟时序不需要SPI外设二是它的电源、传感器激励和信号地共用一路模拟电源信号链参考一致不容易因两地之间电位差产生读数漂移。HX711参数典型值对51项目的意义通道与增益A通道64/128B通道32常用A通道128倍匹配1mV/V级传感器数据更新率10Hz / 80Hz电子秤选10Hz软件滤波更从容输出格式24位二进制补码读回后需转成有符号数再计算数字接口DOUT、PD_SCK两根IO51任意IO口模拟时序即可更新率的选择是个容易忽略的细节。电子秤称重是慢变量10Hz输出下做8次均值平滑效果通常比80Hz采样后暴力平均更好51的代码负担也小。80Hz档位适合皮带秤这类要求快速响应的场合课程设计里基本用不到。这个选择会直接影响源程序里读函数和滤波函数怎么写。2.3 蓝牙串口透传模型与模块选型蓝牙这部分要理解一个模型HC-05/HC-06是SPP串口透传模块模块把UART收发和蓝牙协议栈完全封装手机连接成功后两端看到的都是透明字节流。51单片机不需要关心射频、配对和链路维护只需要按自己的波特率往串口发数据。代码层面发送一个字节就是标准的SBUF操作void uart_send_byte(unsigned char dat) { SBUF dat; while (!TI); TI 0; }逻辑说明SBUF是51串口发送缓冲寄存器写入一个字节后硬件开始移位输出TI置1表示这一帧发送完毕while循环等待TI是为了防止下一字节覆盖上一字节。参数说明波特率由定时器1的重装值决定HC-05出厂默认一般是960051端UART初始化也按9600配置两边不一致时手机端会收到乱码或干脆没数据。这个函数里看不到任何蓝牙相关寄存器这就是SPP透传的方便之处。选型上HC-06只做从机手机连接它完全够用HC-05支持主从切换适合以后想让模块主动连别的设备。BLE模块也能做但51端要额外控制模块状态、处理连接事件源程序复杂度会明显上一个台阶这套资料里如果用的是HC-05/HC-06建议先按SPP模式把链路跑通再考虑低功耗方向。3. 原理图与硬件接线从模块引脚到51单片机的关键连接3.1 原理图里必看的四个电路节点拿到一份“包含原理图”的资料不要先盯着51单片机最小系统看先找四个节点传感器插座、HX711电源与参考电压、HX711和51的IO连接、蓝牙模块的TXD/RXD。这四个点决定信号链能不能通。原理图上通常有网络标号比如E、E-、A、A-分别接传感器桥路的激励正负和信号正负对照实物传感器定义接线接反了读到的就是负数。HX711的VCC一般取5VAVDD是内部稳压输出用来给传感器供电Vref引脚多数情况下通过一个参考电阻接地这个电阻决定传感器激励电压。换不同量程传感器时不要乱动这个电阻先查传感器手册确认推荐激励电压。电源部分我的习惯是靠近HX711放100uF电解电容加0.1uF陶瓷电容3.3V LDO只给蓝牙模块供电不要让数字电源和模拟电源混在一起否则称重值会在小重量区间来回跳。3.2 引脚连接表与电平匹配下面这张表按STC89C52RC这一类51单片机给出典型连接实际资料包的原理图可能换过引脚通过网络标号比照即可模块引脚功能连接到51单片机说明HC-05 TXD蓝牙发送P3.0RXD3.3V高电平51可直接识别HC-05 RXD蓝牙接收经分压后接P3.1TXD51的5V TTL需降到3.3VHC-05 VCC电源3.3V或5V按模块规格务必与51共地HX711 SCK时钟输入P1.0空闲状态保持低电平HX711 DOUT数据输出P1.1转换完成时会被拉低HX711 VCC模拟电源5V靠近管脚放100uF0.1uF电容HX711 E/E-传感器激励电桥输入正负极极性接反会得到负向读数分压的常见做法是用一个1kΩ和一个2kΩ电阻1kΩ串在51的TXD到模块RXD之间2kΩ从模块RXD接到GND得到约3.3V。有的模块内部已经做电平转换资料包原理图上未必有分压网络但自己画板子时建议补上。排布上HX711的DOUT/SCK不要和HC-05的TXD/RXD并行走长线尽量各走各的区域避免数字翻转噪声耦合进模拟信号。注意51的P3.0接收端接HC-05 TXD不需要分压因为51识别高电平的门限足够低分压只针对51的P3.1输出到HC-05 RXD这一路。3.3 HC-05/HC-06 常用AT指令配置资料包里的蓝牙模块如果连不上九成是模块没有按源程序预期的名称、波特率或角色工作。配置HC-05前要先进入AT模式把模块的KEY/EN引脚拉高或者按住模块上的小按钮再上电。此时模块不转发数据而是接收AT指令。AT模式下波特率常见是38400与正常数据通信的9600不同如果串口助手返回乱码先试38400再试9600。AT指令作用参数说明AT测试通信返回OK表示已进入AT模式ATNAMEScale修改蓝牙名称手机扫描时显示的名字ATROLE0设为从模式手机主动连接模块不需要主模式ATUART9600,0,0设置通信波特率最后两位是停止位和校验位配置ATPSWD1234设置配对密码默认值常见1234或123456配置完成后重新上电模块回到数据模式观察状态灯等待连接和已连接两种状态下指示灯闪烁频率不同这个表现和模块版本有关连不上时直接看手机蓝牙列表里有没有设备名更可靠。遇到“hc05蓝牙模块连接不上”的问题排查顺序是模块是否在AT模式卡住、手机是否已经配对、51源程序里串口初始化波特率是否和ATUART一致、APP连的是不是模块的MAC地址。这四个点查完大部分连接失败都能解决。4. 51单片机源程序HX711时序、重量换算与串口发送4.1 HX711读取时序与C51实现HX711的时序是典型的“脉冲读位”方式。DOUT平时为高一次转换完成后拉低通知单片机取数单片机随后在PD_SCK上送出24个时钟脉冲每个脉冲高电平期间DOUT输出一位数据第25个脉冲用于把下一轮增益设回A通道128。C51工程里常见写法如下sbit HX711_SCK P1^0; sbit HX711_DOUT P1^1; long HX711_Read(void) { unsigned long val 0; unsigned char i; EA 0; // 读时序期间关闭中断防止抖动丢位 HX711_SCK 0; // 空闲保持低电平 while (HX711_DOUT); // 等待转换完成DOUT由高变低 for (i 0; i 24; i) { HX711_SCK 1; // 拉高时钟 val 1; // 读一位之前先移位腾出空间 HX711_SCK 0; if (HX711_DOUT) val; // DOUT为1时该位置1 } HX711_SCK 1; // 第25个脉冲保持A通道128倍增益 HX711_SCK 0; EA 1; if (val 0x800000) // 24位补码转成有符号数 val | 0xFF000000; return (long)val; }逻辑说明while等待DOUT变低这一步实际上也是硬件就绪判断如果传感器没接线或者HX711没供电DOUT一直为高程序会卡在这里这是排查硬件的第一个观察点。24个脉冲里每读一位前先左移一次保证后来读到的低位能落到位。第25个脉冲不读数据只是告诉HX711下一周期继续用A通道128倍增益这个脉冲漏掉会导致后续读数值异常偏小。参数说明EA0关中断是为了避免51的中断服务函数在脉冲高低电平之间插入延迟导致SCK高电平宽度不一致。24位补码转有符号是必须的因为传感器受拉或受压时差分方向不同直接当无符号数用空秤读数可能漂到几百万后面换算系数根本没法算。4.2 AD值到克数的换算与标定参数原始AD值没有任何物理意义。要让电子秤显示克数必须先标定空秤时记一个零点值zero_ad放一个已知重量的砝码M记录读数ad_full于是一克对应的AD数是 calib_ad (ad_full - zero_ad) / M。运行时重量就是 (ad_now - zero_ad) / calib_ad。注意这里的除法顺序calib_ad是“每克多少AD值”不是“每个AD多少克”搞反之后软件会自动“去皮”但换重量就全偏。实际代码里我推荐用长整型定点计算避免在51上频繁做浮点除法long zero_ad 0; long calib_ad 1000; // 每克的AD数标定后写入 long calc_weight_gram_x10(long ad) { long delta; if (ad zero_ad) return 0; delta ad - zero_ad; return (delta * 10L) / calib_ad; // 返回值单位是0.1g }逻辑说明delta是当前读数减零点乘以10是为了保留一位小数比如返回1234表示123.4g。用long而不是unsigned long是为了和HX711_Read返回的有符号数对齐防止ad比zero_ad小的时候产生巨大的无符号数值。参数说明10L中的L提醒Keil编译器按long类型运算否则delta乘10可能以int计算溢出calib_ad默认1000只是占位值实际标定后要替换。标定流程放到APP上更好用APP上按“去皮”发送TARE指令51收到后把当前ad赋给zero_ad再放标准砝码按“标定”发送CAL500051收到后计算 (ad - zero_ad) / 5000 填入calib_ad。这样不用每次烧录程序都改常量。STC89C52RC这类芯片内部有EEPROM区域可以把calib_ad存进去下次上电直接读回不需要电脑重新标定。4.3 串口发送格式与main循环组合C51串口初始化常用定时器1做波特率发生器11.0592MHz晶振下9600波特率对应TH10xFD。Keil工程里重定向putchar之后printf可以直接走串口输出。main循环的骨架如下void main(void) { long ad_now; long weight_x10; UART_Init(); zero_ad filter_ad(); // 上电自动去皮 while (1) { ad_now filter_ad(); if (key_tare_pressed()) // 检测去皮按键需要消抖 zero_ad ad_now; weight_x10 calc_weight_gram_x10(ad_now); printf(W:%ld.%ldg\r\n, weight_x10 / 10, weight_x10 % 10); delay_ms(200); // 控制刷新速率约5Hz } }逻辑说明上电先把当前AD值当作零点适合空秤开机如果开机时秤上已经放了东西这个操作会把实物误判成零所以APP上必须有“去皮”按钮来重置zero_ad。weight_x10是0.1g单位printf把整数部分和小数部分拆开输出避免浮点格式化带来的代码膨胀。参数说明延时200ms让数据刷新率约5Hz蓝牙串口缓存也不会被快速数据流挤爆。这里没有在循环里处理串口接收如果要支持APP发来的TARE和CAL指令需要在主循环里查询RI标志位读到一个完整字符串后做匹配。printf浮点版本的写法“W:%.1fg”更直观但Keil C51的printf对浮点支持需要额外配置库文件所以工程里用定点拆分更省事。5. 手机APP蓝牙连接、帧协议与重量显示5.1 Android经典蓝牙连接流程与权限手机APP这一部分第一个坑是权限。Android 6到11期间蓝牙扫描通常还需要定位权限到了Android 12SDK 31系统拆出了BLUETOOTH_SCAN和BLUETOOTH_CONNECT两个独立权限。资料包里如果是一个老APK在新手机上很可能不弹配对请求所以自己维护源码时建议在Manifest里同时声明旧权限和新权限运行时按API级别分别申请。经典蓝牙是Socket模型HC-05这类SPP模块固定使用一个“串口服务”UUID连接代码的核心部分如下UUID SPP_UUID UUID.fromString(00001101-0000-1000-8000-00805F9B34FB); BluetoothDevice dev mAdapter.getRemoteDevice(macAddress); if (dev.getBondState() ! BluetoothDevice.BOND_BONDED) { dev.createBond(); } mSocket dev.createRfcommSocketToServiceRecord(SPP_UUID); mSocket.connect(); mInput mSocket.getInputStream(); mOutput mSocket.getOutputStream();逻辑说明createRfcommSocketToServiceRecord会向模块发起RFCOMM信道连接connect是阻塞调用必须在后台线程里执行直接放UI线程会卡到ANR。createBond只负责发起配对系统会弹配对码对话框。参数说明macAddress是从蓝牙列表里选中的设备地址格式形如“XX:XX:XX:XX:XX:XX”不要写错成模块名称。连接成功后读出和写入要分别处理写入用mOutput.write把指令字节发出去读取要再开一个线程循环读mInput只要socket没断开就持续消费数据。很多APP只写了连接代码没写读取线程结果界面上“已连接”但重量永远不变。5.2 帧协议设计为什么别直接发“123.4g”51端如果直接发“123.4g”两个数据包粘在一起时手机端会收到“123.4g908.2g”这不是蓝牙丢包而是流式数据本身没有边界。串口和蓝牙SPP都是字节流不像UDP有报文边界解析端必须自己切分。资料包里的源程序如果直接printf数字APP端往往会越写越乱最后只能靠延时猜包。我给电子秤做通信协议时哪怕是最简单场景也会加帧头和帧尾51发送1234.5*表示一帧开始表示一帧结束。手机APP收到字符时读到清空缓存开始收集读到把缓存内容解析成float中间网络不管怎么切包只要一帧长度不超过缓冲区就不会错位。对电子秤这种短数据头尾分隔已经够用不必上完整的Modbus或自定义校验和协议如果以后要传多通道数据再考虑“帧头长度数据校验”的结构。这里有一个设计原则协议格式要由“谁显示谁定义”决定。既然是做手机APP帧格式最好先定好51源程序和APP一起改。常见反例是源程序先按“W:xxxxg”发了一年APP接入时又舍不得改51代码最后APP里做字符串正则匹配数据格式一乱就全盘崩。5.3 数据解析与UI刷新承接上面的协议Android读线程里可以维护一个StringBuilder逐字节判断帧头帧尾private void onByteReceived(byte b) { char c (char) b; if (c ) { frameBuffer.setLength(0); // 新帧开始清空旧内容 } else if (c *) { parseFrame(frameBuffer.toString()); } else { frameBuffer.append(c); } } private void parseFrame(String frame) { try { float gram Float.parseFloat(frame); runOnUiThread(() - { tvWeight.setText(String.format(Locale.US, %.1f g, gram)); }); } catch (NumberFormatException e) { // 帧内容不完整丢弃等下一帧 } }逻辑说明清空、解析、其余拼接这个状态机不需要缓存整包再分段处理速度跟得上HC-05的串口速率。Float.parseFloat在帧被切断时可能抛异常比如读到“123”就遇到这里try/catch直接丢弃等下一个重新开始。参数说明runOnUiThread保证UI更新在主线程读线程里直接setText会报CalledFromWrongThreadException。APP界面上除了重量显示至少要有去皮和标定两个入口。去皮按钮发送字符串TARE标定按钮发送CAL500051端主循环里收到后执行对应的zero_ad重置和calib_ad计算。这套流程不需要把单片机接到电脑现场拿砝码就能完成标定也算把资料包里三部分真正串在了一起。6. 标定与验证把蓝牙电子秤误差调到可用的小技巧6.1 技巧一两点标定法要选在常用称重区间两点标定公式不复杂真正的误差来自标定点选择。不要在空秤标定后只放一个1g砝码去算系数那样满量程误差可能超过5%。原因是传感器响应存在轻微非线性小信号区放大电路的失调误差占比又高。正确做法是用接近日常使用重量的砝码标定比如平时最多称500g就用500g或1kg标准砝码。如果称重范围很宽就做分段标定0~1kg一组系数1~5kg另一组系数软件里按当前AD值所在区间选系数能有效摊平非线性误差。6.2 技巧二漂移的排查顺序重量值长时间漂移或跳动先别改软件滤波。我的排查顺序是供电、接线、再软件。HX711供电要干净VCC旁放100uF电解电容加0.1uF陶瓷电容传感器信号线尽量短并绞合避开蓝牙模块天线和51晶振区域。软件层面在HX711的10Hz输出下做8次均值已经够用不需要写复杂的低通滤波。如果数值持续单方向增长大概率是传感器本身蠕变或环境温度在缓慢变化这时要查机械结构是否卡住而不是加滤波。6.3 技巧三用电脑蓝牙串口做数据验证手机APP调试时界面干扰多我一般先把HC-05配对到电脑配对后Windows会生成一个COM口再用Python或串口助手读数据这样能把“蓝牙问题”和“APP问题”分开定位import serial ser serial.Serial(COM9, 9600, timeout1) while True: line ser.readline().decode(utf-8, ignore).strip() if line.startswith(W:) and line.endswith(g): gram float(line[2:-1]) print(f{gram:.1f})逻辑说明readline按\r\n分行51端printf正好每帧一个回车换行所以这里能稳定解析出重量值。参数说明COM9改成电脑蓝牙分配的实际串口号波特率必须和ATUART配置一致。读出的数据如果喂给matplotlib记录几十秒能清楚区分“毛刺”和“漂移”毛刺是上下快速跳动要查屏蔽和滤波漂移是整体缓慢移动要查供电和零点。分清这两类现象调试方向就不会跑偏。本文还有配套的精品资源点击获取
返回列表