AT89C51单片机做简易计算器的程序。初学C51,有没有大神能帮我改改程序,我自己改了很多遍还不行。

简易计算器

设计基本要求:

1)系统开机能够一位数倒计时

2)设计简易的计算机,能够进行1位数的加减乘除计算,液晶屏上可以显示最长5个数字的表达式参与运算。例如:X1+X2-X3*X4/X5

3)可以将计算的结果存储,并利用按键可以读取,至少存储10次表达式的计算结果

这是用protues画的图:




程序如下:

#include"reg51.h"

#include"stdio.h"
#include"intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
sbit E=P2^4;
sbit W=P2^5;
sbit R=P2^6;
sbit H=P3^2;
int   KeyValue;




void DelayMS(uintxms)//延时函数
{
   uchar i,j,k;
   i=57;j=27;k=112;
   do
   {
   do
   {
   while(--k);
   }
   while(--j);
   }
   while(--i);
}
//按键子程序
uchar anjian_new(void)
{
   char x,a=0;
   P1=0x0f;                                   //测试列
   switch(P1)
  {
   case(0x07):   KeyValue=0;break;
   case(0x0b):   KeyValue=4;break;
   case(0x0d):   KeyValue=8;break;
   case(0x0e):   KeyValue=12;break;
  }
   P1=0xf0;                                   //测试行
   switch(P1)
  {
   case(0x70):   KeyValue=KeyValue+3;break;
   case(0xb0):   KeyValue=KeyValue+2;break;
   case(0xd0):   KeyValue=KeyValue+1;break;
   case(0xe0):   KeyValue=KeyValue;break;
  }
   while((a<50)&&(P1!=0xf0))                  //按键松手检测
  {
    DelayMS(1);
    a++;
  }
  switch(KeyValue)
  {
   case 0:x=14;break;
   case 1:x=0;break;
   case 2:x=15;break;
   case 3:x=13;break;
   case 4:x=1;break;
   case 5:x=2;break;
   case 6:x=3;break;
   case 7:x=12;break;
   case 8:x=4;break;
   case 9:x=5;break;
   case 10:x=6;break;
   case 11:x=11;break;
   case 12:x=7;break;
   case 13:x=8;break;
   case 14:x=9;break;
   case 15:x=10;break;
  }
   return x;
 }




 void write_com_1602(uchar command)           //写命令
{
  E=0;
  R=0;
  W=0;
  P0=command;
  DelayMS(2);
  E=1;
  DelayMS(4);
  E=0;
}


//LCD1602显示屏
void init()                                  //LCD初始化
{
  E=0;
  W=0;
  write_com_1602(0x38);                         //数据位为8位,显示2行字符,5*7点阵字符体
  write_com_1602(0x0f);                         //开显示,光标消失,不闪烁
  write_com_1602(0x06);                         //光标右移,AC递增
  write_com_1602(0x01);                         //清屏
  write_com_1602(0x80);                         //给AC送值
}






void write_data_1602(uchar datum)            //写数据
{
  E=0;
  W=0;
  R=1;
  P0=datum;
  DelayMS(2);
  E=1;
  DelayMS(4);
  E=0;
}


void desplay(uint a)                         //一位数输出显示
{
  uchar b;
  b=a+0x30;
  write_data_1602(b);
}


void show(ulong x)                           //LCD多位数显示
{
  uint num,c,j;
  ulong a=1,k;
  uchar table[]={"0123456789"};
  uchar y;
  num=0;
  write_com_1602(0x80+0x41);
  k=x;
  while(k!=0)
 {
   num++;
   k=k/10;
 }
  for(j=1;j<num;j++)
 {
   a=a*10;
 }
  while(num)
 {
   c=x/a;
   x=x%a;
   a=a/10;
   y=table[c];
   num--;
   write_data_1602(y);
 }
}


//计算函数(判定符号,计算,左移)
ulong js(void)
{
   ulong x,i,j,a[9];
   for(i=1;i<9;i+=2)
  {
   if(a[i]==12||a[i]==13)
  {
   if(a[i]==12)
  {
    a[i-1]=a[i-1]*a[i+1];
    for(j=i;j<9;j++)
    a[j]=a[j+2];
    a[7]=0;
    a[8]=0;
  }
  if(a[i]==13)
  {
   a[i-1]=a[i-1]/a[i+1];
   for(j=i;j<9;j++)
   a[j]=a[j+2];
   a[7]=0;
   a[8]=0;
  }
    i=-1;
 }
 }
   for(i=1;i<9;i+=2)
  {
   if(a[i]==10||a[i]==11)
   {
    if(a[i]==10)
    {
     a[i-1]=a[i-1]+a[i+1];
     for(j=i;j<9;j++)
     a[j]=a[j+2];
     a[7]=0;
     a[8]=0;
    }
    if(a[i]==11)
    {
     a[i-1]=a[i-1]-a[i+1];
     for(j=i;j<9;j++)
     a[j]=a[j+2];
     a[7]=0;
     a[8]=0;
    }
    i=-1;
   }
  }
    x=a[0];
    return x;
}


//回读函数
void int0() interrupt 0
{
   uint num,c,j,t,du[9];
   ulong a=1,k;
   uchar table[]={"0123456789"};
   char y;
   num=0;
   write_com_1602(0x80+0x41);
   k=du[t];
   write_com_1602(0x01);
   while(k!=0)
  {
    num++;
    k=k/10;
  }
   for(j=1;j<num;j++)
  {
    a=a*10;
  }
   while(num)
  {
    c=du[t]/a;
    du[t]=du[t]%a;
    a=a/10;
    y=table[c];
    num--;
    write_data_1602(y);
  }
    t--;
    H=1;
}


//中断函数
void time0() interrupt 1
{
  uint p,time;
  TH0=(65535-50000)/256;
  TL0=(65535-50000)%256;
  p++;
  if(p==20)
 {
   write_com_1602(0x01);
   write_data_1602(time+0x30);
   time--;                                        //倒计时变量自减
   p=0;
 }
}  //主函数
void main()                                
{
   ulong x,i,j,t,r,time,p,key,a[9],du[9];
   _nop_();
   init();
   t=0;j=0;r=0;
   P1=0xF0;                                   //P1赋值以后,矩阵键盘开启
   time=9;                                    //倒计时初值,在定时函数里进行自减
   p=0;
   IT0=1;                                     //选择外部中断0为跳沿触发方式
   TMOD=0x01;
   ET0=1;                                     //定时器中断允许
   EA=1;
   EX0=1;                                     //外中断0允许
   H=1;
   TH0=(65535-50000)/256;
   TL0=(65536-50000)%256;
   TR0=1;
   while(time==-2?0:1);                           //倒计时归零判断
   TR0=0;
   write_com_1602(0X01);                         //清屏
   while(1)
 {
   while(P1==0xf0);
   key=anjian_new();                                 //按键输入
     if(key<=9&&key>=0)                         //判定键值
   {
     a[j]=key;                                  //数字键值,显示数字
     desplay(key);
     j++;
     while(P1!=0xf0);
     DelayMS(30);
   }
     else if(key<=13&&key>=10)                  //符号键值,显示加减乘除符号
   {
     switch(key)
    {
       case 10:write_data_1602('+');a[j]=10;j++;break;
       case 11:write_data_1602('-');a[j]=11;j++;break;
       case 12:write_data_1602('*');a[j]=12;j++;break;
       case 13:write_data_1602('/');a[j]=13;j++;break;
       default:break;
       DelayMS(130);
    }
       DelayMS(130);
   }
    else if(key==15)                           //等号键值
   {
     write_com_1602(0x80+0x40);                 //给AC送值
     write_data_1602('=');
     x=js();
     du[r]=x;
     t=r;
     r++;
     show(x);
   }
    else if(key==14)                           //清零键值
   {
    write_com_1602(0x01);                      //清屏
    write_com_1602(0x80);                      //给AC送值
    for(i=0;i<9;i++)
    a[i]=0;
    j=0;
   }
  }

 }


我的程序在keil4运行后会显示如下结果:

Build target 'Target 1'
compiling 111.c...
linking...
BL51 BANKED LINKER/LOCATER V6.22 - SN: Eval Version
COPYRIGHT KEIL ELEKTRONIK GmbH 1987 - 2009
"111.obj" 
TO "123" 
*** WARNING L15: MULTIPLE CALL TO SEGMENT
    SEGMENT: ?PR?_DELAYMS?111
    CALLER1: ?PR?INT0?111
    CALLER2: ?PR?TIME0?111
*** WARNING L15: MULTIPLE CALL TO SEGMENT
    SEGMENT: ?PR?_DELAYMS?111
    CALLER1: ?PR?TIME0?111
    CALLER2: ?C_C51STARTUP
*** ERROR L114: SEGMENT DOES NOT FIT
    SPACE:   DATA    
    SEGMENT: _DATA_GROUP_
    BASE:    0000H
    LENGTH:  00C7H
******************************************************************************
* RESTRICTED VERSION WITH 0800H BYTE CODE SIZE LIMIT; USED: 0A37H BYTE (127%) *
******************************************************************************
Program Size: data=210.0 xdata=0 code=3298
LINK/LOCATE RUN COMPLETE.  2 WARNING(S),  1 ERROR(S)
*** WARNING L15: MULTIPLE CALL TO SEGMENT
    SEGMENT: ?PR?_DELAYMS?111
    CALLER1: ?PR?INT0?111
    CALLER2: ?PR?TIME0?111
*** WARNING L15: MULTIPLE CALL TO SEGMENT
    SEGMENT: ?PR?_DELAYMS?111
    CALLER1: ?PR?TIME0?111
    CALLER2: ?C_C51STARTUP
*** ERROR L114: SEGMENT DOES NOT FIT
    SPACE:   DATA    
    SEGMENT: _DATA_GROUP_
    BASE:    0000H
    LENGTH:  0018H
*** FATAL ERROR L250: CODE SIZE LIMIT IN RESTRICTED VERSION EXCEEDED
    MODULE:  C:\KEIL\C51\LIB\C51S.LIB (-----)
    LIMIT:   0800H BYTES
Target not created

猜你喜欢

转载自blog.csdn.net/qq_42226659/article/details/80345620
今日推荐