怎样用51单片机做计算器啊?

怎样用51单片机做计算器啊?,第1张

1、硬件仿真图

硬件部分比较简单,当键盘按键按下时它的那一行、那一列的端口为低电平。因此,只要扫描行、列端口是否都为低电平就可以确定是哪个键被按下。

2、主程序流程图

程序的主要思想是:将按键抽象为字符,然后就是对字符的处理。将 *** 作数分别转化为字符串存储, *** 作符存储为字符形式。然后调用compute()函数进行计算并返回结果。具体程序及看注释还有流程图。

3、Altium Designer画的PCB图

4、程序源代码

#include <reg51.h>#include <intrins.h>

#include <ctype.h>         

#include <stdlib.h>         

#define uchar unsigned char

#define uint unsigned int

uchar operand1[9], operand2[9]

uchar operator                 

void delay(uint)

uchar keyscan()

void disp(void)

void buf(uint value)

uint compute(uint va1,uint va2,uchar optor)

uchar code table[] = {0xc0,0xf9,0xa4,0xb0,0x99,

              0x92,0x82,0xf8,0x80,0x90,0xff} 

uchar dbuf[8] = {10,10,10,10,10,10,10,10}         

void delay(uint z)

{

uint x,y

for(x=zx>0x--)

  for(y=110y>0y--)

}

uchar keyscan()

{

  uchar skey                   

  P1 = 0xfe

  while((P1 &0xf0) != 0xf0)      

  {

      delay(3)                 

      while((P1 &0xf0) != 0xf0)  

      {

          switch(P1)              

          {

              case 0xee: skey = '7'break

              case 0xde: skey = '8'break

              case 0xbe: skey = '9'break

              case 0x7e: skey = '/'break   

              default:   skey = '#'

          }

          while((P1 &0xf0) != 0xf0)

             

      }

  }

  P1 = 0xfd 

  while((P1 &0xf0) != 0xf0)

  {

      delay(3)

      while((P1 &0xf0) != 0xf0)

      {

          switch(P1)

          {

              case 0xed: skey = '4'break

              case 0xdd: skey = '5'break

              case 0xbd: skey = '6'break

              case 0x7d: skey = '*'break

              default:   skey = '#'

          }

          while((P1 &0xf0) != 0xf0)

             

      }

  }

  P1 = 0xfb

  while((P1 &0xf0) != 0xf0)

  {

      delay(3)

      while((P1 &0xf0) != 0xf0)

      {

          switch(P1)

          {

              case 0xeb: skey = '1'break

              case 0xdb: skey = '2'break

              case 0xbb: skey = '3'break

              case 0x7b: skey = '-'break

              default: skey = '#'

          }

          while((P1 &0xf0) != 0xf0)

             

      }

  }

  P1 = 0xf7

  while((P1 &0xf0) != 0xf0)

  {

      delay(3)

      while((P1 &0xf0) != 0xf0)

      {

          switch(P1)

          {

              case 0xe7: skey = '$'break

              case 0xd7: skey = '0'break

              case 0xb7: skey = '='break

              case 0x77: skey = '+'break

              default:   skey = '#'

          }

          while((P1 &0xf0) != 0xf0)

             

      }

  }

  return skey

}

void main()

{  

  uint value1, value2, value       

  uchar ckey, cut1 = 0, cut2 = 0 

  uchar operator                   

  uchar i, bool = 0

init:                                 

  buf(0)                         

  disp()

  value = 0

  cut1 = cut2 = 0

  bool = 0

  for(i = 0i <9i++)

  {

      operand1[i] = '\0'

      operand2[i] = '\0'

  }                               

  while(1)

  {

      ckey = keyscan()         

      if(ckey != '#')

      {

          if(isdigit(ckey))      

          {

              switch(bool)  

              {

                  case 0:

                          operand1[cut1] = ckey

                          operand1[cut1+1] = '\0'

                          value1 = atoi(operand1)

                          cut1++

                          buf(value1)

                          disp()

                          break

                  case 1:

                          operand2[cut2] = ckey

                          operand2[cut2+1] = '\0'

                          value2 = atoi(operand2)

                          cut2++

                          buf(value2)

                          disp()

                          break                     

                  default: break

              }

          }

          else if(ckey=='+'||ckey=='-'||ckey=='*'||ckey=='/')

          {

              bool = 1 

              operator = ckey

              buf(0)

              dbuf[7] = 10

              disp()

          }

          else if(ckey == '=')

          {

              value = compute(value1,value2,operator)

              buf(value)

              disp()

              while(1)                  

              {

                  ckey = keyscan()

                  if(ckey == '$')        

                      goto init

                  else

                      {

                          buf(value)

                          disp()

                      }

              }

          }

          else if(ckey == '$')

          {    goto init}

      }

      disp()

  }

}

uint compute(uint va1,uint va2,uchar optor)

{

  uint value

  switch(optor)

  {

      case '+' : value = va1+va2   break

      case '-' : value = va1-va2   break

      case '*' : value = va1*va2   break

      case '/' : value = va1/va2   break 

      default :  break

  }

  return value

}

void buf(uint val)

{

  uchar i

  if(val == 0)

  {

      dbuf[7] = 0

      i = 6

  }

  else

      for(i = 7val >0i--)

      {

          dbuf[i] = val % 10

          val /= 10

      }

  for( i >0i--)

      dbuf[i] = 10

}

void disp(void)

{

  uchar bsel, n

  bsel=0x01

  for(n=0n<8n++)

  {

      P2=bsel

      P0=table[dbuf[n]]

      bsel=_crol_(bsel,1)

      delay(3)

      P0=0xff

  }

}

扩展资料:

PROTEUS 是单片机课堂教学的先进助手

PROTEUS不仅可将许多单片机实例功能形象化,也可将许多单片机实例运行过程形象化。前者可在相当程度上得到实物演示实验的效果,后者则是实物演示实验难以达到的效果。

它的元器件、连接线路等却和传统的单片机实验硬件高度对应。这在相当程度上替代了传统的单片机实验教学的功能,例:元器件选择、电路连接、电路检测、电路修改、软件调试、运行结果等。

课程设计、毕业设计是学生走向就业的重要实践环节。由于PROTEUS提供了实验室无法相比的大量的元器件库,提供了修改电路设计的灵活性、提供了实验室在数量、质量上难以相比的虚拟仪器、仪表,因而也提供了培养学生实践精神、创造精神的平台

随着科技的发展,“计算机仿真技术”已成为许多设计部门重要的前期设计手段。它具有设计灵活,结果、过程的统一的特点。可使设计时间大为缩短、耗资大为减少,也可降低工程制造的风险。相信在单片机开发应用中PROTEUS也能茯得愈来愈广泛的应用。

使用Proteus 软件进行单片机系统仿真设计,是虚拟仿真技术和计算机多媒体技术相结合的综合运用,有利于培养学生的电路设计能力及仿真软件的 *** 作能力;

在单片机课程设计和全国大学生电子设计竞赛中,我们使用 Proteus 开发环境对学生进行培训,在不需要硬件投入的条件下,学生普遍反映,对单片机的学习比单纯学习书本知识更容易接受,更容易提高。

实践证明,在使用 Proteus 进行系统仿真开发成功之后再进行实际制作,能极大提高单片机系统设计效率。因此,Proteus 有较高的推广利用价值。

参考资料来源:百度百科-protues

以下是我编的简易计算器程序,基本成功

//4*4键盘检测程序,按下键后相应的代码显示在液晶屏上

//显示5位后,第6次显示 *** 作符号

//再显示下一个数

// 键值与功能对应表

//键值 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

//功能 0 1 2 3 4 5 6 7 8 9 + - × ÷ = 清零

#include<reg52.h>

sbit beep=P2^3

sbit lcden=P3^4

sbit rs=P3^5

sbit rw=P3^6

#define uint unsigned int

#define ulint unsigned long int

#define uchar unsigned char

#define lcddata P0

ulint bb,dd,ee,ff

uchar d,flag1

uchar fd1,fd2

uchar b1=16,b2=16,b3=16,b4=16,b5=16

uchar d1=16,d2=16,d3=16,d4=16,d5=16

uchar f1=16,f2=16,f3=16,f4=16,f5=16,f6=16,f7=16,f8=16,f9=16,f10=16

uchar key,keyval,c,temp

void Delay1ms(uint i) //1ms延时程序

{

uint j

for(i>0i--)

{

for(j=0j<125j++)

{}

}

}

void write_com(uchar com)

{

lcddata=com

rs=0

rw = 0

lcden=0

Delay1ms(10)

lcden=1

Delay1ms(10)

lcden=0

}

void write_date(uchar date)

{

lcddata=date

rs=1

rw=0

lcden=0

Delay1ms(10)

lcden=1

Delay1ms(10)

lcden=0

}

void init2()

{

rw=0

write_com(0x38)

Delay1ms(10)

write_com(0x0f)

Delay1ms(10)

write_com(0x06)

Delay1ms(10)

write_com(0x01)

Delay1ms(10)

}

void display1(uchar A1,uchar A2,uchar A3,uchar A4,uchar A5) //第1个数显示程序

{

init2()

write_com(0x80)//第1行,第1字

Delay1ms(10)

write_date(0x30+A1)

Delay1ms(10)

write_date(0x30+A2)

Delay1ms(10)

write_date(0x30+A3)

Delay1ms(10)

write_date(0x30+A4)

Delay1ms(10)

write_date(0x30+A5)

Delay1ms(10)

}

void display2(uchar A1,uchar A2,uchar A3,uchar A4,uchar A5) //第2个数显示程序

{

write_com(0x88)//第1行,第1字

Delay1ms(10)

write_date(0x30+A1)

Delay1ms(10)

write_date(0x30+A2)

Delay1ms(10)

write_date(0x30+A3)

Delay1ms(10)

write_date(0x30+A4)

Delay1ms(10)

write_date(0x30+A5)

Delay1ms(10)

}

void display3(uchar a) // *** 作符号显示程序

{

write_com(0x86)//第1行,第1字

Delay1ms(10)

switch(a)

{

case 10:

write_date('+')

Delay1ms(10)

case 11:

write_date('-')

Delay1ms(10)

case 12:

write_date('x')

Delay1ms(10)

case 13:

write_date('/')

Delay1ms(10)

}

}

void display4(uchar A1,uchar A2,uchar A3,uchar A4,uchar A5,uchar A6,uchar A7,uchar A8,uchar A9,uchar A10,uchar A11,uchar A12) //结果显示程序

{

write_com(0x80+0x40)//第2行,第1字

Delay1ms(10)

if (flag1==0)

{

write_date('-')

}

else write_date('+')

Delay1ms(10)

write_date(0x30+A1)

Delay1ms(10)

write_date(0x30+A2)

Delay1ms(10)

write_date(0x30+A3)

Delay1ms(10)

write_date(0x30+A4)

Delay1ms(10)

write_date(0x30+A5)

Delay1ms(10)

write_date(0x30+A6)

Delay1ms(10)

write_date(0x30+A7)

Delay1ms(10)

write_date(0x30+A8)

Delay1ms(10)

write_date(0x30+A9)

Delay1ms(10)

write_date(0x30+A10)

Delay1ms(10)

write_date('.')

Delay1ms(10)

write_date(0x30+A11)

Delay1ms(10)

write_date(0x30+A12)

Delay1ms(10)

}

uchar keyscan()

{

key=16

P3=0xef//P3.7输出1个低电平

temp=P3//读取

temp=temp&0x0f//屏蔽高4位

if(temp!=0x0f)

{

Delay1ms(10)

if(temp!=0x0f)

{

temp=P3

switch(temp)

{

case 0xee:

key=0

break

case 0xed:

key=4

break

case 0xeb:

key=8

break

case 0xe7:

key=12

break

}

while(temp!=0x0f)

{

temp=P3

temp=temp&0x0f

beep=0

}

beep=1

}

}

P3=0xdf

temp=P3

temp=temp&0x0f

if(temp!=0x0f)

{

Delay1ms(10)

if(temp!=0x0f)

{

temp=P3

switch(temp)

{

case 0xde:

key=1

break

case 0xdd:

key=5

break

case 0xdb:

key=9

break

case 0xd7:

key=13

break

}

while(temp!=0x0f)

{

temp=P3

temp=temp&0x0f

beep=0

}

beep=1

}

}

P3=0xbf

temp=P3

temp=temp&0x0f

if(temp!=0x0f)

{

Delay1ms(10)

if(temp!=0x0f)

{

temp=P3

switch(temp)

{

case 0xbe:

key=2

break

case 0xbd:

key=6

break

case 0xbb:

key=10

break

case 0xb7:

key=14

break

}

while(temp!=0x0f)

{

temp=P3

temp=temp&0x0f

beep=0

}

beep=1

}

}

P3=0x7f

temp=P3

temp=temp&0x0f

if(temp!=0x0f)

{

Delay1ms(10)

if(temp!=0x0f)

{

temp=P3

switch(temp)

{

case 0x7e:

key=3

break

case 0x7d:

key=7

break

case 0x7b:

key=11

break

case 0x77:

key=15

break

}

while(temp!=0x0f)

{

temp=P3

temp=temp&0x0f

beep=0

}

beep=1

}

}

return(key)

}

void main()

{ while(1)

{

c=1

while(c<6)//输入第1个5 位数

{

keyval=keyscan()

if(keyval<10)

{

switch(c)

{

case 1:b1=keyval break

case 2:b2=keyval break

case 3:b3=keyval break

case 4:b4=keyval break

case 5:b5=keyval break

}

c++

}

display1(b1,b2,b3,b4,b5)

}

while(c==6) //输入计算符号

{

keyval=keyscan()

if((keyval>=10)&&(keyval<14)) //可去一层括号,因逻辑运算优先级较低

{

d=keyval

}

c=1

display3(d)

}

while(c<6) //输入第2个5 位数

{

keyval=keyscan()

if(keyval<10)

{

switch(c)

{

case 1:d1=keyval break

case 2:d2=keyval break

case 3:d3=keyval break

case 4:d4=keyval break// 除

case 5:d5=keyval break

}

c++

}

display2(d1,d2,d3,d4,d5)

}

bb= b1*10000+b2*1000+b3*100+b4*10+b5

dd=d1*10000+d1*1000+d3*100+d4*10+d5

while(keyval!=14) //等待按下"="

{

keyval=keyscan()

}

Delay1ms(10)

switch(d)

{

case 10:ee=bb+dd break//+

case 11:

flag1=1

if(bb>=dd)

{

ee=bb-dd //-

flag1=0

}

else ee=dd-bb

break

case 12:ee=bb*dd break//*可能会溢出

case 13:ee=bb/dd //除法小数部分会丢失,保留2位

ff=bb%dd

fd1=ff*10/dd

fd2=ff*100/dd%10

break

}

f10=ee/1000000000%10

f9=ee/100000000%10

f8=ee/10000000%10

f7=ee/1000000%10

f6=ee/100000%10

f5=ee/10000%10

f4=ee/1000%10

f3=ee/100%10

f2=ee/10%10

f1=ee%10

display4(f10,f9,f8,f7,f6,f4,f4,f3,f2,f1,fd1,fd2)

while(keyval!=15)

{

keyval=keyscan()

}

b1=0b2=0b3=0b4=0b5=0

d1=0d2=0d3=0d4=0d5=0

bb=0dd=0ee=0

init2()

}

}

给你些子程序,自己看着凑吧。呵呵。有了这些,写出来应该不难了。

@@@@@@@@@双字节整数运算@@@@@@@@@@@@@@@@@@

***********双字节无符号加法**************

入口:R6(H),R7,R4(H),R5,出口:和R6(H),R7(L)

UADD: MOV A,R7

ADD A,R5

MOV R7,A

MOV A,R6

ADDC A,R4

MOV R6,A

RET

***********双字节无符号减法**************

入口:被减数R6(H),R7(L),减数R4(H),R5(L),出口:差R6(H),R7(L)

CLR C

MOV A,R7

SUBB A,R5

MOV R7,A

MOV A,R6

SUBB A,R4

MOV R6,A

RET

***********双字节无符号乘法**************

入口:R6(H),R7(L),R4(H),R5(L),出口:积R6(H),R7(L)

UMUL: MOV A,R7

MOV B,R5

MUL AB

MOV R0,B

XCH A,R7

MOV B,R4

MUL AB

ADD A,R0

XCH A,R6

MOV B,R5

MUL AB

ADD A,R6

MOV R6,A

RET

***********双字节无符号除法*****************

入口:R6(H),R7(L),R4(H),R5(L),出口:商R6(H),R7(L),余R4(H),R5(L)

影响:R2,R3,

堆栈需求:1

UDIV: CLR C

CLR A

MOV R2,A

MOV R3,A

MOV B,#10H

MOVBIT: MOV A,R7R6、R7中数据左移一位到R2、R3中,C到R7

RLC A

MOV R7,A

MOV A,R6

RLC A

MOV R6,A

MOV A,R3

RLC A

MOV R3,A

MOV A,R2

RLC A

MOV R2,A

CLR C R2R3-R4R5

MOV A,R3

SUBB A,R5

PUSH Acc

MOV A,R2

SUBB A,R4

JBC Cy,MOVBIT0不够减,清C继续左移

MOV R2,A够减,存回余数并置位C

POP Acc

MOV R3,A

SETB C

SJMP MOVBIT1

MOVBIT0: POP Acc

MOVBIT1: DJNZ B,MOVBIT

MOV A,R7

RLC A

MOV R7,A

MOV A,R6

RLC A

MOV R6,A

MOV A,R2

MOV R4,A

MOV A,R3

MOV R5,A

RET

(7) 标号: DIVD 功能:双字节二进制无符号数除法

入口条件:被除数在R2、R3、R4、R5中,除数在R6、R7中。

出口信息:OV=0 时,双字节商在R2、R3中,OV=1 时溢出。

影响资源:PSW、A、B、R1~R7 堆栈需求: 2字节

DIVD: CLR C ;比较被除数和除数

MOV A,R3

SUBB A,R7

MOV A,R2

SUBB A,R6

JC DVD1

SETB OV ;溢出

RET

DVD1: MOV B,#10H ;计算双字节商

DVD2: CLR C ;部分商和余数同时左移一位

MOV A,R5

RLC A

MOV R5,A

MOV A,R4

RLC A

MOV R4,A

MOV A,R3

RLC A

MOV R3,A

XCH A,R2

RLC A

XCH A,R2

MOV F0,C ;保存溢出位

CLR C

SUBB A,R7 ;计算(R2R3-R6R7)

MOV R1,A

MOV A,R2

SUBB A,R6

ANL C,/F0 ;结果判断

JC DVD3

MOV R2,A ;够减,存放新的余数

MOV A,R1

MOV R3,A

INC R5 ;商的低位置一

DVD3: DJNZ B,DVD2 ;计算完十六位商(R4R5)

MOV A,R4 ;将商移到R2R3中

MOV R2,A

MOV A,R5

MOV R3,A

CLR OV ;设立成功标志

RET


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11061352.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-13
下一篇 2023-05-13

发表评论

登录后才能评论

评论列表(0条)

保存