《单片机原理及应用课程设计》报告
设计题目: 电子秤设计
专 业:
班 级:
姓 名:
学 号:
起迄日期: 2017年5月26日2017年6月29日
指导教师:
系(室)主任:
目录
1 引言..............................................................1
2 设计的任务与要求..................................................1
3 总体方案设计......................................................2
3.1 系统总体方案设计与论证..........................................2
3.2 硬件的方案设计与选型............................................2
3.2.1 压力传感器....................................................2
3.2.2 放大器和A/D转换..............................................4
3.2.3 显示模块......................................................5
4 硬件电路设计....................................................5
4.1 基于51单片机的主控电路.........................................5
4.1.1 硬件框图......................................................5
4.1.2 整体电路图....................................................5
4.2 压力传感器电路..................................................6
4.3 A/D转化电路.....................................................7
4.4 显示电路........................................................8
4.5 晶振电路和复位电路..............................................9
5 软件系统设计...................................................10
5.1 主程序流程图...................................................10
5.2 AD转换子程序流程图.............................................11
5.3 显示子程序流程图...............................................11
6 仿真测试.........................................................12
7 总结.............................................................14
8 参考文献.........................................................15
9 程序清单.........................................................16
1 引言
电子秤的发展过程与其它事物一样,也经历了由简单到复杂,由粗糙到精密、由机械到机电结合再到全电子化、由单一功能到多功能的过程。特别是近30年以来,工艺流程中的现场称重、配料定量称重、以及产品质量的监测等工作,都离不开能输出电信号的电子衡器。这是由于电子衡器不仅能给出质量或重量信号,而且也能作为总系统中的一个单元承担着控制和检验功能,从而推进工业生产和贸易交往的自动化和合理化。
经过40多年的不断改进与完善,我国电子衡器从最初的机电结合型发展到现在的全电子型和数字智能型。现今电子衡器制造技术及应用得到了新发展。电子称重技术从静态称重向动态称重发展:计量方法从模拟测量向数字测量发展;测量特点从单参数测量向多参数测量发展,特别是对快速称重和动态称重的研究与应用。通过分析近年来电子衡器产品的发展情况及国内外市场的需求,电子衡器总的发展趋势是小型化、模块化、集成化、智能化;其技术性能趋向是速率高、准确度高、稳定性高、可靠性高;其功能趋向是称重计量的控制信息和非控制信息并重的“智能化”功能;其应用性能趋向于综合性和组合性。电子秤是电了衡器中的一种,衡器是国家法定计量器具,是围计民生、国防建设、科学研究、内外贸易不可缺少的计量设备,衡器产品技术水平的高低,将直接影响各行各业的现代化水平和社会经济效益的提高。
单片机以其功能强,体积小,功耗低,易开发等很多优势被广泛应用。但单片机不是万能的,也存在不适合的场合,我们要充分利用单片机的内部资源和选择合适的单片机来完成我们的设计。本数字电子秤的设计过程中需要用到A/D转换、液晶显示、复位电路的知识,同时在软件的设计过程中需要用到液晶显示驱动、模数转换程序的设计,可以很好的将数电、模电、单片机知识进行综合应用。在综合应用中进一步熟悉单片机设计的开发各个流程,最终达到"巩固基础、注重设计、培养技能、追求创新、走向实用"的目的。
2 设计的任务与要求
本课程设计基于51单片机设计一个电子秤,该电子秤能完成称重和显示所称的重量,是一种小型化的电子称量仪器。当被称物体放置在秤体的秤台上时,其重量便通过秤体传递到称重传感器,传感器随之产生力电阻应变效应,将物体的重量转换成与被称物体重量成一定函数关系(一般成正比关系)的电信号(电压或电流等)。此信号由放大电路进行放大、经滤波后再由模/数( A/D)器进行转换,数字信号再送到微处器的CPU处理。运算结果送到内存贮器,需要显示时,CPU发出指令,从内存贮器中读出送到显示器显示。
设计要求如下:1、利用压力传感器检测重量信号,经放大和A/D转换,并经单片机处理后在LED上显示出被称重量值。2、最小显示单位为1克。
3 总体方案设计
3.1 系统总体方案设计与论证
根据电子秤的工作原理可以将电子秤大致能划分为三大部分,数据采集模块、控制器模块和人机交互界面模块。图3.1为系统的整体框图。
数据采集模块由压力传感器、信号的前级处理和A/D转换部分组成。测量过程中把被测物体的重量通过传感器将重量信号转化为电压信号输出。信号的前级处理将来自传感器的微弱信号进行滤波和放大,放大后的电压信号经过模数转换把模拟量转换成数字量。
控制器模块将数据采集模块传来的数字信号进行处理,完成被测物体重量的判断、显示等功能。此部分对软件的设计要求比较高,系统的大部分功能都需要软件来控制。
人机交互界面模块主要由显示器组成。显示器采用LCD液晶显示器,可以直观的显示物品的重量。
图3.1系统整体框图
3.2 硬件的方案设计与选型
3.2.1 压力传感器
压力传感器是电子秤中最主要的一个元器件。因为它关乎着电子秤的量程、精度等性能。市场上使用和出售的电子秤主要使用的压力传感器有电容式、电阻应变式和压电式压力传感器等。在称重传感器的选型时应该充分考虑其精度、灵敏度、稳定性、安全等级、安装环境是不是满足设计的要求。再在其中选择最适合设计要求的型号。以下是三种称重传感器的比较:
(1)电容式压力传感器是把金属薄膜和一个固定的电极形成一个类似电容的结构,当承受重量时,金属弹性元件将发生微小的位移,从而引起电容内部的电容量的变化,用外部测量电路得到变化量从而求得重量。这种传感器的精度和灵敏度高但其寿命一般只有几年,而且不稳定,容易受到外界非人为因素的干扰。
(2)压电式压力传感器时利用正压电效应制成的,当内部晶体受到压力时,内部将产生正、负电荷的相对位移,使晶体的两端生成不同极性(正极、负极)的电荷,其密集程度与测量的重量相对应,从而进行测量。这种传感器不但稳定性好而且精度和灵敏度都很高,但是它的缺点是量程小,不能用于大吨位的测量,一般使用于医疗器械上。
(3)电阻应变片式压力传感器的原理是黏有电阻应变片的弹性元件(一般为金属)受到重物或者外力而发生微小形变时导致电阻值发生改变,从而用于测量重力。这种传感器的稳定性非常好,可以在比较差的环境中使用,而且其精度和准确度也不低。
基于精度、成本等要求,我最终选择HL-8型的电阻应变片式传感器。
表3.2 传感器技术参数
根据上表得出HL-8型3KG电阻应变片式传感器的精度3Kg*0.05%=1.5g。
由于使用的是4.5V供电电压,所以满量程输出电压=4.5V*1mV/V=4.5mV也就是当称重重量为0~3Kg时,对应的输出电压为0~4.5mV,是一种线性的对应关系。
电阻应变片式压力传感器是由一块贴有电阻应变片的金属弹块和电线成,其内部使用的一般是惠更斯电桥。当受到所称量的重物时,金属弹性块就会带动电阻式应变片发生微小的形变,使得贴在上面的电阻式应变片R1、R4受到压力弯曲拉伸,阻值增加;R2、R3被压缩,阻止减小,从而使电桥失去平衡,产生差动电压信号,电压信号与作用在传感器上的P的大小成正比,将重物的压力转换成相应的电。压信号输出,供单片机进行处理。其工作原理图如下图所示:
图3.2 压力传感器工作原理
3.2.2 放大器和A/D转换
由于传感器输出的电压很小一般只有几毫伏,即使通过电桥电路转换后的信号还是不够被单片机控制。所以一般都需要放大模块来放大信号和对信号进行A/D转换,转换成数字信息送入控制器,在控制器的控制下,对数据进行基本运算和逻辑判断。
方案一:使用差分比例运放电路
使用运放搭建一个差分比例运放电路,对微小的电压信号进行放大。并需要在后面加一个A/D转换模块,把经放大器放大后的模拟信号转换为数字信号,送入单片机。但是一般的运放放大效果不是很好且抗干扰能力较弱,还有电路设计比较复杂。
方案二:使用HX711A/D转换模块对信号进行放大和转换
HX711是一款专为高精度称重传感器而设计的24位A/D转换器芯片。与同类型其它芯片相比,该芯片集成了包括稳压电源、片内时钟振荡器等其它同类型芯片所需要的外围电路,具有集成度高、响应速度快、抗干扰性强等优点。降低了电子秤的整机成本,提高了整机的性能和可靠性。芯片内提供的稳压电源可以直接向外部传感器和芯片内的A/D转换器提供电源,系统板上无需另外的模拟电源。HX711A/D与AT89C51单片机的接线也比较简单,可以使用IO口驱动控制信号,不需再对内部的寄存器进行编程,使得程序部分更加简洁。
HX711A/D转换模块特点:
(1)两路可选择差分输入
(2)片内低噪声可编程放大器,可选增益为64 和128
(3)片内稳压电路可直接向外部传感器和芯片内A/D 转换器提供电源
(4)片内时钟振荡器无需任何外接器件,必要时也可使用外接晶振时钟或上电自动复位电路
(5)简单的数字控制和串口通讯:所有控制由管脚输入,芯片内寄存器无需编程
(6)可选择10Hz 或80Hz 的输出数据速率
(7)同步抑制50Hz 和60Hz 的电源干扰
(8)耗电量(含稳压电源电路):典型工作电流:<1.7mA, 断电电流:<1μA
(9)工作电压范围:2.6 ~ 5.5V
(10)工作温度范围:-20 ~ +85℃
(11)16 管脚的SOP-16 封装
在程序中选用了128的放大倍数,当输出电压为满量程电压4.5mV时,放大后的电压为576mV,进过AD转换后输出的24bit的数字值576mV*2^24/4.5V≈2147484。
3.2.3 显示模块
方案一:LED数码管显示
优点:体积小,能耗低,结构简单。
缺点:接线较多会使电路变复杂,显示内容少。
方案二:LCD1602液晶显示屏
优点:线路简单,显示内容较多,单片机可以直接驱动
由于电子秤设计的显示模块需要显示多位数字和字母,如果采用数码管显示的话会占用多个单片机I/O口,使电路变得更为复杂不美观。而且本课设只需要显示字母和数字,所以选LCD1602符合全部条件,能够被使用。
4 硬件电路设计
4.1 基于51单片机的主控电路
4.1.1 硬件框图
图4.1 总体硬件框图
当压力传感器受到不同重量的压力后,会产生不同大小的微弱电压信号,电压信号经过HX711模块放大128倍和转换为数字信号后被送入单片机,再经过计算和处理后再在液晶显示所称重量。
4.1.2 整体电路图
图4.2整体电路图
因为protues元件库里没有应变片式压力传感器和HX711A/D模块,所以我用两个滑动变阻器代替4个桥臂,靠改变滑动变阻器的阻值来模拟传感器受力形变后阻值的改变,电压信号再经ADC0832转换成数字信号传给单片机。
4.2 压力传感器电路
图4.3实际应变片式压力传感器电路图
电桥的四个桥臂上接工作应变片,都参与机械形变,同处一个温度场,温度影响互相抵消,电压输出灵敏度高。当4个应变片的材料、阻值都相同时,可以推导出以下公式:
(4.2)
因为protues元件库里没有应变片式压力传感器,所以我用两个滑动变阻器代替4个桥臂,靠改变滑动变阻器的阻值来模拟传感器受力形变后阻值的改变,经过电桥转换成电压信号。
图4.4 仿真压力传感器电路图
4.3 A/D转换电路
图4.5 实际HX711A/D转换电路模块
串口通讯线由管脚PD_SCK和DOUT组成,用来输出数据,选择输入通道和增益。当数据输出管脚DOUT为高电平时,表明A/D转换器还未准备好输出数据,此时串口时钟输入信号PD_SCK应为低电平。当DOUT从高电平变低电平后,PD_SCK应输入25至27个不等的时钟脉冲。其中第一个时钟脉冲的上升沿将读出输出24位数据的最高位(MSB),直至第24个时钟脉冲完成,24位输出数据从最高位至最低位逐位输出完成。
因为protues元件库里没有HX711A/D模块,所以我用ADC0832代替,经过电桥转换的电压信号经ADC0832转换成数字信号传给单片机。
图4.6 仿真AD转换电路
4.4 显示电路
LCD1602液晶显示模块的引脚连线如图。其中第1、2、3脚为电源;液晶的控制口RS、RW和使能端EN分别接单片机的P2.0、P2.1、P2.2,用于对状态的输入;数据口D0到D7接单片机的P0.0-P0.7口用于数据传输,由于单片机P0没有上拉电阻,所以再再P0口接一个10K的排阻RP1。
图4.7 LCD1602液晶显示模块电路
4.5 晶振电路和复位电路
晶振采用 12MHz。复位电路采用上电加按钮复位。
晶振电路:
图4.5.1晶振电路
复位电路:
图4.8 复位电路
5 软件系统设计
5.1 主程序流程图
主程序的功能是调用子程序和对系统进行初始化,本课设主程序调用各种子程序来实现电子秤每半秒进行一次称重的功能,主程序流程图如下图所示:
图5.1主程序流程图
5.2 A/D转换子程序流程图
首先,单片机选A/D转换器,然后发出信号启动A/D转换进行信号采集,对A/D转换器的数据输出口送来的数据进行存储。
图5.2 AD转换程序流程图
5.3 显示子程序流程图
LCD显示子程序的设计一般要先确定LCD的初始化、光标定位、确定显示字符以及字符串。
图5.3 显示子程序流程图
6 仿真测试
压力传感器输出0V时电子秤所能称量的最小重量:0.019Kg
图6.1 电子秤最小重量仿真图
压力传感器输出1V时电子秤显示的重量:0.996Kg
图6.2 压力传感器输出1V时的仿真图
压力传感器输出3V时电子秤显示的重量:2.988Kg
图6.3 压力传感器输出3V时的仿真图
压力传感器输出5V时电子秤显示满量程的重量:4.980Kg
图6.4 压力传感器输出5V时的仿真图
表6.1 传感器输出电压与重量关系
表6.1是仿真测试时得出的实验数据,从表6.1可以看出传感器输出电压与重量之间是线性关系,从实验效果上验证仿真是成功的。
7 总结
本次课程设计做的电子秤,主要利用了AT89C51单片机、HL-8型电阻应变片式称重传感器以及HX711A/D转换模型,LCD1602显示模块,通过C语言编程来实现电子秤的显示与控制。本次设计完成了称重,显示重量功能,精度达到要求的1g。刚开始的时候还在纠结是用LED数码管还是用LCD1602液晶显示屏,因为LCD1602的编程没学过,而且初始化等程序较多。但后来发现其实LCD1602的程序都是模块化的程序并且能查到每个模块程序具体怎么样使用,所以后来果断选择LCD1602来显示电子秤所秤的重量。
因为第一次用单片机做课程设计在这之前只在单片机实验室用过。以前做仿真用的是Multisim,但Multisim不能仿真单片机课设,所以自学了Protues的仿真过程。Protues仿真器真的很强大,可以和Keil联调,看来Multisim落伍了。本次课程设计使用Keil编写程序,因为大三上学期在做试验时学过怎么使用Keil,所以对于怎么使用Keil并没有什么问题。因为Protues元件库里没有应变片式压力传感器和HX711A/D模块,所以一开始不知道要怎么做仿真,后来在网上查资料后发现可以用两个滑动变阻器代替应变片式压力传感器,再用ADC0832代替HX711A/D模块。用Keil编写完程序后就生成HEX文件然后在Protues中把程序导入51单片机中,调试时发现结果是什么文件打不开导致仿真出错,只好求助万能的百度,之后设置了以下电脑属性里的变量才终于仿真成功了。
通过本次课程设计,从电路原理图的设计到编程调试,让我仔细的回顾了大学三年的学习知识,包括单片机、模电、数电、电工实习的重要基础课程,相信在以后还会用到这些知识。同时这次课程设计还有一些不足之处,比如,精度还差一点,规定是1g,但是结果只有1.5g。
8 参考文献
[1]曹巧媛主编. 单片机原理及应用(第二版). 北京:电子工业出版社,2002
[2]谭浩强著.C程序设计.北京:清华大学出版社,2007;
[3]李朝青 单片机原理及接口技术(第3版)北京航空航天大学出版社 2005
[4]程林 超省电型电子秤的设计方案[J].福建:福建省科学技术研究,2008.
[5]程飞 基于AT89C2051单片机的电子称设计[J].电脑知识与技术,2009.
[6]张景元 李业德 一种基于单片机的多功能电子称[J].微计算机信息,2006.
[7]何立民 单片机高级教材[M].北京:航空航天大学出版社,2000
[8]姜志海等. 单片机的C语言程序设计与应用(第3版).电子工业出版社,2015.
9 程序清单
#include<reg51.h>
#include<intrins.h>
#include <absacc.h>
#include <math.h>
#define uchar unsigned char
#define uint unsigned int
#define BUSY 0x80 //常量定义
#define DATAPORT P0 //单片机P0口定义
//ADC0832的引脚
sbit ADCS =P3^5; //ADC0832片选信号
sbit ADDI =P3^7; //ADC0832数据信号输入,选择通道控制
sbit ADDO =P3^7; //ADC0832数据信号输出,转换数据输出
sbit ADCLK =P3^6; //ADC0832芯片时钟输入
sbit LCM_RS=P2^0; //寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器
sbit LCM_RW=P2^1; //读写信号线,高电平1时进行读操作,低电平1时进行写操作
sbit LCM_EN=P2^2; //使能端,高电平1时读取信息,负跳变时执行指令
uchar ad_data; // //adc采样值存储单元
char press_data; //标度变换存储单元
unsigned char press_ge=0; //显示值百位
unsigned char press_shifen=0; //显示值十位
unsigned char press_baifen=0; //显示值个位
unsigned char press_qianfen=0; //显示值十分位
uchar code str0[]={"Weight: . Kg "}; //要显示的内容
void delay(uint);
void lcd_wait(void);
void delay_LCM(uint); //LCD延时子程序
void initLCM( void); //LCD初始化子程序
void lcd_wait(void); //LCD检测忙子程序
void WriteCommandLCM(uchar WCLCM,uchar BusyC); //写指令到ICM子函数
void WriteDataLCM(uchar WDLCM); //写数据到LCM子函数
void DisplayOneChar(uchar X,uchar Y, uchar code*DData); //显示指定坐标的一个字符子函数
void DisplayListChar(uchar X,uchar Y,uchar code *DData); //显示指定坐标的一串字符子函数
void display(void); //系统显示子函数
uchar Adc0832(unsigned char channel); //AD转换子函数
void data_pro(void); //采样值标度变换子函数
/**********main funcation************/
void main(void)
{
delay(500); //系统延时500ms启动
ad_data=0; //采样值存储单元初始化为0
initLCM( ); //初始化LCD1602
WriteCommandLCM(0x01,1); //清显示屏
DisplayListChar(0,0,str0); //显示"Weight: . Kg "
while(1)
{
ad_data =Adc0832(0); //采样值存储单元初始化为0
data_pro(); //采样值标度变换
display(); //显示重量
}
}
/*********延时K*1ms,12.000mhz**********/
void delay(uint k)
{
uint i,j;
for(i=0;i<k;i++)
{
for(j=0;j<60;j++)
{;}
}
}
/**********写指令到ICM子函数************/
void WriteCommandLCM(uchar WCLCM,uchar BusyC)
{
if(BusyC)lcd_wait();
DATAPORT=WCLCM; //P0口输出高位
LCM_RS=0; // 选中指令寄存器
LCM_RW=0; // 写模式
LCM_EN=1;
_nop_();
_nop_();
_nop_();
LCM_EN=0;
}
/**********写数据到LCM子函数************/
void WriteDataLCM(uchar WDLCM)
{
lcd_wait( ); //检测忙信号
DATAPORT=WDLCM;
LCM_RS=1; // 选中数据寄存器
LCM_RW=0; // 写模式
LCM_EN=1;
_nop_();
_nop_();
_nop_();
LCM_EN=0;
}
/***********lcm内部等待函数*************/
void lcd_wait(void)
{
DATAPORT=0xff; //读LCD前若单片机输出低电平,而读出LCD为高电平,则冲突,Proteus仿真会有显示逻辑黄色
LCM_EN=1;
LCM_RS=0;
LCM_RW=1;
_nop_();
_nop_();
_nop_();
while(DATAPORT&BUSY)
{ LCM_EN=0;
_nop_();
_nop_();
LCM_EN=1;
_nop_();
_nop_();
}
LCM_EN=0;
}
/**********LCM初始化子函数***********/
void initLCM( )
{
DATAPORT=0;
delay(15);
WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号
delay(5);
WriteCommandLCM(0x38,0);
delay(5);
WriteCommandLCM(0x38,0);
delay(5);
WriteCommandLCM(0x38,1);//8bit数据传送2行显示,5*7字型检测忙信号
WriteCommandLCM(0x08,1); //关闭显示,检测忙信号
WriteCommandLCM(0x01,1); //清屏,检测忙信号
WriteCommandLCM(0x06,1); //显示光标右移设置,检测忙信号
WriteCommandLCM(0x0c,1);//显示屏打开光标不显示,不闪烁,检测忙信号
}
/****显示指定坐标的一个字符子函数****/
void DisplayOneChar(uchar X,uchar Y,uchar DData)
{
Y&=0x01;
X&=0x0f;
if(Y)X|=0x40; //若y为1(显示第二行),地址码+0X40
X|=0x80; //指令码为地址码+0X80
WriteCommandLCM(X,1);
WriteDataLCM(DData);
}
/*******显示指定坐标的一串字符子函数*****/
void DisplayListChar(uchar X,uchar Y,uchar code *DData)
{
uchar ListLength=0;
Y&=0x01;
X&=0x0f;
while(X<16)
{
DisplayOneChar(X,Y,DData[ListLength]);
ListLength++;
X++;
}
}
/*****************系统显示子函数*****************/
void display(void)
{
WriteCommandLCM(0x0c,1); //显示屏打开光标不显示,不闪烁,检测忙信号
DisplayListChar(0,0,str0); //显示"Weight: . Kg "
DisplayOneChar(8,0,press_ge+0x30); //显示值百位
DisplayOneChar(10,0,press_shifen+0x30); //显示值十位
DisplayOneChar(11,0,press_baifen+0x30); //显示值个位
DisplayOneChar(12,0,press_qianfen+0x30); //显示值十分位
delay(1000); //稳定显示
}
/************读ADC0832函数************/
uchar Adc0832(unsigned char channel) //AD转换,返回结果
{
uchar i=0;
uchar j;
uint dat=0;
uchar ndat=0;
if(channel==0)channel=2;
if(channel==1)channel=3;
ADDI=1;
_nop_();
_nop_();
ADCS=0;//拉低CS端
_nop_();
_nop_();
ADCLK=1;//拉高CLK端
_nop_();
_nop_();
ADCLK=0;//拉低CLK端,形成下降沿1
_nop_();
_nop_();
ADCLK=1;//拉高CLK端
ADDI=channel&0x1;
_nop_();
_nop_();
ADCLK=0;//拉低CLK端,形成下降沿2
_nop_();
_nop_();
ADCLK=1;//拉高CLK端
ADDI=(channel>>1)&0x1;
_nop_();
_nop_();
ADCLK=0;//拉低CLK端,形成下降沿3
ADDI=1;//控制命令结束
_nop_();
_nop_();
dat=0;
for(i=0;i<8;i++)
{
dat|=ADDO;//收数据
ADCLK=1;
_nop_();
_nop_();
ADCLK=0;//形成一次时钟脉冲
_nop_();
_nop_();
dat<<=1;
if(i==7)dat|=ADDO;
}
for(i=0;i<8;i++)
{
j=0;
j=j|ADDO; //收数据
ADCLK=1;
_nop_();
_nop_();
ADCLK=0; //形成一次时钟脉冲
_nop_();
_nop_();
j=j<<7;
ndat=ndat|j;
if(i<7)ndat>>=1;
}
ADCS=1;//拉低CS端
ADCLK=0;//拉低CLK端
ADDO=1;//拉高数据端,回到初始状态
dat<<=8;
dat|=ndat;
return(dat); //采样值AD转换后返回
}
/*********采样值放大子程序********/
void data_pro(void)
{
unsigned int temp;
float press;
if(0<ad_data<256) //当压力值介于0到5之间时,遵循线性变换
{
int vary=ad_data;
press=(0.0195312*vary);
temp=(int)(press*1000); //放大1000倍,便于后面的计算
press_ge=temp/1000; //取压力值百位
press_shifen=(temp%1000)/100; //取压力值十位
press_baifen=((temp%1000)%100)/10; //取压力值个位
press_qianfen=((temp%1000)%100)%10; //取压力值十分位
}
}
|