精华内容
下载资源
问答
  • 用51单片机实现整数的加减乘除,通过矩阵按键实现数据的输入和处理,通过8个数码管实现数据及结果的显示。
  • 51单片机实现计算器

    2018-06-16 19:30:33
    16按键模拟计算器,1602显示 含protuse图 、
  • 单片机实现计算器加减乘除,可以实现四则运算的计算器,代码内有详细解释,keil软件实现,有兴趣欢迎大家下载 更多资料可私聊
  • 题目要求: 1、根据开发板设计10以内的加法.../*根据题目要求,设计计算器,51单片机矩阵按键的S4,S8,S12,S16分别代表着+,-,*,/;而S13键表示为清零;S1,S2,S3代表着1,2,3;S5,S6,S7代表着4,5,6;S9,S10,S1

    题目要求:

    1、根据开发板设计10以内的加法计算器,用LED数码管显示数字和计算结果。(必做)。

    2、根据开发板设计100以内的计算器,用LED数码管显示数字和计算结果,要求可实现加法、减法、乘法和除法的整型运算(选作)。

    备注:做了第2题可不做第1题

    选做第2题.功能实现如附件视频所示。

    /*根据题目要求,设计计算器,51单片机矩阵按键的S4,S8,S12,S16分别代表着+,-,*,/;而S13键表示为清零;S1,S2,S3代表着1,2,3;S5,S6,S7代表着4,5,6;S9,S10,S11代表着7,8,9。如下排列所示:

     

    1    2    3    +

    4  5    6    -

    7    8    9    *

    清零 0    =    /

    */

    #include<reg51.h>
    typedef unsigned char u8;         //对数据类型进行声明定义
    typedef unsigned int u16;
    
    sbit LSA=P2^2;  //74HC138译码器数码管位选
    sbit LSB=P2^3;
    sbit LSC=P2^4;
    
    #define GPIO_KEY P1
    #define GPIO_DIG P0
    
    u16 KeyValue;        //用来存放读取到的键值
    u16 keyflag,i;       //用来判断按下的数字还是运算符或清空键
    u8 code smgduan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};  //显示0~F、负号‘-’
    
    u16 wei[8]={0};    //用来存放每一位数码管数字的数组
    
    void delay(u16 i)//延时函数
    {  
         while(i--);
    }
    
    void display()    //扫描显示动态数码管
    {    
         LSA=0; LSB=0; LSC=0; GPIO_DIG=smgduan[wei[7]];delay(50); GPIO_DIG=0x00; //消隐
         LSA=1; LSB=0; LSC=0; GPIO_DIG=smgduan[wei[6]];delay(50); GPIO_DIG=0x00;
         LSA=0; LSB=1; LSC=0; GPIO_DIG=smgduan[wei[5]];delay(50); GPIO_DIG=0x00; 
         LSA=1; LSB=1; LSC=0; GPIO_DIG=smgduan[wei[4]];delay(50); GPIO_DIG=0x00; 
    }
    /*
    1    2    3    +
    4	 5    6	   -
    7    8    9    *
    清零 0    =    /
    */
    
    void KeyDown(void)//检测有按键按下并读取键值
    {
        u16 a=0;
        GPIO_KEY=0x0f;
        if(GPIO_KEY!=0x0f)//读取按键是否按下
        {
            delay(1000);//延时10ms进行消抖
            if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
            {   
                //测试列
                GPIO_KEY=0x0f;
                switch(GPIO_KEY)//行列扫描法
                {
                    case(0X07): KeyValue=1;break;
                    case(0X0b): KeyValue=2;break;
                    case(0X0d): KeyValue=3;break;
                    case(0X0e): KeyValue=13;break;
                }
                //测试行
                GPIO_KEY=0xf0;
                switch(GPIO_KEY)
                {
                    case(0X70): KeyValue=KeyValue;break;
                    case(0Xb0): KeyValue=KeyValue+3;break;
                    case(0Xd0): KeyValue=KeyValue+6;break;
                    case(0Xe0): KeyValue=KeyValue+9;break;
                }
    			if(KeyValue==11)
    			{
    				KeyValue=0;
    			}
                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(keyflag==1)  
             {                                 
                //输入一位,数字向左移动一位     
    			for(i = 4; i <7;i++)
    			{wei[i]=wei[i+1];}  
    			wei[7] = KeyValue;                      
                keyflag=0;                                  
             }
    
             else if(KeyValue==10)
             {
                  for(i=0;i<8;i++)
                      wei[i]=0;              //对数码管清零
        
                   display(); 
            }
    
            else if(KeyValue==13)//加法运算      
             {
                 a=wei[0]*10000000+wei[1]*1000000+wei[2]*100000+wei[3]*10000+wei[4]*1000+wei[5]*100+wei[6]*10+wei[7];   //计算a的值
                 for(i=0;i<8;i++)
                 wei[i]=0;
                 while(1)                               //输入第二个数
                 {
                         display();
                         KeyDown();
                         if(KeyValue==12) break;//当读到等于号,既,KeyValue=12时,停止输入
                         if(keyflag==1)
                         {  
                            for(i = 4; i <7;i++)
    						{wei[i]=wei[i+1];}  
    						wei[7] = KeyValue;                      
              				keyflag=0;
                         }
                  }
                  b=wei[0]*1000000+wei[1]*1000000+wei[2]*100000+wei[3]*10000+wei[4]*1000+wei[5]*100+wei[6]*10+wei[7];   //计算b的值
                 c=a+b;
                 wei[0]=c/10000000%10;               //计算C的各个位的数字
                 wei[1]=c/1000000%10;
                 wei[2]=c/100000%10;
                 wei[3]=c/10000%10;
                 wei[4]=c/1000%10;
                 wei[5]=c/100%10;
                 wei[6]=c/10%10;
                 wei[7]=c%10;
     
                 display();
            }
     
            else if(KeyValue==16)//减法运算      
             {
                 a=wei[0]*10000000+wei[1]*1000000+wei[2]*100000+wei[3]*10000+wei[4]*1000+wei[5]*100+wei[6]*10+wei[7];   //计算a的值
                 for(i=0;i<8;i++)
                 wei[i]=0;
                 while(1)                                //输入第二个数
                 {
                         display();
                         KeyDown();
                         if(KeyValue==12) break;//当读到等于号,既,KeyValue=12时,停止输入
                         if(keyflag==1)
                         {  
                            for(i = 4; i <7;i++)
    						{wei[i]=wei[i+1];}  
    						wei[7] = KeyValue;                      
              				keyflag=0;
                         }
                  }
                  b=wei[0]*1000000+wei[1]*1000000+wei[2]*100000+wei[3]*10000+wei[4]*1000+wei[5]*100+wei[6]*10+wei[7];   //计算b的值
                 c=a-b;
                 wei[0]=c/10000000%10;               //计算C的各个位的数字
                 wei[1]=c/1000000%10;
                 wei[2]=c/100000%10;
                 wei[3]=c/10000%10;
                 wei[4]=c/1000%10;
                 wei[5]=c/100%10;
                 wei[6]=c/10%10;
                 wei[7]=c%10;
     
                 display();
            }
              
    
            else if(KeyValue==19)//乘法运算      
             {
                 a=wei[0]*10000000+wei[1]*1000000+wei[2]*100000+wei[3]*10000+wei[4]*1000+wei[5]*100+wei[6]*10+wei[7];   //计算a的值
                 for(i=0;i<8;i++)
                 wei[i]=0;
                 while(1)                                //输入第二个数
                 {
                         display();
                         KeyDown();
                         if(KeyValue==12) break;//当读到等于号,既,KeyValue=12时,停止输入
                         if(keyflag==1)
                         {  
                            for(i = 4; i <7;i++)
    						{wei[i]=wei[i+1];}  
    						wei[7] = KeyValue;                      
              				keyflag=0;
                         }
                  }
                  b=wei[0]*1000000+wei[1]*1000000+wei[2]*100000+wei[3]*10000+wei[4]*1000+wei[5]*100+wei[6]*10+wei[7];   //计算b的值
                 c=a*b;
                 wei[0]=c/10000000%10;               //计算C的各个位的数字
                 wei[1]=c/1000000%10;
                 wei[2]=c/100000%10;
                 wei[3]=c/10000%10;
                 wei[4]=c/1000%10;
                 wei[5]=c/100%10;
                 wei[6]=c/10%10;
                 wei[7]=c%10;
     
                 display();
            }
    
            else if(KeyValue==21)//除法运算      
             {
                 a=wei[0]*10000000+wei[1]*1000000+wei[2]*100000+wei[3]*10000+wei[4]*1000+wei[5]*100+wei[6]*10+wei[7];   //计算a的值
                 for(i=0;i<8;i++)
                 wei[i]=0;
                 while(1)                                //输入第二个数
                 {
                         display();
                         KeyDown();
                         if(KeyValue==12) break;//当读到等于号,既,KeyValue=12时,停止输入
                         if(keyflag==1)
                         {  
                            for(i = 4; i <7;i++)
    						{wei[i]=wei[i+1];}  
    						wei[7] = KeyValue;                      
              				keyflag=0;
                         }
                  }
                  b=wei[0]*1000000+wei[1]*1000000+wei[2]*100000+wei[3]*10000+wei[4]*1000+wei[5]*100+wei[6]*10+wei[7];   //计算b的值
                 c=a/b;
                 wei[0]=c/10000000%10;               //计算C的各个位的数字
                 wei[1]=c/1000000%10;
                 wei[2]=c/100000%10;
                 wei[3]=c/10000%10;
                 wei[4]=c/1000%10;
                 wei[5]=c/100%10;
                 wei[6]=c/10%10;
                 wei[7]=c%10;
     
                 display();
            }
                         
       }
    }

     

    展开全文
  • C语言实现的基于51单片机计算器,包含带括号的浮点数运算。实现6位数以内的加减乘除四则运算。 基本没有特殊的BUG。代码可以直接运行,可通过PZISP烧制,通过Keil3_Full编译
  • 单片机实现计算器功能

    千次阅读 2018-03-04 23:20:57
    #include &lt;reg51.h&gt;sbit E=P2^2;sbit RS=P2^0;sbit RW=P2^1;#define GPIO_KEY P1unsigned char KeyValue=17; //键盘按键值void KeyDown(void); //键盘扫描void delay1ms(unsigned int x);...
    #include <reg51.h>
    
    sbit E=P2^2;
    sbit RS=P2^0;
    sbit RW=P2^1;
    #define GPIO_KEY P1
    unsigned char KeyValue=17;  //键盘按键值
    void KeyDown(void);   //键盘扫描
    void delay1ms(unsigned int x);
    void init();      //lcd1602初始化
    void writecom(unsigned char j);   //写命令
    void writedata(unsigned char j);   //写数据
    void fbusy(); //忙检测
    unsigned char LEDBuffer[5];


    unsigned char i=0;           //x作为第一个数据   注意char型的数据位数只有8位,最高计数到256
    unsigned char flag=0;
    unsigned int result=0,temp=0,x;
    unsigned int numbuffer[10];   //用于缓存数据
    unsigned int j=0;
    unsigned char pflag=0,mflag=0,hflag=0,lflag=0;     //用于定义乘除法的优先级
    void main()
    {
    IT0=1;   //定义外部中断用于清屏
    EX0=1;
    EA=1;
        SP=0x50;
    init();
    writecom(0x80);
    writedata('1');
    writedata('5');
    writedata('0');
    writedata('0');
    writedata('9');
    writedata('0');
    writedata('5');
    writedata('1');
    writedata('3');
    writedata('0');
    writedata(' ');
    writedata(' ');
    writedata('m');
    writedata('c');
    writedata('l');
    delay1ms(500);
    init();   
    writecom(0x80);
    while(1)
    {
    //    writecom(0x80);
       KeyDown();
      
    switch(KeyValue)
    {
      case 0:
      case 1:
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
      case 7:
      case 8:
      case 9:{
          writedata('0'+KeyValue);
      temp=temp*10+KeyValue;      //第一个数字
      KeyValue=17;
      }
      break;
      case 10:{
          writedata('+');
      numbuffer[j]=temp;   //缓存区数据
      temp=0;
      j++;
                   if(pflag)
      {
          numbuffer[j-2]=numbuffer[j-1]*numbuffer[j-2];
      numbuffer[j-1]=0;
      j--;
      pflag=0;
    }
    if(mflag)
      {
          numbuffer[j-2]=numbuffer[j-2]/numbuffer[j-1];
      numbuffer[j-1]=0;
      j--;
      mflag=0;
    }
    if(hflag)
      {
          numbuffer[j-1]=-1*numbuffer[j-1];
      hflag=0;
    }
    if(lflag)
      {
          numbuffer[j-2]=numbuffer[j-2]%numbuffer[j-1];
      j--;
      lflag=0;
    }
      KeyValue=17;
      flag=1;    //定义一个加法的标志位
      }
      break;
      case 11:{
          writedata('-');
      numbuffer[j]=temp;   //缓存区数据
      j++;
      temp=0;
                   if(pflag)
      {
          numbuffer[j-2]=numbuffer[j-2]*numbuffer[j-1];
      j--;
      pflag=0;
    }
    if(mflag)
      {
          numbuffer[j-2]=numbuffer[j-2]/numbuffer[j-1];
      j--;
      mflag=0;
    }
    if(hflag)
      {
          numbuffer[j-1]=-1*numbuffer[j-1];
      hflag=0;
    }
    if(lflag)
      {
          numbuffer[j-2]=numbuffer[j-2]%numbuffer[j-1];
      j--;
      lflag=0;
    }
    hflag=1;
      KeyValue=17;
      flag=2;
      }
      break;
      case 12:{
          writedata('*');
      numbuffer[j]=temp;   //缓存区数据
      j++;
      if(pflag)
      {
          numbuffer[j-2]=numbuffer[j-1]*numbuffer[j-2];
      numbuffer[j-1]=0;
      j--;
      pflag=0;
    }
    if(mflag)
      {
          numbuffer[j-2]=numbuffer[j-2]/numbuffer[j-1];
      numbuffer[j-1]=0;
      j--;
      mflag=0;
    }
    if(hflag)
      {
          numbuffer[j-1]=-1*numbuffer[j-1];
      hflag=0;
    }
    if(lflag)
      {
          numbuffer[j-2]=numbuffer[j-2]%numbuffer[j-1];
      j--;
      lflag=0;
    }
      temp=0;
      pflag=1;     //定义乘除法的高优先级
      KeyValue=17;
      flag=3;
      }
      break;
      case 13:{
          writedata('/');
      numbuffer[j]=temp;   //缓存区数据
      j++;
      if(pflag)
      {
          numbuffer[j-2]=numbuffer[j-1]*numbuffer[j-2];
      numbuffer[j-1]=0;
      j--;
      pflag=0;
    }
    if(mflag)
      {
          numbuffer[j-2]=numbuffer[j-2]/numbuffer[j-1];
      numbuffer[j-1]=0;
      j--;
      mflag=0;
    }
    if(hflag)
      {
          numbuffer[j-1]=-1*numbuffer[j-1];
      hflag=0;
    }
    if(lflag)
      {
          numbuffer[j-2]=numbuffer[j-2]%numbuffer[j-1];
      j--;
      lflag=0;
    }
      temp=0;
      mflag=1;
      KeyValue=17;
      flag=4;
      }
      break;
      case 14:{
          writedata('%');
      numbuffer[j]=temp;   //缓存区数据
      j++;
      temp=0;
                   lflag=1;  //求余优先级
      KeyValue=17;
      flag=5;
      }
      break;
      case 15:{
          writedata('=');
      numbuffer[j]=temp;   //缓存区数据
      temp=0;
      j++;   
      if(pflag)
      {
          numbuffer[j-2]=numbuffer[j-2]*numbuffer[j-1];
      j--;
      j--;   
      pflag=0;
    }
    if(mflag)
      {
          numbuffer[j-2]=numbuffer[j-2]/numbuffer[j-1];
      j--;
      j--;
      mflag=0;
    }


    if(hflag)
      {
          numbuffer[j-1]=-1*numbuffer[j-1];
      hflag=0;
    }
    if(lflag)
      {
          numbuffer[j-2]=numbuffer[j-2]%numbuffer[j-1];
      j--;
      j--;
      lflag=0;
    }
      KeyValue=17;
                   for(i=0;i<=j;i++)
      {
          result+=numbuffer[i];
    }
    i=0;
    while(result)
             {
                LEDBuffer[i]=result%10;    //将数据存储在缓存区中
            result/=10;
            i++; //i的值比实际位数多一个值
             }
     for(i;i>0;i--)
     {
        writedata('0'+LEDBuffer[i-1]);   //显示输出结果
     }
    }
      break;
    }
    }
    }


    void init()
    {
        writecom(0x01);
    writecom(0x38);
    writecom(0x0c);
    writecom(0x06);
    }
    void writecom(unsigned char j)
    {
    fbusy();
        E=0;
    RS=0;
    RW=0;
    E=1;
    P0=j;
    E=0;
    }
    void fbusy()
    {    
    E=0;
        P0=0xff;
    RS=0;
    RW=1;
    E=1;
    while(P0&0x80)
    {
      E=0;
      E=1;
    }
    }
    void writedata(unsigned char j)
    {
    fbusy();
    E=0;
    RS=1;
    RW=0;
    E=1;
    P0=j;
    E=0;


    }
    void KeyDown(void)  //键盘扫描
    {
    char a=0;
    GPIO_KEY=0x0f;
    if(GPIO_KEY!=0x0f)         //读取按键是否按下
    {
    delay1ms(10);          //延时10ms进行消抖
    if(GPIO_KEY!=0x0f)    //再次检测键盘是否按下
    {

    //测试列
    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;
    }
    while((a<50)&&(GPIO_KEY!=0xf0)) //检测按键松手检测
    {
    delay1ms(10);
    a++;
    }
    }
    }
    }
    void delay1ms(unsigned int x)
    {
       unsigned int i,j;
       for(i=0;i<x;i++)
         for(j=0;j<120;j++);
    }
    void init1(void) interrupt 0
    {
         for(i=0;i<=4;i++)
    {
    LEDBuffer[i]=0;         //清空数组中的数据
    }
    for(i=0;i<=8;i++)
    {
    numbuffer[i]=0;         //清空数组中的数据
    }    
     result=0;
     i=0;
     x=0;
     temp=0;
          init();
          writecom(0x80);
    }
    展开全文
  • 单片机51芯片实现计算器功能的一个小程序,。
  • 使用PIC16F877单片机实现计算器仿真设计 包含源程序及仿真文件
  • 51单片机实现简易计算器

    千次阅读 2021-04-14 14:15:53
    使用的单片机型号为"STC89C52",使用的模块为独立键盘和矩阵键盘,LED,蜂鸣器,数码管这些较基础的模块。 具体功能: 可以实现两个数字的加减乘除运算(两个数字为整数,位数可调,区分正负),结果保留整数,区分...

    简介:
    使用的单片机型号为"STC89C52",使用的模块为独立键盘和矩阵键盘,LED,蜂鸣器,数码管这些较基础的模块。
    具体功能:
    可以实现两个数字的加减乘除运算(两个数字为整数,位数可调,区分正负),结果保留整数,区分正负。在输入错误时有删除键,可以一位一位的删除(比如输入34,按下删除键后就变为3)。数码管显示时,需要用到的点亮,不需要用到的没有被点亮(个人认为这样比较舒服~)。
    计算器的按键分布:
    7 8 9 +
    4 5 6 -
    1 2 3 *
    D 0 = ÷
    F T W R
    (D为删除键,F为关机键,T为开机键,W为存储键,R为读取键)
    另外自己加的小功能:
    在得到结果后,还设置有结果的保存键和读取键,按下后可以储存结果和读取结果。另外设置有不掉电的伪开机和伪关机键,按下后可以实现显示的关闭和打开。每按下一次键盘后LED灯都会循环点亮,并且蜂鸣器会发出短暂的声音。
    完整的代码如下:

    #include <reg52.h>
    #include <intrins.h>
    
    typedef unsigned int uint;
    typedef unsigned char uchar;
    
    sbit DU=P2^6;
    sbit WE=P2^7;
    sbit Beep=P2^3;
    
    uchar code SMGduan[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//数码管0-9
    uchar code LED[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//数码管位选
    
    int num;
    int n1=0,n2=0;//数据传递的中间变量
    uchar flag;//运算符号标志位
    uchar F,T;//输入负数的标志位
    uchar i=0;//LED灯移位标志位
    uchar j=0;//计算器开关标志位
    uchar A=0;//储存结果数组变量
    uchar C=0;//读取结果数组变量
    int tabel5[20]={0};//计算器计算结果储存数组
    
    //数码管动态显示
    void delay(uint z)
    {
    	uint x,y;
    	for(x=z;x>0;x--)
    		for(y=114;y>0;y--);
    }
    
    void display(int i)
    {
    	if(i>=0)
    	{
    		if(i<10)
    		{
    			P0=0XFF;
    			WE=1;
    			P0=0XFE;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i];
    			DU=0;
    			delay(8);
    		}
    		if(i>=10&&i<99)
    		{
    			P0=0XFF;
    			WE=1;
    			P0=0XFE;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i/10];
    			DU=0;
    			delay(8);
    			P0=0XFF;
    			WE=1;
    			P0=0XFd;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i%10];
    			DU=0;
    			delay(8);
    		}
    		if(i>=100&&i<999)
    		{
    			P0=0XFF;
    			WE=1;
    			P0=0XFE;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i/100];
    			DU=0;
    			delay(8);
    			P0=0XFF;
    			WE=1;
    			P0=0XFd;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i%100/10];
    			DU=0;
    			delay(8);
    			P0=0XFF;
    			WE=1;
    			P0=0XFb;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i%10];
    			DU=0;
    			delay(8);
    		}
    	}
    	else
    	{
    		i=-i;
    		if(i<9)
    		{
    			P0=0XFF;
    			WE=1;
    			P0=0XFE;
    			WE=0;
    			DU=1;
    			P0=0x40;
    			DU=0;
    			delay(8);
    			P0=0XFF;
    			WE=1;
    			P0=0XFd;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i];
    			DU=0;
    			delay(8);
    		}
    		if(i>=10&&i<99)
    		{
    			P0=0XFF;
    			WE=1;
    			P0=0XFe;
    			WE=0;
    			DU=1;
    			P0=0x40;
    			DU=0;
    			delay(8);
    			P0=0XFF;
    			WE=1;
    			P0=0XFd;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i/10];
    			DU=0;
    			delay(8);
    			P0=0XFF;
    			WE=1;
    			P0=0XFb;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i%10];
    			DU=0;
    			delay(8);
    		}
    		if(i>=100&&i<999)
    		{
    			P0=0XFF;
    			WE=1;
    			P0=0XFe;
    			WE=0;
    			DU=1;
    			P0=0x40;
    			DU=0;
    			delay(8);
    			P0=0XFF;
    			WE=1;
    			P0=0XFd;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i/100];
    			DU=0;
    			delay(8);
    			P0=0XFF;
    			WE=1;
    			P0=0XFb;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i%100/10];
    			DU=0;
    			delay(8);
    			P0=0XFF;
    			WE=1;
    			P0=0XF7;
    			WE=0;
    			DU=1;
    			P0=SMGduan[i%10];
    			DU=0;
    			delay(8);
    		}
    	}
    }
    //也可以用中断来实现
    
    //矩阵键盘的扫描
    void keyscan()
    {
    	uchar temp;
    	P3=0XFF;
    	P3=0XFE;
    	temp=P3&0XF0;
    	if(temp!=0xf0)
    	{
    		delay(20);
    		P3=0XFE;
    		temp=P3&0xf0;
    		if(temp!=0xf0)
    		{
    			temp=P3;
    			switch(temp)
    			{
    				case 0xee: 	Beep=0;
    							delay(20);
    							Beep=1;
    							if(T==0)
    							{
    								n1=10*n1+7;num=n1;F=1;i++;break;
    							}
    							if(T==1)
    							{
    								n1=10*n1-7;num=n1;F=1;i++;break;
    							}	
    				case 0xde: 	Beep=0;
    							delay(20);
    							Beep=1;
    							if(T==0)
    							{
    								n1=10*n1+8;num=n1;F=1;i++;break;
    							}
    							if(T==1)
    							{
    								n1=10*n1-8;num=n1;F=1;i++;break;
    							}
    				case 0xbe: 	Beep=0;
    							delay(20);
    							Beep=1;
    							if(T==0)
    							{
    								n1=10*n1+9;num=n1;F=1;i++;break;
    							}
    							if(T==1)
    							{
    								n1=10*n1-9;num=n1;F=1;i++;break;
    							}
    				case 0x7e: 	Beep=0;
    							delay(20);
    							Beep=1;
    							n2=n1;
    							n1=0;
    							flag=1;
    							WE=1;
    							P0=0XFF;
    							WE=0;
    							T=0;
    							F=0;
    							i++;
    							break;
    			}//+
    			while(temp!=0xf0)
    			{
    				temp=P3;
    				temp=temp&0xf0;
    			}
    			P3=0XFF;
    		}
    	}
    	P3=0XFF;
    	P3=0XFD;
    	temp=P3&0xf0;
    	if(temp!=0xf0)
    	{
    		delay(20);
    		P3=0XFD;
    		temp=P3&0xf0;
    		if(temp!=0xf0)
    		{
    			temp=P3;
    			switch(temp)
    			{
    				case 0xed:	Beep=0;
    							delay(20);
    							Beep=1;
    							if(T==0)
    							{
    								n1=10*n1+4;num=n1;F=1;i++;break;
    							}
    							if(T==1)
    							{
    								n1=10*n1-4;num=n1;F=1;i++;break;
    							}
    				case 0xdd: 	Beep=0;
    							delay(10);
    							Beep=1;
    							if(T==0)
    							{
    								n1=10*n1+5;num=n1;F=1;i++;break;
    							}
    							if(T==1)
    							{
    								n1=10*n1-5;num=n1;F=1;i++;break;
    							}
    				case 0xbd: 	Beep=0;
    							delay(20);
    							Beep=1;
    							if(T==0)
    							{
    								n1=10*n1+6;num=n1;F=1;i++;break;
    							}
    							if(T==1)
    							{
    								n1=10*n1-6;num=n1;F=1;i++;break;
    							}
    				case 0x7d: 	Beep=0;
    							delay(20);
    							Beep=1;
    				 		   if(F==1)
    						   {
    								n2=n1;
    								n1=0;
    								flag=2;
    								WE=1;
    								P0=0XFF;
    								WE=0;
    								T=0;
    								F=0;
    								i++;
    								break;
    							}//-
    							if(F==0)
    							{
    								T=1;
    								break;
    							}//负号					
    			}
    			while(temp!=0xf0)
    			{
    				temp=P3;
    				temp=temp&0xf0;
    			}
    			P3=0XFF;
    		}
    	}
    	P3=0XFF;
    	P3=0XFB;
    	temp=P3&0xf0;
    	if(temp!=0xf0)
    	{
    		delay(20);
    		P3=0XFB;
    		temp=P3&0XF0;
    		if(temp!=0xf0)
    		{
    			temp=P3;
    			switch(temp)
    			{
    				case 0xeb: 	Beep=0;
    							delay(20);
    							Beep=1;
    							if(T==0)
    							{
    								n1=10*n1+1;num=n1;F=1;i++;break;
    							}
    							if(T==1)
    							{
    								n1=10*n1-1;num=n1;F=1;i++;break;
    							}
    				case 0xdb: 	Beep=0;
    							delay(20);
    							Beep=1;
    							if(T==0)
    							{
    								n1=10*n1+2;num=n1;F=1;i++;break;
    							}
    							if(T==1)
    							{
    								n1=10*n1-2;num=n1;F=1;i++;break;
    							}
    				case 0xbb: 	Beep=0;
    							delay(20);
    							Beep=1;
    							if(T==0)
    							{
    								n1=10*n1+3;num=n1;F=1;i++;break;
    							}
    							if(T==1)
    							{
    								n1=10*n1-3;num=n1;F=1;i++;break;
    							}
    				case 0x7b: 	Beep=0;
    							delay(20);
    							Beep=1;
    							n2=n1;
    							n1=0;
    							flag=3;
    							WE=1;
    							P0=0XFF;
    							WE=0;
    							T=0;
    							F=0;
    							i++;
    							break;
    			}//  X
    			while(temp!=0xf0)
    			{
    				temp=P3;
    				temp=temp&0xf0;
    			}
    			P3=0XFF;
    		}
    	}
    	P3=0XFF;
    	P3=0XF7;
    	temp=P3&0xf0;
    	if(temp!=0xf0)
    	{
    		delay(20);
    		P3=0XF7;
    		temp=P3&0xf7;
    		if(temp!=0xf0)
    		{
    			temp=P3;
    			switch(temp)
    			{
    				case 0xe7: 	Beep=0;
    							delay(20);
    							Beep=1;
    							i++;
    							n1=n1/10;
    							num=n1;
    							break;
    				case 0xd7: 	Beep=0;
    							delay(20);
    							Beep=1;
    							if(T==0)
    							{
    								n1=10*n1;num=n1;F=1;i++;break;
    							}
    							if(T==1)					
    							{
    								n1=10*n1;num=n1;F=1;i++;break;
    							}
    				case 0xb7: 	Beep=0;
    							delay(20);
    							Beep=1;
    							if(flag==1) num=n2+n1;	
    						   	if(flag==2) num=n2-n1;
    						   	if(flag==3) num=n2*n1;
    						   	if(flag==4) num=n2/n1;
    						  	n1=0;
    						   	WE=1;
    						   	P0=0XFF;
    						  	WE=0;
    						   	F=0;//一次计算完成后重置标志位
    						   	i++;
    						   	break;//=
    				case 0x77: 	Beep=0;
    							delay(20);
    							Beep=1;
    							n2=n1;
    							n1=0;
    							flag=4;
    							WE=1;
    							P0=0XFF;
    							WE=0;
    							T=0;
    							F=0;
    							i++;
    							break;//÷
    			}
    			while(temp!=0xf0)
    			{
    				temp=P3;
    				temp=temp&0xf0;
    			}
    			P3=0XFF;
    		}
    	}
    	P3=0XFF;
    	if(P3==0XFB)
    	{
    		delay(20);
    		if(P3==0XFB)
    		{
    			tabel5[A]=num;
    			C=A;//将数组变量赋给读取数组的变量
    			A++;
    			n1=0;
    			num=0;
    			if(A>9)
    			{
    				for(A=9;A>-1;A--)
    				{
    					tabel5[A]=0;
    				}
    				A=0;
    			}//存满后自动清零
    			while(P3==0XFB);
    		}
    	}
    	if(P3==0XF7)
    	{
    		delay(20);
    		if(P3==0XF7)
    		{
    			num=tabel5[C];
    			C--;
    			while(P3==0XF7);
    		}
    	}				
    }
    void keyscan1()//部分独立键盘判断
    {
    	if(P3==0XFE)
    	{
    		delay(10);
    		if(P3==0XFE)
    		{
    			j=1;
    			WE=1;
    			P0=0xFF;
    			WE=0;
    			num=0;
    			n1=0;
    			Beep=0;
    			delay(20);
    			Beep=1;
    			P1=0XFF;
    			while(P3==0XFE);
    		}
    	}
    	P3=0XFF;
    	if(P3==0XFD)
    	{
    		delay(20);
    		if(P3==0XFD)
    		{
    			j=0;
    			Beep=0;
    			delay(20);
    			Beep=1;
    			while(P3==0XFD);
    		}
    	}
    }
    void main()
    {
    	while(1)
    	{
    		if(j==1)
    		{
    			keyscan1();
    		}
    		if(j==0)
    		{	
    			keyscan();
    			display(num);
    			P1=LED[i];
    			if(i>7)
    			{
    				i=0;
    			}
    			keyscan1();
    		}
    	}
    }
    

    已经通过编译测试,代码可以正常使用。个人认为写的还比较好理解,毕竟我学单片机也没多久(=。=)。
    代码可能看起来比较冗余,欢迎各位大神提出意见,我看到后会努力精简的!
    第一次尝试在CSDN平台发布自己写的代码,希望读到本文的各位多多鼓励哈~相信我们很快会再次见面的!

    展开全文
  • 使用51单片机制作的简易计算器,文件夹中含有proteus的仿真文件和对应的代码hex、c文件,含有代码注释。
  • 51实现智能计算器
  • 51单片机计算器(包含小数计算) 编写语言:C 运行情况:完美运行,尚未发现bug 备注:同普通实现小数计算程序不一样(浮点型数据计算存在精度丢失的情况),本程序全部采用整形进行计算,对小数点进行记录,最后...
  • 用C语言实现单片机计算器 仿真的计算器
  • 简易计算器单片机实现

    千次阅读 2020-06-28 21:53:18
    1、用按键和液晶实现最简易计算器,可以完成整数的加减乘除运算; 2、加减乘除分别用上下左右键来代替,回车表示等于,ESC 表示归 0(也可以只用回车键, 第 1 次表示等于,第 2 次表示归 0,循环); 3、在 LCD1602...

    任务和要求:
    1、用按键和液晶实现最简易计算器,可以完成整数的加减乘除运算;
    2、加减乘除分别用上下左右键来代替,回车表示等于,ESC 表示归 0(也可以只用回车键,
    第 1 次表示等于,第 2 次表示归 0,循环);
    3、在 LCD1602 上显示操作数 1、操作数 2、操作符(+ -/)和运算结果。
    扩展部分
    1、考虑小数;
    2、将操作数 1、操作数 2、操作符(±
    /)和运算结果发给串口调试助手。
    我的工程下有4个文件:
    1.主函数.c

    #include <reg52.h>
    #define uchar unsigned char
    #define uint unsigned int
    #define ulong unsigned long
    #define slong signed long
    #define schar signed char
    uchar step = 0;//操作步骤
    uchar oprt = 0;//运算类型
    double num1 = 0;//操作数1
    double num2 = 0;//操作数2
    float result = 0;//运算结果
    uchar T0RH = 0;//T0重载的高字节
    uchar T0RL = 0;//T0重载的低字节
    bit exchange = 0;//改变回车和Esc功能
    bit flagdot = 0;//小数点记录
    uchar div10 = 0;
    uchar str2[12];
    uchar count_str2=0;
    void ConfigTimer0(uint ms);
    extern void KeyScan();
    extern void KeyDriver();
    extern void InitLcd1602();
    extern void LcdShowStr(uchar x, uchar y, uchar *str);
    extern void LcdAreaClear(uchar x, uchar y, uchar len);
    extern void LcdFullClear();
    extern void UartRxMonitor(uchar ms);
    extern void UartWrite(uchar *buf);
    extern void UartDriver();
    extern void ConfigUART(uint baud);
    void process(uchar *str);
    uchar LongToString(uchar *str, slong dat);
    uchar FloatToString(uchar *str, double dat);
    void main()
    {
    	EA = 1;//开关总中断
    	ConfigTimer0(1);//配置T0定时1ms
    	InitLcd1602();//初始化液晶
    	LcdShowStr(15, 1, "0");//初始时显示一个数字0
    	ConfigUART(9600);
    	while(1)
    	{
    		KeyDriver();//按键驱动
    		UartDriver();
    	}
    }
    void copy(uchar *str,uchar length)
    {
    	uchar i,j,str4[3];
    	for(i=count_str2;i<count_str2+length;i++)
    	{
    		j = i - count_str2;
    		str2[i] = *str++;
    		//str2[i] = '1';
    	}
    	count_str2 += length;
    	//UartWrite(str2);
    	//str4[0]='\r';
    	//str4[1]='\n';
    	//str4[2]='\0';
    	//UartWrite(str4);
    }
    //长整形转换为字符串,str-字符串指针,dat-待转换数
    uchar LongToString(uchar *str, slong dat)
    {
    	schar i = 0;
    	uchar len = 0;
    	uchar 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;//返回字符串长度
    }
    //长整形转换为字符串,str-字符串指针,dat-待转换数
    uchar FloatToString(uchar *str, double dat)//*str是最终显示的结果
    {
    	schar i = 0;//总的部分
    	schar i1 = 0;//整数部分
    	uchar i2 = 0;//小数部分
    	uchar len = 0;
    	uchar buf[12];
    	bit flag = 0;
    	double tmp=0;
    	unsigned long tmp2;
    	unsigned long tmp3;
    
    	if(dat < 0)	//如果时负数,首先取绝对值,并在指针上加上负号
    	{
    		dat = -dat;
    		*str++ = '-';
    		len++;					 
    	}
    	tmp3  = dat;//tmp3取dat的正的部分
    	do {	//先转换为低位在前的十进制数组,因为是倒着显示的
    		buf[i++] = tmp3%10;
    		tmp3 /= 10;
    	}  while (tmp3 > 0);
    	i1 = i;
    	if(dat - (unsigned long)dat > 0.0001)//判断是否存在小数部分
    	{
    		flag = 1;				        
    		tmp = dat;
    		tmp = tmp;
    		do {								  
    			tmp = 10 * tmp;
    			tmp2 = tmp;
    			buf[i++] = tmp2%10;
    		} while(tmp - tmp2 > 0.0001 & i<4);//不能达到很精确
    	}
    	i2=i1;
    	len += i;	//i最后的值就是有效字符的个数
    	while (i1-- > 0)//将数组的ASCII值反向拷贝到接收指针上
    	{
    		*str++ = buf[i1] + '0';
    	}
    	
    	if (flag != 0)
    	{
    		* str++ = '.';
    		while (i2<i)
    		{
    			*str++ = buf[i2] + '0';	
    			//*str++ = (uchar)tmp2%10 + '0';
    			i2++;	
    			
    		}
    		len++;
    	}
    	* str = '\0';//加上字符串结束符	
    	return len;//返回字符串长度,加上小数点部分
    }	
    //显示运算符,显示位置y,运算符类型type
    void ShowOprt(uchar y, uchar type)
    {
    	uchar str3;
    	switch(type)
    	{
    		case 0:str3 = '+';break;//0代表+
    		case 1:str3 = '-'; break;
    		case 2:str3 = '*'; break;
    		case 3:str3 = '/'; break;
    		default:break;
    	}
    	LcdShowStr(0, y, &str3);
    	if(y==1)
    		copy(&str3,1);//复制操作符
    }
    
    //计算器复位,清零变量值,清除屏幕显示
    void Reset()
    {
    	num1 = 0;
    	num2 = 0;
    	step = 0;
    	count_str2 = 0;
    	LcdFullClear();
    }
    //数字键动作函数,n-按键输入的数值
    void NumKeyAction(float n)
    {
    	uchar len;
    	uchar str[12];
    	uchar i;
    
    	if (step > 1)//如果已经计算完成,则重新开始新的运算
    	{
    		Reset();
    		flagdot=0;
    		div10=0;
               exchange = 0;
    	}
    	if (step == 0)//输入第一操作数
    	{
    		if(flagdot==0)
    		{
    			num1 = num1*10 + n;//输入数值累加到原操作数上
    			len = LongToString(str, (slong)num1);//新数值转换为字符串
    			LcdShowStr(16-len, 1, str);//显示到液晶第二行上
    		}
    		else
    		{
    			div10++;
    			for(i=0;i<div10;i++)
    			{
    			 	n=n/10;//每次除以10的次数不一样
    			}
    			num1 = num1 + n;
    			len = FloatToString(str, num1);//新数值转换为字符串
    			LcdShowStr(16-len, 1, str);//显示到液晶第二行上
    		}
    	}
    	else//输入第二操作数
    	{
    		if(flagdot==0)
    		{
    			num2 = num2*10 + n;//输入数值累加到原操作数上
    			len = LongToString(str,(slong)num2);//新数值转换为字符串
    			LcdShowStr(16-len, 1, str);//显示到液晶第二行上
    		}
    		else
    		{
    			div10++;
    			for(i=0;i<div10;i++)
    			 	n=n/10;//每次除以10的次数不一样
    			num2 = num2 + n;
    			len = FloatToString(str, num2);//新数值转换为字符串
    			LcdShowStr(16-len, 1, str);//显示到液晶第二行上
    		}
    	}
    }
    
    //运算符按键动作函数,运算符类型为type
    void OprtKeyAction(uchar type)
    {
    	uchar len;
    	uchar str[12];
    
    	if (step == 0)//第二操作数尚未输入时响应,即不支持连续操作
    	{
    		len = FloatToString(str, num1);//第一操作数转换为字符串
    
    		copy(str,len);//复制第一操作数
    
    		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;
    		flagdot=0;
    		div10=0;
    	}
    }
    
    //计算结果函数
    void GetResult()
    {
    	uchar len;
    	uchar 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 = FloatToString(str, num2);//原第二操作数和运算符显示到第一行
    		copy(str,len);	 //复制第二操作符
    		copy("=",1);
    		ShowOprt(0, oprt);
    		LcdAreaClear(1, 0, 16-1-len);
    		LcdShowStr(16-len,0,str);
    		len = FloatToString(str, result);
    		copy(str,len);
    		LcdShowStr(0, 1, "=");
    		LcdAreaClear(1, 1, 16-1-len);
    		LcdShowStr(16-len, 1, str);
    
    		str2[count_str2+1]='\r';
    		str2[count_str2+2]='\n';
    
    		//FloatToString(str, count_str2);
    		str2[count_str2]='\0';
    		UartWrite(str2);
    		UartWrite("\r\n\0");
    	}
    }
    
    //按键动作函数,根据按键码执行相应的操作,keycode-按键码
    void KeyAction(uchar 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  && exchange == 0 )//回车键,计算结果
    	{
    		GetResult();
    		exchange = ~exchange;
    	}
    	else if(keycode == 0x0D && exchange == 1 )//Esc键,清除
    	{
    		Reset();
    		LcdShowStr(15, 1, "0");
    		exchange = ~exchange;
    		flagdot=0;
    		div10=0;
    	}
    	else if(keycode == 0x1B)
    	{
    		flagdot=1;
    	}
    }		
    
    //配置并启动T0,ms-T0定时时间
    void ConfigTimer0(uint ms)
    {
    	ulong tmp;
    	tmp = 11059200 / 12;
    	tmp = (tmp * ms) / 1000;
    	tmp = 65536 - tmp;
    	tmp = tmp + 28;
    	T0RH = (uchar)(tmp >> 8);
    	T0RL = (uchar)tmp;
    	TMOD &= 0xf0;
    	TMOD |= 0x01;
    	TH0 = T0RH;
    	TL0 = T0RL;
    	ET0 = 1;//使能T0中断
    	TR0 = 1;//启动T0
    }
    
    //T0中断服务函数,执行按键扫描
    void InterruptTimer0() interrupt 1
    {
    	TH0 = T0RH;
    	TL0 = T0RL;
    	KeyScan();//按键扫描
    	UartRxMonitor(1);
    }
    

    2.keyboard.c键盘驱动程序

    #include <reg52.h>
    #define uchar unsigned char 
    
    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;
    
    uchar code KeyCodeMap[4][4] = {
    	{'1', '2', '3', 0x26},//向上键
    	{'4', '5', '6', 0x25},//向左键
    	{'7', '8', '9', 0x28},//向下键
    	{'0',0x1B, 0x0D, 0x27}//ESC键,回车键,向右键
    };
    
    uchar pdata KeySta[4][4] = {
    	{1,1,1,1}, {1,1,1,1}, {1,1,1,1}, {1,1,1,1} 
    };
    
    extern void KeyAction(uchar keycode);
    
    void KeyDriver()
    {
    	uchar i, j;
    	static uchar 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++)
    	{
    		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];//刷新备份
    			}
    		}
    	}
    }
    
    //按键扫描函数
    void KeyScan()
    {
    	uchar i;
    	static uchar keyout = 0;//矩阵按键扫描输出索引
    	static uchar keybuf[4][4] = {
    		{0xff,0xff,0xff,0xff}, {0xff,0xff,0xff,0xff},
    		{0xff,0xff,0xff,0xff}, {0xff,0xff,0xff,0xff}
    	};
    	//将一行的四个键值移入缓冲区
    	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++)
    	{
    		if((keybuf[keyout][i] & 0x0f) == 0x00)
    		{
    			KeySta[keyout][i] = 0;
    		}
    		else if((keybuf[keyout][i] & 0x0f) == 0x0f)
    		{
    			KeySta[keyout][i] = 1;
    		}
    	}
    	//执行下一次的扫描输出
    	keyout++;
    	keyout &= 0x03;
    	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;
    	}
    }
    

    3.LCD1602.c屏幕显示程序:

    #include <reg52.h>
    
    #define uchar unsigned char
    #define lcd1602_db P0
    
    sbit lcd1602_rs = P1^0;
    sbit lcd1602_rw = P1^1;
    sbit lcd1602_e = P1^5;
    
    void LcdWaitReady()
    {
    	uchar sta;
    	lcd1602_db = 0xff;
    	lcd1602_rs = 0;
    	lcd1602_rw = 1;
    	do {
    		lcd1602_e = 1;
    		sta = lcd1602_db;
    		lcd1602_e = 0;
    	} while(sta & 0x80);//只是检测是否忙没有执行任何操作,1表示在忙,0表示空闲
    }
    
    //向液晶写入一行命令,cmd-待写入命令值
    void LcdWriteCmd(uchar cmd)
    {
    	LcdWaitReady();
    	lcd1602_rs = 0;//0为命令
    	lcd1602_rw = 0;//0表示写入
    	lcd1602_db = cmd;
    	lcd1602_e = 1;//产生高脉冲
    	lcd1602_e = 0;
    }
    
    //向液晶写入一字节数据,dat-待写入数据值
    void LcdWriteDat(uchar dat)
    {
    	LcdWaitReady();
    	lcd1602_rs = 1;//1为数据
    	lcd1602_rw = 0;//0表示写入
    	lcd1602_db = dat;
    	lcd1602_e = 1;//产生高脉冲
    	lcd1602_e = 0;
    }
    
    //设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标
    void LcdSetCursor(uchar x, uchar y)
    {
    	uchar addr;
    	if(y==0)
    		addr = 0x00 + x;//这意味着第一个显示字符x=0
    	else
    		addr = 0x40 + x;
    	LcdWriteCmd(addr | 0x80);//设置RAM地址
    }
    
    /*
    //在液晶上显示字符串,和设置函数的功能部分重复
    void LcdShowStr(uchar x,uchar y,uchar *str,uchar len)
    {
    	LcdSetCursor(x, y);	
    	while(len--)//通过长度来改变,而静态显示时是通过判断最后一个字符是否为/0,while(*str!='\0')
    	{
    		LcdWriteDat(*str++);
    	}
    }
    */
    
    void LcdShowStr(uchar x,uchar y,uchar *str)
    {
    	LcdSetCursor(x, y);	
    	while(*str != '\0')//通过长度来改变,而静态显示时是通过判断最后一个字符是否为/0,while(*str!='\0')
    	{
    		LcdWriteDat(*str++);
    	}
    }
    
    //打开光标闪烁效果
    void LcdOpenCursor()
    {
    	LcdWriteCmd(0x0f);
    }
    
    //关闭光标显示
    void LcdCloseCursor()
    {
    	LcdWriteCmd(0x0c);
    }
    
    //区域清除,清除从(x,y)坐标起始的len个字符位
    void LcdAreaClear(uchar x,uchar y,uchar len)
    {
    	LcdSetCursor(x, y);
    	while(len--)
    	{
    		LcdWriteDat(' ');
    	}
    } 
    
    
    //整屏清除
    void LcdFullClear()
    {
    	LcdWriteCmd(0x01);
    }
    
    
    //初始化1602液晶
    void InitLcd1602()
    {
    	LcdWriteCmd(0x38);//写入
    	LcdWriteCmd(0x0c);//显示器开,光标关闭
    	LcdWriteCmd(0x06);//文字不动,地址自动+1
    	LcdWriteCmd(0x01);//清屏操作
    }
    

    4.Uart串口通信部分:

    #include <reg52.h>
    #define uchar unsigned char
    #define uint unsigned int
    
    bit flagFrame = 0;//帧接收完成标志
    bit flagTxd = 0;//单字节发送完成标志,用来代替TXD中断标志位
    uchar cntRxd = 0;//接收字节计数器
    uchar pdata bufRxd[64];//接收字节缓冲区
    
    //extern void UartAction(uchar *buf, uchar len);
    
    //串口配置函数,baud-通信波特率
    void ConfigUART(uint baud)
    {
    	SCON = 0x50;//配置串口为模式1
    	TMOD &= 0x0F;//清零T1的控制位
    	TMOD |= 0x20;//配置T1为模式2
    	TH1 = 256 - (11059200/12/32)/baud;//计算T1重载值
    	TL1 = TH1;//初值等于重载值
    	ET1 = 0;//禁止T1中断
    	ES = 1;//使能串口中断
    	TR1 = 1;//启动T1
    } 
    
    //串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定发送的长度
    void UartWrite(uchar *buf)
    {
    	while(*buf != '\0')
    	{
    		flagTxd = 0;//清零发送标志
    		SBUF = *buf++;//发送一个字节数据
    		while(!flagTxd);//等待该字节发送完成
    	}
    	flagTxd = 0;//清零发送标志
    	SBUF = '\n';//发送一个字节数据
    	while(!flagTxd);//等待该字节发送完成
    }
    /*
    void UartWrite(uchar *buf, uchar len)
    {
    	while(len--)
    	{
    		flagTxd = 0;//清零发送标志
    		SBUF = *buf++;//发送一个字节数据
    		while(!flagTxd);//等待该字节发送完成
    	}
    }
    */
    
    //串口数据读取函数,buf-接收指针,len-指定读取长度,返回值实际读到的长度
    uchar UartRead(uchar *buf, uchar len)
    {
    	uchar i;
    
    	if(len > cntRxd)//指定读取长度实际接收到的数据长度
    	{
    		len = cntRxd;//读取长度设置为实际接收到的数据长度
    	}
    	for(i=0;i<len;i++)
    	{
    		*buf++=bufRxd[i];
    	}
    	cntRxd = 0;//接收计数器清零
    	return len;//返回实际读取长度
    }
    
    //串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔
    void UartRxMonitor(uchar ms)
    {
    	static uchar cntbkp = 0;
    	static uchar idletmr = 0;
    
    	if (cntRxd > 0)//接收计数器大于零时,监控总线空闲时间
    	{
    		if (cntbkp != cntRxd)//接收计数器发生改变,即刚接收到数据时,清零空闲计时
    		{
    			cntbkp = cntRxd;
    			idletmr = 0;
    		}
    		else//空闲计时小于30ms时,持续累积
    		{
    			if (idletmr < 30)//空闲计时小于30ms时,持续累加
    			{
    				idletmr += ms;
    				if (idletmr >= 30)//空闲时间达到30ms时,即判断一帧接收完毕
    				{
    					flagFrame = 1;//设置帧接收完成标志
    				}
    			}
    		}
    	}
    	else
    	{
    		cntbkp = 0;
    	}
    }
    
    //串口驱动函数,检测数据帧的接收,调度功能
    void UartDriver()
    {
    	uchar len;
    	uchar pdata buf[40];
    	if(flagFrame)//有命令到达时,读取处理该命令
    	{
    		flagFrame = 0;
    		len = UartRead(buf, sizeof(buf));
    		//UartAction(buf, len);
    	}
    }
    
    //串口中断服务函数
    void InterruptUART() interrupt 4
    {
    	if (RI)//接收到新字节
    	{
    		RI = 0;//清零接收中断标志位
    		if(cntRxd < sizeof(bufRxd))
    		{
    			bufRxd[cntRxd++] = SBUF;
    		}
    	}
    	if(TI)
    	{
    		TI = 0;//清零发送中断标志位
    		flagTxd = 1;//设置字节发送完成标志
    	}
    }
    

    结果分析:
    ①可以实现基础计算功能,以及后面的扩展功能。
    ②在小数部分还有待改进,因为最多只能输出3位小数牺牲了准确性,应该有能够计算更加准确的算法。

    展开全文
  • 基于51单片机计算器

    万次阅读 2020-04-04 16:34:15
    具体实现计算器的加减乘除功能,并且自带八位密码锁,输入密码后按“=”确定,错误输入三次密码就会锁定,重启后解除锁定,密码可以在密码表中设定。显示部分采用了1602显示屏。 这一次在使用AD画PCB时,考虑到...
  • 51单片机实现计算器带CH452,高精度,带小数点,完全由存储原理实现
  • 本设计是实现一个有加、减、乘、除、计算功能的多功能计算器。它的硬件主要由四部分组成,一个STC89C52单片机芯片,一块LCD1602液晶显示器,一个4*4的键盘。采用STC89C52单片机为主要控制电路,然后使用液晶显示管...
  • 基于51单片机计算器程序加仿真,可以连续计算 ,混合运算没有bug 可以判断加减乘除的运算顺序
  • 基于51单片机利用键盘和LCD设计的计算器
  • c语言编程单片机实现计算器(带Proteus仿真)用数码管显示
  • 基于51单片机的简易计算器

    万次阅读 多人点赞 2019-01-08 21:17:44
    计算器是以MCS-51系列AT89C51单片机为核心构成的简易计算器系统。该系统通过单片机控制,实现对4*4键盘扫描进行实时的按键检测,并由LCD1602显示屏将过程与结果显示出来。 2.硬件原理图 硬件主要由四部分组成 ...
  • 三、编程实现 1、主函数部分: #include #include "LCD1602.h" #include "MatrixKey.h" /*********************************************** 51单片机大作业 —— 基于AT89C51的简易计算器 作者:智能医学工程2002班...
  • 用AT89S52 单片机实现计算器(LED显示)
  • 运用51单片机制作计算器的源代码

    千次阅读 2019-05-21 19:36:56
    运用51单片机制作计算器的源代码@TOC /* S16 S12 S8 S4分别是123+ S15 S11 S7 S3分别是456- S14 S10 S6 S2分别是789* S13 S9 S5 S1分别是0 CLR = / */ /* 实现两个数的运算,每个数的位数至少可以八位 */ #include&...
  • 51单片机简单计算器

    2017-08-05 15:29:41
    51单片机结合1602液晶屏实现简单的计算器
  • 单片机计算器课程设计,有报告的,总共花了好几天才完成的,共享一下,多多指教!

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,746
精华内容 698
关键字:

单片机实现计算器