找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于51单片机的多功能计算机程序与Proteus仿真图设计

[复制链接]
ID:398204 发表于 2022-5-9 19:40 | 显示全部楼层 |阅读模式
资料包括:
1.Proteus仿真文件,Proteus软件版本为8.9
2.程序源代码,C语言编译器为keilv4
3.实现的功能:
   主要是计算器的基本功能和科学计算器许多功能,用最少的按键实现最多的计算功能,包括三角函数、指数、开根号以及天文数字、角度转换的运算,此外还带有记忆功能。
   系统用20个按键实现这些功能。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
51hei.gif
仿真截图.png

单片机源程序如下:
  1. #include<reg52.h>
  2. #include<stdlib.h>//包含atof(),字符串->实数
  3. #include<stdio.h>
  4. #include<string.h>
  5. #include<math.h>
  6. #define uchar unsigned char
  7. #define uint unsigned int
  8. uchar num;
  9. /**********LCD*********/
  10. sbit lcdrs=P3^7;   //LCD控制脚
  11. sbit lcdrw=P3^6;
  12. sbit lcden=P3^5;
  13. sbit beep=P0^7;

  14. bit form;  //LCD切换方式
  15. uchar idata state;
  16. /********计算器*******/
  17. sbit reset=P3^0;
  18. sbit back=P3^1;
  19. sbit save=P3^2;
  20. sbit sfyong=P3^3;
  21. bit eqsign;
  22. bit press;
  23. bit savesign;
  24. bit sc;

  25. uchar idata process[30],proc;
  26. uchar idata continu=0;
  27. uchar idata pai[2][2];
  28. uchar idata ferror;
  29. uchar idata ywei;
  30. uchar idata count=0;
  31. uchar idata count_num=0;//组号计数
  32. uchar idata result[15];//计算结果立存,save
  33. uchar idata saveresult[15];//存储结果数组,sc+save
  34. uchar idata jieguo[15];//结果字符串
  35. uchar idata bdate[2][14];//待计算字符串二维组
  36. uchar idata on_symbol; //运算符号
  37. uchar idata fsym[2];     //函数前符号
  38. uchar idata ssym[2];  //存储组前符号
  39. uchar idata bfun[2];   //计算值调用函数选择
  40. uchar idata futojiao[2];  //幅度?to?角度变换
  41. double idata date[2];    //计算值双精度变量组
  42. double idata resultdate;    //双精度结果值
  43. /*******************函数声明******************/

  44. /****************延时******************/
  45. void delay(uchar z);
  46. /*************lcd写命令***************/  
  47. void write_com(uchar com);
  48. /*************lcd写数据***************/  
  49. void write_date(uchar date);
  50. /*************lcd读状态***************/  
  51. void read_date(void);
  52. /*************lcd写字符串*************/  
  53. void write_str(uchar *str);
  54. /************液晶初始化***************/  
  55. void init(void );   
  56. /**********移屏*******************/  
  57. void write();
  58. /**********复用提示开关***************/  
  59. void shift(void);
  60. /**************键盘扫描***************/  
  61. uchar keyscan(void);
  62. /*************计算器复位**************/  
  63. void fuwei();
  64. /************error处理****************/  
  65. void callerror(void);
  66. /***************撤销键入**************/  
  67. void huifu(void);
  68. /**********函数组前符号处理***********/  
  69. uchar funqian(void);
  70. /************运算符预处理*************/  
  71. void  cullars(uchar);
  72. /***********输出存储数据预处理********/  
  73. char  memory(void);
  74. /***********按键功能主处理************/  
  75. void process_date(uchar press_date);
  76. /***********按键功能子处理************/  
  77. void calculator(uchar press_date);  
  78. /************************************************/  
  79. void write()  
  80. {     
  81.      for(num=0;num<16;num++)        
  82.         {         
  83.             write_com(0x18);         
  84.             delay(200);        
  85.         }  
  86. }
  87. /*************LCD程序****************/

  88. /**************延时******************/  
  89. void delay(uchar z)        
  90. {        
  91.     uchar  x,y;        
  92.     for(x=z;x>0;x--)        
  93.     for(y=100;y>0;y--);  
  94. }   

  95. /**************写命令*****************/  
  96. void write_com(uchar com)  
  97. {        
  98.     lcdrs=0;        
  99.     lcdrw=0;        
  100.     lcden=0;        
  101.     P1=com;        
  102.     delay(5);        
  103.     lcden=1;        
  104.     delay(5);        
  105.     lcden=0;  
  106. }
  107.    
  108. /*************写数据******************/  
  109. void write_date(uchar date)  
  110. {        
  111.     lcdrs=1;        
  112.     lcdrw=0;        
  113.     lcden=0;        
  114.     P1=date;        
  115.     delay(5);        
  116.     lcden=1;        
  117.     delay(5);        
  118.     lcden=0;  
  119. }
  120. /*************读AC 地址*****************/  
  121. void read_date(void)  
  122. {        
  123.     lcdrs=0;        
  124.     lcdrw=1;     
  125.     delay(5);     
  126.     P1=0xff;        
  127.     lcden=1;        
  128.     delay(5);        
  129.     state=P1;        
  130.     delay(5);        
  131.     lcden=0;delay(5);     
  132.     state=state&127;  
  133. }

  134. /*************写字符串******************/  
  135. void write_str(uchar *str)  
  136. {        
  137.     uchar idata i;        
  138.     for(i=0;str[i]!='\0';i++)           
  139.     write_date(str[i]);  
  140. }
  141. /***********液晶初始化***************/  
  142. void init(void )  
  143. {
  144.     write_com(0x38);  //模式:8位数据,两行,5*7字体
  145.     write_com(0x0c); //开显示,无光标
  146.     write_com(0x06);//向左增量移动
  147.     write_com(0x01);       //清屏  
  148. }   
  149. /**********复用提示开关***************/  
  150. void shift(void)  
  151. {     
  152.     if(sc==1)     
  153.     {        
  154.         read_date();   //读状态        
  155.         write_com(0xc0); //显示复用提示,左下角's'     
  156.         write_date('s');     
  157.         write_com(state+0x80);//光标还回原来位置
  158.     }   
  159.     else   
  160.     {        
  161.     read_date();        
  162.     write_com(0xc0);    //关闭复用提示     
  163.     write_date(' ');     
  164.     write_com(state+0x80);   
  165.     }   
  166.     return;  
  167. }   
  168. /**************键盘扫描*************/

  169. //  s1~s4   .    0    =    +
  170. //  s5~8    1    2    3    -
  171. //    s9~s12  4    5    6    *
  172. //  s13~s16 7    8    9    /
  173. //    k1~k4   C    DEL  M=   FS&S
  174. //
  175. uchar keyscan(void)          //按行扫描,有键按下则返回键符号,否则返回null  
  176. {     
  177.     uchar idata key0,key1,keyment=0;        
  178.     P2=0XFe;        //行1        
  179.     key0=P2;        
  180.     key0=key0&0xf0;        
  181.     key1=key0;        
  182.     if(key0!=0xf0)        
  183.     {
  184.         delay(5);               //键抖动处理
  185.         P2=0XFe;            
  186.         key0=P2;            
  187.         key0=key0&0xf0;            
  188.         if(key0==key1)            
  189.         {
  190.             beep=1;
  191.             delay(200);
  192.             beep=0;                  
  193.             switch(key0)                  
  194.             {                    
  195.                 case 0xe0:keyment='7';break;
  196.                 case 0xd0:keyment='8';break;
  197.                 case 0xb0:keyment='9';break;
  198.                 case 0x70:keyment=0xfd;break;  //0xfd除号在1602液晶中的代码                  
  199.             }
  200.             while(key0!=0xf0)  //键释放处理  
  201.             {                    
  202.             key0=P2;                    
  203.             key0=key0&0xf0;                  
  204.             }                  
  205.             press=1;     //键按标志置1   
  206.             return(keyment);            
  207.         }        
  208.     }        
  209.     P2=0XFd;       //行2        
  210.     key0=P2;        
  211.     key0=key0&0xf0;        
  212.     key1=key0;        
  213.     if(key0!=0xf0)        
  214.     {            
  215.         delay(5);            
  216.         P2=0XFd;            
  217.         key0=P2;            
  218.         key0=key0&0xf0;            
  219.         if(key0==key1)            
  220.         {   
  221.             beep=1;
  222.             delay(200);
  223.             beep=0;              
  224.             switch(key0)                 
  225.             {                    
  226.                 case 0xe0:keyment='4';break;
  227.                 case 0xd0:keyment='5';break;
  228.                 case 0xb0:keyment='6';break;  
  229.                 case 0x70:keyment='*';break;
  230.             }                 
  231.             while(key0!=0xf0)              
  232.             {                    
  233.             key0=P2;                    
  234.             key0=key0&0xf0;
  235.             }
  236.             press=1;                 
  237.             return(keyment);            
  238.         }        
  239.     }        
  240.     P2=0XFb;       //行3        
  241.     key0=P2;        
  242.     key0=key0&0xf0;        
  243.     key1=key0;        
  244.     if(key0!=0xf0)        
  245.     {            
  246.         delay(5);            
  247.         P2=0XFb;            
  248.         key0=P2;            
  249.         key0=key0&0xf0;            
  250.         if(key0==key1)            
  251.         {   
  252.             beep=1;
  253.             delay(200);
  254.             beep=0;              
  255.             switch(key0)                 
  256.             {                    
  257.                 case 0xe0:keyment='1';break;
  258.                 case 0xd0:keyment='2';break;  
  259.                 case 0xb0:keyment='3';break;
  260.                 case 0x70:keyment='-';break;
  261.             }                 
  262.             while(key0!=0xf0)               
  263.             {                     
  264.             key0=P2;                     
  265.             key0=key0&0xf0;                 
  266.             }                 
  267.             press=1;                 
  268.             return(keyment) ;            
  269.         }        
  270.     }        
  271.     P2=0XF7;       //行4        
  272.     key0=P2;        
  273.     key0=key0&0xf0;        
  274.     key1=key0;        
  275.     if(key0!=0xf0)        
  276.     {   
  277.         beep=1;
  278.         delay(200);
  279.         beep=0;           
  280.         delay(5);            
  281.         P2=0XF7;            
  282.         key0=P2;            
  283.         key0=key0&0xf0;            
  284.         if(key0==key1)            
  285.         {   
  286.             switch(key0)                 
  287.             {                  
  288.                 case 0xe0:keyment='.';break;   
  289.                 case 0xd0:keyment='0';break;                  
  290.                 case 0xb0:keyment='=';break;                  
  291.                 case 0x70:keyment='+';break;                 
  292.             }                 
  293.             while(key0!=0xf0)                 
  294.             {                  
  295.             key0=P2;                  
  296.             key0=key0&0xf0;                 
  297.             }                 
  298.             press=1;                 
  299.             return(keyment);            
  300.         }      
  301.     }
  302.     if(reset==0)          //复位键         
  303.         {   
  304.             beep=1;
  305.             delay(200);
  306.             beep=0;               
  307.             keyment=' ';            
  308.             press=1;
  309.             while(reset==0);//键释放            
  310.             return(keyment);   
  311.         }      
  312.     else if(back==0)        //撤销前次输入
  313.         {   
  314.             beep=1;
  315.             delay(200);
  316.             beep=0;   
  317.             keyment='c';            
  318.             press=1;            
  319.             while(back==0);            
  320.             shift();            
  321.             return(keyment);   
  322.         }      
  323.     else  if(save==0)     //储存数据键           
  324.         {      
  325.             delay(5);      
  326.             if(save==0)      
  327.             {
  328.                 beep=1;
  329.                 delay(200);
  330.                 beep=0;
  331.                 if(sc==0)    //输出前次计算结果键   
  332.                 {         
  333.                     keyment='m';               
  334.                     press=1;               
  335.                     while(save==0);               
  336.                     return(keyment);      
  337.                 }      
  338.                 else      //更新存储的数据或输出存储的数据
  339.                 {               
  340.                     keyment='n';               
  341.                     press=1;
  342.                     sc=0;      
  343.                     shift();               
  344.                     while(save==0);         
  345.                     return(keyment);      
  346.                 }   
  347.             }      
  348.         }
  349.         else if(sfyong==0)     //计算器时为复用功能键      
  350.         {               
  351.             delay(5);      
  352.             if(sfyong==0)      
  353.             {  
  354.                 beep=1;
  355.                 delay(200);
  356.                 beep=0;
  357.                 keyment='h';              
  358.                 press=1;              
  359.                 while(sfyong==0);         
  360.                 return(keyment);     
  361.             }return(0);      
  362.         }else return(0);    //无键按下返回null
  363.         return(0);
  364. }

  365.    
  366. /**************计算器复位****************/  
  367. void fuwei()  
  368. {   
  369.     uchar idata j,i;      
  370.     write_com(0x0f);     //lcd设置      
  371.     write_com(0x01);      
  372.     write_com(0x80);      
  373.     resultdate=0;      
  374.     for(i=0;i<2;i++)   
  375.     {
  376.         date[i]=0;bfun[i]=0;pai[0][i]=0;pai[1][i]=0;fsym[i]=0;futojiao[i]=0; //各标志置 0     
  377.         for(j=0;j<14;j++)  //字符数组初始化  
  378.         {         
  379.             bdate[i][j]='\0';        
  380.         }   
  381.     }      
  382.     count=0;    //各标志置0      
  383.     count_num=0;   
  384.     proc=0;      
  385.     ferror=0;      
  386.     eqsign=0;   
  387.     sc=0;   
  388.     savesign=0;   
  389.     ywei=0;   
  390.     press=0;   
  391.     on_symbol=0;  
  392. }

  393.   
  394. /**************error处理******************/
  395. void callerror(void)  
  396. {   
  397.     uchar idata i;      
  398.     write_com(0x01);      
  399.     write_com(0x80);      
  400.     write_str("     error!     ");
  401.     for(i=0;i<200;i++)
  402.     delay(25); //持续显示 1s  
  403. }
  404. /*************函数组前符号处理************/
  405. uchar funqian(void)    //输入函数前检查是否错误  
  406. {  
  407.     if((bdate[ferror][0]=='+'||bdate[ferror][0]=='-')&&count==1)     
  408.     {      
  409.         fsym[ferror]=bdate[ferror][0];      
  410.         bdate[ferror][0]='\0';   
  411.         bdate[ferror][1]='\0';   
  412.         count=0;     
  413.     }
  414.     if(bdate[ferror][0]!='\0'||bfun[ferror]!=0)//错误输入方式处理     
  415.     {
  416.         callerror();         
  417.         huifu();   
  418.         return(1);     
  419.     }     
  420.     return(0);  
  421. }
  422. /****************撤销上次输入****************/
  423. void huifu(void)  
  424. {      
  425.     uchar j,pro;    //pro变量用于恢复proc
  426.     if(proc!=0)proc--;   
  427.     pro=proc;   
  428.     fuwei();   
  429.     proc=pro;   
  430.     for(j=0;j<proc;j++)calculator(process[j]); //依次恢复之前的操作   
  431.     return;  
  432. }
  433. /*****************运算符预处理*****************/  
  434. void  cullars(uchar csym)  
  435. {
  436.     read_date();     //看第二组是否有输入   
  437.     ferror++;              //检错标志+1   
  438.     continu=csym;     //存储运算符号   
  439.     if(ferror==2&&state<0x43){callerror();huifu();return;}// 第二组无输入且ferror=2,错误   
  440.     if(ferror==2&&state>0x42) //第二组有输入且ferror=2,则进行连续计算   
  441.     {      
  442.         press=1;     //模拟按键'='和'M+';将本次的计算结果作为下一次计算的第一组
  443.         process_date('=');      
  444.         press=1;      
  445.         process_date('m');      
  446.         ferror=1;    //恢复现场,避免变化      
  447.         if(continu=='^'||continu=='%'){process[proc]='h';
  448.                proc++;process[proc]=continu;proc++;}
  449.         else{process[proc]=continu;proc++;}   //恢复连续计算过程   
  450.     }   
  451.     if(continu=='%'){write_str(" f");}else write_date(' ');
  452.     write_date(continu);//将用与连续计算的运算符号取出   
  453.     ywei=0;   
  454.     savesign=0;   
  455.     count_num=1;     //组标志加1   
  456.     count=0;   //输入计数清零   
  457.     on_symbol=continu;  //运算符号调用   
  458.     write_com(0xc2);   
  459.     return;  
  460. }
  461. /*************输出存储数据预处理************/
  462. char  memory(void)  
  463. {
  464.     if((bdate[count_num][0]=='+'||bdate[count_num][0]=='-')&&count==1)//符号处理      
  465.     {
  466.          ssym[count_num]=bdate[count_num][0];
  467.          bdate[count_num][0]='\0';   
  468.          bdate[count_num][1]='\0';   
  469.          count=0;
  470.     }      
  471.     if(bdate[count_num][0]!='\0'){callerror();huifu();return(1);} //错误输入方式处理   
  472.     return(0);  
  473. }
  474. /**************按键功能主处理****************/
  475. void process_date(uchar press_date)  
  476. {
  477.     if(form==0){write_com(0x0f);form=1;}   //显示方式切换 光标闪烁      
  478.     if(eqsign==1&&press==1)fuwei();  //复位再次计算,记忆过程清零   
  479.     press=0;   
  480.     if(press_date=='c'){huifu();press_date=0;}   
  481.     if(press_date==0)return;          //无按键   
  482.     process[proc]=press_date;   
  483.     proc++;   
  484.     calculator(press_date);   
  485.     return;  
  486. }
  487. /***************按键功能子处理***************/
  488. void calculator(uchar press_date)  
  489. {
  490.     uchar idata j=0;   
  491.     /*************************************/   
  492.     if(press_date==('h'))    //复用键   
  493.     {        
  494.         sc=~sc;     //按键功能切换,sc为1时调用函数     
  495.         shift();     //显示与关闭复用提示   
  496.     }      
  497.     /*************************************/
  498.     else if((press_date<='9'&&press_date>='0')||(press_date=='.')) //数字键处理      
  499.     {
  500.         savesign=0;     //不可更新存储数据         
  501.         if(sc==0)     //是否为复用sc为0,是数字         
  502.         {
  503.             if(count<14-ywei)  //未调用函数时最多输入14位数,包括小数点            
  504.             {            
  505.                 write_date(press_date);
  506.                 bdate[count_num][count]=press_date; //储存键值                     
  507.                 count++;            
  508.             }
  509.             else {callerror();huifu();}  //超出14位出错,恢复
  510.         }
  511.         else switch(press_date)   //复用时         
  512.         {             //     排错   置函数标志符号 复用清零  移位,此时数据只能(14-ywei)位            
  513.             case '7':  j=funqian();if(j==1)return;bfun[ferror]='s';sc=0;shift();ywei=4;write_str("sin ");break; //函数sin            
  514.             case '8':  j=funqian();if(j==1)return;bfun[ferror]='c';sc=0;shift();ywei=4;write_str("cos ");break; //函数cos            
  515.             case '9':  j=funqian();if(j==1)return;bfun[ferror]='t';sc=0;shift();ywei=4;write_str("tan ");break; //函数tan      
  516.             case '4':  j=funqian();if(j==1)return;bfun[ferror]='e';sc=0;shift();ywei=4;write_str("exp ");break; //函数exp      
  517.             case '5':  j=funqian();if(j==1)return;bfun[ferror]='l';sc=0;shift();ywei=3;write_str("ln ");break;  //函数ln      
  518.             case '6':  j=funqian();if(j==1)return;bfun[ferror]='g';sc=0;shift();ywei=3;write_str("Lg ");break;  //函数Lg      
  519.             case '1':  j=funqian();if(j==1)return;bfun[ferror]='q';sc=0;shift();ywei=5;write_str("sqrt ");break;//函数sqrt      
  520.             case '0':  j=funqian();if(j==1)return;bfun[ferror]='d';sc=0;shift();ywei=4;write_str("dao ");break; //函数dao(倒数)
  521.             case '.': if(count==0){ pai[count_num][0]=1;count=14-ywei;     }   //圆周率 pai处理    π前面无加权        
  522.             else{ pai[count_num][1]=1;count=14;}   //  π前面可以有加权,后面不能跟数据        
  523.             write_date(247);sc=0;shift();break;      
  524.     /************************2和3是双参数函数 当运算符使用 *************************/      
  525.             case '2':  //x^y x的y次方        
  526.             cullars('^');   //调用运算符号处理程序        
  527.             sc=0;shift();        
  528.             break;      
  529.             case '3': //A/B的余数(双精度)        
  530.             cullars('%');   //调用运算符号处理程序        
  531.             sc=0;shift();        
  532.             break;           
复制代码

Keil5代码与Proteus8.8仿真下载: 仿真代码.7z (141.67 KB, 下载次数: 28)

评分

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

查看全部评分

回复

使用道具 举报

ID:262 发表于 2022-5-10 23:55 | 显示全部楼层
好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:398204 发表于 2022-5-15 01:34 | 显示全部楼层
heicad 发表于 2022-5-10 23:55
好资料,51黑有你更精彩!!!

近期会分享很多本科时做的各种仿真,希望和大家一起学习
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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