基于51单片机的数码管和矩阵按键实现的简易计算器,其实可以加入的东西有很多,就像我这个负数运算还没有加进去,以及我的除法运算只能算655(65535/100)以内的数,不过就先做到这里,这个作品至少已经叫做计算器了。
首先我这个工程里加入了两个文件,数码管显示文件,查询式矩阵按键文件,直接调用这两块功能的函数,然后在主函数里解决相当于软件层的计算器功能。
简易计算器实现的功能(待完善)
- 四则运算
- 可以显示2位小数
- 利用矩阵按键输入,用数码管显示
- 连续运算
- 负数运算
代码的解释和功能实现
其它函数说明:
/*定义局部函数*/
void deletenum(int s[]);//退位函数,用于退1位,等同'c'
void addnum(int s[]);//加位函数,在输入下一位数的时候将前面的数后移1位
void count(void);//计算函数等同'='
unsigned long pow10(u8 n);//计算10的n次方
void init(void);//计算完成后初始化第二个输入数
void division(void);//除法运算
void multiplication(void);//乘法运算
void subtraction(void);//减法运算
void addition(void);//加法运算
/*定义变量*/
int gDigValue[8];//gDigValue用于显示数码管作为全局变量
int val[8],a[8],b[8];//分别存放运算结果,第一个数,第二个数
unsigned long sum=0,um=0;//sum用于存储被除数
u8 num=0,ch=0;//ch存放运算符,num存放键值
u8 flag1=0,flag2=1,next_flag=1;//分别代表是否有小数点,是否显示运算结果,是否要输入下一个数
/*主函数
用于放置主要流程:1.获取键值,根据键值进行操作 2.分情况将数值显示在数码管
(输入数字时显示正在输入的数,运算后显示结果)
*/
void main(void)
{
while(1)
{
num=key_val();//获取键值
if(num!=17)
flag2=1;//当有按键按下,不再显示运算结果,改为显示正在输入的数
WaitForKeyUp();
if(next_flag)
{
if(num>9)
{
switch(num)
{
case 14:deletenum(a);break;//退位
case 15:break;//没有输入运算符的时候不能计算
case 17:break;//没有按键按下
default:ch=num;next_flag=0;break;//当按下的是运算符,用ch先保存,然后输入下一个数的标志next_flag等于0(逻辑否)
}
}
else
{
addnum(a);
a[7]=num;
}
}
else
{
if(num>9)
{
switch(num)
{
case 14:deletenum(b);break;
case 15:count();break;//在输入运算符后可以计算
case 17:break;//没有按键按下
default:ch=num;break;
}
}
else//如果输入数字,所有数字左移一格,然后输入新的数字
{
addnum(b);//左移
b[7]=num;
}
}
if(flag2)//是否显示运算结果
{
if(next_flag)//显示正在输入的数
for(u8 i=0;i<8;i++)
{
gDigValue[i]=a[i];
}
else
for(u8 i=0;i<8;i++)
{
gDigValue[i]=b[i];
}
}
else
{
if(flag1 && val[7]==0 && val[6]==0)//如果没有小数位(小数点后两位为0),则去掉小数点,所有数字右移两格
{
flag1=0;//不再显示小数点
for(int j=7;j>=2;j--)//右移两格
{
val[j]=val[j-2];
}
val[0]=0;
val[1]=0;
}
for(u8 i=0;i<8;i++)
{
a[i]=val[i];//让第一个数变为运算的结果,可以连续运算
gDigValue[i]=val[i];//显示运算结果
}
}
DigDisplayVal();//数码管显示数值
}
}
/*用于获取键值,方便键值的改变,包含在key.c文件中*/
u8 key_val(void)
{
switch(KeyScan())//获得查询式获取键值的结果
{
case 1:return 7;break;//数字7
case 2:return 8;break;//数字8
case 3:return 9;break;//数字9
case 4:return 11;break;// / 除号
case 5:return 4;break;//数字4
case 6:return 5;break;//数字5
case 7:return 6;break;//数字6
case 8:return 12;break;// * 乘号
case 9:return 1;break;//数字1
case 10:return 2;break;//数字2
case 11:return 3;break;//数字3
case 12:return 13;break;// - 减号
case 13:return 14;break;// 退位
case 14:return 0;break;//数字0
case 15:return 15;break;// = 等于
case 16:return 16;break;// + 加号
default:return 17;//没有按下按键时返回17
}
}
四则运算函数,除了除法
,其他的类比列式计算
是不是生动形象
/*减法运算*/
void subtraction(void)
{
for(int i=7;i>=0;i--)
{
val[i]=a[i]-b[i];
if(val[i]<0)//小于0的要借位
{
val[i]+=10;
a[i-1]-=1;
}
}
}
/*加法运算*/
void addition(void)
{
for(int i=7;i>=0;i--)
{
val[i]=a[i]+b[i];
if(val[i]>9)//大于10的要进位
{
val[i]-=10;
val[i-1]+=1;
}
}
}
/*乘法运算*/
void multiplication(void)
{
for(int i=7;i>=0;i--)//类比我们的列式乘法,将乘数的每一位分别和被乘数的每一位相乘。
{
for(int j=7;j>=0;j--)
{
if(i+j>=7)
val[i-7+j]+=a[i]*b[j];
}
}
for(int i=7;i>=0;i--)//将每一位大于10的进位
while(val[i]>9)
{
val[i]-=10;
val[i-1]+=1;
}
}
/*除法运算,这个算法受51单
片机运算能力限制只能运算输
入数字在655以内的除法。顺
带一提,要显示小数点,我们
需要回到数码管显示的底层函
数里,将段码|(位与)一个0x80,
也就是DIG_PORT=gDuanMa[gDigVal[i]] | 0x80;
*/
void division(void)
{
for(int i=7;i>=0;i--)
{
sum=sum+a[i]*pow10(7-i);//将输入的第一个数(被除数)获取
um=um+b[i]*pow10(7-i);//将输入的第二个数(除数)获取
}
if(sum<1000000)//共两位小数点,所以整数部分最多6位,实际上到不了那么多位
{
sum=(sum*100)/um;
for(int i=0;i<8;i++)
{
val[7-i]=(sum%pow10(i+1))/pow10(i);
}
flag1=1;
}
}