【51单片机系列】矩阵按键扩展实验
本文对矩阵按键的一个扩展,利用矩阵按键和动态数码管设计一个简易计算器。代码参考:https://blog.csdn.net/weixin_47060099/article/details/106664393
实现功能:使用矩阵按键,实现一个简易计算器,将计算数据及计算结果显示在数码管中。
矩阵按键设计如下图
代码实现:
/*
实现功能:使用矩阵按键实现简易计算器
[2023-12-07] zoya
*/
#include "reg52.h"
typedef unsigned char u8;
typedef unsigned int u16;
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
#define GPIO_DIG P0 // 动态数码管
#define GPIO_KEY P1 // 矩阵按键
u16 KeyValue; // 存放读取到的键值
u16 keyflag, i; // 用来判断按下的数字还是运算符或是清空键
u8 code smg[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x00}; // 共阴极数码管
u16 wei[8] = {0}; // 存放每一位数码管数字的数组
// 延时函数,i=1延时10us
void delay(u16 i)
{
while(i--);
}
// 扫描显示动态数码管
void Display()
{
LSA = 0; LSB = 0; LSC = 0; GPIO_DIG = smg[wei[7]]; delay(50); GPIO_DIG = 0x00; // 段选Y0,位选显示,延时,消隐
LSA = 1; LSB = 0; LSC = 0; GPIO_DIG = smg[wei[6]]; delay(50); GPIO_DIG = 0x00; // 段选Y0,位选显示,延时,消隐
LSA = 0; LSB = 1; LSC = 0; GPIO_DIG = smg[wei[5]]; delay(50); GPIO_DIG = 0x00; // 段选Y0,位选显示,延时,消隐
LSA = 1; LSB = 1; LSC = 0; GPIO_DIG = smg[wei[4]]; delay(50); GPIO_DIG = 0x00; // 段选Y0,位选显示,延时,消隐
LSA = 0; LSB = 0; LSC = 1; GPIO_DIG = smg[wei[3]]; delay(50); GPIO_DIG = 0x00; // 段选Y0,位选显示,延时,消隐
LSA = 1; LSB = 0; LSC = 1; GPIO_DIG = smg[wei[2]]; delay(50); GPIO_DIG = 0x00; // 段选Y0,位选显示,延时,消隐
LSA = 0; LSB = 1; LSC = 1; GPIO_DIG = smg[wei[1]]; delay(50); GPIO_DIG = 0x00; // 段选Y0,位选显示,延时,消隐
LSA = 1; LSB = 1; LSC = 1; GPIO_DIG = smg[wei[0]]; delay(50); GPIO_DIG = 0x00; // 段选Y0,位选显示,延时,消隐
}
// 检测有按键按下并读取键值
void KeyDown()
{
u16 a = 0;
GPIO_KEY = 0x0f; // 行全部为低电平,列全部为高电平
if(0x0f != GPIO_KEY) // 读取按键是否按下
{
delay(1000); // 延时10ms进行消隐
if(0x0f != GPIO_KEY)
{
// 测试列
GPIO_KEY = 0x0f;
switch(GPIO_KEY) // 行列扫描法
{
case 0x07: KeyValue = 0; break;
case 0x0b: KeyValue = 1; break;
case 0x0d: KeyValue = 2; break;
case 0x0e: KeyValue = 3; break;
}
// 测试行
GPIO_KEY = 0xf0;
switch(GPIO_KEY) // 行列扫描法
{
case 0x70: KeyValue = KeyValue; break;
case 0xb0: KeyValue = KeyValue + 4; break;
case 0xd0: KeyValue = KeyValue + 8; break;
case 0xe0: KeyValue = KeyValue + 12; break;
}
if(KeyValue==0 || KeyValue==1 || KeyValue==2 || KeyValue==3 || KeyValue==4 || KeyValue==5
|| KeyValue==6 || KeyValue==7 || KeyValue==8 || KeyValue==9)
{
keyflag=1;
}
}
while( (a < 50) && (GPIO_KEY != 0xf0) ) // 按键松手检测
{
delay(1000);
a++;
}
}
}
void main()
{
u16 a=0, b=0, c=0;
while(1)
{
Display();
KeyDown(); // 键入第一个数字
if(1 == keyflag)
{
for(i=7;i>0;i--)
{
wei[i] = wei[i-1]; // 键入一位数字向左移动一位
}
wei[0] = KeyValue;
keyflag = 0;
}
else if(14 == KeyValue) // 清空显示
{
for(i=0;i<8;i++)
{
wei[i] = 0;
}
Display();
}
else if(10 == KeyValue) // 加法运算
{
a = wei[0] + wei[1]*10 + wei[2]*100 + wei[3]*1000 +
wei[4]*10000 + wei[5]*100000 + wei[6]*1000000 +
wei[7]*10000000;
for(i=0; i<8; i++)
{
wei[i] = 0;
}
// 输入第二个数
while(1)
{
Display();
KeyDown(); // 输入第二个数
if(15 == KeyValue)
break; // 当识别到等号时,停止输入
if(1 == keyflag)
{
for(i=7; i>0; i--)
{
wei[i] = wei[i-1];
}
wei[0] = KeyValue;
keyflag = 0;
}
}
b = wei[0] + wei[1]*10 + wei[2]*100 + wei[3]*1000 +
wei[4]*10000 + wei[5]*100000 + wei[6]*1000000 +
wei[7]*10000000;
c = a + b;
wei[0] = c%10; // 计算C的各个位的数字
wei[1] = c/10%10;
wei[2] = c/100%10;
wei[3] = c/1000%10;
wei[4] = c/10000%10;
wei[5] = c/100000%10;
wei[6] = c/1000000%10;
wei[7] = c/10000000%10;
Display();
}
else if(11 == KeyValue) // 减法运算
{
a = wei[0] + wei[1]*10 + wei[2]*100 + wei[3]*1000 +
wei[4]*10000 + wei[5]*100000 + wei[6]*1000000 +
wei[7]*10000000;
for(i=0; i<8; i++) // 清空数码管
{
wei[i] = 0;
}
// 输入第二个数
while(1)
{
Display();
KeyDown(); // 输入第二个数
if(15 == KeyValue)
break; // 当识别到等号时,停止输入
if(1 == keyflag)
{
for(i=7; i>0; i--)
{
wei[i] = wei[i-1];
}
wei[0] = KeyValue;
keyflag = 0;
}
}
b = wei[0] + wei[1]*10 + wei[2]*100 + wei[3]*1000 +
wei[4]*10000 + wei[5]*100000 + wei[6]*1000000 +
wei[7]*10000000;
if(a > b)
{
c = a - b;
wei[0] = c%10; // 计算C的各个位的数字
wei[1] = c/10%10;
wei[2] = c/100%10;
wei[3] = c/1000%10;
wei[4] = c/10000%10;
wei[5] = c/100000%10;
wei[6] = c/1000000%10;
wei[7] = c/10000000%10;
}
else if(a < b)
{
u16 e = 0;
c = b-a;
wei[0] = c%10;
wei[1] = c/10%10;
if(wei[1] == 0)
{
wei[1] = 16;
e=1;
}
wei[2] = c/100%10;
if(wei[2]==0 && e==0)
{
wei[2] = 16;
e=1;
}
wei[3] = c/1000%10;
if(wei[3]==0 && e==0)
{
wei[3] = 16;
e=1;
}
wei[4] = c/10000%10;
if(wei[4]==0 && e==0)
{
wei[4] = 16;
e=1;
}
wei[5] = c/100000%10;
if(wei[5]==0 && e==0)
{
wei[5] = 16;
e=1;
}
wei[6] = c/1000000%10;
if(wei[6]==0 && e==0)
{
wei[6] = 16;
e=1;
}
wei[7] = c/10000000%10;
if(wei[7]==0 && e==0)
{
wei[7] = 16;
e=1;
}
}
Display();
}
else if(12 == KeyValue) // 乘法运算
{
a = wei[0] + wei[1]*10 + wei[2]*100 + wei[3]*1000 +
wei[4]*10000 + wei[5]*100000 + wei[6]*1000000 +
wei[7]*10000000;
for(i=0; i<8; i++)
{
wei[i] = 0;
}
// 输入第二个数
while(1)
{
Display();
KeyDown(); // 输入第二个数
if(15 == KeyValue)
break; // 当识别到等号时,停止输入
if(1 == keyflag)
{
for(i=7; i>0; i--)
{
wei[i] = wei[i-1];
}
wei[0] = KeyValue;
keyflag = 0;
}
}
b = wei[0] + wei[1]*10 + wei[2]*100 + wei[3]*1000 +
wei[4]*10000 + wei[5]*100000 + wei[6]*1000000 +
wei[7]*10000000;
c = a * b;
wei[0] = c%10; // 计算C的各个位的数字
wei[1] = c/10%10;
wei[2] = c/100%10;
wei[3] = c/1000%10;
wei[4] = c/10000%10;
wei[5] = c/100000%10;
wei[6] = c/1000000%10;
wei[7] = c/10000000%10;
Display();
}
else if(13 == KeyValue) // 除法运算
{
a = wei[0] + wei[1]*10 + wei[2]*100 + wei[3]*1000 +
wei[4]*10000 + wei[5]*100000 + wei[6]*1000000 +
wei[7]*10000000;
for(i=0; i<8; i++)
{
wei[i] = 0;
}
// 输入第二个数
while(1)
{
Display();
KeyDown(); // 输入第二个数
if(15 == KeyValue)
break; // 当识别到等号时,停止输入
if(1 == keyflag)
{
for(i=7; i>0; i--)
{
wei[i] = wei[i-1];
}
wei[0] = KeyValue;
keyflag = 0;
}
}
b = wei[0] + wei[1]*10 + wei[2]*100 + wei[3]*1000 +
wei[4]*10000 + wei[5]*100000 + wei[6]*1000000 +
wei[7]*10000000;
if(0 != b)
{
c = a / b;
wei[0] = c%10; // 计算C的各个位的数字
wei[1] = c/10%10;
wei[2] = c/100%10;
wei[3] = c/1000%10;
wei[4] = c/10000%10;
wei[5] = c/100000%10;
wei[6] = c/1000000%10;
wei[7] = c/10000000%10;
Display();
}
}
}
}
仿真结果: