产品概述

单片机 简单计算器 送给初学单片机朋友干货之二——用单片机制作简易计算器

小编 2024-11-24 产品概述 23 0

送给初学单片机朋友干货之二——用单片机制作简易计算器

计算器简介

计算器是现代人发明的可以进行数字运算的电子机器。现代的电子计算器能进行数学运算的手持电子机器,拥有集成电路芯片,但结构简单,功能弱,但较为方便与廉价,可广泛运用于商业交易中,主要是计算结果是必备的办公用品之一。为节省电能,计算器都采用CMOS工艺制作的大规模集成电路。低档计算器的运算器、控制器由数字逻辑电路实现简单的串行运算,键盘是计算器的输入部件,一般采用接触式或传感式。为减小计算器的尺寸,一键常常有多种功能。显示器是计算器的输出部件,有数码管显示器或液晶显示器等。那么今天给各位朋友介绍的是用单片机制作的简单的模拟计算器。

简易计算器

为了帮助单片机爱好者学习单片机,本计算器是系列STC89C51RC单片机为核心构成的简易计算器系统。该系统通过单片机控制,实现对4*4键盘扫描进行实时的按键检测,并由LCD1602显示屏将过程与结果显示出来。硬件相对比较简单,主要由四部分组成。第一部分是单片机最小系统;第二部分是 4*4矩阵键盘;第三部分是LCD1602显示屏;第四部分是系统+5V电源。还是先说说制作流程:

第一步是绘制电路原理图

以单片机为主控芯片的简易计算器原理图

第二步是根据设计绘制的原理图购买电子元器件

所用电子元器件明细表

单片机主控芯片——-STC89C52RC 1片

LCD液晶显示模块——LCD1602 1片

点动按键BUTTON -- -- 17个

自锁开关按键------ 1个

10K可调电阻-----1个

晶振----- 1个

10K电阻-----9个

10UF电解电容-----1个

稳频电容30PF----2个

PCB万能实验板 ----1块

第三步是万能实验板的焊接

由于所用原件比较少焊接相对比较简单,焊接时主要注意单片机芯片最好用插座,便于烧写程序,还有就是LCD1602 的引脚要焊接正确,不能焊接错误,再一个就是16X16的矩阵按键焊接时也要留心。其他都比较好焊接。

简易计算器电路板正面

简易计算器焊接反面

下面主要说说LCD1602液晶这个显示模块,那个大大的,平时第一行显示 16 个小黑块,第二行什么都不显示的东西就是 1602 液晶, 1602 液晶主要显示容量 16 x 2 个字符,芯片工作电压 4.5~5.5V ,工作电流 2.0mA(5.0V) ,模块最佳工作电压 5.0V 1602 液晶,从它的名字我们就可以看出它的显示容量,就是可以显示 2 行,每行 16 个字符的液晶。它的工作电压是 4.5V~5.5V,这点我们直接按照 5V电源接上就可以了,但是保证我们的 5V 系统最低不能低于 4.5V。在 5V 工作电压下测量它的工作电流是 2mA,大家注意,这个 2mA 仅仅是指液晶,而它的黄绿背光都是用 LED 做的,所以功耗一般有一二十毫安。1602 液晶一共 16 个引脚,每个引脚的功能如下注释说明。

1, VSS--- 电源地

2, VDD---- 电源正极

3 ,VL---- 液晶显示偏压信号

4 ,RS---- 数据/命令选择端(H/L)

5, R/W---- 读/写选择端(H/L)

6, E---- 使能信号端

7, D0 --Data I/O (输入输出口)

8, D1--- Data I/O(输入输出口)

9, D2--- Data I/O (输入输出口)

10, D3 ---Data I/O (输入输出口)

11, D4--- Data I/O (输入输出口)

12 ,D5 ---Data I/O (输入输出口)

13 ,D6 ---Data I/O (输入输出口)

14, D7 ---Data I/O (输入输出口)

15, BLA ---背光源正极(输入输出口)

16, BLK ----背光源负极(输入输出口)

LCD1602正面

LCD1602背面

第四部分是程序编写部分

我们制作最简易的计算器可由按键和液晶两个元件为核心。下面我们来共同学习一个简易整数计算器。为了不让程序太复杂,我们这个计算器不考虑连加,连减等连续计算,不考虑小数情况。加键、减键、乘键、除键、和0-9键、等于键、清零键等16个按键,组成一个矩阵键盘。我们通过模块化编程,其程序共分为三部分,第一部分是主函数模块,第二部分是1602 液晶显示模块,第三部分是按键动作和扫描模块,我们先说主程序模块。在必要的语句后面都加了注释,方便大家理解。

主函数模块

#include <reg52.h>

unsigned char step = 0; //操作步骤

unsigned char oprt = 0; //运算类型

signed long num1 = 0; //操作数1

signed long num2 = 0; //操作数2

signed long result = 0; //运算结果

unsigned char T0RH = 0; //T0重载值的高字节

unsigned char T0RL = 0; //T0重载值的低字节

void ConfigTimer0(unsigned int ms);//配置时间函数声明

extern void KeyScan();//外部按键扫描函数声明

extern void KeyDriver();//外部按键驱动函数声明

extern void InitLcd1602();//外部液晶LCD1602函数初始化声明

extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);//外部显示字符声明

extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);//清屏

extern void LcdFullClear();//清屏函数声明

void main( void)

{

EA = 1; //开总中断

ConfigTimer0(1); //配置T0定时1ms

InitLcd1602(); //初始化液晶

LcdShowStr(15, 1, "0"); //初始显示一个数字0

while (1)

{

KeyDriver(); //调用按键驱动

}

}

/* 长整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度 */

unsigned char LongToString(unsigned char *str, signed long dat)

{

signed char i = 0;

unsigned char len = 0;

unsigned char buf[12];

if (dat < 0) //如果为负数,首先取绝对值,并在指针上添加负号

{

dat = -dat;

*str++ = '-';

len++;

}

do { //先转换为低位在前的十进制数组

buf[i++] = dat % 10;

dat /= 10;

} while (dat > 0);

len += i; //i最后的值就是有效字符的个数

while (i-- > 0) //将数组值转换为ASCII码反向拷贝到接收指针上

{

*str++ = buf[i] + '0';

}

*str = '\0'; //添加字符串结束符

return len; //返回字符串长度

}/* 显示运算符,显示位置y,运算符类型type */

void ShowOprt(unsigned char y, unsigned char type)

{

switch (type)

{

case 0: LcdShowStr(0, y, "+"); break; //0代表+

case 1: LcdShowStr(0, y, "-"); break; //1代表-

case 2: LcdShowStr(0, y, "*"); break; //2代表*

case 3: LcdShowStr(0, y, "/"); break; //3代表/

default: break;

}

}

/* 计算器复位,清零变量值,清除屏幕显示 */

void Reset()

{

num1 = 0;

num2 = 0;

step = 0;

LcdFullClear();

}

/* 数字键动作函数,n-按键输入的数值 */

void NumKeyAction(unsigned char n)

{

unsigned char len;

unsigned char str[12];

if (step > 1) //如计算已完成,则重新开始新的计算

{

Reset();

}

if (step == 0) //输入第一操作数

{

num1 = num1*10 + n; //输入数值累加到原操作数上

len = LongToString(str, num1); //新数值转换为字符串

LcdShowStr(16-len, 1, str); //显示到液晶第二行上

}

else //输入第二操作数

{

num2 = num2*10 + n; //输入数值累加到原操作数上

len = LongToString(str, num2); //新数值转换为字符串

LcdShowStr(16-len, 1, str); //显示到液晶第二行上

}

}

/* 运算符按键动作函数,运算符类型type */

void OprtKeyAction(unsigned char type)

{

unsigned char len;

unsigned char str[12];

if (step == 0) //第二操作数尚未输入时响应,即不支持连续操作

{

len = LongToString(str, num1); //第一操作数转换为字符串

LcdAreaClear(0, 0, 16-len); //清除第一行左边的字符位

LcdShowStr(16-len, 0, str); //字符串靠右显示在第一行

ShowOprt(1, type); //在第二行显示操作符

LcdAreaClear(1, 1, 14); //清除第二行中间的字符位

LcdShowStr(15, 1, "0"); //在第二行最右端显示0

oprt = type; //记录操作类型

step = 1;

}

}

/* 计算结果函数 */

void GetResult()

{

unsigned char len;

unsigned char str[12];

if (step == 1) //第二操作数已输入时才执行计算

{

step = 2;

switch (oprt) //根据运算符类型计算结果,未考虑溢出问题

{

case 0: result = num1 + num2; break;

case 1: result = num1 - num2; break;

case 2: result = num1 * num2; break;

case 3: result = num1 / num2; break;

default: break;

}

len = LongToString(str, num2); //原第二操作数和运算符显示到第一行

ShowOprt(0, oprt);

LcdAreaClear(1, 0, 16-1-len);

LcdShowStr(16-len, 0, str);

len = LongToString(str, result); //计算结果和等号显示在第二行

LcdShowStr(0, 1, "=");

LcdAreaClear(1, 1, 16-1-len);

LcdShowStr(16-len, 1, str);

}

}

/* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */

void KeyAction(unsigned char keycode)

{

if ((keycode>='0') && (keycode<='9')) //输入字符

{NumKeyAction(keycode - '0'); }

else if (keycode == 0x26) //向上键,+

{ OprtKeyAction(0);}

else if (keycode == 0x28) //向下键,-

{ OprtKeyAction(1); }

else if (keycode == 0x25) //向左键,*

{ OprtKeyAction(2);}

else if (keycode == 0x27) //向右键,÷

{OprtKeyAction(3);}

else if (keycode == 0x0D) //回车键,计算结果

{ GetResult();}

else if (keycode == 0x1B) //Esc键,清除

{

Reset();

LcdShowStr(15, 1, "0");

}

}

/* 配置并启动T0,ms-T0定时时间 */

void ConfigTimer0(unsigned int ms)

{

unsigned long tmp; //临时变量

tmp = 11059200 / 12; //定时器计数频率

tmp = (tmp * ms) / 1000; //计算所需的计数值

tmp = 65536 - tmp; //计算定时器重载值

tmp = tmp + 28; //补偿中断响应延时造成的误差

T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节

T0RL = (unsigned char)tmp;

TMOD &= 0xF0; //清零T0的控制位

TMOD |= 0x01; //配置T0为模式1

TH0 = T0RH; //加载T0重载值

TL0 = T0RL;

ET0 = 1; //使能T0中断

TR0 = 1; //启动T0

}

/* T0中断服务函数,执行按键扫描 */

void InterruptTimer0() interrupt 1

{

TH0 = T0RH; //重新加载重载值

TL0 = T0RL;

KeyScan(); //按键扫描

}

1602 液晶显示模块

#include <reg52.h

#define LCD1602_DB P0

sbit LCD1602_RS = P1^0;

sbit LCD1602_RW = P1^1;

sbit LCD1602_E = P1^5;

/* 等待液晶准备好 */

void LcdWaitReady()

{

unsigned char sta;

LCD1602_DB = 0xFF;

LCD1602_RS = 0;

LCD1602_RW = 1;

do {

LCD1602_E = 1;

sta = LCD1602_DB; //读取状态字

LCD1602_E = 0;

} while (sta & 0x80); //bit7等于1表示液晶正忙,重复检测直到其等于0为止

}

/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */

void LcdWriteCmd(unsigned char cmd)

{

LcdWaitReady();

LCD1602_RS = 0; LCD1602_RW = 0; LCD1602_DB = cmd;

LCD1602_E = 1; LCD1602_E = 0;

}

/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */

void LcdWriteDat(unsigned char dat)

{

LcdWaitReady();

LCD1602_RS = 1; LCD1602_RW = 0; LCD1602_DB = dat;

LCD1602_E = 1; LCD1602_E = 0;

}

/* 设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */

void LcdSetCursor(unsigned char x, unsigned char y)

{

unsigned char addr;

if (y == 0) //由输入的屏幕坐标计算显示RAM的地址

addr = 0x00 + x; //第一行字符地址从0x00起始

else

addr = 0x40 + x; //第二行字符地址从0x40起始

LcdWriteCmd(addr | 0x80); //设置RAM地址

}

/* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */

void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)

{

LcdSetCursor(x, y); //设置起始地址

while (*str != '\0') //连续写入字符串数据,直到检测到结束符

{

LcdWriteDat(*str++);

}

}

/* 区域清除,清除从(x,y)坐标起始的len个字符位 */

void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len)

{

LcdSetCursor(x, y); //设置起始地址

while (len--) //连续写入空格

{

LcdWriteDat(' ');

}

}

/* 整屏清除 */

void LcdFullClear()

{

LcdWriteCmd(0x01);

}

/* 初始化1602液晶 */

void InitLcd1602()

{

LcdWriteCmd(0x38); //16*2显示,5*7点阵,8位数据接口

LcdWriteCmd(0x0C); //显示器开,光标关闭

LcdWriteCmd(0x06); //文字不动,地址自动+1

LcdWriteCmd(0x01); //清屏

}

Lcd1602.c 文件中根据上层应用的需要增加了2 个清屏函数:区域清屏——LcdAreaClear,

整屏清屏——LcdFullClear。

按键动作和扫描模块

#include <reg52.h>

sbit KEY_IN_1 = P2^4;sbit KEY_IN_2 = P2^5;sbit KEY_IN_3 = P2^6;

sbit KEY_IN_4 = P2^7;//定义输入端口

sbit KEY_OUT_1 = P2^3;sbit KEY_OUT_2 = P2^2;sbit KEY_OUT_3 = P2^1;

sbit KEY_OUT_4 = P2^0;//定义输出端口

unsigned char code KeyCodeMap[4][4] = { //矩阵按键编号到标准键盘键码的映射表

{ '1', '2', '3', 0x26 }, //数字键1、数字键2、数字键3、加号键

{ '4', '5', '6', 0x25 }, //数字键4、数字键5、数字键6、乘号键

{ '7', '8', '9', 0x28 }, //数字键7、数字键8、数字键9、减号键

{ '0', 0x1B, 0x0D, 0x27 } //数字键0、清零键、 等于键、 除号键

};

unsigned char pdata KeySta[4][4] = { //全部矩阵按键的当前状态

{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}

};

extern void KeyAction(unsigned char keycode);

/* 按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用 */

void KeyDriver()

{

unsigned char i, j;

static unsigned char pdata backup[4][4] = { //按键值备份,保存前一次的值

{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}

};

for (i=0; i<4; i++) //循环检测4*4的矩阵按键

{

for (j=0; j<4; j++)

{

if (backup[i][j] != KeySta[i][j]) //检测按键动作

{

if (backup[i][j] != 0) //按键按下时执行动作

{

KeyAction(KeyCodeMap[i][j]); //调用按键动作函数

}

backup[i][j] = KeySta[i][j]; //刷新前一次的备份值

}

}

}

}

/* 按键扫描函数,需在定时中断中调用,推荐调用间隔1ms */

void KeyScan()

{

unsigned char i;

static unsigned char keyout = 0; //矩阵按键扫描输出索引

static unsigned char keybuf[4][4] = { //矩阵按键扫描缓冲区

{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},

{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}

};

//将一行的4个按键值移入缓冲区

keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;

keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;

keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;

keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4; //消抖后更新按键状态

for (i=0; i<4; i++) //每行4个按键,所以循环4次

{

if ((keybuf[keyout][i] & 0x0F) == 0x00)

{ //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下

KeySta[keyout][i] = 0;

}

else if ((keybuf[keyout][i] & 0x0F) == 0x0F)

{ //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起

KeySta[keyout][i] = 1;

}

} //执行下一次的扫描输出

keyout++; //输出索引递增

keyout &= 0x03; //索引值加到4即归零

switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚

{

case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;

case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;

case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;

case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;

default: break;

}

}

keyboard.c 是对之前已经用过多次的矩阵按键驱动的封装,具体到某个按键要执行的动

作函数都放到上层的 main.c 中实现,在这个按键驱动文件中只负责调用上层实现的按键动作函数即可。 main.c 文件实现所有应用层的操作函数,即计算器功能所需要信息显示、按键动作响应等,另外还包括主循环和定时中断的调度。 通过这样一个程序,我们可以学习如何进行多个.c 文件的编程,另外一个方面学会多个函数之间的灵活调用。可以把这个程序看成是一个简单的小项目进行练习。

第五部分是调试

调试分为硬件调试和软件调试两部分,调试时先调试硬件电路,然后再调试软件。硬件比较简单容易调试,主要是软件的调试要费些时间,只要有信心,就能在调试过程中锻炼自己的发现问题、分析问题、解决问题的能力。这个程序有点长,希望喜欢单片机的小伙伴们耐下心,慢慢理解,有问题可以留言、讨论!

调试完成的界面3795X593的结果

调试好的界面 3795x593

希望这个小项目能对喜欢单片机的小伙伴们有一定的帮助!喜欢的话请关注、留言、别忘了点个赞哦!你的支持是我前进的动力!

单片机DIY简易计算器

有小伙伴给我私信说老师让用单片机做一个简易计算器,让我帮帮他。

正好没事就用PROTEUS做了一个,希望对他有所帮助,也希望小伙伴看完后能有所收获。

单片机 计算器DIY 计算5+5请看以下连接视频

视频:单片机DIY简易计算器

编程语言参考源代码如下:

KEYBUF EQU 40H ;键号存放单元

ORG 0000H

LJMP MAIN

ORG 0030H

MAIN: MOV KEYBUF,#0 ;初始键号设为0,也可以为任意值

MOV R0,#30H ;显示首地址

MOV R2,#0CH ;计算数据存放单元个数

CLR A

QING: MOV @R0,A ;将数据存放单元清零

INC R0

DJNZ R2,QING

MOV P0,#8FH ;关闭显示

MOV R1,#30H ;将显示首地址存放R1里

;===============================================

;五位无符号显示子程序

DIS1: MOV R0,#30H ;把显示数据第一位放在R0里

MOV R2,#04H ;把显示的位码放在R2里

MOV R3,#05H ;把显示的长度放在R3里

DIS2: MOV A,@R0

ANL A,#0FH ;屏蔽显示数据的高四位

MOV B,A

MOV A,R2

ANL A,#0FH ;屏蔽位码的高四位

SWAP A

ORL A,B

MOV P0,A ;送总显示数据到P0显示

LCALL DELY4ms ;调用延时4ms

INC R0 ;取下一个显示数据

DEC R2

DJNZ R3,DIS2 ;四位显示完后重新开始显示

;===================================================

;键盘扫描子程序

WAIT: MOV P1,#0FFH ;P1口送高电平

CLR P1.0 ;第一行清零

MOV A,P1 ;读P1口

ANL A,#0F0H ;低位屏蔽

XRL A,#0F0H ;判断低位是否有低电平 ,即判断是否有按键按下

JZ NOKEY1 ;地位有低电平继续扫描,否者跳到第二行去扫描

LCALL DELY10ms ;延时10ms去抖在进行判断是否有按键按下

MOV A,P1 ;继续读P1口

ANL A,#0F0H ;判断低位是否有低电平

CJNE A,#0E0H,NK1 ;如果扫描数据不为0E0H就转到NK1

MOV KEYBUF,#0 ;否者判断为0号键

AJMP DK ;转DK1查表程序

NK1: CJNE A,#0D0H,NK2 ;如果扫描数据不为0D0H就转到NK2

MOV KEYBUF,#1 ;否者判断为1号键

AJMP DK ;转DK2查表程序

NK2: CJNE A,#0B0H,NK3 ;如果扫描数据不为0B0H就转到NK3

MOV KEYBUF,#2 ;否者判断为2号键

AJMP DK ;转DK3查表程序

NK3: CJNE A,#70H,NK4 ;如果扫描数据不为70H就转到NK4

LJMP SAN_CHU

NK4: NOP

NOKEY1: MOV P1,#0FFH ;和上面相同

CLR P1.1

MOV A,P1

ANL A,#0F0H

XRL A,#0F0H

JZ NOKEY2

LCALL DELY10MS

MOV A,p1

ANL A,#0F0H

XRL A,#0F0H

JZ NOKEY2

MOV A,P1

ANL A,#0F0H

CJNE A,#0E0H,NK5

MOV KEYBUF,#3

AJMP DK

NK5: CJNE A,#0D0H,NK6

MOV KEYBUF,#4

AJMP DK

NK6: CJNE A,#0B0H,NK7

MOV KEYBUF,#5

AJMP DK

NK7: CJNE A,#70H,NK8

MOV KEYBUF,#10 ;否者判断为3号键

AJMP DK ;转DK4查表程序

NK8: NOP

NOKEY2: MOV P1,#0FFH

CLR P1.2

MOV A,P1

ANL A,#0F0H

XRL A,#0F0H

JZ NOKEY3

LCALL DELY10MS

MOV A,P1

ANL A,#0F0H

XRL A,#0F0H

JZ NOKEY3

MOV A,P1

ANL A,#0F0H

CJNE A,#0E0H,NK9

MOV KEYBUF,#6

AJMP DK

NK9: CJNE A,#0D0H,NK10

MOV KEYBUF,#7

AJMP DK

NK10: CJNE A,#0B0H,NK11

MOV KEYBUF,#8

AJMP DK

NK11: CJNE A,#70H,NK12

LJMP DENG_HAO

NK12: NOP

NOKEY3: MOV P1,#0FFH

CLR P1.3

MOV A,P1

ANL A,#0F0H

XRL A,#0F0H

JZ NOKEY4

LCALL DELY10MS

MOV A,P1

ANL A,#0F0H

XRL A,#0F0H

JZ NOKEY4

MOV A,P1

ANL A,#0F0H

CJNE A,#0E0H,NK13

LJMP CHU

NK13: CJNE A,#0D0H,NK14

LJMP CHENG

NK14: CJNE A,#0B0H,NK15

LJMP JIAN

NK15: CJNE A,#70H,NK16

LJMP JIA

NK16: NOP

;=======================================================

;查表求键值程序

DK: MOV B,#00H

MOV A,KEYBUF ;查表程序 查对应的键号数据

MOV DPTR,#TABLE ;把表头地址放入DPTR

MOVC A,@A+DPTR ;A里面存放的为键号,利用A和表头地址找到对应的键号数据

MOV B,A ;把查到的数据送往显示单元

INC R1 ;取下一个显示单元

MOV A,R1

CJNE A,#36H,DKA1 ;判断显示单元是否已满

MOV R1,#35H ;35H,36H单元用于更好地控制五位显示

AJMP DKA

DKA1: MOV 34H,33H ;按键代码按左移显示,先按先显示

MOV 33H,32H

MOV 32H,31H

MOV 31H,30H

MOV 30H,B

DKA: MOV A,P1 ;读P1口

ANL A,#0F0H ;屏蔽高四位

XRL A,#0F0H ;地位是有低电平

JNZ DKA ;如果有低电平继续读P1口,否者向下执行,查找第二行

NOKEY4: LJMP DIS1

;===================================

;功能按键功能设定

DENG_HAO:MOV DPTR,#JI_SUAN ;等号键功能通过加、减、乘、除设定的偏移量来调用子程序

MOV A,3CH ;3CH存放的为功能程序入口地址偏移量

JMP @A+DPTR ;转移到按键功能程序

JI_SUAN: AJMP JIA1 ;加计算子程序

AJMP JIAN1 ;减计算子程序

AJMP CHENG1 ;乘计算子程序

AJMP CHU ;除计算子程序

;=======删除键功能

SAN_CHU: ACALL QING_DIS

AJMP DKA

;=======加键功能

JIA: MOV 3CH,#00H

ACALL CUN_SHU

ACALL QING_DIS

AJMP DKA

;=======减键功能

JIAN: MOV 3CH,#02H

ACALL CUN_SHU

ACALL QING_DIS

AJMP DKA

;=======乘键功能

CHENG: MOV 3CH,#04H

ACALL CUN_SHU

ACALL QING_DIS

AJMP DKA

;=======除键功能

CHU: MOV 3DH,#06H

ACALL CUN_SHU

ACALL QING_DIS

AJMP DKA

;=================================

;存被加(减、乘、除)数,存放在37H~3BH里

CUN_SHU: MOV 37H,30H ;36H存放的为最低位

MOV 38H,31H

MOV 39H,32H

MOV 3AH,33H

MOV 3BH,34H ;3AH存放的为最高位

RET

;================================

;清除显示单元

QING_DIS: MOV R1,#30H

QING1: MOV @R1,#00H

INC R1

MOV A,R1

CJNE A,#36H,QING1

MOV R1,#30H

LOP1: RET

;================================

;十进制加法子程序

JIA1:

MOV A,37H ;个位被加数

ADD A,30H ;个位被加数+加数

MOV B,#10 ;十六进制除10转换成BCD码

DIV AB

MOV 30H,B ;余数即个位存放在30H

MOV 37H,A ;商存放在37H

MOV A,38H ;十位被加数

ADD A,31H ;十位被加数+加数

ADD A,37H ;加上个位之和的进位

MOV 37H,#00H ;清除37H

MOV B,#10 ;十六进制除10转换成BCD码

DIV AB

MOV 31H,B ;余数即十位存放在31H

MOV 38H,A ;商存放在38H

MOV A,39H ;百位计算同十位

ADD A,32H

ADD A,38H

MOV 38H,#00H

MOV B,#10

DIV AB

MOV 32H,B

MOV 39H,A

MOV A,3AH ;千位计算同十位

ADD A,33H

ADD A,39H

MOV 39H,#00H

MOV B,#10

DIV AB

MOV 33H,B

MOV 3AH,A

MOV A,3BH ;万位计算同十位

ADD A,34H

ADD A,3AH

MOV 3AH,#00H

MOV B,#10

DIV AB

MOV 34H,B

MOV 3BH,#00H

AJMP DKA

;=====================

JIAN1: AJMP DKA

CHENG1: AJMP DKA

CHU1: AJMP DKA

;=============================================

;延时程序和查表表格

DELY4ms: MOV R6,#8 ;延时4毫秒

D1: MOV R7,#248

DJNZ R7,$

DJNZ R6,D1

RET

DELY10ms:MOV R6,#20 ;延时10毫秒

D2: MOV R7,#248

DJNZ R7,$

DJNZ R6,D2

RET

TABLE: DB 07H, 04H, 01H ; / 本表格是以键盘为参考 7 8 9 /

DB 08H, 05H, 02H ; * 4 5 6 *

DB 09H, 06H, 03H ; - 1 2 3 -

DB 00H, 00H ;= + 清除 0 = +

END

最后,如果有什么意见或者建议欢迎您留言给我,让我们共同学习一起进步,

如果需要 程序完整的源代码和 设计文件,请在下方留言或者私信我,看到后会第一时间回复。

谢谢!

感谢你的阅读,希望您有所收获,喜欢请点赞评论加关注!

相关问答

51 单片机 C语言编程,简易 计算器 ,复位键如何编程会 简单 些?要求...

51单片机C语言编程,简易计算器,复位键如何编程会简单些?要求能任何时候返回主程序开头。。鼠标3R3R简易鼠标讨论回答(4)提供个思路void(*RecallBp)...

olin是什么牌子 计算器 ?

是奥灵品牌的计算器。精灵计算器,国产软件,是一款单片机辅助开发工具,提供常用51系列单片机的参数计算和资料查询功能。是奥灵品牌的计算器。精灵计算器,国...

单片机 之父?

1.单片机是由以下两位共同发明的:日本bijikon公司的嶋正利。美国inter公司的特德·hofu。他们的单片机命名为4004.2.开发单片机的经过。在日本由于IC...

【普通 计算器 上的显示器是什么显示器就是那种8字型的那种我...

[最佳回答]1、普通计算器上的显示器称为笔段式液晶显示器.一般为定制液晶产品.可以做成任意形状笔段,比如早期的BP机,数字式电表,数字万用表,液晶显示器上有数...

单片机 的独立键盘有什么用?

很多的嵌入式或者单片机系统中,一般都需要向嵌入式或者单片机系统输入信息的外设,以及嵌入式或者单片机向外输出信息的外设我们常见的显示屏,数码管等就是嵌...

52 单片机 的优缺点?

优点:1.52单片机的成本低,价格便宜。2.52单片机的性能稳定,可靠性高。3.52单片机的性能强,可用于多种应用场景,广泛应用于各种电子产品。4.52单片机...

单片机 ADDC的算法若(A)=83H,(C)=1,则ADDCA,#90H执行后,(A)=...

[最佳回答]ADDCA,#90H;为16进制用计算器16进制算再+1=114A83H10000011+90H10010000C=11=114H100010100A=14...

八位计算机是什么?

你好,八位计算机是指能够一次性处理8位二进制数据的计算机。每位二进制数只有0和1两种状态,通过8位二进制数可以表示256个不同的状态。因此,八位计算机的处理...

gm2103k 单片机 作用?

答gm2103k单片机作用是单片机比专用处理器最适合应用于嵌入式系统,现代人类生活中所用的几乎每件电子和机械产品中都会集成有单片机。手机、电话、计算器、家...

大型机,小型机,微型机, 单片机 是以计算机的什么性能辨别的?_...

单片机是一种微型计算机,它以较低的性能水平来满足特定应用需求。单片机通常用于控制设备,如汽车电子系统、家用电器等。与传统的多芯片计算机相比,单片机具有...

猜你喜欢