简介:一份基于电阻应变式传感器的电子秤课程设计文档,面向电子、测控类专业学生及传感器应用开发者。方案围绕2kg手提电子秤展开,完整覆盖电阻应变式传感器工作原理、惠斯通电桥测量电路、LM358差动放大电路、A/D转换与LED显示电路,并给出Tedea-Huntleigh 2kg拉式称重传感器等具体选型及放大倍数推导,可用于课程设计、答辩准备或入门实践参考。资源共1个doc文件,压缩包约91KB,文档内含系统框图、单元电路设计、参数计算与工作原理说明,结构完整、便于直接研读。目前已有261人学习下载,内容详实,能帮助读者快速掌握电阻应变式传感器的工程应用与电子秤设计全流程。
1. 电子秤方案选型:为什么说电阻应变式传感器是性价比之王
网上几十块钱的厨房秤,拆开外壳,核心部件就是一颗铝合金悬臂梁传感器、一片或四片电阻应变片,再加上一颗24位ADC芯片和一颗单片机。基于电阻应变式传感器电子秤设计,听起来像一门传感器课程的作业题,但实际上它是当前从家用厨房秤到工业料斗秤都绕不开的技术底座。做一台电子秤最难的从来不是把重量读出来,而是让读数在温度变化、机械振动、长时间加载的情况下依然稳得住。
这篇文章会从应变片为什么能称重讲起,逐步拆解传感器选型、信号采集、标定算法和常见坑。如果你正准备做一款称重模块、智能家居里的嵌入式秤,或者正在做传感器课程设计,按着这篇文章的顺序走,能少走很多弯路。适合有一定单片机基础、但第一次接触桥式传感器信号链的开发者阅读。
2. 电阻应变式传感器的工作原理与选型参数:从应变片到惠斯通电桥
2.1 应变片为什么能称重:电阻变化率和电桥电路
电阻应变片的核心是一层金属箔栅,它被粘贴在弹性体表面。弹性体受力变形时,箔栅跟着一起拉长或压缩,金属导体的电阻值随之变化。这个变化量虽然极小,但存在一个稳定的比例关系:相对电阻变化率约等于灵敏系数乘以应变,金属箔应变片的灵敏系数常见为2左右。
单个应变片的电阻变化量太小了,直接测量不现实。实际情况中,电子秤传感器内部会用四个应变片构成惠斯通电桥。四个电阻两两配对,受力时其中两个被拉伸电阻变大,另外两个被压缩电阻变小,电桥的输出电压变化量就能被放大处理。这个接法还顺带解决了温度问题:温度漂移对四个桥臂的影响相同,互相抵消。
值得注意的是,电桥输出差分信号,而且满量程输出非常小。一颗灵敏度为2mV/V的传感器,用5V激励电压时,满量程输出只有10mV。这个数量级决定了后端信号链路的底噪和放大倍数必须经过仔细设计,否则重量还没称出来,噪声先把信号淹没了。
2.2 电子秤传感器选型的5个关键参数
到淘宝或元器件商城搜“电阻应变式称重传感器”,会看到长条形的铝制平行梁传感器,量程从几百克到几十公斤都有。选型不是只看量程,下面这五个参数必须逐一核对,少一个后面都会出问题。
| 参数 | 说明 | 常见值 | 选型要点 |
|---|---|---|---|
| 量程 | 传感器能承受的最大称重质量 | 3kg / 5kg / 10kg / 30kg | 日常使用量程别超过满量程的70%,留出过载余量 |
| 灵敏度 | 满量程时单位激励电压对应的输出 | 1.0~2.0mV/V | 灵敏度越高,后端ADC的增益压力越小 |
| 综合误差 | 非线性、迟滞等误差的综合指标 | 0.02%~0.05%FS | 做0.1g精度的秤,传感器综合误差要小于目标精度 |
| 输入/输出阻抗 | 桥路阻抗,影响驱动能力 | 350Ω / 1000Ω | 350Ω是行业主流,多数ADC芯片按这个设计 |
| 蠕变 | 恒载下输出随时间的变化 | 0.02%FS/30min | 称重后读数缓慢变化,多半是蠕变而非ADC问题 |
我一般会把传感器的综合误差当成硬约束。想要秤显示精度做到±0.5g,量程3kg的情况下就是约0.017%FS,这已经超出很多国产普通传感器的能力,此时要选综合误差不低于0.02%的型号,而不是指望标定算法去弥补。标定能修正的是系统误差,传感器本身非线性造成的误差,算法修不干净。
2.3 拿到传感器怎么快速判断好坏:万用表三分钟测试
新买的传感器上电之前,先用万用表做一次电阻测试,能排除大部分“翻车”风险。传感器引出线通常有四根:激励正(红线)、激励负(黑线)、信号正(绿线)、信号负(白线)。桥路总阻抗标称350Ω,测量激励两端和信号两端应该都在350Ω附近;测量激励正与信号正之间,则是两个桥臂电阻串联,约175Ω。
顺带验证一下传感器是否真的在工作:给激励端加上稳定的5V直流电,然后用万用表的毫伏档测信号输出端。空载时输出电压应该在0mV附近,正常情况不超过±0.1mV;用手施加压力(注意不要超过量程),输出应该随之变化。如果输出纹丝不动,大概率内部应变片已经断裂或者桥路某处开路。这一步花三分钟,能避免把坏传感器焊到主板上之后还要花半小时排查信号链路。
注意:电桥输出是差分信号,万用表测量时表笔要分别接信号正和信号负,不要以地为参考。
3. 信号调理与ADC采集:把微伏级信号变成稳定数字量的电路设计
3.1 信号链方案:仪表放大器加ADC,还是集成24位ADC
电桥输出的满量程信号只有10mV左右,直接接单片机内置的12位ADC,哪怕是满量程也被切成最多4096份,每份2.4mV,实测一个重量档位都分辨不出来。放大和高分辨率采样是必须的,目前工程上有两条成熟路线。
第一条路线是仪表放大器加独立ADC,比如AD620加16位ADC,优点是增益精度和噪声指标可调,适合工业仪表这类对采样率和分辨率要求更极致的场合;缺点是外围器件多,布局稍不注意电源噪声就串进模拟链路。第二条路线是使用集成可编程增益放大器的24位ADC芯片,芯片内部集成了128倍增益和差分输入,外部只需要几个去耦电容。这类芯片通吃小量程电子秤,做3kg~30kg的传感器绰绰有余,而且软件配置简单,非常适合单片机系统集成。
对于绝大多数电子秤设计,我推荐第二条路线。24位ADC配合128倍增益,理论上能分辨微伏级信号,已经远超传感器本身的分辨能力。这背后有一个工程逻辑:ADC的分辨率应该高于传感器的固有噪声,这样系统性能的天花板由传感器决定,而不是被采样链路拉低。画原理图时,ADC的电源引脚要加10μF电解电容和0.1μF陶瓷电容并联去耦,模拟电源和数字电源在进入芯片之前单点汇合。
3.2 典型接线与电源注意事项:四线传感器怎么接
传感器输出的四根线,以及ADC芯片的连接方式,是有标准接法的。常见做法是红线和黑线分别接ADC的激励正和激励负,绿线和白线接差分输入的A+和A-。传感器的屏蔽线不能悬空,要单端接到系统的模拟地,否则高阻抗的屏蔽层会变成天线,把环境噪声耦合进信号线。
电源设计对电子秤的影响经常被低估。ADC的参考电压直接来源于供电,如果供电有纹波,等于给信号叠加了一个几十Hz到几百Hz的干扰源。开关电源供电的场合,建议在ADC供电前端加一颗低噪声LDO,输出端并上10μF和0.1μF电容组合。传感器激励端的走线要尽量短,远离继电器、电机驱动等大电流开关回路。
还有一个常被忽视的细节:传感器和ADC之间的信号线用双绞线,并且长度越短越好。信号线如果和电源线并行走线超过10厘米,开关电源的纹波就会通过寄生电容串进差分信号。差分输入共模抑制能力强,但那是针对平衡信号而言的,一旦两根线受到的干扰强度不一致,共模干扰就会变成差模干扰,后端怎么滤波都滤不掉。
3.3 数据读取与滤波的平衡:平均次数与采样率怎么配
24位ADC芯片通常提供可选的输出速率,比如10SPS或80SPS。电子秤属于静态称重场景,不追求高速率,10SPS是更合理的选择,因为输出速率越低,内部数字滤波器对带外噪声的抑制越强。如果软件里再做多次平均,最终呈现给用户的稳定速度依然可以达到每秒2到3次更新,完全满足人眼读数习惯。
读取ADC时要特别注意:芯片输出的是24位有符号数,需要用32位有符号变量来承接,否则右移扩展符号位时会出现数据错乱。下面这段典型的读取代码,可以作为模板直接抄进项目。
// 假设 PD_SCK 接 P1.0,DOUT 接 P1.1 // 返回值为去除符号扩展后的实际差分读数 long hx711_read(void) { long value = 0; unsigned char i; // 等待DOUT拉低,表示转换完成 while (HX711_DOUT); for (i = 0; i < 24; i++) { HX711_SCK = 1; // 产生时钟脉冲,逐位读出 value = value << 1; // 先移位再读位 HX711_SCK = 0; if (HX711_DOUT) value++; } // 第25个脉冲:决定增益并恢复为普通模式 HX711_SCK = 1; HX711_SCK = 0; // 24位数据读出时为二进制补码,第24位是符号位 // 若符号位为1,需要扩展为32位负数 if (value & 0x800000) { value |= ~0xFFFFFF; // 把高8位置1,形成正确的负数 } return value; }读取逻辑本身不复杂,重点在最后一步的符号扩展。有符号数的最高位是1时代表负值,直接把24位左移8位再右移8位也能达到同样的效果。代码里把DOUT下降沿等待放在函数开头,这样每次调用都会同步到芯片的转换完成时刻,不会读到上一组的旧数据。
平均次数是另一个需要调的参数。10SPS下,单次读数的峰峰值噪声通常在几个到十几个LSB之间,做5到20次平均可以显著压低随机噪声。但平均次数不能无限增加,因为每多一次平均都会增加响应时间。我的经验值是10SPS速率下取8到16次平均,对应0.8到1.6秒的稳定时间。大于16次平均如果读数还是跳,问题大概率在电源或接地,而不是滤波不够。
// 简易滑动平均:buf保存最近N次读数,每次输出平均值 #define AVG_N 8 long avg_filter(long new_sample) { static long buf[AVG_N] = {0}; static unsigned char idx = 0; long sum = 0; unsigned char i; buf[idx] = new_sample; // 覆盖最旧的数据 idx = (idx + 1) % AVG_N; // 环形缓冲 for (i = 0; i < AVG_N; i++) sum += buf[i]; return sum / AVG_N; // 返回平均结果 }滑动平均和每次都重新累加的普通平均效果一样,区别在于滑动平均每次只需更新一个数据点,计算量稳定。ARM内核的单片机上,这段代码几乎没有可感知的开销。实际调试的时候,可以先跑一个测试程序,把原始读数和滤波后的读数通过串口打印出来对比,这样滤波参数的调整有数据支撑,而不是靠感觉。
4. 称重标定与数据处理:从原始读数到稳定克数的完整流程
4.1 两点标定法:先把零点做稳,再算斜率
拿到ADC原始读数之后,它只是一个与重量成线性关系的整数,还没有量纲。标定的目标就是确定两个关键参数:零点和斜率。空载时采集的原始值记为zero,放上标准砝码后的原始值与零件之差,除以砝码质量,就是每个ADC数对应的克数,也就是斜率scale。
// 标定参数结构体,保存到EEPROM typedef struct { long zero; // 空载时滤波后的ADC值 float scale; // 每个ADC读数对应的克数,单位 g/LSB long tare; // 当前皮重对应的ADC值 } cal_param_t; // 标定流程伪代码:串口命令触发 // "Z" 记录零点, "C1000" 表示放上1000g砝码并计算斜率 void calibrate_proc(char cmd) { if (cmd == 'Z') { g_cal.zero = avg_filter(hx711_read()); g_cal.tare = g_cal.zero; // 标定零点后皮重清零 printf("zero ok\r\n"); } else if (cmd == 'C') { // 假设当前砝码质量为1000g long raw_full = avg_filter(hx711_read()); g_cal.scale = (float)(raw_full - g_cal.zero) / 1000.0f; printf("scale=%f\r\n", g_cal.scale); } }标定时两个细节决定成败。第一,零点的采集必须在传感器完全不受力且机械结构稳定后进行,任何螺丝未拧紧导致的残余应力都会让零点慢慢漂移;第二,标准砝码要放在秤盘的中心位置,偏载会让弹性体产生额外的弯曲应力,测出来的斜率和实际使用场景不一致。放砝码之后要等待读数稳定再按下确认键,一般等3到5秒。
4.2 为什么不能只用简单平均:限幅加滑动平均的组合拳
前文提到的滑动平均能压制随机噪声,但对付不了突发干扰。比如秤体被不小心碰了一下,或者附近有电机启停产生的电磁脉冲,这类尖峰噪声如果不做处理,即使后面平均了也会把一个明显错误的数混进去。更合理的做法是先用限幅滤波判断数据是否可信,再做滑动平均。
理想的处理流程是:读取原始ADC值,与上一次的有效值比较,如果差值超过预设阈值就丢弃这次数据;如果差值在阈值范围内,才把它送入滑动平均滤波器。这个阈值需要根据实际噪声水平设定。用串口观察一段时间原始数据,统计相邻两次读数的最大跳变量,阈值设置成这个值的2到3倍即可。对于10SPS下的3kg传感器,阈值通常取几十个LSB。
// 限幅+平均组合滤波:valid为上一轮有效值 #define LIMIT_TH 30 // 相邻两次允许的最大跳变 #define FILTER_N 8 // 平均窗口 long filter_with_limit(long new_raw) { static long last_valid = 0; static long buf[FILTER_N] = {0}; static unsigned char idx = 0; long sum = 0; unsigned char i; // 超出阈值,判定为干扰,直接弃用 if (last_valid != 0 && (new_raw > last_valid + LIMIT_TH || new_raw < last_valid - LIMIT_TH)) { return last_valid; } last_valid = new_raw; buf[idx] = new_raw; idx = (idx + 1) % FILTER_N; for (i = 0; i < FILTER_N; i++) sum += buf[i]; return sum / FILTER_N; }这段代码有一个需要调的地方:首次上电时last_valid为0,如果此时实际ADC值距离0很远,会触发误判。解决方法是开机后先连续读取N次并直接送入滑动平均,完成初始化之后再把last_valid设为有效值。这个细节在调试时很容易漏掉,表现就是电子秤上电后前几秒读数乱跳,过一会儿才恢复正常。
4.3 去皮和置零是两个不同操作,别搞混
去皮和置零在用户界面看起来都是让显示变成0,实际上两者保存的内容完全不同。置零是把当前空载状态作为零参考点,直接更新zero参数;去皮则是把一个容器(比如碗)的重量记入tare,之后显示的重量就是当前总重量减去碗的重量。置零会影响标定的基准,去皮不影响。
工程实现上,去皮和置零会写成两个独立按键。置零功能要加限制条件:只有当前重量在满量程的±2%以内才允许执行,防止用户端着满满一锅菜的时候误触置零,直接把零点改到几公斤的位置。去皮则没有任何重量限制,因为用户可能拿一个很重的容器来称东西。
// 去皮与显示计算 // 去皮:记录当前滤波ADC值作为皮重 void do_tare(void) { g_cal.tare = filter_with_limit(hx711_read()); } // 显示:当前重量 = (当前ADC - 皮重ADC - 零点ADC) * 斜率 float get_weight_g(void) { long raw = filter_with_limit(hx711_read()); long delta = raw - g_cal.tare - g_cal.zero; // 小于灵敏度阈值时强制显示0,避免微小漂移引起数字跳动 if (delta < MIN_LSB && delta > -MIN_LSB) return 0.0f; return (float)delta * g_cal.scale; }去皮操作执行后,真实零点与皮重零点之间的偏差会被储存在tare字段。显示值计算时用当前读数减去皮再减零点,逻辑上等价于“以皮重为参考重新置零”。这个方案的优点是置零功能依然受限于±2%FS,但去皮可以随时操作,用户界面行为更符合直觉。
4.4 标定参数掉电保存:EEPROM与Flash的写入技巧
标定参数必须掉电保存,否则用户每次开机都要重新标定。常见的做法是把cal_param_t结构体写入EEPROM或Flash。写入时不能直接覆盖,因为EEPROM有擦写寿命限制,频繁标定会耗尽寿命。更稳妥的方案是双备份存储:写入前先读当前版本号,新数据写入备用区,校验通过后更新主用区的版本号,这样即使写入中途掉电,系统重启后也能从另一个区恢复。
// 双备份存储示意:addr_base 为扇区首地址 void save_cal_to_flash(void) { uint8_t buf[sizeof(cal_param_t)]; memcpy(buf, &g_cal, sizeof(g_cal)); // 先写备用区,校验成功后更新主区标识 flash_erase(ADDR_BACKUP); flash_write(ADDR_BACKUP, buf, sizeof(buf)); flash_erase(ADDR_MAIN); flash_write(ADDR_MAIN, buf, sizeof(buf)); }双备份的代价是多占用一倍的存储空间,但对于标定参数这种“丢了就报废”的数据,这点空间非常值得。读取侧的逻辑是:先读主区,校验失败再读备用区,两个区都失败才要求用户重新标定。这样处理后,现场抗掉电能力大幅提高,几乎不会出现“标定好之后断电重启数据丢失”的返修事故。
5. 电子秤设计与调试中的高频坑:现象、原因与解决
5.1 空载读数缓慢漂移,开机十分钟还不稳
现象:电子秤上电后,显示值从0慢慢涨到0.3g、0.5g,过几分钟还能再变,像是有只无形的手一直在加东西。
原因:最常见的是传感器弹性体与外壳之间的紧固件没有完全锁紧,或者锁紧力矩不均匀,导致残余应力在通电后随着温度变化悄悄释放;其次是ADC的参考电压源温漂过大,电源芯片刚上电时输出电压缓慢爬升,参考电压变化被直接换算成了重量变化。
解决:先把机械结构重新紧固,四颗固定螺丝采用对角顺序拧紧,保证弹性体受力均匀;然后用万用表监测ADC供电电压,如果上电后电压漂移超过10mV就需要换更高精度的LDO。最后在软件上做一个开机预热逻辑,上电后先进行5秒的零点采集,不急着显示重量,预热窗口结束后再进入称重流程。
5.2 放上砝码读数猛跳,屏幕数字像在蹦极
现象:空载时读数稳定,一旦放上标准砝码,显示值在正确值上下剧烈跳动,偏差达到几十克,远大于传感器和ADC的正常噪声水平。
原因:大概率不是传感器坏了,而是信号线受到了机械振动或接触不良的影响。放上砝码的一瞬间,秤盘发生微小形变,信号线跟着抖动,如果连接点存在虚焊或者接插件氧化,接触电阻就会在受力过程中发生变化,叠加在有效信号上形成大幅跳变。
解决:用放大镜检查传感器四根引线的焊点,特别是传感器端部出线位置,这里经常因为弯折导致内部导线断裂但外部皮套完好。重新焊接时不要在焊盘上堆太多锡,焊后做拉拽测试,确保线皮和焊点都能承受一定的机械拉力。另外,传感器与主板的连接器要选用带锁扣的型号,振动环境下的直插式排针是天然的故障源。
5.3 同一个传感器,换了一块主板后标定全部失效
现象:传感器和标定好的参数都保存着,换上一块新焊接的主板后,同样的重量读数偏差巨大,重新标定之后又能正常。
原因:不同主板上ADC芯片的参考电压存在差异,参考电压直接决定了满量程输入对应的数字量。标定参数是在旧主板的环境下计算出来的,迁移到新主板上,同样的模拟输入电压产生不同的数字码,旧斜率自然不适用。很多人会误以为是传感器游移,其实问题出在参考源不一致。
解决:批量生产时,标定参数必须按单品存储,不能做“烧录一套参数复制到所有主板”的操作。调试阶段简化处理的方式是把标定流程内置到产品中,主板更换后重新执行一次两点标定即可。如果量产时希望减少标定时间,可以考虑使用低温漂的内部基准ADC,但即使这样也不能完全跳过单品标定。
5.4 称同一物体,连续称三次结果各不相同
现象:一个装满水的杯子放上去,显示223.4g;拿下来再放上去,显示223.1g;第三次放偏一点,显示224.0g。掉电重新开机,又回到223.6g附近。
原因:这个现象误导性极强,其实多数情况下传感器本身没有问题,而是机械定位不够精确。秤盘和传感器之间如果只是简单的平面接触,没有定位柱或定位槽,每次放置的位置偏差会带来不同大小的侧向力,弹性体在这种非垂直受力下输出自然不同。再加上环境气流扰动,读数就会在小范围内浮动。
解决:增加机械限位结构,让秤盘每次都能落到同一个位置。调试阶段验证传感器性能时,直接用标准砝码而不是用杯碗之类的器具,标准砝码的底面是平整的,定位重复性远比日常器具好。如果经过机械调整后重复性依然超过目标精度,再考虑传感器本身是否存在迟滞过大的问题。
5.5 标定完成时精度很好,使用几天后慢慢偏大
现象:新标定的电子秤误差在±0.2g以内,用了一周后再测,同一个砝码显示值比实际情况大了1.5g,而且偏差还在继续变大。
原因:典型的机械蠕变现象。传感器弹性体在长期受力的情况下,即使卸载后也不会完全回到初始位置,产生了塑性形变。另一个常见原因是固定传感器的螺丝发生松动,等效于改变了弹性体的刚性。还有一种情况是秤盘下方堆积了灰尘或异物,这部分重量被传感器感知但没有被去皮。
解决:返修时先清灰再测零点,如果零点偏差超过满量程的1%,需要重新标定零点。检查四颗安装螺丝的力矩,扭力扳手紧固到传感器手册给出的推荐值并涂上螺纹胶。如果是弹性体本身发生塑性形变,只能更换传感器,这类问题在超载使用过的秤上特别常见,标定算法救不回来。
6. 进阶:用三点分段线性补偿,把精度从0.1%提升到0.05%
两点标定假设传感器在全量程范围内是理想线性响应,但真实弹性体在受力较大时会表现出轻微的非线性,表现为高量程段的斜率与低量程段略有不同。如果目标精度高于0.1%FS,两点标定往往不够。这时候可以用多段线性插值逼近真实响应曲线。
具体做法是选择三个标定点:空载、50%满量程、满量程。例如3kg量程,分别用0g、1500g、3000g的标准砝码采集三个ADC值,计算出每两个相邻点之间的斜率。称重时先判断当前ADC值落在哪一段区间,再用该区间的斜率计算重量。代码实现上是查段插值,分段点越多精度越高,但每多一个点就要多一次标定操作和一组存储空间。
// 三点标定:r1/r2/r3为各标定点ADC读数,w1/w2/w3为对应砝码质量 // r数组必须单调递增,标定时确保砝码从轻到重依次放置 float weight_by_interp(long raw, long *r, float *w) { if (raw <= r[1]) { // 落在第一段:r[0]到r[1] return w[0] + (float)(raw - r[0]) * (w[1] - w[0]) / (float)(r[1] - r[0]); } else { // 落在第二段:r[1]到r[2] return w[1] + (float)(raw - r[1]) * (w[2] - w[1]) / (float)(r[2] - r[1]); } }逻辑上,分段线性插值就是把真实响应曲线用折线逼近,段数越多误差越小。工程上不推荐追求过细的分段,三段到五段已经能覆盖大多数低成本传感器的非线性特性,再细分就是典型的“收益递减”。标定过程中还可以顺手记录每个标定点的实际误差,用来验证插值效果。
我现在的习惯是:无论最终用两点还是三点标定,每次调试都要记录标定数据和实测数据,保存成表格留档。这一份记录在后续排查“怎么用着用着不准了”的问题时价值极大——翻一下表格,如果零点没漂、斜率没变,那问题就在机械结构,不用再往电路和算法上反复折腾。这套习惯帮我省了无数次重复排查,希望帮到你。
本文还有配套的精品资源,点击获取