找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机行列式按键及计算器仿真及程序 显示错误 求帮助

[复制链接]
跳转到指定楼层
楼主
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)


行列式按键及计算器仿真及程序程序如下
  1. #include"at89x51.h"     //  C计时器参考
  2.                                                                                                                                                          
  3. unsigned int  da1=0, da2=0, resu=0;
  4. unsigned char fh=0, zhuangtai=0, key, keyzhi, jianzhi;
  5. unsigned char code  tv[]={0xfe,0xfd,0xfb,0xf7};        //位选数组
  6. unsigned char code  a[]={0x3f,0x06,0x5b,0x4f,
  7.                      0x66,0x6d,0x7d,0x07,0x7f,
  8.                      0x6f,0x77,0x7c,0x39,0x5e,
  9.                                  0x79,0x71,0x00};                 //显示是P0口的值对应的数组
  10. unsigned char data led[4] = {0, 16, 16, 16}; //将首位定义成零,在计算器的初始显示的时候右边有‘0’表示计算器已经开始工作

  11. //函数名:delay                        时间:
  12. //作用:在显示函数中延时
  13. //说明:延时的时间不用太长即i的峰值不要定太大
  14. //作者:ymx                                

  15. void delay()
  16. {
  17.         unsigned char i;
  18.         for (i=0; i<200; i++)
  19.         {
  20.                 ;
  21.         }
  22. }


  23. //函数名:keydeal                        时间:
  24. //作用:扫描键盘,通过低电位会将高电位拉成低电位的原理,分别判断出按键的横纵坐标并将jianzhi传递到jianhao函数
  25. //说明:传递0x0f判断纵坐标,传递0xf0判断横坐标
  26. //作者:ymx

  27. unsigned char keydeal()
  28. {
  29.         unsigned char x, y;
  30.         P3 = 0xff;
  31.         P3 = 0x0f;
  32.         x = P3;
  33.         P3 = 0xff;
  34.         P3 = 0xf0;
  35.         y = P3;
  36.         jianzhi = x + y;
  37.         return jianzhi;
  38. }

  39. //函数名:jisuan                        时间:
  40. //作用:根据记录的运算符号和两个数的值计算出结果
  41. //说明:
  42. //作者:ymx

  43.     jisuan(void)
  44. {
  45.         switch(fh)
  46.         {
  47.                 case '+':
  48.                         resu = da1+da2;
  49.                         break;
  50.                 case '-':
  51.                         resu = da1-da2;
  52.                         break;
  53.                 case '*':
  54.                         resu = da1*da2;
  55.                         break;
  56.                 case '/':
  57.                         resu = da1/da2;
  58.                         break;
  59.         }
  60.             fh=0;   //将符号清零
  61. }

  62. //函数名:jianhao                        时间:
  63. //作用:通过keydeal传递的数值判断按下的按键分别代表的意义,如数字,运算符号等。并根据按键和按下键盘前的状态来切换此时的状态
  64. //说明:                                                                                                                                                                  
  65. //作者:ymx

  66. void jianhao()
  67. {
  68.         key = keydeal();
  69.         switch(key)
  70.         {
  71.                   case 0xff: keyzhi=16; break; //什么键都没有按下
  72.               case 0xd7: keyzhi=0; break;
  73.                   case 0xeb: keyzhi=1; break;
  74.                   case 0xdb: keyzhi=2; break;
  75.                   case 0xbb: keyzhi=3; break;
  76.                   case 0xed: keyzhi=4; break;
  77.                   case 0xdd: keyzhi=5; break;
  78.                   case 0xbd: keyzhi=6; break;
  79.                   case 0xee: keyzhi=7; break;
  80.                   case 0xde: keyzhi=8; break;
  81.                   case 0xbe: keyzhi=9; break;

  82.                   case 0xe7:
  83.                   keyzhi=10; da1=0; da2=0; fh=0; resu=0; zhuangtai=0;
  84.                   led[1]=led[2]=led[3]=16; led[0]=0;break; //按下no键时将所有的值与状态复位,显示清零
  85.                   case 0xb7: keyzhi=11; zhuangtai=3; break; //按下等号键将状态换为3

  86.           case 0x77: keyzhi=12; break;
  87.                   case 0x7b: keyzhi=13; break;
  88.                   case 0x7d: keyzhi=14; break;
  89.                   case 0x7e: keyzhi=15; break;
  90.         }

  91.         //如果按下的键在0~9的时候
  92.         if (keyzhi<10)
  93.         {
  94.                 if(zhuangtai==1)//如果前一状态为1。表示完成运算符号的记录,应当记录第二个数。状态切换为2
  95.                 {
  96.                         zhuangtai=2;
  97.                 }
  98.                 else if(zhuangtai==3) //如果前一状态为3,表示已经进行过一次运算并且得出了结果。此时将结果和原有数据清零进行新的运算。状态切换为0.
  99.                 {
  100.                         da1=da2=resu=0;
  101.                         zhuangtai=0;
  102.                 }
  103.         }

  104.         //如果按下的键在12~15的时候
  105.         if (keyzhi>11 && keyzhi<16)
  106.         {
  107.                 if (zhuangtai==0) //如果前一状态为0,表示记录好第一个数,此时应当记录运算符号。状态切换为1
  108.                 {                                                   
  109.                         zhuangtai=1;
  110.                 }
  111.                 else if(zhuangtai==3)//如果前一状态为3,即表示按下运算符号表示要利用原有结果进行运算。将结果值赋给da1并将
  112.                 {
  113.                         da1=resu;                 //并将结果值赋给da1,resu和da2清零。否则原有的值会影响第二次的运算结果。并将状态切换为1,记录下运算符号。
  114.                         da2=resu=0;
  115.                         zhuangtai=1;
  116.                 }
  117.                 else if(zhuangtai==2)//如果前一状态为2,即表示已经完成了da1和运算符和da2的记录。现在不按下等号进行连续运算(如1+2+3)。
  118.                 {                                         
  119.                         jisuan();   //先计算出前面两个数的结果
  120.                         da1=resu;   //将结果赋给da1
  121.                         da2=0;            //结果和da2清零,并且将状态切换为1
  122.                         resu=0;
  123.                         zhuangtai=1;
  124.                 }
  125.         }
  126. }

  127. //函数名:ysf                        时间:
  128. //作用:记录下在状态1时所按下的运算符号
  129. //说明:
  130. //作者:ymx

  131. void ysf()
  132. {
  133.         switch(keyzhi)
  134.         {
  135.                 case 12:
  136.                         fh='+';
  137.                         break;
  138.                 case 13:
  139.                         fh='-';
  140.                         break;
  141.                 case 14:
  142.                         fh='*';
  143.                         break;
  144.                 case 15:
  145.                         fh='/';
  146.                         break;
  147.                 default:
  148.                         break;
  149.         }
  150.         
  151. }



  152. void move()
  153. {
  154.         unsigned int  linshi=0;
  155.         linshi = keyzhi;  //保存下按下的数值
  156.          while(keyzhi != 16)
  157.         {
  158.                  jianhao();
  159.         }
  160.         if(led[0]==0&&led[1]==16&&led[2]==16&&led[3]==16&&linshi!=16) //if里的条件表示初始的只是0的时候
  161.         {
  162.                 led[0]=linshi;  //移位时要将原有的0替换掉否则数显示的数的前面都会有一个零如:0123
  163.         }
  164.         else
  165.         {
  166.                 if(linshi!=16)  //如果按下了键才开始移位,否则会有空白
  167.                 {
  168.                         led[3] = led[2];
  169.                         led[2] = led[1];
  170.                         led[1] = led[0];
  171.                         led[0] = linshi;
  172.                 }
  173.         }               
  174.         if(zhuangtai==0) //状态为0时记录第一个数
  175.         {                                
  176.                 da1=da1*10+linshi;
  177.         }
  178.         if(zhuangtai==2) //状态为2时记录第二个数
  179.         {
  180.                 da2=da2*10+linshi;
  181.         }

  182. }


  183. //函数名:jieguo                        时间:
  184. //作用:将结果转化为可以显示的形式
  185. //说明:
  186. //作者:ymx

  187. void jieguo()  //计算出的结果是        一个整型的书,数码管并不能直接显示,需要把它替换成单个的数赋给显示的led数组
  188. {                                
  189.         if(resu<10000) //如果显示的结果小于5位才显示
  190.         {
  191.                 if (resu>999)
  192.                 {
  193.                         led[3]=resu/1000; //记录下千位的值
  194.                 }
  195.                 else
  196.                 {
  197.                         led[3]=16;
  198.                 }
  199.                 if(resu>99)
  200.                 {
  201.                         led[2]=(resu/100)%10;  //记录下百位的值
  202.                 }
  203.                 else
  204.                 {
  205.                         led[2]=        16;
  206.                 }
  207.                 if(resu>9)
  208.                 {
  209.                         led[1]=(resu/10)%10;
  210.                 }
  211.                 else
  212.                 {
  213.                         led[1]=16;
  214.                 }
  215.                 if(resu>0)
  216.                 {
  217.                         led[0]=resu%10;
  218.                 }
  219.                 else
  220.                 {
  221.                         led[0]=0;
  222.                 }
  223.         }
  224.         else        //如果不是小于5位的话,则显示‘E’表示错误
  225.         {
  226.                 led[0]=14;
  227.         }
  228. }


  229. //函数名:xianshi                        时间:
  230. //作用:位选和显示不同的数时所对应的P0口的电位值
  231. //说明:
  232. //作者:ymx

  233. void xianshi()
  234. {
  235.         unsigned char i, k;
  236.          for (i=0; i<4; i++)
  237.         {
  238.                 k = led[i];
  239.                 P0 = a[k];
  240.                 P2 = tv[3-i];
  241.                 delay();
  242.         }
  243. }

  244. //函数名:main                        时间:
  245. //作用:完成整个程序的循环
  246. //说明:main函数中除了记录数值得两个状态之外剩下的的状态里的jianhao函数均是用于切换状态和复位用的
  247. // zhuangtai=0表示记录第一个数,1表示记录运算符号,2表示记录第二个数,3表示计算结果并显示
  248. //作者:ymx
  249.                                 
  250. void main(void)
  251. {                                 
  252.         while(1)
  253.         {
  254.                 while(zhuangtai==0)
  255.                 {
  256.                         resu=0;
  257.                         jianhao();
  258.                         if(keyzhi<=9)//判断是按下的是否是数,是得话才移位和显示数值否则显示不变。下面状态2同
  259.                         {
  260.                                 move();
  261.                         }
  262.                                 xianshi();
  263.                                 resu=0;
  264.                 }
  265.                 while(zhuangtai==1)
  266.                 {
  267.                         led[0]=led[1]=led[2]=led[3]=16;//将显示清零
  268.                         jianhao();                                       
  269.                         ysf(); //记录下运算符号
  270.                 }
  271.                 while(zhuangtai==2)
  272.                 {         
  273.                         resu=0;
  274.                         jianhao();
  275.                         if(keyzhi<=9)
  276.                         {
  277.                                 move();
  278.                         }
  279.                                 xianshi();
  280.                 }
  281.                 while(zhuangtai==3)
  282.                 {
  283.                         jianhao();
  284.                         jisuan();
  285.                         jieguo();
  286.                         xianshi();
  287.                 }
  288.         }
  289. }
复制代码

全部资料51hei下载地址:
行列式按键及计算器.rar (46.07 KB, 下载次数: 9)

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

使用道具 举报

沙发
ID:332444 发表于 2020-10-12 08:30 | 只看该作者
扫描键盘如果不用消抖和检测释放大部分会有问题
回复

使用道具 举报

板凳
ID:332444 发表于 2020-10-12 08:31 | 只看该作者
回复

使用道具 举报

地板
ID:276663 发表于 2020-10-12 08:51 | 只看该作者
授予鱼不如授予渔,你先单独显示,然后加入按键。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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