/************************************
*
*实验项目:基于51单片机的多功能计算器设计
*整理日期:2015年11月13日16:32:20
*设计人: 天空之恋
*联系: 2764908789
*淘宝店: 桂电电子实验室
地址: https://shop106644217.taobao.com/?spm=a230r.7195193.1997079397.2.ILTxcp
牛x的功能。。。完整版未删节。。。后面有改进的程序,实现起来更加简单
还没有整理。。。
********************************************************************/
#include "reg51.h"
#include "液晶.h"
#include "ds1302.h"
#include "math.h"
#include "timer.h"
#include "delay.h"
#define uchar unsigned char
#define uint unsigned int
#define pi 3.141592653
//特殊位定义
sbit func=P3^5;//因为是4行5列,需要9个数据口,这个地方单独声明3.5口作为调节时间使用
sbit fun_math=P3^6;
sbit beep=P2^4;
//全局变量定义,这个地方可以统一使用一个结构体进行操作。
//计算器部分全局变量
uchar dis_time=0; //当distime为1时,显示一次时间,
uchar state=0; //定义系统所处的状态0-1-2-3
uchar codes;//定义当前输入键值
uchar key_num[10]; //
uchar key_n=0;//记录按下的次数
uchar arith=0;//定义运算符号
long data0; //第一个数据 ,因为计算器是对两个数据进行计算,这个第一个输入的数据
long data1; //第二个数据 这是第二个数据的数据,按下等号键后对这两个数据进行相关运算
uchar point_en=0; //小数点使能,一个数据中只能有一个小数点,这个变量作为控制小数点输入的开关
double result1=0; //最终的运算结果
uchar dis_num=0;//记录结果中的个数
uchar fir_n=0; //
uchar unlock=0; //键盘不锁住
uchar clear=0;//清除系统的全局性标志变量
uchar neg_label=0; //输入负号的标志变量
uchar wrong=0; //计算超限标志位
uchar TIM=0;//控制大约1S显示一次时间
unsigned char get_fun=0;
uchar code dis[20]={
0XE7,0XEB,0XDB,0XBB,0XED,0XDD,0XBD,
0XEE,0XDE,0XBE,0XD7,0XB7,0X77,0X7B,0X7D,0X7E,
0X0E,0X0D,0X0B,0X07
};//矩阵键盘键值
uchar dat_out[12];
uchar code mathlabel[4]={43,45,42,47};//运算符
extern uchar time_en; //显示时间使能
extern uchar en_alarm; // 闹钟使能
extern uchar cursor;
//万年历部分的标志变量
//显示星期字符
uchar point_x[4];//
////////////////////////////////////////////////////
/**********************************
* 开始界面计算器部分的程序
/////////
/*****************************
* 函数名称:计算器变量初始化 init_var
* 函数功能:初始化计算器 所使用的变量
*
*
*
********************************************/
void init_var()
{
uchar i=0;
point_en=1;//允许输入小数点
state=0;
unlock=0;
arith=0;
fir_n=0;
neg_label=1;
wrong=0;
for(i=0;i<10;i++)
{
key_num[i]=0;
}
}
/*****************************
* 函数名称:键盘扫描函数 keyscan
* 函数功能:对矩阵键盘进行扫描,获取键值
7 8 9 +(光标选择) 复位/时钟
4 5 6 - 改时间/设闹钟
1 2 3 * 增加
0 . = / 减小
*
*
*
********************************************/
void keyscan()
{
uchar mm;
uchar mm2=0;
uchar i=0;
mm=0;
P1=0XF0;
mm=P1;//读数据
mm=mm&0XF0;
if(mm!=0xf0||func==0||fun_math==0)//需要对func 进行判断
{
delay(20);
mm=P1;
mm=mm&0XF0; //消抖
if(mm!=0xF0||func==0||fun_math==0)
{
unlock=1;
if((func!=0))
{
if(fun_math!=0)
{
P1=0X0F;
for(i=0;i<20;i++);
mm2=P1;
mm2=mm2&0x0f;
mm=mm+mm2;
for(i=0;i<16;i++)//读取0-15键值
{
if(mm==dis[i])
{
codes=i;
}
}
if(codes==15&&time_en==1)//这个地方考虑到使用复用功能----光标显示位置控制
{
if(en_alarm>0)
{
cursor++; // 是这个的原因
delay(300);//尽量简单处理
}
}
}
else
{
P1=0XFF;
get_fun=0;
fun_math=0;
mm=P1&0X0F;
for(i=16;i<20;i++)
{
if(mm==dis[i])
{
codes=i+1; //分别对应的是sin cos tan log这些函数
}
}
fun_math=1;
delay(30);
get_fun=1;
//这个地方应该直接求函数了
}
}
else //16-19 万年历控制
{
P1=0XFF;
func=0;
mm=P1&0X0F;
for(i=16;i<20;i++)
{
if(mm==dis[i])
{
codes=i;
}
}
func=1;
delay(30);
}
}
}
}
/*****************************
* 函数名称:输入数据转成实数 get_num
* 函数功能: 为了计算,需要把输入的数据变成实数。
* 此外这个地方需要考虑小数点问题,处理小数计算问题的
方法是:对齐法,比如12.36-2.3 我们实际计算的时候是用
1236-230,首先把12.36小数点后面数据多,先把最多的这个变成实数,因为最高的
乘100,而则需要2.3成100,就是230.计算都是使用整数进行运算的。
*
********************************************/
void get_num(uchar set_dat)
{
//
//将数组中的数据转换成实数
long num=0;
uchar i;
uchar re_num=0;
for(i=0;i<key_n;i++) //key_n要仔细的检查
{
re_num=key_num[i];
if(re_num<10)
{
num=num*10+re_num;//变量的类型要特别的注意
}
}
if(set_dat==0)
{
if(point_x[0]!=0)
{
point_x[1]=key_n-point_x[0];//这个地方保存小数点后面的数据
}
data0=num;
if(neg_label==0)
{
data0=0-data0;
}
}
else
{
if(point_x[2]!=0)
{
point_x[3]=key_n-point_x[2];//这个地方保存小数点后面的数据
}
data1=num;
if(neg_label==0)
{
data1=0-data1;
}
}
}
/*****************************
* 函数名称:获得第一次输入数据 get_first
* 函数功能: 获得第一个数据,主要用于计算器计算中。
第一个数据可能是数字键-----负号----以及功能切换键
其他键不作出响应。
此函数系统工作在0状态和 2时调用的,也就是输入一个运算数据和第二个运算数据时调用
*
********************************************/
void get_first(uchar set_state)
{
if(codes<10)//这个地方还是要限定一次的
{
if(clear==1)
{
//这个地方要清屏了
lcd_wcmd(0x01); //清除LCD的显示内容
init_var();
clear=0;
}
key_num[0]=codes;//获取键值,并转移到下一个状态
key_n=1;
state=set_state;//获取下一个状态
lcd_pos(key_n-1+fir_n);//这个要加上上一次的
lcd_wdat(codes+48);//这个地方只是显示数字
//
}
else if(codes==14&&neg_label==1) //就出在这个地方了
{
//这个只允许一次
if((arith==0)&&(clear==1))
{
//这里是第二个刷屏的地方
lcd_wcmd(0x01); //清除LCD的显示内容
init_var();
clear=0;
}
neg_label=0; //有负数出现
lcd_pos(key_n+fir_n);
fir_n=fir_n+1;//这个不计入,只是微调显示部分就可以了
lcd_wdat(45);
}
else if(codes==16) //这个地方是来启动的
{
//这个把定时器打开了
if(time_en==0) //
{
time_en=1;
lcd_wcmd(0x01); //清除LCD的显示内容
init_var();
dis_timer_char();//进入定时器模式
state=1;//
}
}
}
/*****************************
* 函数名称: get_array
* 函数功能: 在获得第一个数据之后,就开始调用函数,获得以后输入的数据。这个地方之所以与第一个数据
分开是因为,需要进行运算的数据必须以数字键或符号键开头,不能以+ *这些符号键开头,在第一个值输入后,就
可以输入这些符号了,该函数是在第1和3状态中调用
*
********************************************/
void get_array(uchar t)
{
if(key_n==1)//对于第二个数据要讨论
{
if(key_num[0]==0)//第一个数据为0
{
//这里只能是小数点
if(codes==10&&point_en==1)
{
//显示小数点
key_num[1]=46;
key_n++;//显示新的数据
point_x[t]=key_n;
point_en=0;//这个地方禁止第二次按下小数点
lcd_pos(key_n-1+fir_n);//这个要加上上一次的
lcd_wdat(46);
}
else if(codes<10)
{
key_num[0]=codes;//获取键值,并转移到下一个状态
key_n=1;
if(state==0)
{
state=1;
}
else if(state==2)
{
state=3;
}
// state=set_state;//获取下一个状态
lcd_pos(key_n-1+fir_n);//这个要加上上一次的
lcd_wdat(codes+48);//这�
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
完整版51计算器.zip (34个子文件)
完整版计算器
计算器第一版程序
test.M51 77KB
液晶.LST 5KB
test.uvproj 14KB
test.uvgui.zhonhkai 71KB
test.uvopt 8KB
test.plg 0B
ds1302.c 1KB
ds1302.OBJ 4KB
delay.h 26B
test.lnp 96B
timer.c 13KB
main.OBJ 37KB
timer.OBJ 23KB
delay.LST 1KB
ds1302.h 198B
test.uvgui.lenovo 79KB
test_uvproj.bak 14KB
test_uvopt.bak 58KB
timer.LST 28KB
delay.c 249B
液晶.OBJ 6KB
ds1302.LST 4KB
test.hex 21KB
timer.h 412B
main.LST 47KB
delay.OBJ 733B
main.c 19KB
液晶.h 133B
test 59KB
液晶.c 2KB
test.uvgui_lenovo.bak 76KB
计算器仿真
计算器仿真环境.PWI 935B
计算器仿真环境.DSN 147KB
Last Loaded 计算器仿真环境.DBK 147KB
共 34 条
- 1
sunlinyi66
- 粉丝: 116
- 资源: 13
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
- 1
- 2
前往页