单片机小数点计算器_单片机计算的小数怎么四舍五入 - CSDN
精华内容
参与话题
  • 基于51单片机的超强科学计算器,用LCD1602显示, 键盘6X6共36个键,可以实现一般科学计算器的大部分功能,具体指标如下: 1、数字可处理10e-38~10e38 2、7位有效数字 3、精确到小数后六位 4、操作出错提醒 5、用户可...
  • 51单片机计算器(包含小数计算) 编写语言:C 运行情况:完美运行,尚未发现bug 备注:同普通实现小数计算程序不一样(浮点型数据计算存在精度丢失的情况),本程序全部采用整形进行计算,对小数点进行记录,最后...
  • 基于51单片机计算器设计

    万次阅读 多人点赞 2019-04-22 16:05:21
    能做计算器单片机 单片机的出现是计算机制造技术高速发展的产物,它是嵌入式控制系统的核心,如今,它已广泛的应用到我们生活的各个领域,电子、科技、通信、汽车、工业等。本次设计是设计一个简易计算器,能够...

    能做计算器的单片机

    单片机的出现是计算机制造技术高速发展的产物,它是嵌入式控制系统的核心,如今,它已广泛的应用到我们生活的各个领域,电子、科技、通信、汽车、工业等。本次设计是设计一个简易计算器,能够进行多位的加减乘除运算。它主要由51单片机的数码管,键盘等模块组成。本计算器是将键盘输入信息经处理通过缓存,送入数码管显示,数码管采用动态扫描方式,计算功能通过软件实现,用C语言对单片机可编芯片进行编程,实现计算器的设计。

    把期中做的作业放上来哈哈

    硬件电路描述

    要进行数据的计算就必须先进行数据的输入,也就必须确定按键输入的数值是什么,这就需要对键盘进行扫描,从而确定究竟是哪个键按下。 对于键盘的扫描,这里采用行列扫描的方法来完成对键盘的扫描。原理就是先确定按键在哪一行,接着再确定是哪一列,这样就可以知道是哪个按键被按下了。我是将P3口作为按键扫描口的,比如,先使行线输出全“0”,读列线,再使列线输出全为“0”,读行线。两次结果再相与,则得到一个值为键值。同理,每个按键都会有一个对应的十六进制值,把它们列出来进行一一对应就行了。如下图。
    在这里插入图片描述

    程序设计描述

    1.程序总流程图
    在这里插入图片描述
    2.编程思路
    在单片机接通电源后,单片机就会一直重复检测键盘上的按钮是否被按下。如果有键被按下,就会进入选择判断,当按下数字键,相应数字计入变量keynum中并在数码管上移位显示;当按下运算符键和特殊功能键,也将对应的10到15数字计入到keynum中并进行第二次判断,如果keynum是0~9,则将数据变量dat×10加上keynum;如果是10(加号对应值),进入加法程序(加法标识变量加1,其他运算符标识变量归零,把dat赋值给另一变量datA;当法标识变量大于1时,就是连加,需要将dat等于dat加上datA的值)。其他运算符也是差不多的程序。keynum等于14,就进入等于运算程序。这个程序中也就是四个if语句,如果运算符变量为1就运行相应代码。如加法运算符为1,则使dat加上datA的值赋给dat。最后将dat放入显示程序中显示,而无论何时按下keynum等于15时,所有状态清零。这就是我写的代码的主要思路。

    源代码及注释

    #include <reg51.h>
    #define long unsigned long
    #define KEYPORT P3
    sbit beep=P1^4;
    bit dot;
    typedef unsigned char byte;
    
    long dat;       //数据
    long datA;      //过度数据
    byte addflag;   //加法标志位
    byte subflag;   //减法标志位
    byte mulflag;   //乘法标志位
    byte divflag;   //除法标志位
    byte clrflag;   //数据处理标志位
    byte scanok;
    int checkok;
    int keynum;    //按键键值
    static byte dispbuf[6];
    //数码管字段表
    sbit duan=P2^6;
    sbit wela=P2^7;
    unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                            0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
    //变量定义
    
    void delayms(int ms)//这个软件大约可以等待ms毫秒
    {
    	  int i,k;
    	  for(k=0; k<ms;k++)	{   for(i=0;i<50;i++);  }
    }
    
    
    /*---------------------------------------------------------------
    查询是否有键按下,有键按下返回键值,无键按下则返回0xff
    ---------------------------------------------------------------*/
    byte keysearch(void)
    {
    	byte k;
     	KEYPORT=0xf0;
     	k=KEYPORT;
     	KEYPORT=0x0f;
     	k=KEYPORT|k;
     	scanok=1;return k;
    }
    void HEX_TO_BCD(int num)
    {	dispbuf[5]  = num%1000000/100000;
        dispbuf[4]  = num%100000/10000;
        dispbuf[3]  = num%10000/1000;
        dispbuf[2]  = num%1000/100;
        dispbuf[1]  = num%100/10;
        dispbuf[0]  = num%10;
    }
    /*---------------------------------------------------------------
    显示子程序
    轮流导通各位数码管,再送出字段码
    延时显示一段时间后再继续导通下一位
    ---------------------------------------------------------------*/
    void scandisp(void)       
    {
    	byte posi=0x1f,i,temp;
    	//posi,为position的缩写,指显示哪一个8字
    	for(i=0;i<6;i++)
     	{
        	temp= dispbuf[i];         //显示缓存区数据查表
        	temp= table[temp];
        	if(i==2&&dot)temp|=0x80;  //i是小数点位置,变量dot=1,点亮小数点
        	P0 = 0;	     duan=1;   duan=0;//先关闭数码管,再切换
        	P0 = posi;   wela=1;   wela=0;  	
        	P0 = temp;   duan=1;   duan=0;
        	delayms(5);//延时 
        	posi>>=1;  posi|=0x20;    //循环右移
     	}
    }
    
    /*---------------------------------------------------------------
    移位显示子程序
    把显示数组中的最低3位赋给高3位,使最新输入的键盘值赋给数组的最低位
    输入:键值
    返回:无
    ---------------------------------------------------------------*/
    void digitin(byte val)               
    { 
    	dispbuf [3]= dispbuf [2];
     	dispbuf [2]= dispbuf [1];
    	dispbuf [1]= dispbuf [0];
     	dispbuf [0]= val;
    }
    
    /*---------------------------------------------------------------
    扫描得到的键值和实际需要的键盘任务的转换函数
    也叫键盘码散转程序
    输入:键值,有0x00~0xff钟可能性,根据显示的键值可以修改此函数
    返回:无
    ---------------------------------------------------------------*/
    void keybranch(byte k)          
    {	if(scanok)
       {scanok=0;
    	switch(k)
     	{
     	    case 0x00:break;
         	case 0xee:keynum=1;break;
         	case 0xde:keynum=2;break;
         	case 0xbe:keynum=3;break;
         	case 0xed:keynum=4;break;
         	case 0xdd:keynum=5;break;
        	case 0xbd:keynum=6;break;
         	case 0xeb:keynum=7;break;
         	case 0xdb:keynum=8;break;
         	case 0xbb:keynum=9;break;
         	case 0xd7:keynum=0;break;
    		case 0x7e:keynum=10;break;//加法
    		case 0x7d:keynum=11;break;//减法
    		case 0x7b:keynum=12;break;//乘法
    		case 0x77:keynum=13;break;//除法
    		case 0xb7:keynum=14;break;//等于
    		case 0xe7:keynum=15;break;//清零
         	default:break;
     	 } checkok=1;
    } }
    /*---------------------------------------------------------------
    处理程序,键值为15时或者清除标志为1时,数据清零
    ---------------------------------------------------------------*/
    void datchuli(void)
    {if(keynum==15)
      {
       dat=0;  datA=0;
       HEX_TO_BCD(dat);
      }
    else if(clrflag)                    //清除标志为1,则执行以下。
      {        
       dat=0;
       clrflag=0;                 //为下次使用准备。
       HEX_TO_BCD(dat);
      }
      if(keynum<10)
      {
      digitin(keynum);
      dat=dat*10+keynum;
      }
    }
    
    void add(void)
    {
       addflag++;                          //加法标志置1。。。
       subflag=mulflag=divflag=0;          //将其它运算标志清零。。(一次只能作一种运算)
       clrflag=1;                          //清零标标置1,(当按下加号后,再按第二个加数时,这时应该显示第二加数。。所以要清掉第一个加数。)
       if(addflag>1)
       {
       dat=datA+dat;
       datA=dat;
       }
       datA=dat;
    }
    void sub(void)						   //减法
    { subflag++;
      addflag=mulflag=divflag=0;
      clrflag=1;
      if(subflag>1)
      {
      dat=datA-dat;
      datA=dat;
      }
      datA=dat;
    }
    void mul(void)							//chengfa
    { mulflag++;
      addflag=subflag=divflag=0;
      clrflag=1;
      if(mulflag>1)
      {
      dat=dat*datA;
      datA=dat;
      }
      datA=dat;
    }
    void div(void)							//chufa
    { divflag++;
      addflag=subflag=mulflag=0;
      clrflag=1;
      if(divflag>1)
      {
      dat=datA/dat;
      datA=dat;
      }
      datA=dat;
    }
    void equ(void)
    {
     
       if(addflag)                           //如果些时做加法运算。。
       {
       dat=dat+datA;                     //计算各存入dat(显示程序会将dat显示的。。)
       }
       if(subflag)
       {
       dat=datA-dat;
       }
       if(mulflag)
       {
       dat=datA*dat;
       }
       if(divflag)
       {
       dat=datA/dat;
       }
       addflag=subflag=mulflag=divflag=0;//运算一次完成后将所有运标志清零。为下次运算作准备。。
       HEX_TO_BCD(dat);	clrflag=1;
    }
    void calculate_handle(void)//计算函数。。
    {	
     if(checkok)//如果检测键值完。则执行以下。
     {
      checkok=0;//检测完标志清零..
      switch (keynum)//如果是+,-,*,/,=则进入相应的函数。。
      {
       case 10 : {add();HEX_TO_BCD(dat);} break;    //如果是按了"+",则进入加法函数。
       case 11 : {sub();HEX_TO_BCD(dat);} break;    //如果是按了"-",则进入减法函数。
       case 12 : {mul();HEX_TO_BCD(dat);} break;    //如果是按了"*",则进入乘法函数。
       case 13 : {div();HEX_TO_BCD(dat);} break;    //如果是按了"/",则进入除法函数。
       case 14 : equ(); break;    //如果是按了"=",则进入等于函数。
       default : datchuli();       //如果不是,计算符(即为数字),则进入数据处理函数。
      }
    
     }}
    /*---------------------------------------------------------------
    主函数:将4X4键盘的键值显示在数码管上
    ---------------------------------------------------------------*/
    void main(void)
    {
    	byte k;
    	while(1)
     	{
     		k=keysearch();
    		
    		if(k!=0xff)   
        {
        	delayms(10);//有键按下
        	k=keysearch();
    		keybranch(k);
      		do
    		{
      			k=keysearch();
    			scandisp();
      		} while(k!=0xff);      //等待键释放
         }
    	 calculate_handle();
    	 scandisp();
      }
    }
    
    

    设计体会

    一开始只是会矩阵键盘和LCD扫描显示,所以当时是想做一个计算器应该还是挺容易的,但直到真正开始做的时候,才发现并不简单。一开始,想的就是,把运算键前输入的数值存到一个变量,后面的数值存到另一个变量内,然后再运算。但问题就来了,如何让单片机知道两次输入的数值要存到不同的变量去?如何把这些变量分别显示到显示管上?然后就要引入更多的变量、设计更多的函数。做出来的第一个版本,能实现加减乘除了,但还有一些问题。按下运算符时,数码管就会直接清零,不像真正计算器那样,按下运算符数码管上数值先不变,等下一数值输入时才变。还有不能实现连续运算的问题,最后还是修改好了。总的来说,这次设计的过程是很有挑战的,尤其对于我这种不善于编程的人来讲,遇到的问题,虽说比较麻烦,但还是车到山前必有路

    展开全文
  • 运用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单片机制作计算器的源代码@TOC

    /* S16 S12 S8 S4分别是123+
    S15 S11 S7 S3分别是456-
    S14 S10 S6 S2分别是789*
    S13 S9 S5 S1分别是0 CLR = /
    */

    /* 实现两个数的运算,每个数的位数至少可以八位 */
    #include<reg52.h>
    typedef unsigned char uint8;
    typedef unsigned int uint16;

    sbit rw=P2^5;
    sbit rs=P2^6;
    sbit e=P2^7;
    sbit led=P3^7;

    sbit beep=P2^0;
    uint8 key,num;
    uint8 fuhao;//定义具体的那个符号,是加减还是乘除。
    uint8 flag; //定义有没有按下符号键,这个是统称
    long a,b,c,d; //定义运算数据的第一个和第二个及等于的数变量
    uint8 k; //定义小数点后面显示的位数
    uint8 biao;

    uint8 dat1[]={1,2,3,0x2b-0x30, 4,5,6,0x2d-0x30, 7,8,9,0x2a-0x30, 0,0x01-0x30,0x3d-0x30,0x2b-0x30 };//保存显示的数据

    void delay(uint16 i)
    {
    while(i–);
    }
    void lcdwrc(uint8 c)
    {
    delay(1000);
    rs=0;
    rw=0;
    e=0;
    P0=c;
    e=1;
    delay(1000);
    e=0;
    }
    void lcdwrd(uint8 dat)
    {
    delay(1000);
    rs=1;
    rw=0;
    e=0;
    P0=dat;
    e=1;
    delay(1000);
    e=0;
    rs=0;
    }

    void lcdinit()
    {
    delay(1500);
    lcdwrc(0x38);
    delay(500);
    lcdwrc(0x38);
    delay(500);
    lcdwrc(0x38);
    delay(500);
    lcdwrc(0x38);
    lcdwrc(0x08);
    lcdwrc(0x01);
    lcdwrc(0x06);
    lcdwrc(0x0c);
    key=0;
    num=0;
    flag=0;
    fuhao=0;
    a=0;
    b=0;
    c=0;
    d=0;
    biao=0;
    led=0;

    }

    void keyscan()
    {
    P1=0xfe; //令第一行为0,然后判断是哪一列按下
    if(P1!=0xfe)
    {
    delay(1000);
    if(P1!=0xfe)
    {
    key=P1&0xf0;
    switch(key)
    {
    case 0xe0: num=0;break; //1
    case 0xd0: num=1;break; //2
    case 0xb0: num=2;break; //3
    case 0x70: num=3;break; //加
    }
    }
    while(P1!=0xfe);
    if(num0||num1||num2) //确认第一行的数1,2,3
    {
    if(flag
    0) //没有按下符号键
    {
    //led=1;
    a=a10+dat1[num];
    }
    else
    {
    //led=1;
    b=b
    10+dat1[num];
    }

    	}
    	if(num==3)
    	{
    		//led=0;
    		flag=1;
    		fuhao=1;//加号+	
    	}
    	lcdwrd(0x30+dat1[num]);
    }
    
    
    P1=0xfd;				//令第二行为0,判断是哪一列按下
    if(P1!=0xfd)
    {
    	delay(1000);
    	if(P1!=0xfd)
    	{
    		key=P1&0xf0;
    		switch(key)
    		{
    			case 0xe0: num=4;break;	  //4
    			case 0xd0: num=5;break;	  //5
    			case 0xb0: num=6;break;	  //6
    			case 0x70: num=7;break;	  //减—
    		}	
    	}
    	while(P1!=0xfd);
    	if(num==4||num==5||num==6)
    	{
    		if(flag==0)	 //没有按下符号键
    		{
    			//led=1;
    			a=a*10+dat1[num];	
    		}
    		else
    		{
    			//led=1;
    			b=b*10+dat1[num];
    		}			
    	}
    	else
    	{
    		flag=1;
    		fuhao=2;//带表减号
    	}
    	lcdwrd(0x30+dat1[num]);
    }
    
    
    P1=0xfb;		 //令第三行为0,判断哪一列按下
    if(P1!=0xfb)
    {
    	delay(1000);
    	if(P1!=0xfb)
    	{
    		key=P1&0xf0;
    		switch(key)
    		{
    			case 0xe0: num=8;break;	  //7
    			case 0xd0: num=9;break;	  //8
    			case 0xb0: num=10;break;  //9
    			case 0x70: num=11;break;  //乘*
    		}	
    	}
    	while(P1!=0xfb);
    	if(num==8||num==9||num==10)
    	{
    		if(flag==0)	 //没有按下符号键
    		{
    			//led=1;
    			a=a*10+dat1[num];	
    		}
    		else
    		{
    			//led=1;
    			b=b*10+dat1[num];
    		}			
    	}
    	else
    	{
    		flag=1;
    		fuhao=3;//带表乘号*
    	}
    	lcdwrd(0x30+dat1[num]);
    }
    
    
    P1=0xf7;		 //令第四行为0,判断哪一列按下
    if(P1!=0xf7)
    {
    	delay(1000);
    	if(P1!=0xf7)
    	{
    		key=P1&0xf0;
    		switch(key)
    		{
    			case 0xe0: num=12;break;  //0
    			case 0xd0: num=13;break;  //清除rst
    			case 0xb0: num=14;break;  //等号=
    			case 0x70: num=15;break;  //除/
    		}	
    	}
    	while(P1!=0xf7);
    	switch(num)
    	{
    		case 12: 
    				if(flag==0)	 //没有按下符号键
    				{
    					//led=1;
    					a=a*10+dat1[num];
    					lcdwrd(0x30);	
    				}
    				else
    				{
    					//led=1;
    					b=b*10+dat1[num];
    					lcdwrd(0x30);
    				}
    				break;
    		
    		case 13: 
    				lcdwrc(0x01);	//清屏指令			
    				a=0;
    				b=0;
    				flag=0;
    				fuhao=0;
    				break;
    
    		case 15:
    		
    				flag=1;
    				fuhao=4;
    				lcdwrd(0x2f);//除号/
    				break;
    				
    		case 14: 
    				if(fuhao==1)//加
    				{
    					lcdwrc(0x4f+0x80);
    					lcdwrc(0x04);//设置光标左移,屏幕不移动
    					c=a+b;
    					while(c!=0)	 //一位一位显示
    					{
    						lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
    						c=c/10;//取前面的结果数据	
    					}
    					lcdwrd(0x3d); //显示等于号=
    					a=0;
    					b=0;
    					flag=0;
    					fuhao=0;//全部清除为0
    				}
    				if(fuhao==2)   //减
    				{
    					lcdwrc(0x4f+0x80);
    					lcdwrc(0x04);//设置光标左移,屏幕不移动
    					if(a>b)
    						c=a-b;
    					else
    						c=b-a;
    					
    					while(c!=0)	 //一位一位显示
    					{
    						lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
    						c=c/10;//取前面的结果数据	
    					}
    					if(a<b)	lcdwrd(0x2d); //显示-号
    					lcdwrd(0x3d); //显示等于号=
    					a=0;
    					b=0;
    					flag=0;
    					fuhao=0;//全部清除为0
    				}
    				if(fuhao==3)//乘法		
    				{
    					lcdwrc(0x4f+0x80);
    					lcdwrc(0x04);//设置光标左移,屏幕不移动
    					c=a*b;
    					while(c!=0)	 //一位一位显示
    					{
    						lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
    						c=c/10;//取前面的结果数据	
    					}
    					lcdwrd(0x3d); //显示等于号=
    					a=0;
    					b=0;
    					flag=0;
    					fuhao=0;//全部清除为0	
    				}
    				if(fuhao==3)//乘法		
    				{
    					lcdwrc(0x4f+0x80);
    					lcdwrc(0x04);//设置光标左移,屏幕不移动
    					c=a*b;
    					while(c!=0)	 //一位一位显示
    					{
    						lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
    						c=c/10;//取前面的结果数据	
    					}
    					lcdwrd(0x3d); //显示等于号=
    					a=0;
    					b=0;
    					flag=0;
    					fuhao=0;//全部清除为0	
    				}
    				if(fuhao==4)
    				{
    					k=0;
    					lcdwrc(0x4f+0x80);
    					lcdwrc(0x04);//设置光标左移,屏幕不移动
    					c=(long)(((float)a/b)*1000);//强制转换为long。
    					while(c!=0)	 //一位一位显示
    					{
    						k++;
    						lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
    						c=c/10;//取前面的结果数据
    						if(k==3)
    						{
    							lcdwrd(0x2e);
    							k=0;
    						}		
    					}
    					if(a/b<0)	  //如果a比b小的话那么除的结果最高位是0
    					{
    						lcdwrd(0x30);	
    					}
    					lcdwrd(0x3d); //显示等号
    					a=0;
    					b=0;
    					flag=0;
    					fuhao=0;//全部清除为0
    				}
    				break;
    
    	}
    }
    

    }

    void main()
    {
    lcdinit();
    while(1)
    {
    keyscan();
    }
    }
    谢谢使用

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

    万次阅读 多人点赞 2019-01-08 21:17:44
    计算器是以MCS-51系列AT89C51单片机为核心构成的简易计算器系统。该系统通过单片机控制,实现对4*4键盘扫描进行实时的按键检测,并由LCD1602显示屏将过程与结果显示出来。 2.硬件原理图 硬件主要由四部分组成 ...

    1.简介
    本计算器是以MCS-51系列AT89C51单片机为核心构成的简易计算器系统。该系统通过单片机控制,实现对4*4键盘扫描进行实时的按键检测,并由LCD1602显示屏将过程与结果显示出来。
    2.硬件原理图
    在这里插入图片描述
    硬件主要由四部分组成

    • 单片机最小系统
    • 4*4矩阵键盘
    • LCD1602显示屏
    • 系统电源

    3.程序设计
    (1)矩阵键盘驱动程序

    /*------------------------------------------------
             矩阵键盘按键值
      			| 1 | 2 | 3 | + |  
      			| 4 | 5 | 6 | - |  
      			| 7 | 8 | 9 | * |  
      			| 0 | . | = | / | 
      #define KeyPort P1
    
    /*------------------------------------------------
    按键扫描函数,返回扫描键值
    ------------------------------------------------*/
    unsigned char KeyScan(void)  //键盘扫描函数,使用行列反转扫描法
    {
     unsigned char cord_h,cord_l;//行列值中间变量
     KeyPort=0x0f;            //行线输出全为0
     cord_h=KeyPort&0x0f;     //读入列线值
     if(cord_h!=0x0f)    //先检测有无按键按下
     {
      DelayMs(10);        //去抖
      if((KeyPort&0x0f)!=0x0f)
      {
        cord_h=KeyPort&0x0f;  //读入列线值
        KeyPort=cord_h|0xf0;  //输出当前列线值
        cord_l=KeyPort&0xf0;  //读入行线值
    
        while((KeyPort&0xf0)!=0xf0);//等待松开并输出
    
        return(cord_h+cord_l);//键盘最后组合码值
       }
      }return(0xff);     //返回该值
    }
    /*------------------------------------------------
              按键值处理函数,返回扫键值
               可以根据需要改变返回值
    ------------------------------------------------*/
    unsigned char KeyPro(void)
    {
     switch(KeyScan())
     {
      case 0x7e:return '1';break;//0 按下相应的键显示相对应的码值
      case 0x7d:return '2';break;//1
      case 0x7b:return '3';break;//2
      case 0x77:return '+';break;//3
    
      case 0xbe:return '4';break;//4
      case 0xbd:return '5';break;//5
      case 0xbb:return '6';break;//6
      case 0xb7:return '-';break;//7
    
      case 0xde:return '7';break;//8
      case 0xdd:return '8';break;//9
      case 0xdb:return '9';break;//a
      case 0xd7:return 'x';break;//b
    
      case 0xee:return '0';break;//c
      case 0xed:return '.';break;//d
      case 0xeb:return '=';break;//e
      case 0xe7:return '/';break;//f
      default:return 0xff;break;
     }
    }
    

    (2)LCD1602驱动程序

    #define CHECK_BUSY
    
    sbit RS = P2^4;   //定义端口 
    sbit RW = P2^5;
    sbit EN = P2^6;
    
    #define RS_CLR RS=0 
    #define RS_SET RS=1
    
    #define RW_CLR RW=0 
    #define RW_SET RW=1 
    
    #define EN_CLR EN=0
    #define EN_SET EN=1
    
    #define DataPort P0
    
    /*------------------------------------------------
                  判忙函数
    ------------------------------------------------*/
     bit LCD_Check_Busy(void) 
     { 
    #ifdef CHECK_BUSY
     DataPort= 0xFF; 
     RS_CLR; 
     RW_SET; 
     EN_CLR; 
     _nop_(); 
     EN_SET;
     return (bit)(DataPort & 0x80);
    #else
     return 0;
    #endif
     }
    /*------------------------------------------------
                  写入命令函数
    ------------------------------------------------*/
     void LCD_Write_Com(unsigned char com) 
     {  
     while(LCD_Check_Busy()); //忙则等待
     RS_CLR; 
     RW_CLR; 
     EN_SET; 
     DataPort= com; 
     _nop_(); 
     EN_CLR;
     }
    /*------------------------------------------------
                  写入数据函数
    ------------------------------------------------*/
     void LCD_Write_Data(unsigned char Data) 
     { 
     while(LCD_Check_Busy()); //忙则等待
     RS_SET; 
     RW_CLR; 
     EN_SET; 
     DataPort= Data; 
     _nop_();
     EN_CLR;
     }
    
    /*------------------------------------------------
                    清屏函数
    ------------------------------------------------*/
     void LCD_Clear(void) 
     { 
     LCD_Write_Com(0x01); 
     DelayMs(5);
     }
    /*------------------------------------------------
                  写入字符串函数
    ------------------------------------------------*/
     void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s) 
     {     
           
     while (*s) 
     	{     
     LCD_Write_Char(x,y,*s);     
     s ++;  x++;   
     	}
     }
    /*------------------------------------------------
                  写入字符函数
    ------------------------------------------------*/
    void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data) 
     {     
     if (y == 0) 
     	{     
     	LCD_Write_Com(0x80 + x);     
     	}    
     else 
     	{     
     	LCD_Write_Com(0xC0 + x);     
     	}        
     LCD_Write_Data( Data);  
     }
    /*------------------------------------------------
                  初始化函数
    ------------------------------------------------*/
    void LCD_Init(void) 
    {
    	 LCD_Write_Com(0x38);    /*显示模式设置*/ 
    	 DelayMs(5); 
    	 LCD_Write_Com(0x38); 
    	 DelayMs(5); 
    	 LCD_Write_Com(0x38); 
    	 DelayMs(5); 
    	 LCD_Write_Com(0x38);  
    	 LCD_Write_Com(0x08);    /*显示关闭*/ 
    	 LCD_Write_Com(0x01);    /*显示清屏*/ 
    	 LCD_Write_Com(0x06);    /*显示光标移动设置*/ 
    	 DelayMs(5); 
    	 LCD_Write_Com(0x0C);    /*显示开及光标设置*/
    } 
    

    (3)主函数

    /*------------------------------------------------
                        主程序
    ------------------------------------------------*/
    main()
    {
     unsigned char num,i,sign;                  
     unsigned char temp[16];        //最大输入16个
     bit firstflag;
     float a=0,b=0;
     unsigned char s;
    
     
     LCD_Init();         //初始化液晶屏
     DelayMs(10);        //延时用于稳定,可以去掉
     LCD_Clear();
     LCD_Write_String(0,0," LCD calculator");    //写入第一行信息,主循环中不再更改此信息,所以在while之前写入
     LCD_Write_String(0,1," Fun: + - x / ");    //写入第二行信息,提示输入密码
     while (1)         //主循环
     {
       num=KeyPro();  //扫描键盘
       if(num!=0xff)  //如果扫描是按键有效值则进行处理
       { 
          if(i==0)    //输入是第一个字符的时候需要把改行清空,方便观看
    	  LCD_Clear();
    	 if(('+'==num)|| (i==16) || ('-'==num) || ('x'==num)|| ('/'==num) || ('='==num))//输入数字最大值16,输入符号表示输入结束
    	  {
    	     i=0;  //计数器复位
    	     if(firstflag==0)  //如果是输入的第一个数据,赋值给a,并把标志位置1,到下一个数据输入时可以跳转赋值给b
    	     {
    	       sscanf(temp,"%f",&a);
               firstflag=1;
    		 }
    	     else  
    	       sscanf(temp,"%f",&b);
    	     for(s=0;s<16;s++) //赋值完成后把缓冲区清零,防止下次输入影响结果
    		    temp[s]=0;
             LCD_Write_Char(0,1,num); 
    	  ///
    	     if(num!='=')      //判断当前符号位并做相应处理
    	       sign=num;      //如果不是等号记下标志位
    	     else
    	     {  
    		    firstflag=0;   //检测到输入=号,判断上次读入的符合
                switch(sign)
    	       {
    		     case '+':a=a+b;
    			 break;
    			 case '-':a=a-b;
    			 break;
    			 case 'x':a=a*b;
    			 break;
    			 case '/':a=a/b;
    			 break;
    			 default:break;
    		   }
    		   sprintf(temp,"%g",a);    //输出浮点型,无用的0不输出
               LCD_Write_String(1,1,temp);//显示到液晶屏
    		   sign=0;a=b=0;            //用完后所有数据清零
    		   for(s=0;s<16;s++)
    		      temp[s]=0;
    		 }
    	  }
         else	if(i<16)
    	 {
    	    if((1==i)&& (temp[0]=='0') )//如果第一个字符是0,判读第二个字符
    	    {
    		  if(num=='.')  //如果是小数点则正常输入,光标位置加1
    		  {
    		    temp[1]='.';
    			LCD_Write_Char(1,0,num);//输出数据
    			i++;
              }           //这里没有判断连续按小数点,如0.0.0 
    		 else
    		 {
    		   temp[0]=num; //如果是1-9数字,说明0没有用,则直接替换第一位0
    		   LCD_Write_Char(0,0,num);//输出数据
    		 }
    	   }
    	   else
    	   {
             temp[i]=num; 
             LCD_Write_Char(i,0,num);//输出数据
    	     i++;   //输入数值累加
    	   }
    	 }
        }	
      }
    }
    

    源码+AD电路图 下载:关注公众号,首页回复“计算器”获取资料
    在这里插入图片描述

    展开全文
  • 基于51单片机的简易计算器制作

    万次阅读 2018-05-08 23:16:13
    基于51单片机的简易计算器制作 51单片机可以实现的功能很多,今天笔者介绍一种使用4*4矩阵键盘和八位共阴数码制作的简易计算器。数码管使用的是CL3641AH。原理图如下: S15 S11 S7 S3分别是4,5,6,- S14 S10 S6 ...

    基于51单片机的简易计算器制作

    51单片机可以实现的功能很多,今天笔者介绍一种使用4*4矩阵键盘和八位共阴数码制作的简易计算器。数码管使用的是CL3641AH。原理图如下:捕获

    捕获

    S15 S11 S7 S3分别是4,5,6,-
    S14 S10 S6 S2分别是7,8,9,*
    
    /*  S16 S12 S8 S4分别是1,2,3,+
    
    ​```
    S15 S11 S7 S3分别是4,5,6,-
    S14 S10 S6 S2分别是7,8,9,*
    S13 S9 S5 S1分别是0,CLR,=,/
    ​```
    
    */
    
    /* 可以实现两个数运算,每个数至多八位  */
    
    # include<reg52.h>
    
    typedef unsigned char uint8;
    typedef unsigned int uint16;
    
    sbit rw=P2^5;
    sbit rs=P2^6;
    sbit e=P2^7;
    sbit led=P3^7;
    
    sbit beep=P2^0;
    uint8 key,num;
    uint8 fuhao;//定义那个具体的符号是加减还是乘除
    uint8 flag; //定义有没有按下符号按键,这个是统称
    long a,b,c,d;   //定义运算数据的第一个和第二个及等于的数变量
    uint8 k; //定义小数点后面显示的位数
    uint8 biao;
    
    uint8 dat1[]={1,2,3,0x2b-0x30, 4,5,6,0x2d-0x30, 7,8,9,0x2a-0x30, 0,0x01-0x30,0x3d-0x30,0x2b-0x30 };//保存显示的数据
    
    void delay(uint16 i)
    {
    
    ​```
    while(i--);
    ​```
    
    }
    void lcdwrc(uint8 c)
    {
    
    ​```
    delay(1000);
    rs=0;
    rw=0;
    e=0;
    P0=c;
    e=1;
    delay(1000);
    e=0;
    ​```
    
    }
    void lcdwrd(uint8 dat)
    {
    
    ​```
    delay(1000);
    rs=1;
    rw=0;
    e=0;
    P0=dat;
    e=1;
    delay(1000);
    e=0;
    rs=0;
    ​```
    
    }
    
    void lcdinit()
    {
    
    ​```
    delay(1500);
    lcdwrc(0x38);
    delay(500);
    lcdwrc(0x38);
    delay(500);
    lcdwrc(0x38);
    delay(500);
    lcdwrc(0x38);
    lcdwrc(0x08);
    lcdwrc(0x01);
    lcdwrc(0x06);
    lcdwrc(0x0c);
    key=0;
    num=0;
    flag=0;
    fuhao=0;
    a=0;
    b=0;
    c=0;
    d=0;
    biao=0;
    led=0;
    ​```
    
    }
    
    void keyscan()
    {
    
    ​```
    P1=0xfe;   //定义第一行为零,然后判断哪一列按下
    if(P1!=0xfe)
    {
        delay(1000);
        if(P1!=0xfe)
        {
            key=P1&0xf0;
            switch(key)
            {
                case 0xe0: num=0;break;   //1
                case 0xd0: num=1;break;   //2
                case 0xb0: num=2;break;   //3
                case 0x70: num=3;break;   //¼Ó
            }
        }
        while(P1!=0xfe);
        if(num==0||num==1||num==2)   //确认第一行的数1,2,3
        {
            if(flag==0)  //没有按下符号建
            {
                //led=1;
                a=a*10+dat1[num];   
            }
            else
            {
                //led=1;
                b=b*10+dat1[num];
            }
    
        }
        if(num==3)
        {
            //led=0;
            flag=1;
            fuhao=1;//加号
        }
        lcdwrd(0x30+dat1[num]);
    }
    ​```
    
    ​```
    P1=0xfd;                //令第二行为零,然后判断第几行按下
    if(P1!=0xfd)
    {
        delay(1000);
        if(P1!=0xfd)
        {
            key=P1&0xf0;
            switch(key)
            {
                case 0xe0: num=4;break;   //4
                case 0xd0: num=5;break;   //5
                case 0xb0: num=6;break;   //6
                case 0x70: num=7;break;   //减-
            }   
        }
        while(P1!=0xfd);
        if(num==4||num==5||num==6)
        {
            if(flag==0)  //没有按下符号建
            {
                //led=1;
                a=a*10+dat1[num];   
            }
            else
            {
                //led=1;
                b=b*10+dat1[num];
            }           
        }
        else
        {
            flag=1;
            fuhao=2;//´代表减号
        }
        lcdwrd(0x30+dat1[num]);
    }
    ​```
    
    ​```
    P1=0xfb;         //令第三行为零,然后判断第几列按下
    if(P1!=0xfb)
    {
        delay(1000);
        if(P1!=0xfb)
        {
            key=P1&0xf0;
            switch(key)
            {
                case 0xe0: num=8;break;   //7
                case 0xd0: num=9;break;   //8
                case 0xb0: num=10;break;  //9
                case 0x70: num=11;break;  //乘*
            }   
        }
        while(P1!=0xfb);
        if(num==8||num==9||num==10)
        {
            if(flag==0)  //没有按下符号键
            {
                //led=1;
                a=a*10+dat1[num];   
            }
            else
            {
                //led=1;
                b=b*10+dat1[num];
            }           
        }
        else
        {
            flag=1;
            fuhao=3;//代表乘号
        }
        lcdwrd(0x30+dat1[num]);
    }
    ​```
    
    ​```
    P1=0xf7;         //另第四行为零,然后判断第几列按下
    if(P1!=0xf7)
    {
        delay(1000);
        if(P1!=0xf7)
        {
            key=P1&0xf0;
            switch(key)
            {
                case 0xe0: num=12;break;  //0
                case 0xd0: num=13;break;  //清楚rst
                case 0xb0: num=14;break;  //等号=
                case 0x70: num=15;break;  //除/
            }   
        }
        while(P1!=0xf7);
        switch(num)
        {
            case 12: 
                    if(flag==0)  //没有按下符号键
                    {
                        //led=1;
                        a=a*10+dat1[num];
                        lcdwrd(0x30);   
                    }
                    else
                    {
                        //led=1;
                        b=b*10+dat1[num];
                        lcdwrd(0x30);
                    }
                    break;
    
            case 13: 
                    lcdwrc(0x01);   //清屏指令      
                    a=0;
                    b=0;
                    flag=0;
                    fuhao=0;
                    break;
    
            case 15:
    
                    flag=1;
                    fuhao=4;
                    lcdwrd(0x2f);//除号/
                    break;
    
            case 14: 
                    if(fuhao==1)//加
                    {
                        lcdwrc(0x4f+0x80);
                        lcdwrc(0x04);//设置光标左移¯,屏幕不移动
                        c=a+b;
                        while(c!=0)  //一位一位显示
                        {
                            lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
                            c=c/10;//取前面的结果数据   
                        }
                        lcdwrd(0x3d); //显示等于号=
                        a=0;
                        b=0;
                        flag=0;
                        fuhao=0;//全部清除为零
                    }
                    if(fuhao==2)   //减
                    {
                        lcdwrc(0x4f+0x80);
                        lcdwrc(0x04);//设置光标左移,屏幕不移动
                        if(a>b)
                            c=a-b;
                        else
                            c=b-a;
    
                        while(c!=0)  //一位一位的显示
                        {
                            lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
                            c=c/10;//取前面的结果数据   
                        }
                        if(a<b) lcdwrd(0x2d); //显示减号-
                        lcdwrd(0x3d); //显示等号=
                        a=0;
                        b=0;
                        flag=0;
                        fuhao=0;//全部清除为零
                    }
    
                    if(fuhao==3)//乘法        
                    {
                        lcdwrc(0x4f+0x80);
                        lcdwrc(0x04);//设置光标左移,屏幕不移动
                        c=a*b;
                        while(c!=0)  //一位一位的显示
                        {
                            lcdwrd(0x30+c%10);//显示结果的位置在0x4f的位置
                            c=c/10;//取前面的结果数据   
                        }
                        lcdwrd(0x3d); //显示等于号=
                        a=0;
                        b=0;
                        flag=0;
                        fuhao=0;//全部清除为零    
                    }
                    if(fuhao==4)
                    {
                        k=0;
                        lcdwrc(0x4f+0x80);
                        lcdwrc(0x04);//设置光标左移,屏幕不移动
                        c=(long)(((float)a/b)*1000);//强制转化为long
                        while(c!=0)  //一位一位的显示
                        {
                            k++;
                            lcdwrd(0x30+c%10);//显示接轨的最后一位在0x4f的位置
                            c=c/10;//取前面的结果数据
                            if(k==3)
                            {
                                lcdwrd(0x2e);
                                k=0;
                            }       
                        }
                        if(a/b<0)     //如果a比b小的话那么除的结果最高位是零
                        {
                            lcdwrd(0x30);   
                        }
                        lcdwrd(0x3d); //显示等号
                        a=0;
                        b=0;
                        flag=0;
                        fuhao=0;//全部清除为零
                    }
                    break;
    
        }
    }
    ​```
    
    }
    
    
    
    void main()
    {
    
    ​```
    lcdinit();
    while(1)
    {
        keyscan();  
    }
    ​```
    
    }
    
    展开全文
  • 基于51单片机的科学计算器

    千次阅读 2018-11-25 21:35:49
    科学计算器1.任务 设计制作一个科学计算器。 2. 要求 (1)按数字 0-9 时应发出蜂鸣器声音,数越大,频率越高。 (20 分) (2) 完成任意两位数(范围 0-99)的加减乘除运算,结果只需显示整数部分,但如果结果...
  • 本程序实现了完整版计算器,包括加减乘除、带小数点显示、带小数点输入、此外还有带时钟功能。当然也可以实现函数功能,只是东西太多了,放不开了。。就没有加上。以后在上传吧.带仿真文件的,一定要用Proteus7.8...
  • 关注【电子开发圈】微信公众号,一起学习吧!...电子DIY、Arduino、51单片机、STM32单片机、FPGA…… 电子百科、开发技术、职业经验、趣味知识、科技头条、设备拆机…… 点击链接,免费下载100G+电子设计学习资料! ...
  • 本设计是基于51单片机科学型计算器。 能够实现的功能包括: (1) 四则运算(加、减、乘、除) (2) 带小数点数据的运算(小数点后面最多8位) (3) 有符号数据运算 (4) sin、cos、tan、log函数的运算(如果要实现...
  • 本设计介绍了单片机计算器领域的应用技术,以常用的MCS-51系列(本次选用8051)单片机为基础,简单介绍了单片机与键盘之间以及与显示器之间的应用技术。  本次设计中的键盘的识别是一个非常重要的部分,我们此次...
  • 51单片机计算器的编写及实现

    千次阅读 2017-12-25 08:44:25
    code:/* S16 S12 S8 S4分别是123+ S15 S11 S7 S3分别是456- S14 S10 S6 S2分别是789* S13 S9 S5 S1分别是0 CLR = / */ /* 实现两个数的运算,每个数的位数至少可以八位 */ #include typedef unsigned char ...
  • 在上一篇简绍了几个重要的部分,下面先说一下计算器程序的 大体思路 : /这个计算器没有等于键,按下加号或减号相当于等号。/ 初始化中断,设置三个变量先用AB表示,值全部为零。 进入输入数字子程序,等待数字输入...
  • LCD计算器设计 1.能实现加减乘除、幂次方、取根号等操作 2.数据结果能实现小数 3.使用LCD1602显示 4.个人代码还有bug 代码实现 #include"reg52.h" #include"math.h" /*********************************************...
  • 中国石油大学(北京) 课程设计报告 课程名: 硬件综合实践 姓 名 许恺 学 号 2014011329 班 级 计算机14-1班 设计时间 2018年1月5日 ...在51单片机上编写烧录十进制...
  • 51单片机开发,计算器加减乘除带小数点参考
  • /* S16 S12 S8 S4分别是123+ S15 S11 S7 S3分别是456- S14 S10 S6 S2分别是789* S13 S9 S5 S1分别是0 CLR = / */ /* 实现两个数的运算,每个数的位数至少可以八位 */ #include<reg52.h>...
  • /* S16 S12 S8 S4分别是123+ S15 S11 S7 S3分别是456- S14 S10 S6 S2分别是789* S13 S9 S5 S1分别是0 CE =/*//* 实现两个数的运算,每个数的位数至少可以八位 (在液晶显示屏上显示) */#include&...
  • 简易计算器案例

    2020-07-10 15:07:11
    计算器基本功能: 实现单击数字按钮 录入数字 实现单击功能按钮 进行对应的运算 实现基本的四则运算(加减乘除) 实现正负号功能 实现退位功能 实现清屏功能 注意点: 7. 录入框不能通过其他方式更改其数字 8. 四...
1 2 3 4 5
收藏数 93
精华内容 37
关键字:

单片机小数点计算器