单片机计算器设计论文讲解.docx
《单片机计算器设计论文讲解.docx》由会员分享,可在线阅读,更多相关《单片机计算器设计论文讲解.docx(34页珍藏版)》请在冰豆网上搜索。
单片机计算器设计论文讲解
目录
⒈原理分析1
⒉方案选择1
2.1主控制芯片1
2.1.1芯片介绍1
2.1.2单片机特性1
2.1.3参数2
2.2显示模块2
2.3时钟模块4
3.电路原理图绘制及仿真4
3.1元件型号4
3.2电路原理图5
3.3仿真结果5
3.3.1常态下时钟显示6
3.3.2带小数点的加法运算6
3.3.3带负数的减法运算6
3.3.4乘法运算7
3.3.5除法运算7
4.综合调试7
4.1硬件电路7
4.1.1单片机最小系统电路7
4.1.2时钟电路8
4.1.3复位电路9
4.1.4LCD1602显示电路10
4.1.5DS1302电路11
4.1.6矩阵键盘电路11
4.2软件设计12
4.2.1程序整体框架12
4.2.2主函数流程图13
4.2.3时钟显示模式14
4.2.4计算器模式14
5.总结16
附录一:
主函数源程序17
附录二:
计算器函数22
⒈原理分析(陈小波,崔畅,程露)
计算器包含了输入按键然后计算再到显示屏显示,主要有3部分构成,输入、计算和显示。
采用单片机做主控制单元,从矩阵键盘读取键值送入cpu计算然后将结果送到显示器显示。
⒉方案选择(陈小波,崔畅,程露)
2.1主控制芯片
2.1.1芯片介绍
STC89C52是STC公司生产的一种低功耗、高性能CMOS8位微控制器,具有8K在系统可编程Flash存储器。
STC89C52使用经典的MCS-51内核,但做了很多的改进使得芯片具有传统51单片机不具备的功能。
在单芯片上,拥有灵巧的8位CPU和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。
具有以下标准功能:
8k字节Flash,512字节RAM,32位I/O口线,看门狗定时器,内置4KBEEPROM,MAX810复位电路,3个16位定时器/计数器,4个外部中断,一个7向量4级中断结构(兼容传统51的5向量2级中断结构),全双工串行口。
另外STC89C52可降至0Hz静态逻辑操作,支持2种软件可选择节电模式。
空闲模式下,CPU停止工作,允许RAM、定时器/计数器、串口、中断继续工作。
掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。
最高运作频率35MHz,6T/12T可选。
2.1.2单片机特性
STC89C52RC单片机:
8K字节程序存储空间;
512字节数据存储空间;
内带2K字节EEPROM存储空间;
可直接使用串口下载;
2.1.3参数
1.增强型8051单片机,6时钟/机器周期和12时钟/机器周期可以任意选择,指令代码完全兼容传统8051.
2.工作电压:
5.5V~3.3V(5V单片机)/3.8V~2.0V(3V单片机)
3.工作频率范围:
0~40MHz,相当于普通8051的0~80MHz,实际工作频率可达48MHz
4.用户应用程序空间为8K字节
5.片上集成512字节RAM
6.通用I/O口(32个),复位后为:
P0/P1/P2/P3是准双向口/弱上拉,P0口是漏极开路输出,作为总线扩展用时,不用加上拉电阻,作为I/O口用时,需加上拉电阻。
7.ISP(在系统可编程)/IAP(在应用可编程),无需专用编程器,无需专用仿真器,可通过串口(RxD/P3.0,TxD/P3.1)直接下载用户程序,数秒即可完成一片
8.具有EEPROM功能
9.共3个16位定时器/计数器。
即定时器T0、T1、T2
10.外部中断4路,下降沿中断或低电平触发电路,PowerDown模式可由外部中断低电平触发中断方式唤醒
11.通用异步串行口(UART),还可用定时器软件实现多个UART
12.工作温度范围:
-40~+85℃(工业级)/0~75℃(商业级)
13.PDIP封装。
2.2显示模块
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。
它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形。
1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块。
1602采用标准的16脚接口,其中:
第1脚:
GND为电源地
第2脚:
VCC接5V电源正极
第3脚:
V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。
第4脚:
RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:
RW为读写信号线,高电平1时进行读操作,电平0时进行写操作。
第6脚:
E(或EN)端为使能(enable)端,高电平
(1)时读取信息,负跳变时执行指令。
第7~14脚:
D0~D7为8位双向数据端。
第15~16脚:
空脚或背灯电源。
15脚背光正极,16脚背光负极。
管脚图如下图所示:
图1LCD1602引脚图
2.3时钟模块
DS1302是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。
采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。
DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。
DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后备电源双电源引脚,同时提供了对后备电源进行涓细电流充电的能力。
DS1302的引脚排列,其中Vcc1为主电源,VCC2为后备电源。
在主电源关闭的情况下,也能保持时钟的连续运行。
DS1302由Vcc1或Vcc2两者中的较大者供电。
当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。
当Vcc2小于Vcc1时,DS1302由Vcc1供电。
X1和X2是振荡源,外接32.768kHz晶振。
RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。
RST输入有两种功能:
首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据传送的方法。
当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。
如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。
上电运行时,在Vcc>2.0V之前,RST必须保持低电平。
只有在SCLK为低电平时,才能将RST置为高电平。
I/O为串行数据输入输出端(双向),后面有详细说明。
SCLK为时钟输入端。
下图为DS1302的引脚功能图:
图2DS1302引脚图
3.电路原理图绘制及仿真(陈小波,崔畅,程露)
3.1元件型号
本设计主要采用单片机做主控制,所以采用protues仿真。
元件型号:
AT89C51x1
DS1302x1
LCD1602x1
10K排阻x1
12Mhz排阻x1
按键若干
电阻若干
电容若干
3.2电路原理图
仿真原理图用protues绘制,图中大部分导线连接采用网络标号代替。
图3protues仿真原理图
3.3仿真结果
3.3.1常态下时钟显示
图4时钟显示
3.3.2带小数点的加法运算
图5带小数的加法
3.3.3带负数的减法运算
图6带负数的减法
3.3.4乘法运算
图7乘法运算
3.3.5除法运算
图8除法运算
结果中如果只取前三位的时候,第四位四舍五入。
4.综合调试(陈小波,崔畅,程露)
4.1硬件电路
4.1.1单片机最小系统电路
单片机的最小系统是由组成单片机系统必需的一些元件构成的,除了单片机之外,还需要包括电源供电电路、时钟电路、复位电路。
单片机最小系统电路如图所示。
图9最小系统原理图
4.1.2时钟电路
单片机工作时,从取指令到译码再进行微操作,必须在时钟信号控制下才能有序地进行,时钟电路就是为单片机工作提供基本时钟的。
单片机的时钟信号通常有两种产生方式:
内部时钟方式和外部时钟方式。
在单片机XTAL1和XTAL2引脚上跨接上一个晶振和两个稳频电容,可以与单片机片内的电路构成一个稳定的自激振荡器。
晶振的取值范围一般为0~24MHz,常用的晶振频率有6MHz、12MHz、11.0592MHz、24MHz等。
一些新型的单片机还可以选择更高的频率。
外接电容的作用是对振荡器进行频率微调,使振荡信号频率与晶振频率一致,同时起到稳定频率的作用,一般选用20~30pF的瓷片电容。
电路如下:
图10晶振电路
外部时钟方式则是在单片机XTAL1引脚上外接一个稳定的时钟信号源,它一般适用于多片单片机同时工作的情况,使用同一时钟信号可以保证单片机的工作同步。
时序是单片机在执行指令时CPU发出的控制信号在时间上的先后顺序。
51单片机的时序概念有4个,可用定时单位来说明,包括振荡周期、时钟周期、机器周期和指令周期。
振荡周期:
是片内振荡电路或片外为单片机提供的脉冲信号的周期。
时序中1个振荡周期定义为1个节拍,用P表示。
时钟周期:
振荡脉冲送入内部时钟电路,由时钟电路对其二分频后输出的时钟脉冲周期称为时钟周期。
时钟周期为振荡周期的2倍。
时序中1个时钟周期定义为1个状态,用S表示。
每个状态包括2个节拍,用P1、P2表示。
机器周期:
机器周期是单片机完成一个基本操作所需要的时间。
一条指令的执行需要一个或几个机器周期。
一个机器周期固定的由6个状态S1~S6组成。
指令周期:
执行一条指令所需要的时间称为指令周期。
一般用指令执行所需机器周期数表示。
51单片机多数指令的执行需要1个或2个机器周期,只有乘除两条指令的执行需要4个机器周期。
4.1.3复位电路
无论是在单片机刚开始接上电源时,还是运行过程中发生故障都需要复位。
复位电路用于将单片机内部各电路的状态恢复到一个确定的初始值,并从这个状态开始工作。
单片机的复位条件:
必须使其RST引脚上持续出现两个(或以上)机器周期的高电平。
单片机的复位形式:
上电复位、按键复位。
上电复位和按键复位电路如下。
上电复位电路中,利用电容充电来实现复位。
在电源接通瞬间,RST引脚上的电位是高电平(Vcc),电源接通后对电容进行快速充电,随着充电的进行,RST引脚上的电位也会逐渐下降为低电平。
只要保证RST引脚上高电平出现的时间大于两个机器周期,便可以实现正常复位。
按键复位电路中,当按键没有按下时,电路同上电复位电路。
如在单片机运行过程中,按下RESET键,已经充好电的电容会快速通过200Ω电阻的回路放电,从而使得RST引脚上的电位快速变为高电平,此高电平会维持到按键释放,从而满足单片机复位的条件实现按键复位。
按键复位图如下:
图11复位电路
4.1.4LCD1602显示电路
LCD1602显示电路图如下,该部分主要负责常态的时钟显示,计算器模式时按键数字以及结果的显示,使得系统更加直观。
图12LCD1602电路
4.1.5DS1302电路
DS1302负责时钟显示部分的数据,能在单片机掉电的情况下使用备用电池维持时间的正常。
主要电路如下:
图13DS1302电路
4.1.6矩阵键盘电路
本系统键盘输入采用4x4矩阵键盘,键盘包括0-9以及加减乘除小数点等按键。
电路图如下:
图14矩阵键盘电路
该矩阵键盘带中断,当有按键发生只有产生一个终端请求,单片机跳入终端读取键值,改设计可以使IO复用,在没有按键事件发生的时候按键接的IO口可以正常的数据输入输出,并使得单片机不用一直扫描按键,CPU工作量大大降低。
4.2软件设计
本系统所有代码全部采用C语言编写,keil编译调试。
程序整体框架包含信息采集和信息显示两方面。
首先由MCU主控制从外部矩阵键盘读入键值,时钟芯片读取时间等,然后控制液晶显示器的不同功能显示。
4.2.1程序整体框架
图15程序整体框架
主函数只要处理两个大任务,分别为时钟显示和计算器模式。
有一个外部中断按键控制切换显示器显示。
上电复位之后开始外围器件的初始化,初始化完成开始读取有外部中断连接的独立按键KEY1,键值默认为0,键值为0的时候系统处于时钟显示模式,显示当前时间以及日期。
当检测到有按键按下后,键值取反为1,当键值为1的时候主函数执行计算器模式,开始矩形键盘的扫描,扫描到的键值全部存入数组待处理。
再次触发按键键值再次取反,从计算器模式中挑出,并清空存键值数组数据。
系统再次进去时钟显示模式。
交替运行互不干扰,以实现整个系统任务。
4.2.2主函数流程图
图16主函数流程图
4.2.3时钟显示模式
单片机从IO口读取外设DS1302输出的数据,读取完成后存入数组,由于DS1302读出的事BCD码,所以要对其进行处理转化为10进制码以便显示。
转换完成后送1602显示,显示完成继续读取重复以上步骤,实现数据时间实时更新效果。
DS1302外部接有备用电池,单片机以及芯片电源断开的时候,备用电池供电时间不短依旧在持续运行,故下次单片机上电可直接读取到当前时间,送显示。
4.2.4计算器模式
当单片机进去计算器模式后,LCD显示清除屏幕,等待读取输入键值的显示。
矩阵不停行列扫描,有按键按下后进行判断为哪一位的键值,存数组并送显示。
等号键按下为本次输入的结束标志,呆等号键松开后,进入计算器函数,先遍历一边数组,首先判断是否有多个符号输入,当有多个符号输入的时候分几种情况,有一个或者两个负数的输入,一个负号输入的时候有判断前一个数为负或者后一个为负,进行不同的处理。
当检测到的多个符号并不属于负号输入的时候跳出并显示ERROR表示输入错误。
当负号判断处理完成之后把运算负号存入一个标志位,然后对数组数据进行由字符到数值的处理,处理完成后进入对应负号的计算,计算出结果并显示。
显示完成等待任意按键清除屏幕以及数组并等待下一次的输入。
本系统加入了小数点的输入,当检测到小数点的时候会对相应数值处理并以float形式进行保存和运算。
图17错误输入演示
最后显示的结果分有小时和没显示显示,有小数的时候默认显示小数点后3位小时,没有小数点的时候不显示小数。
图18结果小数显示
另外结果可显示负数结果。
图19结果负号显示
5.总结(陈小波,崔畅,程露)
本次实验刚开始认为比较简单,想法方案没有仔细想就采用了一个笨方法,加之对C语言的一些库函数的不熟悉,导致走了很多弯路。
最后在大神同学的指导启发下对方案进行了大的调整,花了更多的心思,写了更少量的代码实现了更多的功能。
在此非常感谢大神的帮助。
本组在经过一系列的失败以及反思,请教之后完成了作品。
感触最深刻的就是不论做什么之前应该先深思方法步骤,不要急于下手,学会用巧妙的办法解决更多的事。
收获颇丰!
本系统还存在一些可以改进的地方,后期我希望能在时钟显示的基础上加入闹钟,以及时间校准功能,但由于期末来临更多的心思放在了学习上。
待期末结束后会进行进一步的功能完整以及方案的完整改进。
附录一:
主函数源程序
#include"reg52.h"
#include"1602.h"
#include"key_board.h"
#include"calculator.h"
#include"ds1302.h"
#include
#defineconst_key_time1500//按键去抖动延时的时间
bitucKeySec=0;//被触发的按键编号
unsignedintuiKeyTimeCnt1=0;//按键去抖动延时计数器
unsignedcharucKeyLock1=0;//按键触发后自锁的变量标志
sbitkey=P3^7;
voidcal_function(void);
voidbutton_servce(void);
voidbutton_scan(void);
staticvoiddelay_ms(unsignedintz)
{
unsignedintx,y;
for(x=z;x>0;x--)
for(y=114;y>0;y--)
;
}
intmain(void)
{
EA=1;//全局中断开
EX1=1;//外部中断0开
IT1=0;//琁T1=0表示电平触发
EX0=1;//外部中断0开
IT0=0;//琁T1=0表示电平触发
lcd_init();//lcd初始化
Ds1302_Init();//DS1302初始化
//Ds1302_Write_Time();
//Ds1302_Init();
while
(1)
{
//lcd_write_char('c');
button_servce();
}
}
voidbutton_scan(void)
{
if(key==1)//IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
{
ucKeyLock1=0;//按键自锁标志清零
uiKeyTimeCnt1=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
}
elseif(ucKeyLock1==0)//有按键按下,且是第一次被按下
{
++uiKeyTimeCnt1;//延时计数器
if(uiKeyTimeCnt1>const_key_time1)
{
uiKeyTimeCnt1=0;
ucKeyLock1=1;//自锁按键置位,避免一直触发
ucKeySec=~ucKeySec;//触发1号键
}
}
}
voidbutton_servce(void)
{
//button_scan();
if(ucKeySec==0)
{
delay_ms(50);
Ds1302_Read_Time();
delay_ms(50);//读取时间
Ds1302_Display();
delay_ms(50);//显示时间
//button_scan();
}
elseif(ucKeySec==1)
{
lcd_clr();//
cal_function();//计算器
//button_scan();
}
}
voidcal_function(void)
{
unsignedchartemp=0;
unsignedcharinput_buf[20];//输入的数据转换为字符串保存
unsignedcharoutput_buf[20];//输出的数据保存空间
unsignedchar*ptr=input_buf;
longdoubleoutput=0;//输出结果,double型
unsignedchari;
for(i=0;i{
input_buf[i]=0;
}
ptr=input_buf;
locateXY(0,0);
do{
//button_scan();
if(ucKeySec==0)
break;
temp=0;
temp=key_board();
while((P1&0XF0)!
=0XF0);//等待按键弹起
switch(temp)
{
case1:
*ptr++='1';break;
case2:
*ptr++='2';break;
case3:
*ptr++='3';break;
case5:
*ptr++='4';break;
case6:
*ptr++='5';break;
case7:
*ptr++='6';break;
case9:
*ptr++='7';break;
case10:
*ptr++='8';break;
case11:
*ptr++='9';break;
case14:
*ptr++='0';break;
case15:
*ptr++='.';break;
case13:
*ptr++='\0';break;
case4:
*ptr++='+';break;
case8:
*ptr++='-';break;
case12:
*ptr++='*';break;
case16:
*ptr++='/';break;//按键对应符号
}
if(temp)//显示到屏幕上
{
lcd_write_char(*(ptr-1));
}
}while(temp!
=13);
delay_ms(10);//当按键为'='时跳出循环
locateXY(0,0);
lcd_write_str(input_buf);
lcd_write_str("");
output=calculator(input_buf);//保存结果
if(output==ERROR)
{
locateXY(5,1);
lcd_write_str("Error");//输入错误,在屏幕显示ERROR
}
else
{
if(output-(longint)output!
=0)//如果结果有小数,转换为小数形式保存字符串
sprintf(output_buf,"%.3f",output);
else
sprintf(output_buf,"%ld",(long)output);//如果结果是整数,保存为长整数形式保存字符串
locateXY(0,1);
lcd_write_char('=');
lcd_write_str(output_buf);
}
delay_ms(15);
do{
//button_scan();
if(ucKeySec==0)
break;
temp=0;//"="键进行下一次计算
temp=key_board();
while((P1&0XF0)!
=0XF0);
}while(temp==0);