资源描述
一、 设计任务及要求:设计任务: 完成一个简单的使用数字电子秤的硬件与软件部分的设计。设计要求:1.利用单片机实现对所设计的电子秤的各项功能的控制。2.电子秤能够LCD液晶显示出商品的名称、价格,重量、总价等信息。3.电子秤具有储存几种简单商品价格的功能。4.电子秤的测量范围要求达到5KG,测量精度要求达到0.001。5.电子秤能够自动完成商品的价格计算。 指导教师签名: 2010年 6 月 16 日 二、指导教师评语:指导教师签名: 2010年 7 月 3 日 三、成绩 验收盖章 2010年 7 月 日基于单片机的实用电子秤的设计1设计目的 单片机以其功能强,体积小,功耗低,易开发等很多优势被广泛应用。本次数字电子秤的设计就是需要通过选择合适的单片机来进行主控,再结合A/D转换、键盘、液晶显示、复位电路和蜂鸣器报警驱动电路的知识,同时在软件的设计过程中用到键盘扫描、液晶显示驱动、模数转换程序及汉字库的的设计,做到对我们所学数电、模电、单片机等知识的综合应用,最终实现所设计数字电子秤的各项功能,达到“巩固知识,培养技能,学而用之”的实践目的。通过这次课程设计,不但要提高我们在工作中的学习能力、探究能力、应用能力和动手能力,还要历练我们不畏艰难、不懂便学、有漏必补的认真严谨的工作态度,强化我们的社会适应力和社会竞争力,为走向社会提前试水,完善自我。 2设计的主要内容及要求 本设计主要完成一个简单实用数字电子秤的硬件电路部分和软件部分的设计。硬件部分包括数据采集、最小系统板、人机交互界面三大部分。其中,数据采集部分由压力传感器和 A/D 转换部分组成;人机界面部分为键盘输入、液晶显示。软件部分应用单片机 C 语言实现了本设计的全部控制功能。本设计的数字电子秤要求能够显示商品的名称、价格、总量、总价等;能够自动完成商品的价格计算;能够储存几种简单商品的价格;能够具有超重提醒功能,一旦重量超出了自身重量的测量的范围,发出警报;同时对数字电子秤的测量范围要达到5KG,测量精度要求达到0.001。3整体设计方案整个数字电子秤电路由压力传感电路(ADC0832采样)、模数转换系统、单片机主控制电路、LM4229显示电路、蜂鸣器报警电路和4*4键盘电路6个部分组成。如图3.1所示。报警电路键盘电路A/D转换器压力传感电路AT89C51LCD显示电路 图3.1 基于单片机的实用电子秤组成框图电子秤的测量过程实际是通过电阻应变传感器将被测物体的重量转换成电压信号输出,电压信号经过模数转换把模拟信号转换成数字量,数字量通过显示器显示重量。打开电源,数字电子秤开始工作。接通电源时,数字电子秤进入欢迎界面“欢迎使用电子秤 设计······”。数字电子秤上MCU开始工作,键盘不断进行扫描,同时通过ADC0832也不断进行外部称量数据采样,LCD上显示“实用电子秤 名称 单价······”。当载物台上放有物体时,ADC0832立即将数据收集送给单片机处理。在键盘输入对应商品的代码编号,在240*128的LCD上可以看到相应商品的名称,单价,总重,总价格等信息。在称量的过程中,一旦物体自身的重量超出电子秤的称量范围,蜂鸣器立即会发出“滴滴····”警报声告诉工作人员,所称量物品超重。4硬件电路设计4.1整体电路图数字电子秤采用AT89C51单片机作为微处理器,接口电路由晶振、LM4229显示电路、4*4按键电路、ADC0832电路、报警电路、存储器等组成。控制器系统的硬件电路如图4.1所示。控制器系统硬件电路的工作过程是:打开电源时,MCU及各个部分电路开始工作,MCU调用内部存储数据对各部分接口电路初始化。200ms后LM4229进入欢迎界面,ADC0832不断对外部数据进行采样交给MCU进行处理,一旦有物品放入载物台,ADC0832立即发送中断请求,并将本次采集数据交给MCU处理,之后LM4229显示相应数据量。在此过程中,键盘也在不断进行扫描,一旦有键按下,单片机也会对其数据进行相应处理,然后将对LM4229进行写操作。图4.1 实用数字电子称的硬件电路图4.2压力传感器 本设计要求称量不超过5KG,误差不大于0.001KG。考虑到秤台自重、振动和冲击分量,还要避免超重损坏传感器,所以传感器量程必须大于额定称重。我们选择的是L-PSIII型传感器,量程20Kg,精度为0.01%,满量程时误差±0.002Kg ,可以满足本系统的精度要求。其原理如图4.2所示。图4.2 传感器电路工作原理称重传感器主要由弹性体、电阻应变片电缆线等组成,内部线路采用惠更斯电桥,当弹性体承受载荷产生变形时,输出信号电压可由下式给出:4.3数模转换系统首先考虑用常用的模数转换芯片adc0809,由于本设计只需采集一路数据,adc0809为并行的8路数据采集芯片,且接线较复杂,因此考虑采用串行的AD转换芯片adc0832完成设计。ADC0832 与MCS- 51 单片机接口构成了串行的8位通道。微处理器通过软件写入3位串行控制命令决定ADC0832的工作方式。CH0单端输入,输入范围0- 5V。非调整误差为±1L SB。电路仅使用微处理器的两根控制线,两根数据线可方便进行光电隔离增强抗干扰能力。适用于智能化信号检测仪器、仪表。4.4 键盘显示电路的设计本设计中采用4*4矩阵是键盘,又称行列式键盘。它有4条I/O线作为行线,用4条作为列线。用AT89S51的并行口P1接4×4矩阵键盘,行线接P1.0-P1.3口,列线接P1.4-P1.7口。在行线与列线每一个交叉点设置一个键,键盘设置了“015”个按键,其中的“0”键表示取消,其他键代表可供选择商品品种及价格。4.5 液晶显示器电路的设计 LM4229通过CD WRITE READ三个引脚的电平来确定是读数据还是读状态,或者是写数据还是写命令。数据D0-D7连接到单片机的P0口,可以和单片机进行直接的数据交换,P2口为液晶显示的控制端。5软件设计本设计中的程序由主控制程序、LM4229液晶显示驱动程序、ADC0832采样程序和4*4键盘程序组成。5.1主控制程序整个设计中采用由下向上的设计思路。主程序中主要完成对LCM4229、ADC0832、及键盘扫描程序的调用。在编写程序的过程中,各变量统一采用全局变量方式命名,同时考虑到电子秤对精度的要求,本设计中的价格及总量相关的变量全部采用浮点数。主程序流程图如图5.1所示。N开 始MCU初始化、LM4229进入欢迎界面、ADC0832初始化载物台有物体否?结 束MCU存储ADC0832采样值是否输入商品代码按键?MCU执行计算,并将结果送LM4229显示测量结束键是否按下?YYNNY开 始MCU初始化、LM4229进入欢迎界面、ADC0832初始化载物台有物体否?结 MCU存储ADC0832采样值是否输入商品代码按键?MCU执行计算,并将结果送LM4229显示测量结果键是否按下?NYNNNY图5.1 主程序流程图5.2 LM4229液晶显示驱动程序 write_data(place&0xff); /写入地址高位 write_data(place/256); /写入地址低位 write_com(0x24); /地址设置 write_com(0xb0); /设置数据自动写 write_data(ASC_MSK(c1-0x20)*16+k); /*-例如:0的ASCII码为0x30, 在ASC_MSK中的位置为0x10*16 -16字节字码依次写入LCD-*/ write_com(0xb2); /自动复位 place=place+30;LM4229液晶显示驱动程序流程图如图5.2所示。NYNY开 始写 入 控 制 字写 入 初 始 行是 否 换 行?全部数据已写完?结 束结 束左移一位右移一位NN开 始发送行扫描码发送列扫描码列扫描完毕?返回键值行扫描完毕?YYNNYY开 始写 入 控 制 字写 入 初 始 行是 否 行?全部数据已写完?结 束图5.2 LM4229液晶显示驱动程序流程图5.3 ADC0832采样程序MCU通过拉低CS、拉高CLK来启动ADC0832进行外部压力传感转换后的电压信号进行采样,每产生8个CLK脉冲,DATA获得一位完整的8bit数据,此时MCU发送中断请求,拉高CS,拉低CLK,并将数据DAT返回。ADC0832采样程序的程序流程图如图5.3所示。开 始拉低CS、拉高CLKDATA右移8位?拉高CS、拉低CLK,返回数据DAT结 束YN图5.3 ADC0832采样程序程序流程图5.4 4*4键盘程序本设计中采用了4*4矩阵式键盘,单片机定时进行查询。首先单片机发送行扫描代码,然后进行列扫描,当发现某一列出现了低电平时,即返回相应的键盘值。若没有发现则说明当前行没有键按下,行扫描右移一位,继续执行列扫描。MCU根据相应的键值,即可确定被按下的键。4*4键盘程序如图5.4所示。结 束左移一位右移一位NN开 始发送行扫描码发送列扫描码列扫描完毕?返回键值行扫描完毕?YY开 始发送行扫描码发送列扫描码列扫描完毕?返回键值结 束行扫描完毕?左移一位右移一位NNYY 图5.4 4*4键盘程序6系统仿真在protues的ISIS 7.6sp4软件环境下画出电路原理图,接下来就是将设计的程序在Keil C51 Vision3开发集成环境上编译成机器语言,进入Proteus的ISIS,鼠标左键点击菜单“Debug”, 选中“use romote debuger monitor”,便可实现KeilC与Proteus连接调试。首先在Proteus中双击单片机AT89C51,将KeilC下编程生成的 .HEX文件导入到AT89C51中,可在Proteus中单击全速仿真运行按钮,进行现象的查看,能清楚地观察到芯片上每一个引脚的电平变化,红色代表高电平,蓝色代表低电平。6.1实用电子秤初始化仿真导入main.HEX文件以后,进入仿真页面,先按开始,此时数字电子秤进入欢迎界面。LM4229上显示"欢迎使用电子秤 ·····"。如图6.1所示。图6.1 实用电子秤初始化仿真图6.2实用电子秤进入称重界面仿真接下来调节压力传感模拟电路电压,将电压设为0.00表示此时载物台上没有物体。此时LM4229切换到称量画面,显示指示“实用电子秤 单价:0.000元/千克 总重量:0.000千克 总价:00.000元”。如图6.2所示图6.2 实用电子秤进入称重界面仿真图6.3实用电子秤模拟商品选择及最大称量仿真然后,上调压力传感电压表示已载有商品,同时按下“6”号键,表示选择6号商品“苹果”。此时LM4229上显示“名称:苹果 单价:4.200元/千克 总重量:3.496千克 总价:“14.683元”(实际4.200*3.496=14.6832元)。达到基本要求。如图6.3所示。图6.3 模拟商品选择验证性称量仿真图最后,上调压力传感电压使载重达到最大,同时按下“5”号键,表示选择5号商品“西瓜”。液晶显示“名称:西瓜 单价:2.400元/千克 总重量:4.980千克 总价:“11.952元”.达到基本要求,最大称量重量4.980KG,如图6.4。图6.4 实用电子秤模拟商品最大称量仿真图7使用说明利用51系列单片机设计的电子秤不但可以满足并解决现实生活中提出的“快速、准确、连续、自动”称量要求,同时有效地避免人为误差。当载物台上放有物体时,在键盘输入对应商品的代码编号,LCD液晶上可以看到相应商品的名称,单价,总重,总价格等信息。在称量的过程中,一旦物体自身的重量超出电子秤的称量范围,蜂鸣器立即警报,告诉工作人员,所称量物品超重。在称量过程中还可以通过键盘选择商品不同的价位。8设计总结 这次课程设计是对前面所学知识非常系统全面的一次检验。通过这次课程设计与仿真,让我更明确的了解了一些芯片的用途功能,也熟练了对它们的运用。在这个设计的过程中,我需要不断地思考,不断地请教,不断地寻找资料以借鉴,不断的用对知识的深入掌握去解决设计中存在的一些问题和调试时出现的一些故障。虽然说这样的设计很难很烦很累人,但是确实是充实的,是让人感到有意义的。这次课程设计,不但让我了解了一个数字电子秤,更让我收获了专业知识以外的东西,那就是学会了坚信、坚持,同时也磨砺了我的意志和耐心。真的,作为一个本来对这个专业不是很感兴趣的学生,让我收获了一份从来没有过的成就感。虽然到现在我对这个设计的部分原理还是不能用很专业的语言讲述出来,但是当我最初做成功这个设计的时候,我有一种说不出的激动,我写下一句话:“人很怪,上天给予每个人的都是公平的,没有谁没能力去做事,只是在于那个人愿不愿意去做,敢不敢去做,能不能坚持去做!”是的,这就是我这次课程设计之后最大的收获!虽然对这个专业依旧不是很感兴趣,但是我还是想通过这份设计报告来建议老师,希望以后能多搞一些像这样很实际的实践课程,我们作为学生,的确需要好的成绩,但更需要用这种对知识非常全面统一的检验来考察自己,证明自己,坚持自己。参考文献1 郭天祥.51单片机C语言教程M.北京:电子工业出版社,2009:342-354.2 李建忠.单片机原理及应用M.西安:西安电子科技大学出版,2002:63-80.3 张俊谟.单片机中级教程M.北京:北京航空航天大学出版,2000:36-44.4 陈东云,杜敬仓.单片机原理与开发指导M.北京:机械工业出版社,2006:122-156.5 彭伟.单片机C语言程序设计实训100例M.北京:电子工业出版社,2009:160-167.附录A:#include<reg51.h>#include<intrins.h>#include <absacc.h>#include <math.h>#include<lm4229.h>#define uchar unsigned char#define uint unsigned intsbit ADCS =P35; sbit ADDI =P37; sbit ADDO =P37; sbit ADCLK =P36; uint x1,y1,z1=0,w1;uchar ad_data,k,n,m,e,num,s; /采样值存储uint temp1;sbit beep =P30; char press_data; /标度变换存储单元float press;unsigned char ad_alarm,temp; /报警值存储单元unsigned char abc5=48,46,48,48,48;unsigned char price_all6=48,48,46,48,48,48;float price_unit10=5.5,2.8,3.6,4.5,2.4,4.2,3.8,6.0,1.5,0; /商品初始单价uchar price_danjia5=48,46,48,48,48;float price;uint price_temp1,price_temp2; /商品总价 uchar Adc0832(unsigned char channel);void alarm(void);void data_pro(void);void delay(uint k);void keyscan();void disp_init();void price_jisuan();/*主函数*/void main(void) delay(500); /系统延时500ms启动 /ad_data=0; /采样值存储单元初始化为0 lcd_init(); /显示初始化 disp_init(); /开始进入欢迎界面 delay(1000); /延时进入称量画面 clear_lcd(0,4,40); clear_lcd(16,0,100); clear_lcd(28,0,40); clear_lcd(44,0,100); clear_lcd(56,0,40); clear_lcd(72,0,100); clear_lcd(84,0,40); clear_lcd(100,0,100); clear_lcd(112,0,40); write_lcd(0,8,"实用电子秤"); while(1) ad_data =Adc0832(0); /采样值存储单元初始化为0 alarm(); data_pro(); /读取重量 keyscan(); /查询商品种类 write_lcd(40,0,"-"); write_lcd(56,0,"单 价:"); write_lcd(56,11,price_danjia); write_lcd(56,20,"元/千克"); write_lcd(72,0,"总重量:"); write_lcd(72,11,abc); write_lcd(72,20,"千克"); write_lcd(88,0,"总 价:"); price_jisuan(); /计算出价格 write_lcd(88,10,price_all); write_lcd(88,20,"元"); write_lcd(112,0,"设计学生:0712201-23 王 超");/*读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); /return ad k void data_pro(void) unsigned int; if(0<ad_data<256) int vary=ad_data;press=(0.019531*vary); temp1=(int)(press*1000); /放大1000倍,便于后面的计算 abc0=temp1/1000+48; /取压力值百位abc1=46;abc2=(temp1%1000)/100+48; /取压力值十位abc3=(temp1%1000)%100)/10+48; /取压力值个位abc4=(temp1%1000)%100)%10+48;/取压力值十分位 /*报警子函数*/void alarm(void) if(ad_data>=256) beep=0; /则启动报警 else beep=1; void delay(uint k) uint i,j; for(i=0;i<k;i+) for(j=0;j<100;j+); /开机欢迎界面void disp_init() write_lcd(0,8,"欢迎使用电子秤"); write_lcd(16,0,"-"); write_lcd(28,0,"设计学生:王 超"); write_lcd(44,0,"-"); write_lcd(56,0,"班级学号:0712201-23"); write_lcd(72,0,"-"); write_lcd(84,0,"指导老师:谭 跃"); write_lcd(100,0,"-"); write_lcd(112,0,"设计日期:2010年6月29日"); /键盘服务程序void keyscan()P1=0xfe;temp=P1;temp=temp&0xf0;while(temp!=0xf0)delay(5);temp=P1;temp=temp&0xf0;while(temp!=0xf0)temp=P1;switch(temp) case 0xee:num=1,price=price_unit0, write_lcd(24,0,"名 称: 杏 仁");break;case 0xde:num=2,price=price_unit1,write_lcd(24,0,"名 称: 李 子");break;case 0xbe:num=3,price=price_unit2,write_lcd(24,0,"名 称: 草 莓");break;case 0x7e:num=4,price=price_unit3,write_lcd(24,0,"名 称: 葡 萄");break;while(temp!=0xf0)temp=P1;temp=temp&0xf0;P1=0xfd;temp=P1;temp=temp&0xf0;while(temp!=0xf0)delay(5);temp=P1;temp=temp&0xf0;while(temp!=0xf0)temp=P1;switch(temp)case 0xed:num=5,price=price_unit4,write_lcd(24,0,"名 称: 西 瓜");break;case 0xdd:num=6,price=price_unit5,write_lcd(24,0,"名 称: 苹 果");break;case 0xbd:num=7,price=price_unit6,write_lcd(24,0,"名 称: 雪 梨");break;case 0x7d:num=8,price=price_unit7,write_lcd(24,0,"名 称: 核 桃");break;while(temp!=0xf0)temp=P1;temp=temp&0xf0;P1=0xfb;temp=P1;temp=temp&0xf0;while(temp!=0xf0)delay(5);temp=P1;temp=temp&0xf0;while(temp!=0xf0)temp=P1;switch(temp)case 0xeb:num=9,price=price_unit8,write_lcd(24,0,"名 称: 香 蕉");break;case 0xdb:num=10,price=price_unit9,write_lcd(24,0,"名 称: 商品代码");break;case 0xbb:num=11,price=price_unit1;break;case 0x7b:num=12,price=price_unit2;break;while(temp!=0xf0)temp=P1;temp=temp&0xf0;P1=0xf7;temp=P1;temp=temp&0xf0;while(temp!=0xf0)delay(5);temp=P1;temp=temp&0xf0;while(temp!=0xf0)temp=P1;switch(temp)case 0xe7:num=13,price=price_unit3;break;case 0xd7:num=14,price=price_unit4;break;case 0xb7:num=15,price=price_unit5;break;case 0x77:num=16,price=price_unit6;break;while(temp!=0xf0)temp=P1;temp=temp&0xf0; price_temp1=(int)(price*1000); price_danjia0=price_temp1/1000+48; /取单价个位price_danjia1=46; price_danjia2=(price_temp1%1000)/100+48; /取单价十分位 price_danjia3=(price_temp1%1000)%100)/10+48; /取单价百分位 price_danjia4=(price_temp1%1000)%100)%10+48;/取单价千分位void price_jisuan() price_temp2=(int)(price*press*1000); price_all0=price_temp2/10000+48; price_all1=(price_temp2/1000)%10+48; price_all2=46;price_all3=(price_temp2%1000)/100+48; price_all4=(price_temp2%1000)%100)/10+48; price_all5=(price_temp2%1000)%100)%10+48; 19
展开阅读全文