基于单片机的多功能计算器设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
电子信息工程专业综合课程设计任务书
摘要:
单片机的出现是计算机制造技术高速发展的产物,它是嵌入式控制系统的核心,如今,它已广泛的应用到我们生活中的各个领域,电子、科技、通信、汽车、工业等。
我们这次设计的多功能科学计算器也是利用AT89C51单片机制作而成。
该计算器设计是采用C语言编写,实现了六位数范围内的加、减、乘、除基本的四则运算,此外该计算器除了具备基本的计算功能以外还具有计时和倒计时的功能,也就是说该计算器具有两个工作模式,计算模式和计时模式,而计时模式里又包含正计时和倒计时的功能,这样一个简易的计算器实现了多功能,比较实用和方便。
该设计电路是采用AT89C51单片机为主要控制电路,然后使用74LS245缓冲驱动电路驱动六位LED数码管显示数据,利用加上4×4矩阵键盘完成电路的实际操作。
电路比较简单,但是很实用方便。
关键字:AT89C51 多功能74LS245 LED 矩阵键盘
目录
1.方案论证与选择 (4)
1.1输入模块 (4)
1.2显示模块: (5)
2.其他硬件电路模块功能介绍: (6)
2.1驱动模块 (6)
2.2主控制模块 (7)
2.3操作模块 (8)
3.软件设计 (9)
3.1主功能计算器部分 (9)
3.2计时和倒计时部分 (9)
3.3功能按键 (9)
3.4软件流程图 (9)
4硬件设计 (11)
4.1电路工作框图 (11)
4.2 硬件电路图 (12)
4.3引脚锁定 (12)
5.电路测试结果 (12)
5.1代码提示信息 (12)
5.2模式转换电路图 (13)
5.3错误提示电路图 (14)
5.4正常计算结果显示图 (14)
6.该设计电路的改进思想 (15)
7.小结 (15)
8.参考文献 (16)
附录(程序清单) (16)
基于单片机的多功能计算器设计
1.方案论证与选择
1.1输入模块
方案一:采用独立式按键作为输入模块,其特点:直接用I/O口构成单个按键电路,接口电路配置灵活、按键识别和软件结构简单,但是当键数较多时,占用I/O口较多,比较浪费资源;其原理图如图1所示:
图1 独立的功能按键
方案二:采用矩阵式键盘作为输入电路,其特点:电路和软件稍复杂,但相比之下,当键数越多时越节约I/O口,比较节省资源。
其原理图如图2所示:
图2 矩阵键盘输入
本设计使用键盘输入预置用于计算或计时,按键较多。
若采用独立按键,需频繁按键,为软件设计增加负担,且操作界面不友好。
若采用矩阵式按键,可以方便地输入一个数值,使操作界面更具人性化,节约了宝贵的I/O口资源。
通过对比,故采用方案二作为系统输入模块。
1.2显示模块:
方案一:用LCD显示,要用LCD显示,需要学习其专用的驱动控制芯片,比如HD61203,软件实现较为复杂,且LCD的价格昂贵。
方案二:采用LED数码管串行静态显示,虽然其显示亮度高,但是如果显示器的位数较多,需要增加锁存器,故而静态显示占用I/O口线较多,CPU的开销较大。
方案三:采用LED数码管并行动态显示,显示亮度不及静态显示,但电路简单,适合于显示位数较多的情况。
表1 用LED显示器显示十六位进制数的字形代码在下图表示:
7 F8H 07H 灭FFH 00H
8 80H 7FH
综上所述,采用方案三并行动态显示是本设计最佳显示方案。
LED数码管显示器由6个发光二极管组成,因此也称之为6段LED显示器,其排列形状如上。
注:该设计电路中的6段LED数码显示器是共阳极的。
2.其他硬件电路模块功能介绍:
2.1驱动模块
该设计的驱动电路是由74LS245来驱动的。
74LS245是我们常用的芯片,用来驱动LED或者其他的设备,它是8路同相三态双向总线收发器,可双向传输数据。
74LS245还具有双向三态功能,既可以输出,也可以输入数据。
当8051单片机的P0口总线负载达到或超过P0最大负载能力时,必须接入74LS245等总线驱动器。
当片选端/CE低电平有效时,AB/BA=“0”,信号由 B 向 A 传输;(接收)
AB/BA =“1”,信号由 A 向 B 传输;(发送)当/CE为高电平时,A、B均为高阻态。
由于P2口始终输出地址的高8位,接口时74LS245的三态控制端/1G和/2G接地,P2口与驱动器输入线对应相连。
P0口与74LS245输入端相连,/CE端接地,保证数据现畅通。
8051的/RD和/PSEN相与后接DIR,使得/RD或/PSEN有效时,74LS245输入(P0.i←Di),其它时间处于输出(P0.i→Di)。
2.2主控制模块
该设计的核心控制电路是AT89C51单片机。
AT89C51是一种带4K字节闪烁可编程可擦除只读存储器(FPEROM—Falsh Programmable and Erasable Read Only Memory)的低电压,高性能CMOS 8位微处理器,俗称单片机。
其引脚图以及工作原理如下:
现简要介绍各引脚的功能。
⑴.主电源引脚:
Vss-(20脚):地线
Vcc-(40脚):+5V电源
⑵.外接晶振或外部振荡器引脚:
XTAL1-(19脚):当采用芯片内部时钟信号时,接外部晶振的一个引脚;当采用外部时钟信号时,此脚应接地。
XTAL1-(18脚):当采用芯片内部时钟信号时,接外部晶振的一个引脚;当采用外部时钟信号时,外部信号由此脚输入。
⑶.控制、选通或电源复用引脚:
RST/Vp0-(9脚):复位信号输入;Vcc掉电后,此脚可接上备用电源,在低功耗条件下保持内部RAM中的数据。
ALE/PROG-(30脚):ALE即允许地址锁存信号输出,当单片机访问外部存储器时该脚的输出信号用于锁存P0的低8位地址,其输出的频率为时钟振荡频率的1/6。
PROG为编程脉冲输入端,
当选用8751单片机时,由此脚输入编程脉冲。
/PSEN-(29脚):访问外部程序存储器选通信号,低电平有效,用于实现外部程序存储器的
读操作。
/EA-(31脚):EA为访问内部或外部程序存储器选择信号,EA=0,单片机只访问外部程
序存储器,故对8031此脚只能接地;EA=1,单片机访问内部程序存储器,固对8051和8751此脚应接高电平,但若程序指针PC值超过4KB(OFFFH)范围,单片机将自动访问外部程序存储器。
⑷.多功能I/O引:
P0口-(32~39脚):P0数据/地址复用总线端口。
P1口-(1~8脚):P1静态通用端口。
P2口-(21~28脚):P2动态端口。
P3口-(10~17脚):P3双功能静态端口。
除作I/O端口外,它还提供特殊的第二功能,其具体
含义为:
P3.0-(10脚)RXD:串行数据接收端。
P3.1-(11脚)TXD:串行数据发送端。
P3.2-(12脚)INT0:外部中断0请求端,低电平有效。
P3.3-(13脚)INT1:外部中断1请求端,低电平有效。
P3.4-(14脚)T0:定时器/计数器0计数输入端。
P3.5-(15脚)T1:定时器/计数器1计数输入端。
P3.6-(16脚)WR:外部数据存储器写选通,低电平有效。
P3.7-(17脚)RD:外部数据存储器读选通,低电平有效
2.3操作模块
该计算器的实际操作模块如下图所示:
3.软件设计
本作品实现的功能全部是由C语言程序编写实现。
通过程序的编写使简单的器件实现丰富的功能。
3.1主功能计算器部分
使用双精度类型来存放计算器的两个输入数值和最后的计算结果,最大接收的输入位数为6位,超出6位显示报错,并且需要清屏,然后重新输入。
该计算器只能实现正整数范围内的四则运算。
3.2计时和倒计时部分
出于学习的目的,计时和倒计时采用定时器来实现的。
虽然有点误差但误差不大基本达到要求。
此外,该计算器还设有四个功能按键,可以输入相应的按键对应的键值,进行模式转换或数据更改。
3.3功能按键
一开始默认的模式是计算模式即矩阵键盘执行计算模式下的功能。
按功能键“ON/C”切换到计时模式;在计时模式下按“=”功能键又可切换到计算模式;在计时模式下按“=”功能键后再按功能键“ON/C”又可切换到倒计时模式。
3.4软件流程图
4硬件设计
4.1电路工作框图
4.2 硬件电路图
4.3引脚锁定
P0口接驱动器74LS245;
P1口接显示器LED的段选;
P2口接4*4矩阵键盘;
P3口接外部中断0;
5.电路测试结果
5.1代码提示信息
由于该电路可以实现计算、计时以及倒计时三种功能,因此,会有相应的模式转换提示代码信息;此外,由于该设计电路存在设计功能有限,所以会有相应的错误提示信息,主要如下:相关显示代码:
报告代号显示含义
1: -EOR-1 被除数等于0;
2: -EOR-2 被减数小于减数;
3: CHAG-1 表明从计算器模式切换到计时模式;
4: CHAG-0 表明从计时器模式切换到计算器模式;
5:-PAUSE 暂停;
7: -StoP- 停止;
8: OPPOSE 切换到倒计时模式;
9: -EOR-9 超出可显示的最大值。
5.2模式转换电路图
5.3错误提示电路图
5.4正常计算结果显示图
6.该设计电路的改进思想
出于我们水平有限,虽然我们设计的这个计算器具有计算和计时的多功能,但是还有很多不足,例如,该计算器只能实现正整数的加减乘除运算,无法实现小数以及负数的运算。
所以可以将该设计电路进行扩展,真正设计为一个多功能的科学计算器。
7.小结
不知不觉,两个星期的单片机实践课程学习就结束了,在一开始看这本书时,只对这门课程有了大致的了解,但只是理论上的理解,对如何应用却很是模糊,有些东西还是模棱两可,不是很明白,所以一开始进入实验室进行设计操作时,我是一头雾水,不知道到底该怎么办好,尤其是在程序编译时,程序经常有错误,让我们很是头疼郁闷,可没办法只好耐心慢慢找错误,有时真得都快失去耐心了,可是还是不能放弃,于是我们小组就在一起慢慢讨论,边看书边做,或者请教老师和同学,上课没完成,课后我们还是会重新再做,直到得出正确结论,虽然花了不少时间,但至少让我们学会了很多。
这是在软件中遇到的问题,此外在买器材时也遇到一些问题。
如,本来是要去买我们原先设定的标准型号的器材,但是在买器材的过程中发现,有些器材买不到,此时我们只好重新查阅资料,找具有相应功能的元器件代替,但必须要严格相近,否则,会影响电路的功能。
在焊接电路的时候,由于有些器件太小了如:贴片电容、贴片电阻等,所以难免会焊接错误,此时我们必须不停的调试找出错误,否则会导致整个电路的损坏。
虽然,在一开始接到这个设计任务时,我们感觉挺有压力的,担心做不好,但是团队的力量是不可小觑的,我们小组三人互相鼓励学习,所以我们在讨论中一步步进步,最终完成了任务。
当然,我们学到的只是一些最为基础的东西,还有很多东西还得深入学习,进一步加强。
总之在这次单片机学习中我们受益匪浅。
这不仅增强了我们对单片机设计的兴趣,更增强了自己的动手能力,这要感谢老师的指导和同学的帮助!
电子行业是一门发展相当迅速的行业,每天都会有新的产品和应用需求,所以,在学好书
本知识的同时还要时时关注相关领域的最新动态,学会自主分析解决目前技术中存在的问题。
作为一名电子信息类专业的学生,我们目前学习最好的方法就是多实践,多设计,为将来
的工作作好准备。
8.参考文献
(1)《跟我学用单片机》肖洪兵第2版北京:北京航空航天大学出版社, 2008.8
(2)《单片机高级教程》何立民第1版.北京:北京航空航天大学出版社,2006.6
(3)《单片机基础》李广第第1版.北京:北京航空航天大学出版社,1999.8
附录(程序清单)
//**<程序名>:计算器处理主程序,根据计算器的输入状态分派不同的函数对按键进行处理。
//**<功能>:当b_WorkMode=0是,若有键按下则调用此函数对键码进行处理。
头文件及宏定义
#include "CalReady.h"
*全局变量*
extern unsigned long ul_Number; //LCE显示数据,LCD实时显示该数字。
//<<<<<<<<<<<<工作模式(默认为计算器模式)>>>>>>>>>>>>>>>>>>>>>>>>>//
extern bit b_WorkMode; //0--计算器模式;
//1--计时模式。
//定义在KeyProcess.c中。
unsigned char uc_ModeChange=0;
extern bit b_LCDClean;
extern unsigned char uc_ReportSymbol;
unsigned long ul_NumberOne=0; //第一个数
unsigned long ul_NumberTwo=0; //第二个数
unsigned char uc_Operator=0; //运算符
unsigned long ul_Result=0; //运算结果
unsigned char uc_NumPointer=1; //计算状态
//*********************计算器处理主函数*********************//
void vCalculator(unsigned char ucKeyCode)
{
if(ucKeyCode==41) //判断按键是不是'NO/C'。
{
if(uc_NumPointer==1) //如果是‘NO/C’键则判断手机否是状态一。
{
if(uc_ModeChange==2) //如果是状态一则看uc_ModeChange是不是2。
{
uc_ModeChange=0; //如果是2则计时器模式。
b_WorkMode=1;
uc_ReportSymbol=3; //闪烁显示:-CHAG-1。
表明正在切换状态。
b_LCDClean=1;
}
else
{
uc_ModeChange++; //如果uc_ModeChange不是2则加一。
ul_NumberOne=0; //清除所有数据,将所有数据恢复到状态一。
ul_NumberTwo=0;
ul_Number=0;
uc_NumPointer=1;
}
}
else
{
ul_NumberOne=0; //清除所有数据,将所有数据恢复到状态一。
ul_NumberTwo=0;
ul_Number=0;
uc_NumPointer=1;
}
}
else
{ //如果不是“NO/C”键,首先将uc_ModeChange清零。
uc_ModeChange=0;
//<<<<<<<<<<<<<<根据不同状态分派不同的键处理函数>>>>>>>>>//
switch(uc_NumPointer)
{
case 1:
vCalReadyOne(ucKeyCode); //进入状态一。
break;
case 2:
vCalReadyTwo(ucKeyCode); //进入状态二。
break;
case 3:
vCalReadyThree(ucKeyCode); //进入状态三。
break;
default:break;
}
}
}
<程序名>:计算器案件初始处理及运算。
//<功能>:在计算器模式下,对按键进行响应,如清零,计算结果等//
//<错误代码>: -EOR-1:被除数等于0;//
// -EOR-2:被减数小于减数;//
// -EOR-9:超出可显示的最大值。
//
//*********************头文件及宏定义*********************//
//*************************全局变量***********************//
extern unsigned long ul_Number;
extern unsigned long ul_NumberOne;
extern unsigned long ul_NumberTwo;
extern unsigned char uc_Operator;
extern unsigned long ul_Result;
extern unsigned char uc_NumPointer;
extern bit b_LCDClean;
extern unsigned char uc_ReportSymbol;
bit b_Zero=0; //状态一0输入检测,若有0输入则置一。
//*************************计算结果*****************************//
void vGetResult()
{
switch(uc_Operator)
{
//*************************除法运算*****************************// case 14: if(ul_NumberTwo!=0)
ul_Result=ul_NumberOne/ul_NumberTwo;
else
{
ul_Result=0;
uc_ReportSymbol=1; //当被除数等于0时显示错误代码EOR-1//
b_LCDClean=1;
}
break;
//*************************乘法运算*****************************// case 24: if((ul_NumberOne*ul_NumberTwo)>999999)
{
ul_Result=0;
uc_ReportSymbol=9;
b_LCDClean=1; //当结果超出显示范围时显示错误代码EOR-9//
}
else
ul_Result=ul_NumberOne*ul_NumberTwo;
break;
//*************************减法运算*****************************//
case 34:
if(ul_NumberOne>ul_NumberTwo)
ul_Result=ul_NumberOne-ul_NumberTwo;
else
{
ul_Result=0;
uc_ReportSymbol=2; //当被减数小于减数时显示错误代码EOR-2//
b_LCDClean=1;
}
break;
//*************************加法运算*****************************// case 44:
if((ul_NumberOne+ul_NumberTwo)>999999)
{
ul_Result=0;
uc_ReportSymbol=9;
b_LCDClean=1; //当结果超出显示范围时显示错误代码EOR-9//
}
else ul_Result=ul_NumberOne+ul_NumberTwo;
break;
default:break;
}
ul_Number=ul_Result;
ul_NumberOne=0; //恢复计算前初始状态。
ul_NumberTwo=0;
uc_NumPointer=1;
b_Zero=0;
}
//**************************状态一预处理*********************//
//*************将1位数字压入第一个数字中*********************//
void vPushOne(unsigned char ucPushNum)
{
if(ul_NumberOne<100000) //如果数字小于6位则压入数字,否则不执行。
{
ul_NumberOne=ul_NumberOne*10+ucPushNum;
ul_Number=ul_NumberOne;
}
}
//*************状态一按键处理函数*****************************//
void vCalReadyOne(unsigned char ucKeyCode)
{
switch(ucKeyCode)
{ //如果由数字输入,则压入数字一。
case 11: vPushOne(7);break; //'7'
case 12: vPushOne(8);break; //'8'
case 13: vPushOne(9);break; //'9'
case 21: vPushOne(4);break; //'4'
case 22: vPushOne(5);break; //'5'
case 23: vPushOne(6);break; //'6'
case 31: vPushOne(1);break; //'1'
case 32: vPushOne(2);break; //'2'
case 33: vPushOne(3);break; //'3'
case 42: vPushOne(0);b_Zero=1;break; //'0',当压入数字为0时,置0检测标志。
default:
//<<<<<<<<<此处的b_Zero判断主要是为了实现连续运算功能>>>>>>>>>>>>>>>// if(b_Zero==0&&ul_NumberOne==0) //如果是运算符,则首先判断是否有0输入。
{ //如果没有0输入,然而数字1是0,ul_NumberOne=ul_Result; //说明是继续上一次运算,将上一次运算结束
switch(ucKeyCode) //赋给第一个数,进行连续运算。
{
case 14: uc_Operator=14;uc_NumPointer=2;break; //'/'
case 24: uc_Operator=24;uc_NumPointer=2;break; //*
case 34: uc_Operator=34;uc_NumPointer=2;break; //'-'
case 44: uc_Operator=44;uc_NumPointer=2;break; //'+'
default: break;
}
}
else
switch(ucKeyCode) //如果有0输入,则说明是全新计算,正常进行。
// {
case 14: uc_Operator=14;uc_NumPointer=2;break; //'/'
case 24: uc_Operator=24;uc_NumPointer=2;break; //*
case 34: uc_Operator=34;uc_NumPointer=2;break; //'-'
case 44: uc_Operator=44;uc_NumPointer=2;break; //'+'
default: break;
}
break;
}
}
//***********************状态二预处理******************************// //<<<<<<<<<<<<<<<<<<<<<<将1位数字压入第二个数字中>>>>>>>>>>>>>>>>>>//
void vPushTwo(unsigned char ucPushNum)
{
if(ul_NumberTwo<100000) //如果数字小于6位则压入数字,否则不执行。
{
ul_NumberTwo=ul_NumberTwo*10+ucPushNum;
ul_Number=ul_NumberTwo;
}
}
//<<<<<<<<<<<<<<<<<<状态二按键处理函数>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//
void vCalReadyTwo(unsigned char ucKeyCode)
{
switch(ucKeyCode) //状态二下如果有数字输入则将数字压入数字二,转到状态三。
{
case 11: vPushTwo(7);uc_NumPointer=3;break; //'7'
case 12: vPushTwo(8);uc_NumPointer=3;break; //'8'
case 13: vPushTwo(9);uc_NumPointer=3;break; //'9'
case 21: vPushTwo(4);uc_NumPointer=3;break; //'4'
case 22: vPushTwo(5);uc_NumPointer=3;break; //'5'
case 23: vPushTwo(6);uc_NumPointer=3;break; //'6'
case 31: vPushTwo(1);uc_NumPointer=3;break; //'1'
case 32: vPushTwo(2);uc_NumPointer=3;break; //'2'
case 33: vPushTwo(3);uc_NumPointer=3;break; //'3'
case 42: vPushTwo(0);uc_NumPointer=3;break; //'0'
//如果有运算符输入则将运算符键码存储在uc_Operator中。
case 14: uc_Operator=14;break; //'/'
case 24: uc_Operator=24;break; //*
case 34: uc_Operator=34;break; //'-'
case 44: uc_Operator=44;break; //'+'
default: break;
}
}
//*********************状态三预处理***************************//
//<<<<<<<<<<<<<<<<<<<<<状态三继续运算函数>>>>>>>>>>>>>>>>>>>>>//
void vCalContinue(unsigned char ucKeyCode)
{
vGetResult();
ul_NumberOne=ul_Result;
uc_Operator=ucKeyCode;
uc_NumPointer=2;
}
//<<<<<<<<<<<<<<<<<<<<<<状态三按键处理函数>>>>>>>>>>>>>>>>>>//
void vCalReadyThree(unsigned char ucKeyCode)
{
switch(ucKeyCode)
{ //状态三下如果有数字输入,则压入数字二。
case 11: vPushTwo(7);break; //'7'
case 12: vPushTwo(8);break; //'8'
case 13: vPushTwo(9);break; //'9'
case 21: vPushTwo(4);break; //'4'
case 22: vPushTwo(5);break; //'5'
case 23: vPushTwo(6);break; //'6'
case 31: vPushTwo(1);break; //'1'
case 32: vPushTwo(2);break; //'2'
case 33: vPushTwo(3);break; //'3'
case 42: vPushTwo(0);break; //'0'
//如果有“=”号输入则计算结果。
case 43: vGetResult();break; //'='
//如果有运算符输入则执行继续运算。
case 14: vCalContinue(14);break; //'/'
case 24: vCalContinue(24);break; //*
case 34: vCalContinue(34);break; //'-'
case 44: vCalContinue(44);break; //'+'
default: break;
}
}
//<程序名>:按键处理子函数//
//<功能>:当有外部中断0时调用此函数,获得键码,进行相应处理。
//
//*************************头文件及宏定义*********************//
#include "Timer.h"
//****************************全局变量***********************//
extern bit b_KeyShock; //键盘防抖动标志位。
//<<<<<<<<<<<<<<<<<<<工作模式(默认为计算器模式)>>>>>>>>>>>>>>//
bit b_WorkMode=0; //0--计算器模式;
//1--计时模式。
//******************************按键处理函数主函数****************************** *
//*
*
//*********************************************************************************** **************
void vKeyProcess(unsigned char ucKeyCodeTemp)
{
if(b_WorkMode==1)
vTimer(ucKeyCodeTemp); //当工作模式为计时模式时调用计时器处理函数。
else
vCalculator(ucKeyCodeTemp); //当工作模式为计算器模式时调用计算器处理函数。
//*********************************************************************************** **************
//*********************************************************************************** **************
//**<程序名>:键盘扫描子程序
**
//**<功能>:当有外部中断0时调用此函数,使用列扫描的方式获取键码,键码由2位数字组成。
高位为行号 **
//** 低位为列号。
**
//*********************************************************************************** **************
//*********************************************************************************** **************
//*********************************************************************************** **************
//*
*
//* ******************************头文件及宏定义************************** *
//*
*
//*********************************************************************************** **************
#include <at89x51.h>
#define SCANPORT P2 //4×4键盘扫描端口,低4位是行线,高4位是列线。
//采用逐列扫描的方法,无按键时,低4位输出1,高4位输出0。
//当有按键时,高4位输出扫描电位,低4位输入扫描结果。
//*********************************************************************************** **************
//*
*
//* ********************************全局变量****************************** *
//*
*
//*********************************************************************************** **************
unsigned char uca_LineScan[4]={0xEF,0xDF,0xBF,0x7F}; //列线扫描电压,分为第1,2,3,4根列线
//为低电平,其他为高电平。
//*********************************************************************************** **************
//*
*
//* ********************************函数实现****************************** *
//*
*
//*********************************************************************************** **************
unsigned char ucKeyScan()
{
unsigned char ucTemp=0; //扫描状态暂存。
unsigned char ucRow=0,ucLine=0; //行号,列号。
for(ucLine=0;ucLine<4;ucLine++) //列扫描
{
SCANPORT=uca_LineScan[ucLine]; //输出扫描电位。
ucTemp=SCANPORT&0x0F; //输入扫描电位,并屏蔽高4位。
if(ucTemp!=0x0F)
{ //判断该列是否有按键按下。
switch(ucTemp)
{
case 0x0E: ucRow=10;break; //如果有,则判断行号。
case 0x0D: ucRow=20;break;
case 0x0B: ucRow=30;break;
case 0x07: ucRow=40;break;
default: ucRow=50;break;
}
break;
}
}
return ucRow+ucLine+1; //返回按键编码。
格式为2位数,高位为行号,低位为列号。
}
//*********************************************************************************** **************
//*********************************************************************************** **************
//**<程序名>:LED动态扫描子函数。
**
//**<功能>:unsigned char * pucLedNum(unsigned long ulNumber);
**
//** 计算一个在000000到999999之间的数的每位数字并存储在数组中.并返回数组的首地址 **
//** void vShowOneNum(unsigned char ucOneNum,unsigned char ucOrder);
**
//** 输入一个数字以及所要显示的位置,在LED相应位置上显示相应数字.
**
//*********************************************************************************** **************
//*********************************************************************************** **************
//*********************************************************************************** **************
//*
*
//* ******************************头文件及宏定义************************** *
//*
*
//*********************************************************************************** **************
#include "LED6Show.h"
//*********************************************************************************** **************
//*
*
//* ********************************全局变量****************************** *
//*
*
//***********************************************************************************
**************
unsigned char code uca_LEDCode[]=
{0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF};
//0,1,2,3,4,5,6,7,8,9,空白。
unsigned char code uca_LEDSelect[]=
{0x01,0x02,0x04,0x08,0x10,0x20};
//分别点亮第6,5,4,3,2,1号灯。
unsigned char uca_LedNum[6];
//存放数字的各个位。
unsigned char uc_NumberFront=1; //只是数字的首位。
extern unsigned char uca_ShowCustom[]; //在自定义模式下,LCD实时显示该字符。
main.c
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<自定义报告显示字符>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
unsigned char uca_ReportChar1[]={0xBF,0x86,0xC0,0x88,0xBF,0xF9};
//被除数等于0。
-EOR-1
unsigned char uca_ReportChar2[]={0xBF,0x86,0xC0,0x88,0xBF,0xA4};
//被减数小于减数。
-EOR-2
unsigned char uca_ReportChar3[]={0xC6,0x89,0x88,0xC2,0xBF,0xF9};
//表明从计算器模式切换到计时模式。
CHAG-1
unsigned char uca_ReportChar4[]={0xC6,0x89,0x88,0xC2,0xBF,0xC0};
//表明从计时器模式切换到计算器模式。
CHAG-0
unsigned char uca_ReportChar5[]={0xBF,0x8C,0x88,0xC1,0x92,0x86};
//暂停-PAUSE
//unsigned char uca_ReportChar6[]={0xBF,0x92,0x87,0x88,0x88,0x87};
//开始-START
unsigned char uca_ReportChar7[]={0xBF,0x92,0x87,0xC0,0x8C,0xBF};
//停止-StoP-
unsigned char uca_ReportChar8[]={0xC0,0x8C,0x8C,0xC0,0x92,0x86};
//切换到倒计时模式OPPPOSE
unsigned char uca_ReportChar9[]={0xBF,0x86,0xC0,0x88,0xBF,0x90};
//超出可显示的最大值。
-EOR-9
//*********************************************************************************** **************
//*
*
//* ********************************函数实现****************************** *
//*
*
//*********************************************************************************** **************
unsigned char * pucLedNum(unsigned long ulNumber) //将一个数的各个位分别存到
{ //并返回首地址。
if(ulNumber>999999)
ulNumber=999999;
if(ulNumber<0)
ulNumber=0;
uca_LedNum[5] = ulNumber/100000; //最高位存在数组【5】中。
uca_LedNum[4] = (ulNumber-100000*(long)uca_LedNum[5])/10000;
uca_LedNum[3] = (ulNumber-100000*(long)uca_LedNum[5]-10000*(long)uca_LedNum[4])/1000;
uca_LedNum[2] = (ulNumber-100000*(long)uca_LedNum[5]-10000*(long)uca_LedNum[4]
-1000*(long)uca_LedNum[3])/100;
uca_LedNum[1] = (ulNumber-100000*(long)uca_LedNum[5]-10000*(long)uca_LedNum[4]
-1000*(long)uca_LedNum[3]-100*(long)uca_LedNum[2])/10;
uca_LedNum[0] = (ulNumber-100000*(long)uca_LedNum[5]-10000*(long)uca_LedNum[4]
-1000*(long)uca_LedNum[3]-100*(long)uca_LedNum[2]-10*(long)uca_LedNum[1]);
//最低位存在数组【0】中。
for(uc_NumberFront=1;uc_NumberFront<6;uc_NumberFront++)
{
if(uca_LedNum[6-uc_NumberFront]!=0) //判断数据的首位不为零数字在第几位。
break; //例如:8502的uc_NumberFront
} // 0的uc_NumberFront为6;
// 450530的uc_NumberFront为1。
return uca_LedNum;
}
//*********************************************************************************** **********************
//*
*
//* *****************************将1个1位数按顺序显示**************************** *
//*
*
//*********************************************************************************** **********************
void vShowOneNum(unsigned char ucOneNum,unsigned char ucOrder)
{
if(ucOneNum!=0) //如果数字不为0则正常输出。
{
LEDSELECT=0;
LEDCHAR=uca_LEDCode[ucOneNum]; //ucOrder:1~6
LEDSELECT=uca_LEDSelect[ucOrder-1];
}
{
if(ucOrder<uc_NumberFront) //如果为0则判断是不是在数字首位之前。
LEDSELECT=0; //如果在则输出空,不显示数据。
else
{
LEDSELECT=0; //如果在首位之后则正常输出。
LEDCHAR=uca_LEDCode[ucOneNum];
LEDSELECT=uca_LEDSelect[ucOrder-1];
}
}
}
//*********************************************************************************** **********************
//*
*
//* ***************************将1个自定义字符按顺序显示************************* *
//*
*
//*********************************************************************************** **********************
void vShowCustom(unsigned char ucOneCostom,unsigned ucOrder)
{
LEDSELECT=0;
LEDCHAR=ucOneCostom;
LEDSELECT=uca_LEDSelect[ucOrder]; //ucOrder:0~5
}
//*********************************************************************************** **********************
//*
*
//* ***********************将字符数组复制到字符显示数组中************************* *
//*
*
//*********************************************************************************** **********************
void vCharCopy(unsigned char ucaArray[])
{
unsigned char ucCount;
for(ucCount=0;ucCount<6;ucCount++)
{
uca_ShowCustom[ucCount]=ucaArray[ucCount];
}
}
//*********************************************************************************** **********************
//*
*
//* ***********************根据报告代号,显示不同的报告字符
************************* *
//*
*
//*********************************************************************************** **********************
void vShowReport(unsigned char ucSymbol)
{
switch(ucSymbol)
{
case 1:vCharCopy(uca_ReportChar1);break; //显示:-EOR-1--被除数等于0;
case 2:vCharCopy(uca_ReportChar2);break; //显示:-EOR-2--被减数小于减数;
case 3:vCharCopy(uca_ReportChar3);break; //显示:CHAG-1--表明从计算器模式切换到计时模式;
case 4:vCharCopy(uca_ReportChar4);break; //显示:CHAG-0--表明从计时器模式切换到计算器模式;
case 5:vCharCopy(uca_ReportChar5);break; //显示:-PAUSE--暂停;
// case 6:vCharCopy(uca_ReportChar6);break; //显示:-StART--开始;
case 7:vCharCopy(uca_ReportChar7);break; //显示:-StoP---停止;
case 8:vCharCopy(uca_ReportChar8);break; //显示:OPPOSE--切换到倒计时模式;
case 9:vCharCopy(uca_ReportChar9);break; //显示:-EOR-9--超出可显示的最大值。
default:break;
}
}
//*********************************************************************************** **************
//*********************************************************************************** **************
//**<程序名>:多功能计算器
**
//**<功能>:可以进行6位数以内正整数的加减乘除运算,以及计时器和自定义倒计时功能
**
//* ******************************头文件及宏定义************************** *
#include "includes.h"
#define TIME0H 0xFC
#define TIME0L 0x18 //定时器0溢出时间:5ms
#define TIME1H 0x44
#define TIME1L 0x80 //定时器1溢出时间:48ms
//*********************************************************************************** **************
//*
*
//* ********************************全局变量****************************** *
//*
*
//*********************************************************************************** **************
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<定时器0定时刷新LED计数>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
unsigned long ul_Number=0; //LCD实时显示数字。
unsigned char uca_ShowCustom[6]={0x88,0x83,0xC6,0xA1,0x86,0x84};
//存放自定义显示字符。
unsigned char uc_DisCount=1; //LCD时事刷新计数。
bit b_ShowMode=0; //显示模式标志位。
//0--数字模式,将要显示的数字赋给ul_Number便可时事显示数值,
// 默认为数字模式;
//1--自定义模式,该模式下自定义字符显示。
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<定时器1计数刷新定时(计时模式)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
unsigned char uc_TimeCount=1; //定时器1定时计数。
bit b_ClockStart=0; //定时器1显示计数标志位。
extern bit b_ClockOppose; //TimeOppose.c
extern unsigned long ul_ClockOppose;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<防抖动标志>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
bit b_KeyShock=0; //键盘防抖动标志位。
//当按键中断产生时,首先判断此位。
//0--执行键盘扫描及键码处理程序;1--不执行。
bit b_KillShock=0; //防抖标志清除位:0--不清除;1--清除。
unsigned char uc_KillCount=1; //抖动标志清除计数,使用定时器1。
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<LCD闪烁显示报告>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
bit b_LCDClean=0; //通过设置b_LCDClean为1便可启动延时清空LCD显示。
unsigned char uc_CleanCount=1; //延迟时间可在T1中断中设定。
unsigned char uc_ReportSymbol;
bit b_ReportFlash=0;
unsigned char uca_FlashBlank[]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
//*********************************************************************************** **************
//*
*
//* ********************************主函数****************************** *
//*
*
//*********************************************************************************** **************
void main()
{
P2=0x0F; //初始化键盘接口。
TMOD=0x11; //定时器0:模式一;定时器0:模式一.
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<定时器0,用于LCD刷新>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
TH0=TIME0H;
TL0=TIME0L;
TR0=1; //开启定时器0
ET0=1; //开定时器0中断
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<定时器1,用于1s计时 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
TH1=TIME1H;
TL1=TIME1L;
TR1=1; //开启定时器1
ET1=1; //开定时器1中断
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<外部中断0,用于执行键盘扫描和键处理程序>>>>>>>>>>>>>>>>>>>>>>>>>>>
IT0=1; //外部中断0,中断方式:下降沿
EX0=1; //开启外部中断0
PT0=1; //把定时器0溢出中断设为高优先级。
EA=1; //开启总中断
while(1);
}。