找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9999|回复: 9
打印 上一主题 下一主题
收起左侧

51单片机实现简单计算器C语言程序+Proteus仿真

  [复制链接]
跳转到指定楼层
楼主
我们在这里使用4*4的矩阵按键KEYPAD-SMALLCALC与1602液晶屏LMO16L在单片机上实现简单的计算器仿真实验。
首先我们定义一个字符数组存储按键对应的键值,使用程序查询的方法扫描矩阵按键;当结束输入时,我们就对字符串进行处理了并将结果显示在液晶屏上。
在程序中,适当的使用一些库函数可以大大提高我们的编程效率,在这里,我们主要对字符串进行操作,使用了stdlib.h、ctype.h库中的一些函数,如下:
atoi:将字符串转换成整数
atof:将字符串转换成浮点数
isalnum:测试是否为字母数字


单片机源程序如下:
  1. #include<reg51.h>
  2. #include<intrins.h>
  3. #include<ctype.h>
  4. #include<stdlib.h>
  5. #include<stdio.h>
  6. #include<math.h>
  7. #include<string.h>
  8. #define uchar unsigned char
  9. #define        uint unsigned int
  10. sbit LCDEN=P3^4;
  11. sbit RS=P3^5;
  12. sbit RW=P3^6;
  13. sbit BF=P0^7;
  14. sbit BEEP=P1^0;        
  15. uchar str[17];

  16. uchar code keyval[]="789/456*123-c0=+"; //按键对应的符号
  17. void delay(unsigned int xms)
  18. {
  19.         int i,j;
  20.         for(i=xms;i>0;i--)
  21.                 for(j=110;j>0;j--);
  22. }
  23. uchar keypad4_4()//按键扫描函数:要去抖,若有按键按下,返回对应的按键值(0-15),没有按键按下返回16
  24. {
  25.         uchar i,row,temp;
  26.         uchar key=16;//按键号,初值设置为16,目的是:没有按键按下时返回16;
  27.                   //若不设初值(默认值为0),没有按键按下时,将返回0,会误认为0被按下  
  28.         row=0xef; //从第一列开始      
  29.         for(i=0;i<4;i++)
  30.         {
  31.                 P2=0xff;  
  32.                 P2=row;        //第i列信号,对应列为低,其他全为高
  33.                 row=_crol_(row,1);           //生成下一列信号
  34.                 temp=P2; //读入扫描信号
  35.                 temp=temp&0x0f; //屏蔽高4位列信号,只保留低4位行信号
  36.                 if(temp!=0x0f)//有按键被按下,因为第i列某行有按键按下,则低4位中有一位为低  
  37.                  {  
  38.                         delay(20);  //延时去抖
  39.                         temp=P2;  
  40.                         temp=temp&0x0f;  
  41.                         if(temp!=0x0f)   //再次确认有按键被按下
  42.                           {  
  43.                         switch(temp)  //根据低4位行信号,判断哪个按键被按下
  44.                     {  
  45.                             case 0x0e:key=0+i;break; //第i列第1行按键被按下
  46.                         case 0x0d:key=4+i;break; //第i列第2行按键被按下  
  47.                         case 0x0b:key=8+i;break; //第i列第3行按键被按下
  48.                                         case 0x07:key=12+i;      //第i列第4行按键被按下
  49.                     }
  50.                                 
  51.                                 do
  52.                                 {
  53.                                         temp=P2;              //再次扫描按键
  54.                                           temp=temp&0x0f;  
  55.                                   }while(temp!=0x0f); //等待按键释放   
  56.                           }  
  57.              }
  58.         }  
  59.         return(key);//扫面结束,返回按键值
  60. }

  61. uchar RdACAdr()//读当前光标地址
  62. {   
  63.         uchar result;
  64.         P2 = 0xff;        //读地址前先置高电平,防止误判
  65.         RS = 0;
  66.         delay(5);
  67.     RW = 1;
  68.         LCDEN = 1;
  69.         delay(5);
  70.         result=P2&0x7f; //去掉最高位忙闲标记,只保留低7位地址值
  71.         LCDEN = 0;
  72.         return result;                     
  73. }

  74. uchar DectectBusyBit(void)//状态判断函数(忙/闲?)
  75. {   
  76.         bit result;
  77.         P0 = 0xff;        //读状态前先置高电平,防止误判
  78.         RS = 0;
  79.         delay(5);
  80.     RW = 1;
  81.         LCDEN = 1;
  82.         delay(5);
  83.         result=BF; //若LCM忙,则反复测试,在此处原地踏步;当LCM闲时,才往下继续
  84.         LCDEN = 0;
  85.         return result;                     
  86. }

  87. void WrComLCD(unsigned char ComVal)//写命令函数
  88. {
  89.         while(DectectBusyBit()==1);         //先检测LCM是否空闲
  90.         RS = 0;
  91.         delay(1);
  92.     RW = 0;
  93.         LCDEN = 1;
  94.         P0 = ComVal;
  95.         delay(1);
  96.         LCDEN = 0;        
  97. }

  98. void WrDatLCD(uchar DatVal)//写数据函数
  99. {
  100.         while(DectectBusyBit()==1);
  101.         RS = 1;
  102.         delay(1);
  103.     RW = 0;
  104.         LCDEN = 1;
  105.         P0 = DatVal;
  106.         delay(1);
  107.         LCDEN = 0;        
  108. }
  109. void WrStrDat(uchar *p)//显示英文字符串(长度不超过32)
  110. {        
  111.         uchar i=0,t;
  112.    
  113.         while(p[i]!='\0')
  114.         {  
  115.                   WrDatLCD(p[i]);
  116.                 i++;
  117.                 delay(5);
  118.         
  119.                 t=RdACAdr();
  120.         if(t==0x10) WrComLCD(0xc0);//读当前坐标,如果第1行写完换行到第2行        
  121.                 if(t==0x50) WrComLCD(0x80);//读当前坐标,如果第2行写完换行到第1行        
  122.         }        
  123. }

  124. void LCD_Init(void)//1602初始化函数
  125. {
  126.         //delay(15);
  127.         WrComLCD(0x38);
  128.         //delay(5);     // 功能设定:16*2行、5*7点阵、8位数据接口
  129.         WrComLCD(0x38);
  130.         //delay(5);
  131.         WrComLCD(0x38);   
  132. //多次重复设定功能指令,因为LCD启动后并不知道使用的是4位数据接口还是8位的,所以开始时总是默认为4位,这样刚开始写入功能设定指令时,低4位被忽略,为了可靠,最好多写几遍该指令
  133.         WrComLCD(0x01);    // 清屏
  134.         WrComLCD(0x06);    // 光标自增、屏幕不动  
  135.         delay(1);              // 延时,等待上面的指令生效,下面再显示,防止出现乱码
  136.         WrComLCD(0x0C);    // 开显示、关光标
  137. }
  138. double str2num(uchar* str)
  139. {
  140.         uint i=0,j=0,index=0;
  141.         uchar ch[10];
  142.         long a1=atol(str),b1=0;
  143.         double a2=atof(str),b2=0,c=0;
  144.         for(i=0;str[i]!='\0';i++)
  145.         {
  146.                 if(!isalnum(str[i]))
  147.                 {
  148.                         index=i;
  149.                         break;
  150.                 }
  151.         }
  152.         for(j=0,i=index+1;i<=strlen(str);i++)
  153.                 ch[j++]=str[i];
  154.         b1=atol(ch);
  155.         b2=atof(ch);
  156.         switch(str[index])
  157.         {
  158.                 case '+':c=a1+b1;break;
  159.                 case '-':c=a1-b1;break;
  160.                 case '*':c=a2*b2;break;
  161.                 case '/':c=a2/b2;break;
  162.                 default:c=a2;break;
  163.         }
  164.         return c;
  165. }
  166. void main()
  167. {
  168.         
  169.         uchar i=0,j=0,y=16;
  170.         uchar flag=0;
  171.         uchar end=0;        
  172.         LCD_Init();
  173.         delay(5);   //延时,等待初始化完成
  174.         WrComLCD(0x80);           //设置显示地址第一行第一位:0X00(0x80+0x00)  
  175.         delay(1);
  176.            WrComLCD(0xc0);
  177.         delay(1);
  178.         WrDatLCD('0');
  179.         delay(1);
  180.         WrComLCD(0x80);
  181.         while(1)
  182.         {        
  183.                 y=keypad4_4();
  184.                                 
  185.                 if(y<16)
  186.                 {        
  187.                         if(y!=12)
  188.                         {
  189.                                 if(end==1)
  190.                                 {
  191.                                         end=0;
  192.                                         flag=0;
  193.                                         WrComLCD(0x01);         
  194.                                         delay(1);
  195.                                         WrComLCD(0xc0);
  196.                                         delay(1);
  197.                                         WrDatLCD('0');
  198.                                         delay(1);        
  199.                                         WrComLCD(0x80);        
  200.                                 }                  
  201.                                 str[strlen(str)]=keyval[y];
  202.                                 WrDatLCD(keyval[y]);
  203.                                 if(y==14)
  204.                                 {
  205.                                         uchar ch[17];
  206.                                         flag=1;
  207.                                         end=1;
  208.                                         str[strlen(str)]='\0';
  209.                                         WrComLCD(0xc0);
  210.                                                 
  211.                                         sprintf(ch,"%.2f",str2num(str));
  212.                                         WrStrDat(ch);
  213.                                         for(i=0;i<17;i++)
  214.                                                 str[i]='\0';
  215.                                 }
  216.                         }
  217.                         else
  218.                         {
  219. ……………………

  220. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
51简单计算器.zip (141.66 KB, 下载次数: 157)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:432453 发表于 2019-3-7 16:54 | 只看该作者
蜂鸣器没有作用,似乎缺失蜂鸣器功能部分的程序。
回复

使用道具 举报

板凳
ID:404722 发表于 2019-5-19 17:45 | 只看该作者
GameGhost96 发表于 2019-3-7 16:54
蜂鸣器没有作用,似乎缺失蜂鸣器功能部分的程序。

嗯,这里没有使用蜂鸣器
回复

使用道具 举报

地板
ID:663421 发表于 2019-12-13 18:00 | 只看该作者
学习一下,谢谢分享
回复

使用道具 举报

5#
ID:786505 发表于 2020-6-23 11:33 | 只看该作者
多谢,研究一下。
回复

使用道具 举报

6#
ID:786505 发表于 2020-6-23 11:36 | 只看该作者
多谢,研究一下。
回复

使用道具 举报

7#
ID:786505 发表于 2020-6-23 21:04 | 只看该作者
好用,多谢分享。
回复

使用道具 举报

8#
ID:789460 发表于 2020-6-25 16:09 | 只看该作者
下载打不开
回复

使用道具 举报

9#
ID:406255 发表于 2020-11-15 14:14 | 只看该作者
找了很久用于学习的程序,谢谢,但愿能下载,
回复

使用道具 举报

10#
ID:850392 发表于 2020-12-1 19:43 | 只看该作者
没有加入小数点的运算程序。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表