基于STC89C52单片机实现简易计算器

本文介绍了一个使用STC29C52单片机的简易计算器项目,通过矩阵键盘输入数据,并用八位数码管显示结果,支持基本的四则运算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天,我在Keil uVision4中制作了一个小项目,利用STC29C52单片机实现了简易计算器的功能。
此计算器利用矩阵键盘(线扫描法)输入数据,利用八位数码管显示数据。能实现四位整数(及四位以下)与四位整数(及四位以下)的加减乘除运算。
优势是:操作及界面 与日常计算器相同;
具备按键消抖功能;
缺陷是:计算位数有限;
仅支持整数运算;
运算结果最大为65535(受限于int数据类型);

以下为具体程序:
工程组织 及 主程序:
工程组织 及 主程序

矩阵键盘扫描程序:

#include "bsp.h"
#define KEYPORT P1
unsigned char val = 0;
unsigned char mkeyvalue = 99;

void mkey_scan(void)
{
    KEYPORT = 0xf0;
    if(KEYPORT != 0xf0)
    {
        KEYPORT = 0xfe;
        if(KEYPORT != 0xfe)
        {
            val = KEYPORT;
            while(KEYPORT != 0xfe)  seg7_show_CC(); //死等
            //或者delay;
        }

        KEYPORT = 0xfd;
        if(KEYPORT != 0xfd)
        {
            val = KEYPORT;
            while(KEYPORT != 0xfd) seg7_show_CC();
        }

        KEYPORT = 0xfb;
        if(KEYPORT != 0xfb)
        {
            val = KEYPORT;
            while(KEYPORT != 0xfb) seg7_show_CC();
        }

        KEYPORT = 0xf7;
        if(KEYPORT != 0xf7)
        {
            val = KEYPORT;
            while(KEYPORT != 0xf7) seg7_show_CC();
        }
    }
    else
    {
        val = 0xff; //没按键按下时,不进入switch语句;
    }
}

void mkey_pro(void)
{
    if(val != 0xff)
    {

        switch(val)
        {
            case(0x7e): mkeyvalue = 1; break;
            case(0xbe): mkeyvalue = 2; break;
            case(0xde): mkeyvalue = 3; break;
            case(0xee): mkeyvalue = 11; break;

            case(0x7d): mkeyvalue = 4; break;
            case(0xbd): mkeyvalue = 5; break;
            case(0xdd): mkeyvalue = 6; break;
            case(0xed): mkeyvalue = 12; break;

            case(0x7b): mkeyvalue = 7; break;
            case(0xbb): mkeyvalue = 8;  break;
            case(0xdb): mkeyvalue = 9;  break;
            case(0xeb): mkeyvalue = 13; break;

            case(0x77): mkeyvalue = 0; break;
            case(0xb7): mkeyvalue = 16; break;
            case(0xd7): mkeyvalue = 15; break;
            case(0xe7): mkeyvalue = 14; break;

            default: mkeyvalue = 99; break;
        }
    }
}

按键功能程序:

#include "bsp.h"
unsigned char type = 1;
unsigned char distype = 0;
unsigned char num1[4]={0,0,0,0};
unsigned char num2[4]={0};
unsigned char symbol;
unsigned char i = 0;
unsigned char digit1=0, digit2=0;

void key_record(void)
{
    if((mkeyvalue==1||mkeyvalue==2||mkeyvalue==3||
        mkeyvalue==4||mkeyvalue==5||mkeyvalue==6||
        mkeyvalue==7||mkeyvalue==8||mkeyvalue==9||mkeyvalue==0))
    {

        if(type == 1)
        {   
            distype = 1;
            num1[i++] = mkeyvalue;
            digit1++;
        }
        else if(type == 3)
        {
            distype = 3;
            num2[i++] = mkeyvalue;
            digit2++;
        }
        if(i >= 4)
        {
            if(type == 1)
            {
                type = 2;
            }
            else if(type == 3)
            {
                type = 4;
            }       
            i = 0;
        }
        mkeyvalue = 99;
    }

    if((type==1||type==2)&&(mkeyvalue==11||mkeyvalue==12||mkeyvalue==13||mkeyvalue==14))
    {
        symbol = mkeyvalue;
        distype = 2;
        i = 0;
        type = 3;
        mkeyvalue = 99;
    }

    if((type==3||type==4)&&mkeyvalue==15)       //=
    {
        type = 5;
        distype = 5;                  
        result();

        mkeyvalue = 99;     
    //  type = 6;
    }

//  if(type == 6)
//  {
//      while(mkeyvalue == 99);
//      mkeyvalue = 16;
//  }

    if(mkeyvalue == 16)    //清屏
    {
        num1[0] = 0;
        num1[1] = 0;
        num1[2] = 0;
        num1[3] = 0;
        symbol = 0;
        num2[0] = 0;
        num2[1] = 0;
        num2[2] = 0;
        num2[3] = 0;
        showvalue[0] = 0;
        showvalue[1] = 0;
        showvalue[2] = 0;
        showvalue[3] = 0;
        showvalue[4] = 0;
        showvalue[5] = 0;
        showvalue[6] = 0;
        showvalue[7] = 0;
        i = 0;

        distype = 0;

        digit1 = 0;
        digit2 = 0;
        type = 1; 
        mkeyvalue = 99;
    }
}

运算程序:

#include "bsp.h"

unsigned int cal_result = 0;
unsigned int cal_num1 = 0;
unsigned int cal_num2 = 0;

void result(void)
{
    switch(symbol)
    {
        case(11): cal_result = cal_num1 + cal_num2; result_digit_compute();break;   //在此处计算出结果的位数,
        case(12): cal_result = cal_num1 - cal_num2; result_digit_compute();break;   //避免写在reg显示程序中,
        case(13): cal_result = cal_num1 * cal_num2; result_digit_compute();break;   //否则扫描的时候重复计算,
        case(14): cal_result = cal_num1 / cal_num2; result_digit_compute();break;   //占用时间片,造成显示负担
        default: break; 
    }
}

unsigned int adjust(unsigned char *num, unsigned char digit)
{
    unsigned char temp_digit = digit;
    unsigned int true_num = 0;
    true_num = num[0]*1000+num[1]*100+num[2]*10+num[3];
    while((4-temp_digit) > 0)
    {
        true_num = true_num/10;
        temp_digit++;
    }

    return true_num;           
}

数码管显示程序:

#include "bsp.h"
//unsigned char distype = 4;
//unsigned char digit1 = 3;
//unsigned char digit2 = 0;
//unsigned int cal_num1 = 0;
//unsigned int cal_num2 = 0;
//unsigned int cal_result = 0;

#define SEGPORT P0
unsigned char code distab_CC[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,
                                  0x77,0x7c,0x39,0x5e,0x79,0x71};
//unsigned char TABLESEL[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //位选码
unsigned char TABLESEL[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
unsigned char showvalue[8] = {0};
unsigned char dis_digit = 0;
unsigned char result_digit = 0;

sbit LATCH_DUAN = P2^2;
sbit LATCH_WEI = P2^3;

//8位动态扫描
void seg7_show_CC(void)
{
    static unsigned char j = 0;
    if(distype == 0)
    {
        dis_digit = 1;
    }
    if(distype == 1)
    {
        dis_digit = digit1;
    }
    if(distype == 2)
    {
        dis_digit = 1;
    }
    if(distype == 3)
    {
        dis_digit = digit2;
    } 
    if(distype == 5)
    {
//      if(cal_result <= 65535)
//      {
            dis_digit = result_digit;
//      }
//      else if(cal_result > 65535)
//      {
//          dis_digit = 4;
//      }

    }  

    SEGPORT = 0x00;//消除残影
    LATCH_DUAN = 1;
    LATCH_DUAN = 0;  

    SEGPORT = TABLESEL[j];
    LATCH_WEI = 1;//位锁存
    LATCH_WEI = 0;                   

    SEGPORT = showvalue[j];
    LATCH_DUAN = 1;//段锁存
    LATCH_DUAN = 0;   

    j++;
    if(distype == 5)
    {
        if((j==dis_digit+1))
        {
            j = 0;
        }
    }
    else
    {
        if(j == dis_digit)
        {
            j = 0;
        }
    }
}

void showvalue_set(void)
{
    if(distype == 0)
    {
        showvalue[0] = distab_CC[0];
    }
    if(distype == 1)
    {
        dis_num_compute(cal_num1, digit1);
    }
    if(distype == 2)
    {
        showvalue[0] = distab_CC[0];        
    }
    if(distype == 3)
    {
        dis_num_compute(cal_num2, digit2);
    }
    if(distype == 5)
    {
//      if(cal_result <= 65535)
//      {
        //  result_digit_compute(); //此句会造成,重复计算结果的位数,导致显示负担
            dis_num_compute(cal_result, result_digit);
            showvalue[result_digit] = 0x48; //显示‘=’号
//      }
//      else if(cal_result > 65535)
//      {
//          showvalue[4] = 0x75;        //显示Error
//          showvalue[3] = 0x50;
//          showvalue[2] = 0x50;
//          showvalue[1] = 0x5c;
//          showvalue[0] = 0x50;
//      }
    }   
}

void result_digit_compute(void)
{
    unsigned int result_temp = 0;
    result_digit = 0;
    if(cal_result==0)
    {
        result_digit = 1;
    }
    else
    {
        result_temp = cal_result;
        while(result_temp != 0)
        {
            result_temp /= 10;
            result_digit++;
        }
    }
}

void dis_num_compute(unsigned int cal, unsigned char digit)
{
     unsigned char temp = digit;
     unsigned char temp2 = 0;
     unsigned int temp3 = 0;
     unsigned char temp4 = 0;
     while(temp != 0)
     {  
        for(temp3 = cal,temp2 = temp-1; temp2 > 0; temp2--)
        {
            temp3 /= 10;
        }   
        showvalue[temp-1] = distab_CC[temp3];

        temp4 = temp-1;
        while(temp4 != 0)
        {
            temp3 *= 10;
            temp4--;
        }
        cal = cal-temp3; 
        temp--;
     }
}

头文件:
这里写图片描述

#ifndef _BSP_H_
#define _BSP_H_

//系统自带的头文件
#include "reg52.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"

//外设的头文件
//#include "bsp_xx.h"
#include "bsp_seg7.h"
#include "bsp_delay.h"
//#include "bsp_key.h"
//#include "bsp_int.h"
//#include "bsp_timer.h"
#include "bsp_mkey.h"
#include "bsp_mkeyfunc.h"
//#include "bsp_alarm.h"
#include "process.h"

//初始化外设的函数声明
void bsp_init(void);

#endif

每个外设的头文件就不一一上传了。

### STC89C52单片机实现简易计算器的方案 #### 1. 硬件设计 STC89C52单片机可以通过外接键盘矩阵和LCD1602显示屏来构建一个简易计算器。键盘矩阵用于输入数字和运算符,而LCD1602则负责显示计算结果。 - 键盘矩阵通常由4×44×3按键组成,分别对应数字键(0-9)、基本运算符(`+`, `-`, `*`, `/`)以及确认键(如“=”)。这些按键通过行列扫描技术连接到单片机的I/O端口[^1]。 - LCD1602是一种常用的字符型液晶显示器,支持两行每行16个字符的显示能力。其接口包括数据线(D0-D7)、控制信号(RS、RW、E)以及其他电源管理引脚。通过编写驱动程序,可以实现在屏幕上打印文字或数值的功能[^2]。 #### 2. 软件设计 以下是基于Keil C编写的简易计算器的核心算法框架: ```c #include <reg52.h> // 定义延时函数 void delay(unsigned int time) { while(time--); } // 初始化LCD1602 void LcdInit() { // 初始化代码省略... } // 向LCD发送命令 void LcdCommand(unsigned char cmd) { // 命令发送代码省略... } // 向LCD写入数据 void LcdData(unsigned char dat) { // 数据写入代码省略... } // 扫描键盘获取当前按下的键值 unsigned char ScanKeyBoard() { unsigned char row, col; for(row = 0; row < 4; row++) { // 遍历每一行 P2 = ~(0x0F << row); // 设置某行为低电平 if(P2 & 0xF0 != 0xF0) { // 判断是否有列被按下 delay(10); // 消除抖动 if(P2 & 0xF0 != 0xF0) { // 再次确认按键是否有效 for(col = 0; col < 4; col++) { if(!(P2 & (0x10 << col))) { return row * 4 + col; // 返回按键编号 } } } } } return 0xFF; // 如果未检测到按键,则返回特殊标志 } int main(void){ float num1=0,num2=0,result=0; char op=' '; bit flag_start=1; LcdInit(); // 初始化LCD while(1){ unsigned char key = ScanKeyBoard(); if(key!=0xFF){ // 当有按键按下时执行相应操作 switch(flag_start){ case 1:{ // 输入第一个数阶段 if(key>=0 && key<=9){ num1=num1*10+(key-'0'); // 将num1转换成字符串形式并通过LCD显示出来 char buffer[16]; itoa((long)(num1),buffer,10); LcdClear(); LcdString(buffer); }else{ op=key; flag_start=0; } break;} default:{ if(key>='0'&&key<='9'){ num2=num2*10+(key-'0');} else{ // 计算结果 result=(op=='+')?(num1+num2):(op=='-')?(num1-num2):( (op=='*')?(num1*num2):(num1/num2)); // 显示最终的结果 char res_buffer[16]; dtostrf(result, sizeof(res_buffer)-1, 2,res_buffer ); LcdClear(); LcdString(res_buffer); // 准备新一轮计算 num1=result; num2=0; op=key; } break;} } delay(200); // 添加适当延迟防止重复触发 } } } ``` #### 3. 关键点说明 - **键盘扫描**: 使用行列扫描法识别哪个按钮被按下,并将其映射为对应的ASCII码或其他编码以便后续处理。 - **浮点数运算**: 对于涉及小数点的情况,需引入额外库或将整数部分与分数分开存储再组合输出[^3]。 - **状态切换机制**: 设计合理的状态转移逻辑区分用户正在输入的第一个操作数还是第二个操作数或是选择了新的运算符[^2]. ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值