/************************************
*
*实验项目:基于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);//这�
![avatar](https://profile-avatar.csdnimg.cn/2fa002bb6a04410283b494590fddc240_sunlinyi66.jpg!1)
sunlinyi66
- 粉丝: 116
- 资源: 13
最新资源
- 陕理工图书馆管理系统系统ssm.zip
- 小学芙童币和芙童印章管理系统ssm.zip
- 学生过程性评价系统ssm.zip
- 郑州经贸学院迎新系统springboot.zip
- 智慧家政在线预约管理系统的设计与实现ssm.zip
- 支教系统springboot.zip
- 智慧农贸信息化管理平台ssm.zip
- 信息技术寒假作业.zip
- 2003-2019年各省对外开放度数据(含原始数据+计算过程+结果)
- 电机控制直流有刷电机电流采样-LM324电流采样
- 局域网IP搜索工具IPScaner V1.1
- deepseek 8b 本地部署 ollama0.5.9
- 四、RAG接入agent 问答文档
- USB驱动程序.rar
- 收银一体秤顶尖等Windows版电子秤设置(内含图解)
- 2025 DeepSeek隐私政策-如何正确使用DeepSeek和保护隐私.pdf
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
![feedback](https://img-home.csdnimg.cn/images/20220527035711.png)
![feedback](https://img-home.csdnimg.cn/images/20220527035711.png)
![feedback-tip](https://img-home.csdnimg.cn/images/20220527035111.png)
- 1
- 2
前往页