找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5337|回复: 2
收起左侧

51单片机+LCD12864的简易计算器Proteus仿真源程序

  [复制链接]
ID:505058 发表于 2021-3-23 21:09 | 显示全部楼层 |阅读模式
之前看到网上利用51和12864做计算器的资源比较少,找了很久才找到了一个帖子是用12864做的计算器,于是下载下来后做了一定程度的改进,于是想分享出来让更多吧友看到,也欢迎各位留言评论,咱们一起学习,个人的思想还是很狭隘的,一个人想问题时思绪容易走进死胡同出不来,希望各位吧友指出不足和改进意见。附件是仿真和程序,用keil5写的,keil4可能打不开哦(反正我用keil4打不开的),仿真也是protues8.6做的,低版本也可能打不开。

仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
1.png

单片机源程序如下:
  1. #include<reg52.h>
  2. #include<array.h>
  3. #include<stdio.h>
  4. #include<string.h>
  5. #define uint unsigned int
  6. #define uchar unsigned char

  7. sbit E=P2^0;
  8. sbit RW=P2^1;
  9. sbit RS=P2^2;
  10. sbit CS2=P2^3;
  11. sbit CS1=P2^4;
  12. sbit RST=P2^5;
  13. sbit BEEP=P2^6;

  14. uchar  hang,lie;            //行,列
  15. float  dat1,dat2,count; //运算值
  16. uchar  keynum;                    //按键返回值(0~17)
  17. uchar  x;               //按键所对应的字符在字符表中的行号
  18. uchar  keyfun;                    //运算方式选择(1:*, 2:+, 3:-, 4:/)

  19. void delay(uchar i)            //延迟10*n微秒
  20. {
  21.         while(i--);
  22. }

  23. void delay_ms(uchar n) //延迟n毫秒
  24. {
  25.         uchar i,j;
  26.         for(i=n;n>0;n--)
  27.                 for(j=120;j>0;j--);
  28. }


  29. /********************************************************/
  30. /*********************检测工作状态***********************/
  31. //void checkbusy(void)
  32. //{
  33. //     unsigned int timeout = 0;
  34. //     E  = 0;
  35. //     RS = 0;
  36. //     RW = 1;
  37. //     E  = 1;
  38. //     while((P0 & 0x80)&& ++timeout != 0);//忙状态检测,等待超时时间为60ms
  39. //     E  = 0;
  40. //}


  41. /********************************************************/
  42. /************************写命令**************************/
  43. void write_cmd(uchar cmd)
  44. {
  45. //        checkbusy();
  46.         RS=0;
  47.         RW=0;
  48.         E=1;
  49.         P0=cmd;
  50.         delay(20);
  51.         E=0;
  52. }

  53. /****************************************************/
  54. /***********************写数据***********************/
  55. void write_dat(uchar dat)          
  56. {       
  57. //        checkbusy();               
  58.         RS=1;
  59.         RW=0;
  60.         E=1;
  61.         P0=dat;
  62.         delay(20);
  63.         E=0;
  64. }


  65. /****************************************************/
  66. /*********************设置页与列*********************/
  67. void set(uchar page,uchar col)
  68. {
  69.         page=page|0xb8;         //页的首地址为0xb8
  70.         col=col|0x40;         //列的首地址为0x40
  71.         write_cmd(col);
  72.         write_cmd(page);
  73. }

  74. /****************************************************/
  75. /*******************选择左、右屏*********************/
  76. void Select_Screen(uchar swich)
  77. {
  78.          switch(swich)
  79.          {
  80.           case 0:CS1=CS2=0;break;          //全屏
  81.           case 1:CS1=0;CS2=1;break;          //左屏
  82.           case 2:CS1=1;CS2=0;break;          //右屏
  83.           default:break;
  84.          }
  85. }

  86. /***************************************************/
  87. /********************LCD初始化**********************/
  88. void Lcd_Init()
  89. {
  90.         uchar i,j,k=0;
  91.         RST=0;
  92.         delay(10);
  93.         RST=1;
  94.         write_cmd(0xc0);//设置显示起始行11xxxxxx
  95.         write_cmd(0x3f);//0x3f显示开,0x3e显示关
  96.         Select_Screen(0);
  97.         set(0,0);
  98.         for(i=0;i<8;i++)
  99.         {
  100.             for(j=0;j<64;j++)
  101.                         write_dat(0x00);
  102.                         k++;
  103.                         set(k,0);
  104.         }
  105.     lie=2;hang=3;keyfun=0;
  106.         dat1=0.0,dat2=0.0,count=0.0;
  107. }

  108. /*****************************************************/
  109. /********************计算窗口清空*********************/
  110. void Clear_jisuan()
  111. {
  112.          uchar i,j;
  113.         Select_Screen(0);
  114.         for(i=3;i<6;i++)                //从第三页开始写入数据0x00,清空计算窗口
  115.         {
  116.             for(j=0;j<64;j++)
  117.                 {
  118.                         set(i,j);
  119.                         write_dat(0x00);
  120.                 }
  121.         }
  122.         lie=2;hang=3;keyfun=0;
  123.         dat1=0.0,dat2=0.0,count=0.0;
  124. }


  125. /**************************************************/
  126. /********************显示字符**********************/
  127. void Display_zifu(uchar n)
  128. {         
  129.         uchar i;                                         //列数小于64时
  130.         if(lie<64)
  131.         {
  132.            Select_Screen(1);                 //开左屏
  133.            set(hang,lie);                         //设置行,列
  134.            for(i=0;i<6;i++)
  135.            write_dat(zifu[n++]);         //写入数据
  136.              lie=lie+7;                                 //每输出一个字符列数加6
  137.            if(hang>7)                                 //行数大于7时回到初始值
  138.               hang=3;
  139.         }
  140.         else                                                 //列数大于64时
  141.         {
  142.           Select_Screen(2);
  143.           set(hang,lie-64);
  144.           for(i=0;i<6;i++)
  145.                 write_dat(zifu[n++]);
  146.           lie=lie+7;
  147.         if(lie>123)
  148.         {  
  149.            lie=0;hang++;
  150.            Select_Screen(1);
  151.         }
  152.            if(hang>7)
  153.            hang=3;
  154.         }
  155. }

  156. /******************************************************/
  157. /***********将运算结果转化为字符串而后显示*************/
  158. void Display_string(uchar page,uchar col,float num)
  159. {
  160.            uchar str[20];
  161.          uchar tmp[16],i,j,k,c;
  162.          int  len;
  163.          if((int)num==(int)(num+0.99999))//如果为整数
  164.          {
  165.           sprintf(str,"%d",(int)num);     //将结果转化为字符串
  166.           len=sprintf(str,"%d",(int)num); //sprintf函数的返回值为字符串的长度,不含'/0'
  167.      }
  168.          else                                                          //如果为小数
  169.          {
  170.           sprintf(str,"%.3f",num);                  //将结果转化为字符串
  171.           len=sprintf(str,"%.3f",num);  
  172.          }
  173.          
  174.          if(col>63)                                                  //列数大于63开右屏
  175.          {
  176.           Select_Screen(2);
  177.           col=col-64;
  178.          }
  179.          
  180.          for(i=0;i<len;i++)                        //将字符串逐个显示
  181.          {
  182.                  if(col<63)                                //列数小于63开左屏
  183.                 {Select_Screen(1);}
  184.                 c=(str[i]-42)*6;                //数组第一行*号的ASCII值为42,每个数组中的相应元素减去42得到其在数组中的行数
  185.                 for(j=0;j<10;j++)
  186.                 {tmp[j]=zifu[c];}                //将数组zifu相应字符的ASCII码输送给数组tmp

  187.                 set(page,col);
  188.                 for(k=0;k<6;k++)
  189.                 write_dat(zifu[c++]);        //写入数据
  190.                
  191.                 col=col+6;                                //每写一个字符列数加6,继续写入下一个字符
  192.                 delay(100);
  193.          }         
  194. }


  195. /*****************************************************/
  196. /***********************显示汉字**********************/
  197. void Display_Project(uchar screen,uchar page,uchar col,uchar n,uchar table[][32])
  198. {         
  199.          uchar i,temp[32];         
  200.          for(i=0;i<16;i++)                   //将table数组中的相应汉字的ascii码输送给数组temp
  201.          temp[i]=table[n][i];
  202.          for(i=16;i<32;i++)
  203.          temp[i]=table[n][i];       
  204.          
  205.          Select_Screen(screen);                           
  206.          set(page,col);         
  207.          for(i=0;i<16;i++)                   //写汉字的上半部分
  208.          write_dat(temp[i]);
  209.          
  210.          set(page+1,col);
  211.          for(i=0;i<16;i++)                   //写汉字的下半部分
  212.          write_dat(temp[i+16]);          
  213. }

  214. /***********************************************************/
  215. /******************** 响铃 *********************************/
  216. //void play()
  217. //{   
  218. //       
  219. //        BEEP=0;
  220. //        delay_ms(1000);
  221. //        BEEP=1;
  222. //
  223. //}



  224. /***********************************************************/
  225. /********************选择计算类型***************************/
  226. float calulate()
  227. {
  228.         switch(keyfun)
  229.         {
  230.                 case 1: count=dat2*dat1;dat1=count;break;
  231.                 case 2: count=dat2+dat1;dat1=count;break;       
  232.                 case 3: count=dat2-dat1;dat1=count;break;
  233.                 case 4: count=dat2/dat1;dat1=count;break;
  234.                 default:        break;
  235.         }
  236.         return(count);
  237. }

  238. /********************************************************/
  239. /***********************计算过程*************************/                                               
  240. void cal_process()
  241. {                          
  242.         uchar str_mul[10],len_mul;
  243.         if(x!=19)
  244.         {Display_zifu(x*6);}          
  245.         while((P3&0xf0)!=0xf0);        //按键按下有效,显示刷新
  246.        
  247.         switch(keynum)
  248.         {                               
  249.                 case 0:
  250.                 case 1:
  251.                 case 2:
  252.                 case 3:
  253.                 case 4:
  254.                 case 5:
  255.                 case 6:
  256.                 case 7:
  257.                 case 8:
  258.                 case 9:        dat1=dat1*10+keynum;break;  //例如:输入12,初始dat1=0;则dat1=0*10+1=1;dat1=1*10+2=12
  259. /* * */        case 10:calulate();dat2=dat1;dat1=0;keyfun=1;break;         
  260.                
  261. /* + */        case 11:calulate();dat2=dat1;dat1=0;keyfun=2;break;         
  262.                
  263. /* - */        case 12:calulate();dat2=dat1;dat1=0;keyfun=3;break;         
  264.                
  265. /* / */        case 13:calulate();dat2=dat1;dat1=0;keyfun=4;break;                                                     
  266.                
  267. /* = */        case 14:hang=5;lie=0;Display_zifu(19*6);                          
  268.                         switch(keyfun)
  269.                    {
  270.                         case 1: count=dat2*dat1;break;
  271.                         case 2: count=dat2+dat1;break;       
  272.                         case 3: count=dat2-dat1;break;
  273.                            case 4: count=dat2/dat1;break;
  274.                         default:break;
  275.                    }
  276.                            if(count<999999999)
  277.                            {
  278.                              if(keyfun==1)
  279.                              {
  280.                                 if((len_mul=sprintf(str_mul,"%d",count))<8)        //多位整数乘法若结果大于6则显示?
  281.                                            Display_string(5,6,count);
  282.                              }
  283.                                  else if(keyfun==4)
  284.                                  {
  285.                                      if(dat1!=0)                                       //除数为0则输出?
  286.                                          Display_string(5,6,count);
  287.                                  }
  288.                                  else
  289.                                  Display_string(5,6,count);
  290.                            }
  291.                           
  292.                            else Display_zifu(20*6);break;                          

  293.                 default: break;
  294.         }

  295. }

  296. /********************************************************/
  297. /*****************矩阵按键扫描(逐行扫描)*****************/
  298. void keyscan()
  299. {
  300.         uchar key;       
  301.         P3=0xfe;                                //令第一行为0,判断列
  302.         if(P3!=0Xfe)
  303.         {
  304.            delay(100);                        //消抖
  305.           if(P3!=0xfe)
  306.           {
  307.              key=P3&0xf0;
  308.                  switch(key)
  309.                  {
  310.                   case 0xe0:keynum=7; x=13;cal_process();break;  // 7
  311. ……………………

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

所有资料51hei提供下载:
计算器12864带字.rar (139.63 KB, 下载次数: 169)

评分

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

查看全部评分

回复

使用道具 举报

ID:1113217 发表于 2024-3-17 06:58 | 显示全部楼层
找了好久终于找到用12864屏幕的作者了,给作者点个赞
回复

使用道具 举报

ID:1113285 发表于 2024-3-25 16:39 | 显示全部楼层
这个屏幕我喜欢
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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