硬件课程设计报告剖析.docx
《硬件课程设计报告剖析.docx》由会员分享,可在线阅读,更多相关《硬件课程设计报告剖析.docx(25页珍藏版)》请在冰豆网上搜索。
硬件课程设计报告剖析
硬件课程设计实践报告
题目:
智能数字钟
简易计算器
班级:
学号:
姓名:
指导教师:
中国矿业大学计算机学院
2012年12月
目录
1、开发背景………………………………………………………………………3
2、STC89C52单片机引脚图3
3、电路设计及主要功能4
3.1智能数字钟……………………………………………………4
3.2简易计算器…………………………………………………………6
4、编程思想……………………………………………………………………8
5、程序框图……………………………………………………………………10
6、体会与总结……………………………………………………………………12
7、附核心代码……………………………………………………………………13
1.开发背景
单片机的出现是计算机制造技术高速发展的产物,它是嵌入式控制系统的核心,如今,它已广泛的应用到我们生活的各个领域,电子、科技、通信、汽车、工业等。
经历了SCM、MCU、SoC三大阶段,早期的SCM单片机都是8位或4位的。
其中最成功的是INTEL的8031,此后在8031上发展出了MCS51系列MCU系统。
基于这一系统的单片机系统直到现在还在广泛使用。
随着工业控制领域要求的提高,开始出现了16位单片机,但因为性价比不理想并未得到很广泛的应用。
90年代后随着消费电子产品大发展,单片机技术得到了巨大提高。
随着INTELi960系列特别是后来的ARM系列的广泛应用,32位单片机迅速取代16位单片机的高端地位,并且进入主流市场。
2.STC89C52引脚图
3.电路设计及主要功能
3.1智能数字钟
3.1.1功能简介
基于STC89C52单片机作为主控系统,实时读取DS1302芯片中的计时数据,用8位数码管显示当前的年月日、时分秒、星期等信息,并可实现K3、K4、K5调时和设定闹钟功能,通过蜂鸣器播放音乐来响闹钟。
3.1.2原理简介
1.DS1302芯片原理
(1)DS1302实时时钟具有能计算2100年之前的秒、分、时、日、日期、星期、月、年的能力,还有闰年调整的能力。
(2)内部含有31个字节静态RAM,可提供用户访问。
(3)采用串行数据传送方式,使得管脚数量最少,简单SPI3线接口。
(4)工作电压范围宽:
2.0~5.5V。
(5)工作电流:
2.0V时,小于300nA。
(6)时钟或RAM数据的读/写有两种传送方式:
单字节传送和多字节传送方式。
(7)采用8脚DIP封装或SOIC封装。
(8)与TTL兼容,Vcc=5V。
(9)可选工业级温度范围:
-40C~+85C。
(10)具有涓流充电能力。
(11)采用主电源和备份电源双电源供应。
(12)备份电源可由电池或大容量电容实现。
2.数码管显示原理
我们最常用的是七段式和八段式LED数码管,八段比七段多了一个小数点,其他的基本相同。
所谓的八段就是指数码管里有八个小LED发光二极管,通过控制不同的LED的亮灭来显示出不同的字形。
数码管又分为共阴极和共阳极两种类型,其实共阴极就是将八个LED的阴极连在一起,让其接地,这样给任何一个LED的另一端高电平,它便能点亮。
而共阳极就是将八个LED的阳极连在一起。
其原理图如下。
其中引脚图的两个COM端连在一起,是公共端,共阴数码管要将其接地,共阳数码管将其接正5伏电源。
一个八段数码管称为一位,多个数码管并列在一起可构成多位数码管,它们的段选线(即a,b,c,d,e,f,g,dp)连在一起,而各自的公共端称为位选线。
显示时,都从段选线送入字符编码,而选中哪个位选线,那个数码管便会被点亮。
数码管的8段,对应一个字节的8位,a对应最低位,dp对应最高位。
所以如果想让数码管显示数字0,那么共阴数码管的字符编码为00111111,即0x3f;共阳数码管的字符编码为11000000,即0xc0。
3.按键检测原理
当用手按下一个键时,如图3-6所示,往往按键在闭合位置和断开位置之间跳几下才稳定到闭合状态的情况;在释放一个键时,也回会出现类似的情况。
这就是抖动。
抖动的持续时间随键盘材料和操作员而异,不过通常总是不大于10ms。
很容易想到,抖动问题不解决就会引起对闭合键的识别。
用软件方法可以很容易地解决抖动问题,这就是通过延迟10ms来等待抖动消失,这之后,在读入键盘码。
3.2简易计算器
3.2.1功能简介
用单片机作为主控芯片,通过矩阵键盘进行数据输入,进行相应的加、减、乘、除的运算,并在LCD上显示相应的结果,主要功能特点如下:
(1)LCD的第一行显示运算式子,第二行显示运算结果,在任何时候按下AC清零按键时候,都必须退出当前计算,返回初始状态,等下新的一次运算。
(2)当运算完第一次完整的计算以后,可以在不按任何按键的情况下,进行新的一轮运算,若运算完一次运算后继续按运算符按键,则利用之前一次的结果作为第一个算数,直接等待第二运算数的输入并完成计算,即可进行连续运算。
(3)可根据用户需要开启或关闭LCD显示
(4)可进行开方运算、可进行任意次方的运算,即能进行x的y次方的运算。
3.2.2原理简介
1.LCD1602液晶屏原理图
图2.2液晶显示模块
LCD1602,工业字符型液晶,能够同时显示16x02即32个字符(16列2行),故简称1602。
1602字符型LCD通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线VCC(15脚)和地线GND(16脚),其控制原理与14脚的LCD完全一样。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:
阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。
因为1602识别的是ASCII码,试验可以用ASCII码直接赋值,在单片机编程中还可以用字符型常量或变量赋值,如'A’。
1602LCD液晶具有功耗低、显示内容丰富、清晰,显示信息量大,显示速度较快,界面友好等而得到广泛应用,因此使用1602液晶显示屏,可以方便的显示多种字符,特别适用于单片机计算器的双行显示。
液晶显示模块的设计:
2.矩阵键盘原理图
图2.3矩阵键盘
计算器输入数字和其他功能按键要用到很多按键,如果采用独立按键的方式,在这种情况下,编程会很简单,但是会占用大量的I/O口资源,因此在很多情况下都不采用这种方式,而是采用矩阵键盘的方案。
矩阵键盘采用四条I/O线作为行线,四条I/O线作为列线组成键盘,在行线和列线的每个交叉点上设置一个按键。
这样键盘上按键的个数就为4×4个。
这种行列式键盘结构能有效地提高单片机系统中I/O口的利用率。
另外本设计还制定了四个独立按键,在任何时候按下AC清零键或关闭显示键,都必须退出当前操作,数据清零,准备下一次的运算,故应采用独立键盘产生下降沿输入给单片机外部中断处理。
5.编程思想
5.1DS1302时钟:
数字钟需要能够实现五个功能。
在模式一时正常显示当前时间,模式二是能够对当前时间进行调整,模式三是能够对当前日期进行显示和调整。
模式四是能够对当前星期进行显示和调整,模式五主要用来设置闹钟时间。
按键功能设计。
K1是功能模式选择,K1是单片机外部中断0,采用下降沿触发方式,接收外来中断。
K2是调整确认键,对时间、日期的修改操作,需要按下K2进行确认,K2键也是外部中断采用下降沿中断。
K3、K4、K5按照时、分、秒十进制数字进行调整,对日、月、年十进制数字进行调整,K5对星期进行调整。
七段数码管显示部分,显示时间时采用24进制,时分秒之间用短连接符隔开。
显示日期时,年份只显示后两位,年月日之间也用短连接符隔开,在调整时间和日期时为了加以区别调时时数码管显示全零,而调日期时由于日期没有0月0日,所以数码管显示为00-01-01。
本程序为了能够让闹钟音乐和数码管扫描同时进行,采用定时器扫描,通过定时器扫描对应数码管应该显示数字,再通过位控制来循环扫描,从而显示时间或日期。
在主程序中应该对外部中断和定时器进行初始化,同时对调整过后的数据写入DS1302,并从DS1302中读取当前模式所需数据。
主程序中还应该实现当前时间与闹钟时间的对比,如果相等的话则调用闹钟程序,否则不操作。
5.2简易计算器:
根据课程要求和设计指标,本系统采用MCS-51系列单片机作为主控机,通过拓展必要的外围电路,实现对计算器的设计,具体设计思路如下:
(1)由于要显示运算式和结果,为了达到良好的显示效果,本系统采用LCD1602液晶显示屏作为显示模块。
(2)计算器一般包含数字键(0~9),符号键(+、-、×、÷)、小数点按键,等号按键,故采用4*4矩阵键盘结合键盘扫描技术容易达到要求,并且电路和程序也比较简单。
(3)执行过程:
开机显示‘0’,等待按键输入,当键入数字,在LCD上显示出来,计算器内部吧数据储存起来,并等待下一按键输入,当键入+、-、×、÷运算符,计算器在内部进行转换,得到第一运算数,然后等待再次输入数值,按等于号就在LCD上显示结果,如果继续按下+、-、×、÷运算符,则直接利用第一次运算的结果进行下一次运算。
(4)AC清零功能:
在运算的任何时候键入AC键,则把数据清零,等待下一次运算。
为了实现此功能,本系统采用AC按键外部中断输入,运用中断技术,随时对计算器进行清零。
(5)开方和多次方运算功能的实现:
采用独立按键,再检测运算符的时候也检测这两个按键,一旦符合按下则进行开方或者多次方运算,程序可通过条用“math.h”头文件中的sqrt和pow函数实现。
(6)错误提示:
当输入超过范围时,则停止输入,等待输入运算符;当除数为0时,计算器会在LCD上提示错误;当被开方数小于0时,提示错误。
鉴于本设计的计算器的难度以及功能的要求,在本设计中决定使用语言功能丰富、表达能力强、使用方便灵活、可移植性好的C语言编写软件,这样有利于减轻工作量和代码量,提高设计效率。
若使用汇编语言编写程序,会出现汇编语言无法表达、移植困难等问题,而且对于开方和多次方的运算,汇编语言难以表达和设计,这是设计是很不利。
6、程序框图
图5.1DS1302时钟的程序框图
图5.2计算器总程序框图
结果分析:
对比运算结果和实际结果可知,进行一般的整形运算计算器能准确无误计算出来,但是当进行浮点运算时候,会产生精度丢失或者是有尾数产生,这是因为8051单片机对的浮点运算功能差,而且在keil开发环境中,float型和double型浮点数的精度都是一样的,其小数点的有效数字位数都是6~7位,这就决定了本设计的计算器的浮点数精度有限,只能通过小数点补偿来减少浮点数运算误差。
另外,由连续运算、新一轮运算测试、错误提示测试的结果以及运算过程中的AC清零、声音开关设置可见,本设计的计算器的功能基本能实现。
但是,由实际操作可发现本设计存在以下不足:
(1)某些按键不够灵敏,导致需要按很多次才能输入;
(2)当运算式子超过屏幕范围时,不能通过移动屏幕来完全显示式子;
(3)当连续出现错误操作时,如连续输入减号,程序不能自动复位,会产生连续错误;
(4)没有删除输入功能,当输入出错时,只能通过清零后重新输入;
(5)没有数据溢出提示功能。
7.体会与总结:
首先,在硬件电路设计方面自己认识到稳定的重要性,学习到电源稳压滤波降噪的方法。
在焊接方面,自己学习到各种元件的焊接方法,小元件先焊,大原件后焊,焊一部分检测一部分。
只有这样才能避免最后出错检测不出来。
其次,在对于电路板的设计和单片机功能的实现之前,必须要弄清楚电路图的工作原理以及单片机的相关知识。
比如说,电路板的各个部件是如何联系在一起的,各个部件的功能又是怎样等。
对于单片机来说,我们更应该弄明白单片机的定时器以及外部中断是如何工作的。
最后,在程序的设计阶段,最好先画出程序流程框图。
在程序流图框图的帮助下,才能有的放矢,逐步完善编码,实现需要的功能。
而且,如果程序出错的话,可以根据程序框图排查错误,这样的效率更高。
总之,这次的硬件课程设计让我认识到自己在硬件、软件方面还有许多的不足,自己还有许多需要提高和学习的地方。
附:
核心代码
DS1302时钟:
"LED_8.c"
#include
#include"LED_8.h"
#include"DELAY.h"
constuchardula[]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0x76,0x79,0x38,0x00};
constucharwela[]={0XFE,0XFD,0XFB,0XF7,0XEF,0XDF,0XBF,0X7F};
staticucharTIME_S=0,TIME_M=0,TIME_H=0;//记录上次显示的数据,秒、分、小时
staticuchari=0,j=0,k=0,l=0,m=0,n=0;//记录上次显示的数据
voidshow_one_led(uchari,uchardata_8)//显示一位数码管
{
P2=~wela[i];
P0=~dula[data_8];
delayus(100);
P0=0xff;//消隐
}
voidshow_led(uchars,ucharmin,ucharh)//显示动态数码管
{
show_one_led(0,s%10);
show_one_led(1,s/10);
show_one_led(2,16);
show_one_led(3,min%10);
show_one_led(4,min/10);
show_one_led(5,16);
show_one_led(6,h%10);
show_one_led(7,h/10);
}
voidshow_date(uchardate,ucharmonth,ucharyear)//显示日期函数
{
show_one_led(0,date%10);
show_one_led(1,date/10);
show_one_led(2,month%10);
show_one_led(3,month/10);
show_one_led(4,year%10);
show_one_led(5,year/10);
show_one_led(6,0);
show_one_led(7,2);
}
voidshow_week(ucharweek)//显示星期函数
{
show_one_led(7,16);
show_one_led(6,16);
show_one_led(5,16);
show_one_led(4,16);
show_one_led(3,16);
show_one_led(2,16);
show_one_led(1,16);
show_one_led(0,week);
}
“INT.c”
#include//use_nop_()function
#include
#include"INT.h"
#include"DS1302.h"
#include"TIM0.h"
#include"EEPROM.h"
uchardisplay_DS1302_count=0;//定义显示的全局计数值,默认为显示时间
staticuchartimer_stop_count=0;//定义秒表计数变量,正常时为0,暂停时为1
externuchartimer_backcounter_choice;//定义秒表还是倒计时选择标志,0:
秒表,1:
倒计时
externucharpress_key_count0;//对外部中断0中按键按下的检测,若按键按下了,其值为1
externucharpress_key_count1;//对外部中断1中按键按下的检测,若按键按下了,其值为1
externuchars,min,h;
externuchart_s,t_min,t_h;//定义秒表显示变量
externuchardate,month,year;//定义显示日期变量
externucharweek;
externucharweek_count;
externuchartiming_count;
externuchartiming_count1;
externuchardate_count;//调日期开始时对显示日期进行初始化
uchartiming_s=0,timing_min=0,timing_h=0;//记录定时数据
voidINT0_INIT()//外部中断0初始化
{
EA=1;//全局中断开启
EX0=1;//外部中断允许
IT0=0;//外部中断0低电平触发
P3|=BIT
(2);//将P3.2输出高电平
}
voidINT1_INIT()//外部中断1初始化
{
EA=1;//全局中断开启
EX1=1;//外部中断允许
IT1=0;//外部中断1低电平触发
P3|=BIT(3);//将P3.3输出高电平
}
voidINT0_server()interrupt0//外部中断0服务函数
{
display_DS1302_count++;//模式改变
if(display_DS1302_count==5)display_DS1302_count=0;//超出计数,归零
P3|=BIT
(2);
}
voidINT1_server()interrupt2//外部中断1服务函数
{
if(display_DS1302_count==1)//调时模式
{
DS1302Write(0x8e,0x00);//写保护关
DS1302Write(DS1302_SECOND_WRITE,(s/10*16+s%10));//写入秒
DS1302Write(DS1302_MINUTE_WRITE,(min/10*16+min%10));//写入分钟
DS1302Write(DS1302_HOUR_WRITE,(h/10*16+h%10));//写入小时
DS1302Write(0x8e,0x80);//写保护开
display_DS1302_count=0;//正常显示时间
timing_count=0;//将调时进入值初始化
}
elseif(display_DS1302_count==2)//调日期模式
{
DS1302Write(0x8e,0x00);//写保护关
DS1302Write(DS1302_DAY_WRITE,(date/10*16+date%10));//2011年1月1日星期6
DS1302Write(DS1302_MONTH_WRITE,(month/10*16+month%10));
DS1302Write(DS1302_YEAR_WRITE,(year/10*16+year%10));
DS1302Write(0x8e,0x80);//写保护开
display_DS1302_count=0;//正常显示时间
date_count=0;//将调日期进入值初始化
}
elseif(display_DS1302_count==3)//调星期模式
{
DS1302Write(0x8e,0x00);//写保护关
DS1302Write(DS1302_WEEK_WRITE,week);
DS1302Write(0x8e,0x80);//写保护开
display_DS1302_count=0;//正常显示时间
week_count=0;//将调日期进入值初始化
}
elseif(display_DS1302_count==4)//写入定时数据
{
Sector_erase(0X2E00);
Byte_program(0X2E00,timing_s);
Byte_program(0X2E01,timing_min);
Byte_program(0x2E02,timing_h);
display_DS1302_count=0;//正常显示时间
timing_count1=0;//将调时进入值初始化
}
P3|=BIT(3);
}
2、简易计算机:
/****主程序***/
voidmain(void)
{
init();//初始化
while
(1)//整个系统大循环,让计算器一直处于工作状态
{
while
(1)//第一运算数扫描
{
if(ac==1)break;//若清零,则退出输入
if((keyscan()!
='N')&&((num>=0&&num<=9)||num=='.'))//记录按下的数字
{
if(newcalc==1)//新一次运算开始
{
lcdwrite_com(0x01);//清屏
newcalc=0;
lcd_setxy(0,0);
}
if(keynum1<=7)//限制输入位数
{
if(num=='.')
{
lcdwrite_data('.');//显示小数点
}
else
lcdwrite_num1(num);//转化为数字编码进行显示
num1[keynum1]=num;
keynum1++;
}
}
elseif(num=='+'||num=='-'||num=='*'||num=='/'||num=='='||num=='^'||keysqrt==0)
{
if(keynum1==0&&num1[0]==0)//若直接输入运算符而没有输入数字则执行连续运算