摘要
电子秤是将检测与转换技术、计算机技术、信息处理、数字技术等技术综合一体的现代新型称重仪器。它与我们日常生活紧密结合息息相关。
电子称主要以单片机作为中心控制单元,通过称重传感器进行模数转换单元,在配以键盘、显示电路及强大软件来组成。电子称不但计量准确、快速方便,更重要的自动称重、数字显示,对人们生活的影响越来越大,广受欢迎。
本系统的设计主要从硬件电路设计,软件编程调试,实物焊接调试三部分进行详细阐述。硬件电路主要是基于单片机STC89C52为核心的控制单元实现数据的处理,采用压力传感器对数据进行采集,电子秤专用24位AD转换芯片HX711对传感器采集到的模拟量进行AD转换,转换后的数据送到单片机进行处理显示,数据显示由LCD1602液晶实现,液晶显示效果稳定无闪烁。
绪论
称重技术自古以来就被人们所重视,作为一种计量手段,广泛应用于工农业、科研、交通、内外贸易等各个领域,与人民的生活紧密相连。电子秤是电子衡器中的一种,衡器是国家法定计量器具,是国计民生、国防建设、科学研究、内外贸易不可缺少的计量设备,衡器产品技术水平的高低,将直接影响各行各业的现代化水平和社会经济效益的提高。称重装置不仅是提供重量数据的单体仪表,而且作为工业控制系统和商业管理系统的一个组成部分,推进了工业生产的自动化和管理的现代化,它起到了缩短作业时间、改善操作条件、降低能源和材料的消耗、提高产品质量以及加强企业管理、改善经营管理等多方面的作用。称重装置的应用已遍及到国民经济各领域,取得了显著的经济效益。
电子秤是称重技术中的一种新型仪表,广泛应用于各种场合。电子秤与机械秤比较有体积小、重量轻、结构简单、价格低、实用价值强、维护方便等特点,可在各种环境工作,重量信号可远传,易于实现重量显示数字化,易于与计算机联网,实现生产过程自动化,提高劳动生产率。从世界水平看,衡器技术已经经历了四个阶段,从传统的全部由机械元器件组成的机械称到用电子线路代替部分机械元器件的机电结合秤,再从集成电路式到目前的单片机系统设计的电子计价秤。我国电子衡器从最初的机电结合型发展到现在的全电子型和数字智能型。现今电子衡器制造技术及应用得到了新发展:电子称重技术从静态称重向动态称重发展;计量方法从模拟测量向数字测量发展;测量特点从单参数测量向多参数测量发展。常规的测试仪器仪表和控制装置被更先进的智能仪器所取代,使得传统的电子测量仪器在远离、功能、精度及自动化水平定方面发生了巨大变化,并相应的出现了各种各样的智能仪器控制系统,使得科学实验和应用工程的自动化程度得以显著提高。
电子称重的实现首先是通过压力传感器采集到被测物体的重量并将其转换成电压信号。输出电压信号通常很小,需要通过前端信号处理电路进行准确的线性放大。放大后的模拟电压信号经A/D转换电路转换成数字量被送入到主控电路的单片机中,再经过单片机控制译码显示器,从而显示出被测物体的重量。按照设计的基本要求,系统可分为三大模块,数据采集模块、控制器模块、人机交互液晶显示界面模块。其中数据采集模块由压力传感器、信号的前级处理和A/D转换部分组成。转换后的数字信号送给控制器处理,由控制器完成对该数字量的处理,驱动显示模块完成人机间的信息交换。此部分对软件的设计要求比较高,系统的大部分功能都需要软件来控制。在扩展功能上,本设计增加了一个过载报警提示功能使本电子称的设计更人性化智能化。
系统硬件设计方案
系统总体设计方案比较
在设计系统时,针对各个模块实现的功能来设计电子秤的方案有以下几种:
方案一 数码管显示:
此方案利用数码管显示物体重量,简单可行,可以采用内部带有模数转换功能的单片机。由此设计出的电子秤系统,硬件部分简单,接口电路易于实现,并且在编程时大大减少程序量,在电路结构上只有简单的输出输入关系。缺点是:硬件部分简单,虽然可以实现电子称基本的称重功能,但是不能实现外部数据的输入,无法根据实际情况灵活地设定各种控制参数。由于数码管只能实现简单的数字和英文字符的显示,不能显示汉字以及其他的复杂字符,不能达到显示购物清单的要求。又因为采用了具有模数转换功能的单片机,系统电路过于简单,系统硬件的扩展必受到限制,电子秤的功能过于单一,达不到设计的标准。
方案二 在前一种方案的基础上进行扩展,增加一键盘输入装置,增加外界对单片机内部的数据设定,使电子称实现称重计价的功能。
结构简图如图2所示:
此方案设计的电子秤,可以实现称物计价功能,但是局限于数码管的功能,在显示时只能显示单价、购物总额以及简单的货物代码等。在显示重量时,如果数码管没有足够的位数,那么称量物体重量的精度必受到限制,所以此方案需要较多的数码管接入电路中。这样在处理输入输出接口时需要另行扩展足够多的I/O接口供数码管使用,比较麻烦。
方案三 前端信号处理时,选用放大、信号转换等措施来增加信号采集强度但会增加相应的设计成本;显示方面采用具有字符图文显示功能的LCD显示器。这种方案不仅加强了人机交换的能力,而且满足设计要求,可以显示购物清单、所称量的物体信息等相关内容,当需要增加扩展功能时可以通过切换液晶显示界面的方式来实现。
鉴于上述三种方案的优缺点,本系统在设计时充分考虑到系统的实用性及成本的可行性的前提下,设计完成了最终的电子称方案,最终的硬件设计方案图如图4所示,
系统元器件选型及器件参数介绍
传感器选择
压电传感器是一种典型的有源传感器,又称自发电式传感器。其工作原理是基于某些材料受力后在其相应的特定表面产生电荷的压电效应。
压电传感器体积小、重量轻、结构简单、工作可靠,适用于动态力学量的测量,不适合测频率太低的被测量,更不能测静态量。目前多用于加速度和动态力或压力的测量。压电器件的弱点:高内阻、小功率。功率小,输出的能量微弱,电缆的分布电容及噪声干扰影响输出特性,这对外接电路要求很高。
电阻应变式传感器是一种利用电阻应变效应,将各种力学量转换为电信号的结构型传感器。电阻应变片式电阻应变式传感器的核心元件,其工作原理是基于材料的电阻应变效应,电阻应变片即可单独作为传感器使用,又能作为敏感元件结合弹性元件构成力学量传感器。
导体的电阻随着机械变形而发生变化的现象叫做电阻应变效应。电阻应变片把机械应变信号转换为△R/R后,由于应变量及相应电阻变化一般都很微小,难以直接精确测量,且不便处理。因此,要采用转换电路把应变片的△R/R变化转换成电压或电流变化。其转换电路常用测量电桥。
直流电桥的特点是信号不会受各元件和导线的分布电感及电容的影响,抗干扰能力强,但因机械应变的输出信号小,要求用高增益和高稳定性的放大器放大。
图5为一直流供电的平衡电阻电桥, 接直流电源E:
当电桥输出端接无穷大负载电阻时,可视输出端为开路,此时直流电桥称为电压桥,即只有电压输出。
显示器选择
方案一 数码管显示
数码管是一种半导体发光器件,其基本单元是发光二极管。数码管按段数分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管单元(多一个小数点显示);按能显示多少个“8”可分为1位、2位、4位等等数码管;按发光二极管单元连接方式分为共阳极数码管和共阴极数码管。共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管。共阳数码管在应用时应将公共极COM接到+5V,当某一字段发光二极管的阴极为低电平时,相应字段就点亮。当某一字段的阴极为高电平时,相应字段就不亮。共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM)的数码管。共阴数码管在应用时应将公共极COM接到地线GND上,当某一字段发光二极管的阳极为高电平时,相应字段就点亮。当某一字段的阳极为低电平时,相应字段就不亮。
数码管显示信息有限,当显示信息较多时需要多个数码管级联方可,这样会造成硬件连接复杂,成本增加;数码管对大部分字符不能很好的显示,动态扫描时处理不好易出现闪烁现象。
方案二 LCD字符液晶显示
采用点阵字符型 LCD 液晶显示,液晶显示模块具有体积小、功耗低、显示内容丰富等特点,现在字符型液晶显示模块已经是单片机应用设计中最常用的信息显示器件,但采用LCD液晶显示会造成设计成本增加。
LCD1602可以显示2行 16 个字符,有 8 位数据总线 D0-D7,和 RS、R/W、 EN 三个控制端口,工作电压为 5V,并且带有字符对比度调节和背光[4]。
LCD1602 液晶模块内部的字符发生存储器(CGROM)已经存储了 160 个不同 的点阵字符图形,如表 1 所示,这些字符有:阿拉伯数字、英文字母的大小写、 常用的符号、和日文假名等,每一个字符都有一个固定的代码,它的读写操作、 屏幕和光标的操作都是通过指令编程来实现的。
最后综合了多方面因素的考虑采用了方案二,选择 LCD1602 显示器作为系统的显示界面。
AD转换芯片
HX711是一款专为高精度电子秤而设计的24位A/D转换器芯片。与同类型其它芯片相比,该芯片集成了包括稳压电源、片内时钟振荡器等其它同类型芯片所需要的外围电路,具有集成度高、响应速度快、抗干扰性强等优点。降低了电子秤的整机成本,提高了整机的性能和可靠性。该芯片与后端MCU 芯片的接口和编程非常简单,所有控制信号由管脚驱动,无需对芯片内部的寄存器编程。输入选择开关可任意选取通道A 或通道B,与其内部的低噪声可编程放大器相连。通道A 的可编程增益为128 或64,对应的满额度差分输入信号幅值分别为±20mV或±40mV。通道B 则为固定的64 增益,用于系统参数检测。芯片内提供的稳压电源可以直接向外部传感器和芯片内的A/D 转换器提供电源,系统板上无需另外的模拟电源。芯片内的时钟振荡器不需要任何外接器件。上电自动复位功能简化了开机的初始化过程。芯片管脚图如图7所示。
系统硬件电路
系统硬件电路设计
由于该系统中 51 单片机及 AD 转换芯片及液晶显示器所需供电电压均为 5V 电压,所以要保证系统稳定可靠的工作,需要设计一个可以稳定提供 5V 电压的供电系统。本设计采用USB供电方式,USB 接口供电方便程序调试,电源输接口加上LED 电源指示灯,用来判定电源是否正常工作。该系统电源电路设计如图 11 所示。
单片机控制电路设计
系统主控电路由STC89C52单片机及晶振电路和复位电路组成,该电路作为整个系统功能实现的核心单元,其连接方式如图14所示。
晶振全称为晶体振荡器,其作用在于产生原始的时钟频率,这个频率经过频率发生器的放大或缩小后就成了电脑中各种不同的总线频率。晶振一般叫做晶体谐振器,是一种机电器件,是用电损耗很小的石英晶体经精密切割磨削并镀上电极焊上引线做成。这种晶体有一个很重要的特性,如果给它通电,它就会产生机械振荡,反之,如果给它机械力,它又会产生电,这种特性叫机电效应。他们有一个很重要的特点,其振荡频率与他们的形状,材料,切割方向等密切相关。由于石英晶体化学性能非常稳定,热膨胀系数非常小,其振荡频率也非常稳定,由于控制几何尺寸可以做到很精密,因此,其谐振频率也很准确。根据石英晶体的机电效应,我们可以把它等效为一个电磁振荡回路,即谐振回路。他们的机电效应是机-电-机-电…的不断转换,由电感和电容组成的谐振回路是电场-磁场的不断转换。在电路中的应用实际上是把它当作一个高Q值的电磁谐振回路。由于石英晶体的损耗非常小,即Q值非常高,做振荡器用时,可以产生非常稳定的振荡,作滤波器用,可以获得非常稳定和陡削的带通或带阻曲线[10]。
复位电路是用来让单片机返回到初始状态的辅助电路,其作用是当单片机程序跑飞或系统出现死机状态时可以让系统从新恢复工作。本系统复位电路的设计为上电复位复位方式。按键复位就没有太大必要使用看,所以没有设计按键复位。
系统显示电路设计
显示部分采用LCD1602液晶显示模块,液晶板上排列着若干 5×7或 5×10点阵的字符显示位,每个显示位可显示1个字符,从规格上分为每行 8、16、20、24、32、40位,有一行、两行及四行三类。其与单片机的连接电路如图15所示
1脚和2脚为液晶1602地和电源引脚,3脚为背光调节引脚,通过10K电位器接地,背光可通过电位器来调节亮度;4脚、5脚、6脚为液晶片选控制引脚,分别连接到单片机的P2.5、P2.6、P2,7端口,7~14脚为数据接口,与单片机的P0口相连实现数据的传输,15、16、脚为液晶的背光控制脚,分别接到电源和地[9]。
超重报警电路设计
报警指示电路用来在称重测量超出最高值时报警提示,以免重量太高的情况下损坏传感器。报警指示电路由PNP三极管9S8550驱动蜂鸣器来实现,单片机IO口控制三极管的基极,当单片机的IO口输出为低电平时,三极管导通,蜂鸣器的正极与电源接通,蜂鸣器通电发出报警声,当单片机IO口输出高电平时,三极管截止,蜂鸣器停止报警。报警指示电路如图16所示。
按键输入电路设计
按键输入电路用来在电子称测量过程中输入单价值,按键输入电路采用4*4矩阵键盘实现,矩阵键盘电路如图17所示。
此电子秤是开机检测托盘重量,并将托盘重量清零(即电子秤每次开机后检测托盘重量,并程序中自动将托盘重量保存在一个变量中,称量过程中每次都将获得的重量减去托盘重量,而得到所要称量物体的真正的重量),
计算功能:在正确输入了单价之后,按下计算按键,将会计算出金额,并在液晶显示器上显示出重量、单价、总价。
系统软件
主程序
显示部分
按键检测
系统整体调试
硬件电路调试中遇到的问题
1、电子电路的设计中对各种影响因素的考虑不够完全,比如在对过电压情况的处理中未作防范措施。
2、系统设计不够优化,有待改善。比如系统的超量程信号直接由单片机送入报警电路,没有设计保护电路再入单片机处理后送入报警电路。
3、没有扩展更多电路,如温度显示功能,通讯接口电路与上位机(PC机)进行通讯,上位机显示功能从而将大量的商品数据存于上位机,然后通过串口或并口通讯与电子称相连,达到远距离控制的目的。
4、对各种实用芯片价格了解不够,选择上任有欠缺,如所选的称重传感器价格较贵。
这些都为我今后的学习和工作留下了积极的影响。
系统实物调试效果图
代码
#include "main.h"
#include "LCD1602.h"
#include "HX711.h"
unsigned long HX711_Buffer = 0;
unsigned long Weight_Maopi = 0,Weight_Shiwu = 0;
char Price_Count = 0;
unsigned char KEY_NUM = 0;
unsigned char Price_Buffer[3] = {0x00,0x00,0x00};
unsigned long Money = 0;
bit Flag_OK = 0;
//****************************************************
//主函数
//****************************************************
void main()
{
char k = 10 ;
Init_LCD1602(); //初始化LCD1602
LCD1602_write_com(0x80); //指针设置
LCD1602_write_word(" Hello Welcome"); //开机画面第一行
Delay_ms(800); //延时1s
LCD1602_write_com(0x80+0x40); //指针设置
LCD1602_write_word(" ");
Get_Maopi(); //称毛皮重量
Delay_ms(1000); //延时1s
Init_LCD1602(); //初始化LCD1602 消除之前的显示内容
loop:Price_Count = 0;
Price_Buffer[0] = 0;
Price_Buffer[1] = 0;
Price_Buffer[2] = 0;
Flag_OK = 0;
LCD1602_write_com(0x80); //指针设置
LCD1602_write_word(" W: Kg");
LCD1602_write_com(0x80+0x40); //指针
LCD1602_write_word("P: . Z: ");
LCD1602_write_com(0x80+0x40+6); //指针
LCD1602_write_data(0x5c);
LCD1602_write_com(0x80+0x40+15); //指针
LCD1602_write_data(0x5c);
Get_Maopi(); //称毛皮重量
while(1)
{
if( Flag_OK == 0)
{
if( k == 0)
Get_Weight(); //称重
k--;
if( k < 0)
{
k = 10;
}
//显示当前重量
LCD1602_write_com(0x86);
LCD1602_write_data(Weight_Shiwu/1000 + 0x30);
LCD1602_write_data('.');
LCD1602_write_data(Weight_Shiwu%1000/100 + 0x30);
LCD1602_write_data(Weight_Shiwu%100/10 + 0x30);
LCD1602_write_data(Weight_Shiwu%10 + 0x30);
}
KEY_NUM = KEY_Scan();
if( KEY_NUM != 0x55) //当返回的不是初值时候,确认按键按下。
{
if(KEY_NUM == 16) //数字A键,去皮功能
{
Get_Maopi(); //去皮
}
if(KEY_NUM == 15) //数字B键清除键,二次测量
{
goto loop;
}
if(KEY_NUM == 12) //数字C输入单价错误时返回上一步
{
Price_Count--;
if( Price_Count < 0)
{
Price_Count = 0;
}
Price_Buffer[Price_Count] = 0; //清除上一个输入的数据
switch(Price_Count)
{
case 0:
LCD1602_write_com(0x80+0x40+2);
LCD1602_write_data(' ');
break;
case 1:
LCD1602_write_com(0x80+0x40+3);
LCD1602_write_data(' ');
break;
case 2:
LCD1602_write_com(0x80+0x40+5);
LCD1602_write_data(' ');
break;
default : break;
}
}
if(KEY_NUM == 13) //数字D键,计算总价
{
Money = Price_Buffer[0] * 100 + Price_Buffer[1] * 10 + Price_Buffer[2];
Money = Money * Weight_Shiwu / 1000;
LCD1602_write_com(0x80+0x40+10);
LCD1602_write_data(Money/1000 + 0x30);
LCD1602_write_data(Money%1000/100 + 0x30);
LCD1602_write_data(Money%100/10 + 0x30);
LCD1602_write_data('.');
LCD1602_write_data(Money%10 + 0x30);
Flag_OK = 1;
}
if(KEY_NUM >= 0 && KEY_NUM <= 9) //显示输入的价格值
{
Price_Buffer[Price_Count] = KEY_NUM;
switch(Price_Count)
{
LCD1602_write_com(0x80+0x40); //指针
LCD1602_write_word("P: . Z: ");
case 0:
LCD1602_write_com(0x80+0x40+2);
LCD1602_write_data(Price_Buffer[0] + 0x30);
break;
case 1:
LCD1602_write_com(0x80+0x40+3);
LCD1602_write_data(Price_Buffer[1] + 0x30);
break;
case 2:
LCD1602_write_com(0x80+0x40+5);
LCD1602_write_data(Price_Buffer[2] + 0x30);
break;
default : break;
}
Price_Count++;
if( Price_Count >= 3)
{
Price_Count = 3;
}
}
}
}
}
//****************************************************
//矩阵键盘扫描
//****************************************************
unsigned char KEY_Scan()
{
unsigned char temp = 0;
unsigned char com = 0x55 , com1 = 0 , com2 = 0;
P3=0xf0;
if(P3!=0xf0)
{
com1=P3;
P3=0x0f;
com2=P3;
}
P3=0xf0;
while(P3!=0xf0);
temp=com1|com2;
if(temp==0xee)com=1;//数字1
if(temp==0xed)com=4;//数字4
if(temp==0xeb)com=7;//数字7
if(temp==0xe7)com=11;//备用键*号键
if(temp==0xd7)com=0;//数字0
if(temp==0xb7)com=14;//备用键*号键
if(temp==0xde)com=2; //数字2
if(temp==0xdd)com=5; //数字5
if(temp==0xdb)com=8;//数字8
if(temp==0xbe)com=3;//数字3
if(temp==0xbd)com=6; //数字6
if(temp==0xbb)com=9;//数字9
if(temp==0x7e)com=16;//数字A键,去皮功能
if(temp==0x7d)com=15;//数字B键清除键,二次测量
if(temp==0x7b)com=12;//数字C输入单价错误时返回上一步
if(temp==0x77)com=13;//数字D键,计算总价
return(com);
}
//****************************************************
//称重
//****************************************************
void Get_Weight()
{
HX711_Buffer = HX711_Read();
HX711_Buffer = HX711_Buffer/100;
if(HX711_Buffer > Weight_Maopi)
{
Weight_Shiwu = HX711_Buffer;
Weight_Shiwu = Weight_Shiwu - Weight_Maopi; //获取实物的AD采样数值。
Weight_Shiwu = (unsigned int)((float)Weight_Shiwu/4.40+0.05); //计算实物的实际重量
//因为不同的传感器特性曲线不一样,因此,每一个传感器需要矫正这里的4.30这个除数。
//当发现测试出来的重量偏大时,增加该数值。
//如果测试出来的重量偏小时,减小改数值。
//该数值一般在4.0-5.0之间。因传感器不同而定。
//+0.05是为了四舍五入百分位
Buzzer = 1; //关闭警报
}
// else if(HX711_Buffer < Weight_Maopi - 30)
// {
// Buzzer = 0; //负重量报警
// }
// else if(HX711_Buffer > Weight_Maopi + 24970) //大于5Kg的最大量程,报警
// {
// Buzzer = 0;
// }
if(Weight_Shiwu > 5000 || HX711_Buffer < Weight_Maopi - 30)
{
Buzzer = 0;
}
else
{
Buzzer = 1;
}
}
//****************************************************
//获取毛皮重量
//****************************************************
void Get_Maopi()
{
HX711_Buffer = HX711_Read();
Weight_Maopi = HX711_Buffer/100;
}
//****************************************************
//MS延时函数(12M晶振下测试)
//****************************************************
void Delay_ms(unsigned int n)
{
unsigned int i,j;
for(i=0;i<n;i++)
for(j=0;j<123;j++);
}