51单片机实现多功能计算器(附完整代码)——从零开始的电子计算器制作指南

一、项目简介

本教程将带您用51单片机+4x4矩阵键盘+8位数码管,制作一个具备加减乘除功能的电子计算器。最终效果:

  • 支持3位数输入
  • 可进行正负数运算
  • 最大显示999999
  • 错误提示功能

二、硬件准备清单

元件数量说明
STC89C52单片机1主控芯片
4x4矩阵键盘1输入按键
8位共阳数码管1显示结果
74HC573锁存器2驱动数码管
10K电阻排1上拉电阻
杜邦线若干建议不同颜色区分功能

接线示意图
(图示:P3口接键盘行列,P0口接数码管段选,P2.5-P2.7控制锁存器)

三、代码核心功能解析

1. 键盘映射表

/*
 * 键盘布局对应关系:
 * [0] [1] [2] [3]   ->  +  -  ×  ÷
 * [4] [5] [6] [7]   ->  7  8  9  ←
 * [8] [9] [10][11]  ->  4  5  6  →
 * [12][13][14][15]  ->  1  2  3  C
 */

2. 动态显示原理

通过定时器每1ms刷新一位数码管,利用视觉暂留实现稳定显示:

void Servertime0() interrupt 1 {
    // 每1ms切换显示位
    switch((t005)%10) {
        case 8: displaySMG(8,smg8); break;
        case 7: displaySMG(7,smg7); break;
        //...其他位同理
    }
}

3. 输入处理流程

按下按键
是数字键?
存入当前位数
是运算符?
记录运算符
执行清除/确认等操作

四、使用示范

案例1:加法运算

  1. 按下4 → 显示4
  2. 按下+ → 显示A.
  3. 按下5 → 显示5
  4. 按下= → 显示9

案例2:错误处理

输入123 ÷ 0会触发错误提示,数码管显示----并闪烁LED

五、代码烧录步骤

  1. 使用Keil编译工程
  2. 通过STC-ISP下载程序
  3. 开发板通电后自动运行

六、常见问题排查

现象解决方法
数码管部分不亮检查74HC573的OE引脚是否接地
按键响应延迟调整Delay5ms()的延时参数
显示数字错乱核对SMG数组的段码值
无法负数显示检查modecase3()中的符号处理逻辑

七、项目优化建议

  1. 增加小数点功能
// 在SMG数组中添加小数点段码
0x7F // 0. 的段码
  1. 添加声音提示
void Beep() {
    P1 = 0xFE;  // 假设蜂鸣器接P1.0
    Delay100ms();
    P1 = 0xFF;
}
  1. 支持连续运算
// 在modecase3()中保留前次结果
shu1 = jieguo;

完整代码获取

3.1 头文件与变量定义

#include <REGX52.H>
#include <intrins.h>
sfr P4=0xC0;

sbit R1=P3^0;
sbit R2=P3^1;
sbit R3=P3^2;
sbit R4=P3^3;

sbit C1=P3^4;
sbit C2=P3^5;
sbit C3=P4^2;
sbit C4=P4^4;

unsigned char code SMG[19]={0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff,0xbf};

int smg1=16,smg2=16,smg3=16,smg4=16,smg5=16,smg6=16,smg7=16,smg8=16;

unsigned char ledxs=0x00;

int t005=0;
unsigned char ts=0;
unsigned char tm=0;
unsigned char th=0;

unsigned char modecase=1;
unsigned char suanfa=0;

int geiwei1=16;
int baiwei1=16;
int shiwei1=16;
long shu1=0,shu2=0,jieguo=0;
  • 头文件:引入了REGX52.Hintrins.h,分别用于51单片机的寄存器定义和一些内部函数。
  • 特殊功能寄存器:定义了P4口,方便后续使用。
  • 矩阵键盘引脚:通过sbit定义了矩阵键盘的行和列引脚。
  • 数码管段码表SMG数组存储了数码管显示不同数字和符号的段码。
  • 变量:定义了数码管显示变量、LED显示变量、定时器变量、工作模式变量和计算相关变量。

3.2 延时函数

void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

延时函数用于按键消抖和一些时间控制,这里的延时时间约为5ms。

3.3 74HC573锁存器选择函数

void select573(unsigned char channel)
{
	switch(channel)
	{
		case 4:
		{P2=(P2&0x1f)|0x80;
			break;}
		case 5:
		{P2=(P2&0x1f)|0xa0;
			break;}
		case 6:
		{P2=(P2&0x1f)|0xc0;
			break;}
		case 7:
		{P2=(P2&0x1f)|0xe0;
			break;}
	}
		P2=(P2&0x1f);
}

该函数用于选择74HC573锁存器的不同通道,通过P2口的操作来实现。

3.4 LED显示函数和数码管显示函数

void displayled(unsigned char led1)
{
	P0=led1;
	select573(4);
}

void displaySMG(unsigned char pos,int cha)//位置和字符,小展开
{
	P0=0xff;
	select573(7);
	P0=0x01<<pos-1;
	select573(6);
	P0=SMG[cha];	
	select573(7);
}
  • displayled函数用于控制LED指示灯的显示。
  • displaySMG函数用于控制数码管的显示,通过选择数码管的位置和显示的字符来实现。

3.5 系统初始化函数

void initsystem()
{	
	P0=0x00;
	select573(4);
  P0=0x00;
	select573(5);
}

系统初始化函数用于初始化LED和其他相关设备,将P0口清零并选择相应的锁存器通道。

3.6 矩阵键盘扫描函数

int scan_keyborad()
{
	int number=-1;
	R1=0;
	R2=R3=R4=1;
	C1=C2=C3=C4=1;
	// 其他行和列的扫描代码...
	return number;
}

矩阵键盘扫描函数通过逐行扫描的方式来检测按键是否按下,并返回按键对应的编号。

3.7 定时器初始化和中断服务函数

void Inittime()//初始化
{
	TMOD=0x01;
	TH0 = (65536-10000)/256;
	TL0 = (65536-10000)%256;
	
	ET0=1;
	EA=1;
	TR0=1;
}

void Servertime0() interrupt 1
{
	TH0 = (65536-1000)/256; //50ms,即0.001s
	TL0 = (65536-1000)%256;
	
	t005++;
	
	if(t005==1000)
		{
			ts++;
			t005=0;
		}
		if(ts==60)
		{
			tm++;
			ts=0;
		}
		if(tm==60)
		{
			th++;
			tm=0;
		}
		if(th==24)
		{
			th=0;
		}
		
		switch((t005)%10)
		{
			case 8:
			{
		displaySMG(8,smg8);
		break;
		}
			// 其他数码管显示代码...
   }
	displayled(ledxs);
}
  • Inittime函数用于初始化定时器0,设置定时器的工作模式和初值,并开启中断。
  • Servertime0函数是定时器0的中断服务函数,每隔50ms触发一次,用于更新时间和数码管、LED的显示。

3.8 不同工作模式函数

代码中定义了三个工作模式函数modecase1modecase2modecase3,分别对应输入第一个数字、输入第二个数字和显示计算结果的模式。

void modecase1()
{
	// 输入第一个数字的相关代码...
}

void modecase2()
{
	// 输入第二个数字的相关代码...
}

void modecase3()
{
	// 显示计算结果的相关代码...
}

在每个模式函数中,会根据按键输入更新相应的变量,并进行计算和显示。

3.9 主函数

int main()
{
	Inittime();
	initsystem();
	while(1)
	{
     switch (modecase)   {
     case 1:
     {
	     modecase1();
	    break;
     }
		   case 2:
     {
	     modecase2();
	    break;
     }
		  case 3:
     {
	     modecase3();
	    break;
     }
                         }
  }
	return 0;
}

主函数首先调用定时器初始化和系统初始化函数,然后进入一个无限循环,根据当前的工作模式调用相应的模式函数。

#单片机 #51单片机 #简易计算器 #代码分析

创作不易,如果本文对您有帮助,欢迎点赞收藏🌟,有疑问请在评论区留言!


Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐