久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4362|回復: 5
收起左側

單片機5*4矩陣鍵盤計算器制作 附程序Proteus仿真 PCB文件

  [復制鏈接]
ID:706733 發表于 2020-3-13 20:27 | 顯示全部樓層 |閱讀模式
本設計是以STC89C52單片機為核心的計算器模擬系統設計,輸入采用5×8矩陣鍵盤,可以進行加、減、乘、除等十幾種數字運算,同時支持括號的嵌套使用級浮點數的運算,并在LCD1602上顯示操作過程。
本次設計注重設計方法及流程,首先根據原理設計電路,利用keil編程,借助實驗開發平臺進行仿真實驗,進而利用altium designer 制作PCB,最后到焊接元器件,直至調試成功。在設計的同時,特別注重keil軟件和altium designer軟件的使用方法和技巧以及常用的LCD顯示器和矩陣鍵盤的設計和使用方法。

Altium Designer畫的原理圖和PCB圖如下:(51hei附件中可下載工程文件)
51hei.png

仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
51hei.png

制作出來的實物圖如下:
1.png

單片機源程序如下:
  1. #include <REGX51.H>
  2. #include<intrins.h>
  3. #include<stdio.h>
  4. #include<string.h>
  5. #include<math.h>
  6. sbit RS = P2^5;
  7. sbit RW = P2^6;
  8. sbit E  = P2^7;

  9. #define Data  P0//數據端口
  10. //全局變量
  11. float num1;//第一操作數num1     (初始為零)
  12. float num2;//第二操作數num2     (初始為零)
  13. char yun_flag='+';//運算符號 yun_flag    (默認為+ )
  14. char key_last;//上次按鍵狀態標志 key_last
  15. char sqrt_flag;//開方鍵按下標志   sqrt_flag
  16. unsigned long pos_flag=1;//小數位權pos_flag      (默認為1)
  17. char neg_flag;//正負標志 neg_flag
  18. char data c_num1[15]=" ";//c_num1 字符型第一操作數 (數組不定義大小與其他變量沖突)
  19. char data c_num2[15]=" ";//c_num2 字符型第二操作數
  20. char error;//運算法則錯誤;
  21. char len;//小數點后位數
  22. /*                    微秒延時函數                                */
  23. /******************************************************************/
  24. void DelayUs(unsigned char us)//delay us
  25. {
  26. unsigned char uscnt;
  27. uscnt=us>>1;        /*12MHz頻率*/
  28. while(--uscnt);
  29. }
  30. /******************************************************************/
  31. /*                    毫秒函數聲明                                */
  32. /******************************************************************/
  33. void DelayMs(unsigned char ms)
  34. {
  35. while(--ms)
  36.    {
  37.      DelayUs(250);
  38.      DelayUs(250);
  39.          DelayUs(250);
  40.          DelayUs(250);
  41.    }
  42. }
  43. /******************************************************************/
  44. /*                   寫入命令函數                                 */
  45. /******************************************************************/
  46. void WriteCommand(unsigned char c)
  47. {
  48. DelayMs(5);//操作前短暫延時,保證信號穩定
  49. E=0;
  50. RS=0;
  51. RW=0;
  52. _nop_();
  53. E=1;
  54. Data=c;
  55. E=0;
  56. }
  57. /******************************************************************/
  58. /*                   寫入數據函數                                 */
  59. /******************************************************************/
  60. void WriteData(unsigned char c)
  61. {
  62. DelayMs(5);  //操作前短暫延時,保證信號穩定
  63. E=0;
  64. RS=1;
  65. RW=0;
  66. _nop_();
  67. E=1;
  68. Data=c;
  69. E=0;
  70. RS=0;
  71. }
  72. /******************************************************************/
  73. /*                   寫入字節函數                                 */
  74. /******************************************************************/
  75. void ShowChar(unsigned char pos,unsigned char c)
  76. {
  77. unsigned char p;
  78. if (pos>=0x10)
  79.     p=pos+0xb0; //是第二行則命令代碼高4位為0xc
  80. else
  81.     p=pos+0x80; //是第二行則命令代碼高4位為0x8
  82. WriteCommand (p);//寫命令
  83. WriteData (c);   //寫數據
  84. }
  85. /******************************************************************/
  86. /*                   寫入字符串函數                               */
  87. /******************************************************************/
  88. void ShowString (unsigned char line,char *ptr)
  89. {
  90. unsigned char l,i;
  91. l=line<<4;
  92. for (i=0;*(ptr+i)!='\0';i++)
  93.   ShowChar (l++,*(ptr+i));//循環顯示16個字符
  94. }
  95. /******************************************************************/
  96. /*                   初始化函數                                   */
  97. /******************************************************************/
  98. void InitLcd()
  99. {
  100. DelayMs(15);
  101. WriteCommand(0x38); //display mode
  102. WriteCommand(0x38); //display mode
  103. WriteCommand(0x38); //display mode
  104. WriteCommand(0x06); //顯示光標移動位置
  105. WriteCommand(0x0c); //顯示開及光標設置
  106. WriteCommand(0x01); //顯示清屏

  107. }
  108. /*************按鍵掃描****************************/
  109. char scan()
  110. {

  111.   char h_data,l_data,i,key_num;
  112.   P2=P2&0XE0;//P2低5位送0
  113.   P1=P1|0X0F;//P1低4位送1
  114.   while((P1|0xf0)==0xff)//判斷P1低4位是否全為1
  115.   {
  116.    while((P1|0xf0)==0xff);
  117.    DelayMs(10);//延時10ms
  118.   }
  119.    l_data=~(P1|0xf0);//記入列標志
  120.    P2=P2|0X1F;//P2低五位送1
  121.    P1=P1&0XF0;//P1低四位送0
  122.    h_data=~(P2|0xe0);//記入行標志
  123.    for(i=0;i<=4;i++)//計算行號(0~4)
  124.             {
  125.            if(h_data==1)break;
  126.            h_data=h_data>>1;
  127.          }
  128. h_data=i;//行號
  129.   for(i=1;i<=4;i++)//計算列號(1~4)
  130.          {
  131.           if(l_data==1)break;
  132.           l_data=l_data>>1;
  133.         }
  134. l_data=i;//列號
  135.    key_num=h_data*4+l_data;        

  136.   P2=P2&0XE0;//P2低5位送0
  137.   P1=P1|0X0F;//P1低4位送1
  138.   while((P1|0xf0)!=0xff)//判斷P1低4位是否全為1
  139.   {
  140.    while((P1|0xf0)!=0xff);
  141.    DelayMs(10);//延時10ms
  142.   }
  143.   return key_num;
  144. }
  145. void float_to_char(float a,char* p)
  146. {
  147.   char i,flag,length;
  148.   flag=0;
  149.   sprintf(p,"%f",a);
  150.   length=strlen (p);
  151.   for(i=0;i<length;i++)
  152.   {
  153.     if(*(p+i)=='.')flag=1;
  154.   }
  155.   if(flag==1)
  156.   for(i=length-1;i>=0;i--)
  157.   {
  158.     if(*(p+i)=='.'){*(p+i)='\0';break;}
  159.     if(*(p+i)!='0'){*(p+i+1)='\0';break;}
  160.   }
  161. }
  162. /**********************更新液晶*************************/
  163. void refresh()//更新液晶
  164. {
  165.   char length,i,j;
  166.   char dot;
  167.   dot=0;
  168.          
  169.   float_to_char(num2,c_num2);//num2轉為字符型
  170.   length=strlen(c_num2);
  171.   for(i=0,j=0;i<length;i++)        
  172.   {
  173.     if(c_num2[i]=='.')
  174.         dot=1;
  175.         if(dot==1)
  176.     j++;
  177.   }
  178.   if(j<len)
  179.   {
  180.           if(dot==1)
  181.           {        
  182.             for(i=length;i<(length+len-j);i++)
  183.                  {
  184.                    c_num2[i]='0';
  185.         
  186.                  }
  187.                  c_num2[i]='\0';
  188.           }
  189.           else
  190.                 {
  191.                   
  192.                   c_num2[length]='.';
  193.                   if(len-j>1)
  194.                   {
  195.                     for(i=length+1;i<(length+len-j);i++)
  196.                          c_num2[i]='0';
  197.                   }
  198.                   c_num2[length+len-j]='\0';
  199.                 }  
  200.   }

  201.   if(neg_flag==1)//'+/-'按下首位加‘-’
  202.    {
  203.       length=strlen(c_num2);//計算c_num2長度         
  204.                     for(i=length-1;i>=0;i--)
  205.                   {
  206.                           c_num2[i+1]=c_num2[i];
  207.                   }
  208.                   c_num2[length+1]='\0';
  209.                   c_num2[0]='-';
  210.    }
  211.    
  212.    if(sqrt_flag==1)
  213.            {
  214.       length=strlen(c_num2);//計算c_num2長度
  215.              for(i=length-1;i>=0;i--)
  216.           {
  217.                   c_num2[i+1]=c_num2[i];
  218.           }
  219.           c_num2[length+1]='\0';
  220.           c_num2[0]=0xe8;//字符根號
  221.    }
  222.    
  223.    
  224.    if(error==0)
  225.    {
  226.            float_to_char(num1,c_num1);//num1轉為字符型
  227.            WriteCommand(0x01); //顯示清屏
  228.            ShowString(0,c_num1);
  229.            ShowString(1,c_num2);  
  230.            ShowChar(15,yun_flag);
  231.    }else
  232.    {
  233.        WriteCommand(0x01); //顯示清屏
  234.            ShowString(0,"error!!!");
  235.    }
  236. }
  237. //鍵值處理
  238. void operation1(char keynum)//按下 ’+、-、*、/處理
  239. {
  240.   if(key_last==1)//上次按鍵為 數字、小數點、+/-、sqrt
  241.    {
  242.      if(neg_flag==1)num2=-num2;//'+/-'按下
  243.          if(sqrt_flag==1)//sqrt按下
  244.          {
  245.          if(num2>=0)
  246.          num2=sqrt(num2);
  247.          else
  248.          error=1;
  249.          }
  250.          if(yun_flag=='+')num1=num1+num2; //按下的是‘+’
  251.          if(yun_flag=='-')num1=num1-num2;//按下的是‘-’
  252.          if(yun_flag=='*')num1=num1*num2;//按下的是‘*’
  253.          if(yun_flag=='/')//按下的是‘/’
  254.          {
  255.            if(num2!=0)
  256.            num1=num1/num2;
  257.            else
  258.            error=1;
  259.          }
  260.          num2=0;//num2清零
  261.          sqrt_flag=0;//sqrt_flag清零
  262.      neg_flag=0;//neg_flag清零
  263.          pos_flag=1;//pos_flag回1
  264.    }
  265.    if(keynum==4)yun_flag='+';//yun_flag更新
  266.    if(keynum==8)yun_flag='-';
  267.    if(keynum==12)yun_flag='*';
  268.    if(keynum==16)yun_flag='/';
  269.    len=0;
  270.    key_last=0;//key_last更新   
  271.    refresh();
  272. }
  273. //////////////////////////////////////////////////////
  274. void operation2(char keynum)//輸入數字
  275. {
  276.   float Data1;
  277.    
  278.   if(keynum==1)Data1=7;//分析輸入數字
  279.   if(keynum==2)Data1=8;
  280.   if(keynum==3)Data1=9;
  281.   if(keynum==5)Data1=4;
  282.   if(keynum==6)Data1=5;
  283.   if(keynum==7)Data1=6;
  284.   if(keynum==9)Data1=1;
  285.   if(keynum==10)Data1=2;
  286.   if(keynum==11)Data1=3;
  287.   if(keynum==13)Data1=0;
  288.   if(pos_flag==1)//更新num2
  289.   num2=num2*10+Data1;
  290.   else
  291.   {            
  292.     num2=num2+(Data1/pos_flag);
  293.         pos_flag=pos_flag*10;
  294.         len++;
  295.   }
  296.   key_last=1;//更新key_last        
  297.   refresh();
  298. }
  299. ////////////////////////////////////////////////////////////
  300. void operation3()//輸入小數點
  301. {
  302.   if(pos_flag==1)//首次出現小數點
  303.   {
  304.    pos_flag=pos_flag*10;//小數位權*10
  305.    len++;
  306.   }
  307.   key_last=1;//更新key_last
  308.   refresh();//更新液晶
  309. }
  310. /////////////////////////////////////////////////////
  311. void operation4()//輸入'='
  312. {
  313.      if(neg_flag==1)num2=-num2;//'+/-'按下
  314.          if(sqrt_flag==1)//sqrt按下
  315.          {
  316.          if(num2>=0)
  317.          num2=sqrt(num2);
  318.          else
  319.          error=1;
  320.          }
  321.          if(yun_flag=='+')num1=num1+num2; //按下的是‘+’
  322.          if(yun_flag=='-')num1=num1-num2;//按下的是‘-’
  323.          if(yun_flag=='*')num1=num1*num2;//按下的是‘*’
  324.          if(yun_flag=='/')//按下的是‘/’
  325.          {
  326.            if(num2!=0)
  327.            num1=num1/num2;
  328.            else
  329.            error=1;
  330.          }
  331.          num2=0;//num2清零
  332.          sqrt_flag=0;//sqrt_flag清零
  333.      neg_flag=0;//neg_flag清零
  334.          pos_flag=1;//pos_flag回1
  335.      yun_flag='+';//yun_flag更新
  336.          len=0;
  337.    key_last=0;//key_last更新   
  338.    refresh();
  339. }
  340. ////////////////////////////////////////////////////
  341. void operation5()//輸入clear all
  342. {

  343.    num1=0;// num1清零
  344.    num2=0;//num2清零
  345.    sqrt_flag=0;//清sqrt_flag
  346.    neg_flag=0;// 清neg_flag
  347.    pos_flag=1;// Pos_flag=1
  348.    yun_flag='+';// yun_flag(為'+')
  349.    error=0;//清error
  350.    len=0;
  351.    key_last=0;//更新key_flag
  352.    refresh();//更新液晶
  353. }
  354. ///////////////////////////////////////////////////////
  355. void operation6()//輸入'C'
  356. {
  357. num2=0;//num2清零
  358. sqrt_flag=0;//清sqrt_flag
  359. neg_flag=0;//清neg_flag
  360. pos_flag=1;//pos_flag=1
  361. len=0;
  362. key_last=0;//key_last
  363. refresh();//更新液晶
  364. }
  365. ////////////////////////////////////////////////////////////
  366. void operation7()//輸入'+/-'
  367. {
  368.   if(neg_flag==0)//neg_flag反轉
  369.   neg_flag=1;
  370.   else neg_flag=0;
  371.   key_last=1;//key_last
  372.   refresh();// 更新液晶
  373. }
  374. /////////////////////////////////////////////////////////////
  375. void operation8()//輸入'sqrt'
  376. {
  377. if(sqrt_flag==0)//sqrt_flag反轉
  378.   sqrt_flag=1;
  379. else sqrt_flag=0;
  380. key_last=1;//更新key_last
  381. refresh();//更新液晶
  382. }
  383. //鍵值分析
  384. void key(char keynum)
  385. {
  386.   switch(keynum)
  387.   {
  388.     case 4 :
  389.         case 8 :
  390.         case 12:
  391.         case 16://+、-、*、/
  392.                     {
  393.                          if(error==0)
  394.                  operation1(keynum);
  395.                  break;}
  396.                         
  397.         case 1  : //數字7
  398.         case 2  : //數字8
  399.         case 3  : //數字9
  400.         case 5  : //數字4
  401.         case 6  : //數字5
  402.         case 7  : //數字6
  403.         case 9  : //數字1
  404.         case 10 : //數字2
  405.         case 11 : //數字3
  406.         case 13 : //數字0
  407.                  {
  408.                          if(error==0)
  409.                          operation2(keynum);
  410.                          break;}
  411. ……………………

  412. …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼

所有資料51hei提供下載:
計算器 5乘4.7z (3.74 MB, 下載次數: 108)

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

回復

使用道具 舉報

ID:695749 發表于 2020-3-13 21:32 | 顯示全部樓層
謝謝分享!
回復

使用道具 舉報

ID:735165 發表于 2020-4-22 13:53 | 顯示全部樓層
謝謝分享
回復

使用道具 舉報

ID:737198 發表于 2020-4-24 18:04 | 顯示全部樓層
謝謝分享!
回復

使用道具 舉報

ID:848337 發表于 2020-11-25 09:09 來自手機 | 顯示全部樓層
器件多少買啥
回復

使用道具 舉報

ID:849820 發表于 2020-11-26 19:38 | 顯示全部樓層
求4*4的
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: jlzzjlzz国产精品久久 | 一区二区三区欧美在线 | 国产精品一区二区在线免费观看 | 福利一区二区 | 成人国产精品一级毛片视频毛片 | 国产精品自拍视频 | 少妇一级淫片免费放播放 | 国产成人在线播放 | 久久九九网站 | 视频精品一区二区三区 | 国产成人麻豆免费观看 | 羞羞色在线观看 | 国产传媒在线观看 | 美女艹b | 亚洲综合网站 | 成人午夜免费福利视频 | 亚洲一区二区久久久 | 7777奇米影视| 狠狠狠 | 亚洲精品久久久久中文字幕欢迎你 | 亚洲精品视频在线播放 | 91最新视频 | 在线视频中文字幕 | 久久一 | 亚洲国产精品视频 | 欧美日韩在线播放 | 国产中文区二幕区2012 | 天堂成人av | 精品在线一区二区三区 | 7777在线视频免费播放 | 免费黄色大片 | 日本色婷婷| 色综合视频 | 亚洲国产成人精品女人久久久 | 国产精品1区 | 日韩视频免费看 | 亚洲精品短视频 | 蜜桃臀av一区二区三区 | 亚洲成人免费观看 | 成人a在线 | 久久亚洲国产精品 |