本实践环节“51单片机商用电子计价秤设计”要求收集市场电子秤的应用场景的功能列表,给出本系统各功能的参数范围,分析质量检测功能的实现方法,设计单片机仿真系统并通过Proteus进行测试,电子秤是利用物体的重力作用来确定物体质量(重量)的测量仪器, 是将检测与转换技术、计算机技术、信息处理、数字技术等技术综合一体的现代新型称重仪器。。
目的:为培养学生综合运用所学理论知识和技能解决实际问题能力,实际动手能力,查阅文献资料的能力与工程设计的基本能力,培养学生综合运用本专业理论知识的能力。
意义:电子秤是电子衡器中的一种,衡器是国家法定计量器具,是国计民生、国防建设、科学研究、内外贸易不可缺少的计量设备,衡器产品技术水平的高低,将直接影响各行各业的现代化水平和社会经济效益的提高。称重装置不仅是提供重量数据的单体仪表,而且作为工业控制系统和商业管理系统的一个组成部分,推进了工业生产的自动化和管理的现代化,它起到了缩短作业时间、改善操作条件、降低能源和材料的消耗、提高产品质量以及加强企业管理、改善经营管理等多方面的作用。称重装置的应用已遍及到国民经济各领域,取得了显著的经济效益。因此,称重技术的研究和衡器工业的发展各国都非常重视。
50年代中期电子技术的渗入推动了衡器制造业的发展。60年代初期出现机电结合式电子衡器以来,经过40多年的不断改进与完善,我国电子衡器从最初的机电结合型发展到现在的全电子型和数字智能型。现今电子衡器制造技术及应用得到了新发展。电子称重技术从静态称重向动态称重发展:计量方法从模拟测量向数字测量发展;测量特点从单参数测量向多参数测量发展,特别是对快速称重和动态称重的研究与应用。通过分析近年来电子衡器产品的发展情况及国内外市场的需求,电子衡器总的发展趋势是小型化、模块化、集成化、智能化;其技术性能趋向是速率高、准确度高、稳定性高、可靠性高;其功能趋向是称重计量的控制信息和非控制信息并重的“智能化”功能;其应用性能趋向于综合性和组合性。电子秤是电子衡器中的一种,衡器是国家法定计量器具,是国计民生、国防建设、科学研究、内外贸易不可缺少的计量设备,衡器产品技术水平的高低,将直接影响各行各业的现代化水平和社会经济效益的。
近年来,电子秤已愈来愈多地参与到数据处理和过程控制中。现代称重技术和数据系统已经成为工艺技术、储运技术、预包装技术、收货业务及商业销售领域中不可缺少的组成部分。随着称重传感器各项性能的不断突破,为电子秤的发展奠定了其础,国外如美国、西欧等一些国家在2 0世纪6 0年代就出现了0 .1%称量准确度的电子秤,并在7 0年代中期约对75%的机械秤进行了机电结合式的电子化改造。
目前单片机渗透到我们生活的各个领域,几乎很难找到哪个领域没有单片机的踪迹。单片机具有体积小、功耗低、控制功能强、扩展灵活、微型化和使用方便等优点,广泛应用于仪器仪表中,结合不同类型的传感器,可实现诸如电压、功率、频率、湿度、温度、流量、速度、厚度、角度、长度、硬度、元素、压力等物理量的测量。采用单片机控制使得仪器仪表数字化、智能化、微型化,且功能比起采用电子或数字电路更加强大。采用单片机设计的电子称会越来越适应社会的发展,响应经济的要求。
(1)AT89C51:是一种低功耗,高性能的芯片与一个8位微控制器字节的系统内可编程快闪记忆体。该设备的生产使用公司的高密度非易失性存储器技术和兼容的行业—标准80C 51指令集和引脚。片上闪存允许程序存储器重新编程在系统或常规非易失性存储器编程。结合灵活的8位处理器的系统内可编程闪存上单片AT89S 51,爱特梅尔是一个功能强大的微控制器提供了一个高度灵活和成本效益的解决方案的许多嵌入式控制应用。AT89S 51提供以下特征:一个字节,128个字节32内存,输入/输出线,看门狗定时器,双数据指针,2个16位定时器/计数器,一个 5 向量两级中断结构,一个全双工串行通信口,片内振荡器及时钟电路。此外,AT89S 51设计与静态的逻辑操作下降到零频率和支持软件可选的节电模式。空闲模式下停止中央处理器,同时允许存储器,定时器/计数器,串行端口,和中断系统继续工作。在掉电模式节省内存的内容,但振荡器停止工作并禁止其它所有部件工作直到下一个硬件复位。
(2)HX711:是一款专为高精度称重传感器而设计的24位A/D转换器芯片。
(3)LCD:点阵式液晶显示模块能显示的字符多,并且还能显示汉字。
(4)RESPACK:
(5)如果超过9.9kg,就进行报警;
? ? ? ? ? ?
(1)整体原理图:
(2)运行后的电路图:
研究方法:本设计采用模块化设计法,以51单片机为核心设计一款高精度电子秤,当被称物体放置在秤台上时,称重传感器产生力-电效应,将物体的重量转换成与被称物体重量成一定函数关系的电信号。该电信号先通过前端信号处理电路,然后经过A/D转换电路转换成数字信号送入到主控电路的单片机中,单片机通过扫描键盘和各种功能开关,根据键盘输入内容和各种功能开关的状态进行判断、分析和控制,来完成各种运算和显示功能。
其硬件结构主要包括:数据采集模块、最小系统模块、超重报警模块、键盘和显示模块。其中,数据采集模块包括称重传感器和A/D转换电路;最小系统部分主要包括AT89S51、晶振电路和复位电路;键盘由4X4位矩阵键盘组成,可以控制显示重量和价钱等信息;显示部分由LCD1602液晶显示。软件部分由C语言编程,实现对各部分的控制。该电子秤可以实现称重、置零、计价和显示等功能。其称重范围为0~10Kg,分度值为0.001g。整个系统结构简单,使用方便。
利用压力传感器采集因压力变化产生的电压信号,经过电压放大电路放大,然后再经过模数转换器转换为数字信号,最后把数字信号送入单片机。单片机经过相应的处理后,得出当前所称物品的重量及总额,然后再显示出来。
按照本设计功能的要求,系统由5个部分组成:控制器部分、测量部分、数据显示部分、键盘部分、和电路电源部分,系统设计总体方案框图如图所示。
测量部分是利用称重传感器检测压力信号,得到微弱的电信号(本设计为电压信号),而后经处理电路(如滤波电路,差动放大电路,)处理后,送单片机中的A/D转换器,将模拟量转化为数字量输出,控制器接受来自A/D转换器输出的数字信号,经过复杂的运算,将数宁信号转换为物体的实际重量信号,并将其送到显示单元中。
整个仪器软件由主程序和中断服务程序两大部分组成,软件设计采用模块化结构。主要模块的程序流程图设计, 4×4矩阵键盘键号如图所示。
0~9 | “去皮” | “累计” | “清除” | “保持” | “Enter” | · |
0~9 | 10 | 11 | 12 | ? 13 | 14 | 15 |
仪器主程序流程图如图所示:
仪器中断服务程序流程图:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?中断服务程序流程图
通过本课程,熟悉了五一单片机,完成了电子秤的设计,对本次实验有以下几点收获:
Main.c
/*
功能:基于51单片机的智能电子秤系统
实现称重和超量程报警
设计人:讷言敏行
设计时间:2020.4.20
*/
#include <reg52.h>
#include <intrins.h>
#include <string.h>
#include "main.h"
#include "LCD1602.h"
#include "HX711.h"
#include "eeprom52.h"
#define uchar unsigned char
#define uint unsigned int
unsigned long HX711_Buffer = 0;
unsigned long Weight_Maopi = 0;
unsigned long Weight_Maopi_0 = 0;
long Weight_Shiwu = 0;
unsigned int qupi=0;
//键盘处理变量
unsigned char keycode;
unsigned char key_press_num=0;
uint GapValue,GapValue1;
//定义标识
volatile bit FlagTest = 0; //定时测试标志,每0.5秒置位,测完清0
volatile bit FlagKeyPress = 0; //有键按下标志,处理完毕清0
//校准参数
//因为不同的传感器特性曲线不是很一致,因此,每一个传感器需要矫正这里这个参数才能使测量值很准确。
//当发现测试出来的重量偏大时,增加该数值。
//如果测试出来的重量偏小时,减小改数值。
//该值可以为小数
//#define GapValue 349
sbit Buzzer = P1^0;
sbit LED=P1^1;
sbit ROW1=P3^0;
sbit ROW2=P3^1;
sbit ROW3=P3^2;
sbit ROW4=P3^3;
volatile bit ClearWeighFlag = 0; //传感器调零标志位,清除0漂
/******************把数据保存到单片机内部eeprom中******************/
void write_eeprom()
{
SectorErase(0x1000);
GapValue1=GapValue&0x00ff;
byte_write(0x1000, GapValue1);
GapValue1=(GapValue&0xff00)>>8;
byte_write(0x1001, GapValue1);
byte_write(0x1060, a_a);
}
/******************把数据从单片机内部eeprom中读出来*****************/
void read_eeprom()
{
GapValue = byte_read(0x1001);
GapValue = (GapValue<<8)|byte_read(0x1000);
a_a = byte_read(0x1060);
}
/**************开机自检eeprom初始化*****************/
void init_eeprom()
{
read_eeprom(); //先读
if(a_a != 1) //新的单片机初始单片机内问eeprom
{
GapValue = 2450;
a_a = 1;
write_eeprom(); //保存数据
}
}
//显示重量,单位kg,两位整数,三位小数
void Display_Weight()
{
LCD1602_write_com(0x80+0x40+8);
if(Weight_Shiwu/10000==0)
LCD1602_write_data(' ');
else
LCD1602_write_data(Weight_Shiwu/10000 + 0x30);
LCD1602_write_data(Weight_Shiwu%10000/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);
}
//定时器0初始化
void Timer0_Init()
{
ET0 = 1; //允许定时器0中断
TMOD = 1; //定时器工作方式选择
TL0 = 0xb0;
TH0 = 0x3c; //定时器赋予初值
TR0 = 1; //启动定时器
}
//定时器0中断
void Timer0_ISR (void) interrupt 1 using 0
{
uchar Counter;
TL0 = 0xb0;
TH0 = 0x3c; //定时器赋予初值
//每0.5秒钟刷新重量
Counter ++;
if (Counter >= 10)
{
FlagTest = 1;
Counter = 0;
}
}
//按键响应程序,参数是键值
//返回键值:
// 7 8 9 10(清0)
// 4 5 6 11(删除)
// 1 2 3 12(未定义)
// 14(未定义) 0 15(.) 13(确定价格)
void KeyPress()
{
if(ROW1==0) //去皮键
{
Delay_ms(5);
if(ROW1==0)
{
// Get_Maopi();
if(qupi==0)
qupi=Weight_Shiwu;
else
qupi=0;
Buzzer=0;
Delay_ms(50);
Buzzer=1;
while(ROW1==0);
}
}
if(ROW2==0) //加
{
Delay_ms(5);
if(ROW2==0)
{
while(!ROW2)
{
key_press_num++;
if(key_press_num>=100)
{
key_press_num=0;
while(!ROW2)
{
if(GapValue<10000)
GapValue++;
Buzzer=0;
Delay_ms(10);
Buzzer=1;
Delay_ms(10);
Get_Weight();
}
}
Delay_ms(10);
}
if(key_press_num!=0)
{
key_press_num=0;
if(GapValue<10000)
GapValue++;
Buzzer=0;
Delay_ms(50);
Buzzer=1;
}
write_eeprom();
}
}
if(ROW3==0) //减
{
Delay_ms(5);
if(ROW3==0)
{
while(!ROW3)
{
key_press_num++;
if(key_press_num>=100)
{
key_press_num=0;
while(!ROW3)
{
if(GapValue>1)
GapValue--;
Buzzer=0;
Delay_ms(10);
Buzzer=1;
Delay_ms(10);
Get_Weight();
}
}
Delay_ms(10);
}
if(key_press_num!=0)
{
key_press_num=0;
if(GapValue>1)
GapValue--;
Buzzer=0;
Delay_ms(50);
Buzzer=1;
}
write_eeprom(); //保存数
}
}
}
//****************************************************
//主函数
//****************************************************
void main()
{
init_eeprom(); //开始初始化保存的数据
Init_LCD1602(); //初始化LCD1602
EA = 0;
Timer0_Init();
//初中始化完成,开断
EA = 1;
// Get_Maopi();
LCD1602_write_com(0x80); //指针设置
LCD1602_write_word(" Welcome To Use "); //
LCD1602_write_com(0x80+0x40); //指针设置
LCD1602_write_word("Wlectronic Scale");
// Delay_ms(2000);
Get_Maopi();
LCD1602_write_com(0x80); //指针设置
LCD1602_write_word("The Weight: ");
LCD1602_write_com(0x80+0x40); //指针设置
LCD1602_write_word(" 0.000kg");
// Get_Maopi(); //称毛皮重量
while(1)
{
//每0.5秒称重一次
if (FlagTest==1)
{
Get_Weight();
FlagTest = 0;
}
KeyPress();
}
}
//****************************************************
//称重
//****************************************************
void Get_Weight()
{
Weight_Shiwu = HX711_Read();
Weight_Shiwu = Weight_Shiwu - Weight_Maopi; //获取净重
Weight_Shiwu = (unsigned int)((float)(Weight_Shiwu*10)/GapValue)-qupi; //计算实物的实际重量
if(Weight_Shiwu >= 10000) //超重报警
{
Buzzer =0;
LED=1;
LCD1602_write_com(0x80+0x40+8);
LCD1602_write_word("--.---");
}
else
{
if(Weight_Shiwu==0)
LED=0;
else if(Weight_Shiwu>0)
LED=0;
Buzzer = 1;
Display_Weight();
}
}
//****************************************************
//获取毛皮重量
//****************************************************
void Get_Maopi()
{
unsigned char clear;
mm: Weight_Maopi_0 = HX711_Read();
for(clear=0;clear<10;clear++)
{
Buzzer=1;
LED=0;
Delay_ms(100);
LED=1;
Delay_ms(100);
}
Weight_Maopi = HX711_Read();
if(Weight_Maopi/GapValue!=Weight_Maopi_0/GapValue)
goto mm;
Buzzer=0;
Delay_ms(500);
Buzzer=1;
}
//****************************************************
//MS延时函数(12M晶振下测试)
//****************************************************
void Delay_ms(unsigned int n)
{
unsigned int i,j;
for(i=0;i<n;i++)
for(j=0;j<121;j++);
}
LCD1602.c:
#include "LCD1602.h"
//****************************************************
//MS延时函数(12M晶振下测试)
//****************************************************
void LCD1602_delay_ms(unsigned int n)
{
unsigned int i,j;
for(i=0;i<n;i++)
for(j=0;j<123;j++);
}
//****************************************************
//写指令
//****************************************************
void LCD1602_write_com(unsigned char com)
{
LCD1602_RS = 0;
LCD1602_delay_ms(1);
LCD1602_EN = 1;
LCD1602_PORT = com;
LCD1602_delay_ms(1);
LCD1602_EN = 0;
}
//****************************************************
//写数据
//****************************************************
void LCD1602_write_data(unsigned char dat)
{
LCD1602_RS = 1;
LCD1602_delay_ms(1);
LCD1602_PORT = dat;
LCD1602_EN = 1;
LCD1602_delay_ms(1);
LCD1602_EN = 0;
}
//****************************************************
//连续写字符
//****************************************************
void LCD1602_write_word(unsigned char *s)
{
while(*s>0)
{
LCD1602_write_data(*s);
s++;
}
}
void Init_LCD1602()
{
LCD1602_EN = 0;
LCD1602_RW = 0; //设置为写状态
LCD1602_write_com(0x38); //显示模式设定
LCD1602_write_com(0x0c); //开关显示、光标有无设置、光标闪烁设置
LCD1602_write_com(0x06); //写一个字符后指针加一
LCD1602_write_com(0x01); //清屏指令
}
HX711.c:
#include "HX711.h"
//****************************************************
//延时函数
//****************************************************
void Delay__hx711_us(void)
{
_nop_();
_nop_();
}
//****************************************************
//读取HX711
//****************************************************
unsigned long HX711_Read(void) //增益128
{
unsigned long count;
unsigned char i;
HX711_DOUT=1;
Delay__hx711_us();
HX711_SCK=0;
count=0;
while(HX711_DOUT);
for(i=0;i<24;i++)
{
HX711_SCK=1;
count=count<<1;
HX711_SCK=0;
if(HX711_DOUT)
count++;
}
HX711_SCK=1;
count=count^0x800000;//第25个脉冲下降沿来时,转换数据
Delay__hx711_us();
HX711_SCK=0;
return(count);
}