51数码管和矩阵按键实现计算器—满足输出负数和任意小数点的加减乘

目录

总览

边缘模块代码

核心模块代码

思考


总览

数码管和按键两个大方向模块,以及delay和定时器中断(用于判断按键是否按下)边缘模块

数码管:显示逻辑模块+显示什么内容模块

按键:按键状态模块(判断是否按下)+按键扫描(哪个按键被按下了)+按键执行的动作

本次任务核心就是修改上面两个标识重点的模块

边缘模块代码

4x4矩阵键盘模块

#include <REGX52.H> 

// 定义键盘和输出端口的引脚
sbit k1 = P3^0; // 第一行按键输入
sbit k2 = P3^1; // 第二行按键输入
sbit k3 = P3^2; // 第三行按键输入
sbit k4 = P3^3; // 第四行按键输入
sbit o1 = P3^4; // 第一列输出
sbit o2 = P3^5; // 第二列输出
sbit o3 = P3^6; // 第三列输出
sbit o4 = P3^7; // 第四列输出

// 当前状态矩阵,用于记录按键的当前状态
unsigned char cur_sta[4][4] = {
    {1, 1, 1, 1},
    {1, 1, 1, 1},
    {1, 1, 1, 1},
    {1, 1, 1, 1}
};

// 扫描键盘,返回按键值
char key_scan()
{
    static unsigned char pre_sta[4][4] = {
        {1, 1, 1, 1},
        {1, 1, 1, 1},
        {1, 1, 1, 1},
        {1, 1, 1, 1}
    };
    char key_value = -1;
    char i, j;

    for (j = 0; j < 4; j++) 
    {
        for (i = 0; i < 4; i++) 
        {
            if (pre_sta[j][i] != cur_sta[j][i]) 
            {
                if (pre_sta[j][i]) 
                {
                    key_value = 4 * j + i;
                }
                pre_sta[j][i] = cur_sta[j][i];
            }
        }
    }
    return key_value;
}

// 更新按键当前状态
void cur_sta_update()
{
    char i;
    static char j = 0;
    static unsigned char buff[4][4] = {
        {0xFF, 0xFF, 0xFF, 0xFF},
        {0xFF, 0xFF, 0xFF, 0xFF},
        {0xFF, 0xFF, 0xFF, 0xFF},
        {0xFF, 0xFF, 0xFF, 0xFF}
    };

    buff[j][0] = (buff[j][0] << 1) | k1;
    buff[j][1] = (buff[j][1] << 1) | k2;
    buff[j][2] = (buff[j][2] << 1) | k3;
    buff[j][3] = (buff[j][3] << 1) | k4;

    for (i = 0; i < 4; i++) 
    {
        if (buff[j][i] == 0xFF)
        {
            cur_sta[j][i] = 1;
        }
        else if (buff[j][i] == 0x00)
        {
            cur_sta[j][i] = 0;
        }
    }
    
    j++;
    if (j == 4) 
    {
        j = 0;
    }

    switch (j) 
    {
        case 0: o1 = 0; o2 = 1; o3 = 1; o4 = 1; break;
        case 1: o1 = 1; o2 = 0; o3 = 1; o4 = 1; break;
        case 2: o1 = 1; o2 = 1; o3 = 0; o4 = 1; break;
        case 3: o1 = 1; o2 = 1; o3 = 1; o4 = 0; break;
        default: break;
    }
}

数码管显示逻辑模块

#include <REGX52.H> 
#include "delay.h" 

extern unsigned char DispCode[]; // 声明外部变量,存储要显示的段码

// 动态控制LED段码显示的函数
void segled_dynamic()
{
    static unsigned char i = 0; // 静态变量,用于跟踪当前显示的段

    P0 = DispCode[i]; // 设置要显示的段码
    P2 = (0xfe << i) | (0xfe >> (8 - i)); // 控制显示的位置
    delay(1); // 稍微延时以保持显示
    P2 = 0xff; // 关闭所有段的显示

    i++; // 移至下一个段
    if (i == 8) 
    {
        i = 0; // 如果已经显示了最后一个段,回到第一个段
    }
}

核心模块代码

显示什么内容模块

void  Show_value(unsigned int Value,unsigned char point_pos,bit point_flag)//point_pos判断小数点位置
{ unsigned int tmp;																												 //point_flag判断是否有小数点
	unsigned char i, k=0;
	tmp=Value;
 for(i=0;i<8;i++)
	DispCode[i]=0x00;
 do
 {
   DispCode[7-k]=led_mode[tmp%10];
	 k++;
	 tmp=tmp/10;
 }while(tmp);
 if(point_flag)
	 DispCode[7-point_pos]=DispCode[7-point_pos]|0x80;//显示小数点在指定位置
}

按键执行动作模块

void key_action(char key_value)
{
	static unsigned int result=0;
	static unsigned int cur_value=0;
	static unsigned char point_pos=0;
	static bit point_flag=0;
	char op;
 if(key_value>=0 && key_value<=8)// 数字按键,数字往前推
 {
	 cur_value=cur_value*10+key_value;
	 if(point_flag)
	 {
		 point_pos++;//小数点位置也往前推
	 }
	 Show_value(cur_value,point_pos,point_flag);//显示
 }
 else if(key_value==9) // 小数点按键
 {
	 if(point_flag==0)
	 {
    point_flag=1;
		 DispCode[7]=DispCode[7]|0x80;
	 }
 }
 else if(key_value>=10 && key_value<=13)//+ - * /
 {
	 switch(key_value)
	 {
		 case 10:op='+';break;
		 case 11:op='-';break;
		 case 12:op='*';break;
		 case 13:op='/';break;
		 default:break;
   }
	 result=cur_value;
	 point_pos_pre=point_pos;
	 point_pos=0;
	 point_flag=0;
	 cur_value=0;
 }
 else if(key_value==14) // =,没写完的左移!!
 {
	 if(point_pos>point_pos_pre)
	 {
	   left_shift_dec(result,point_pos-point_pos_pre);
	 }
	 else
	 {
	 left_shift_dec(cur_value,point_pos_pre-point_pos);
	 }
  switch(op)
	 {
		case '+': result+=cur_value;break;
		case '-': result-=cur_value;break; 
		case '*': result*=cur_value;break;
		case '/': result/=cur_value;break;
		default:break;
	 }
	 cur_value=result;
	 Show_value(result, point_pos,point_flag);
 }
 else if(key_value==15) //归零
 {
  result=0;
	cur_value=0;
  Show_value(result,point_pos,point_flag); 
 }
}

主函数和定时器

void main()
{
	char key_value=-1;
	timer_config();
	while(1)
	{
	 key_value=key_scan();
	 key_action(key_value);
		segled_dynamic();
	}
}

void timer_2ms() interrupt 1
{
	TH0=63536/256;
	TL0=63536%256;
 cur_sta_update();
}

思考

  • 51无法完成浮点数精度的计算,所以得用点手段才能得到一些高精度的除法结果,按照你要保留的小数点位数n,先给被除数扩大10的n次方倍,再最后的结果去“回点”小数点就可以
  • 显示小数点有很多种逻辑,这种是最简易的,多用一个变量放小数点位置,一个变量判断是否有小数点
  • 减法输出负号就是很简单的一个if判断就好了
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值