找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 5602|回復(fù): 3
收起左側(cè)

單片機(jī)實(shí)現(xiàn)4*4矩陣式鍵盤計(jì)算器源程序+Proteus仿真

[復(fù)制鏈接]
ID:580332 發(fā)表于 2019-7-10 09:07 | 顯示全部樓層 |閱讀模式
以AT89C51單片機(jī)為核心實(shí)現(xiàn)一個(gè)4*4矩陣式鍵盤計(jì)算器,該計(jì)算器可以實(shí)現(xiàn)基本加減乘除功能,并且用LCD顯示鍵盤輸入數(shù)和運(yùn)算符號(hào)。
計(jì)算器仿真圖.png

單片機(jī)源程序如下:
  1. #include<reg51.h>
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. unsigned char n;
  5. float idata a,b;                                                                //兩個(gè)操作數(shù)       
  6. void key_scan(void);                                        //鍵盤掃描
  7. void init();                                                        //LCD初始化
  8. void LCD_dsp_string(unsigned char X,unsigned char Y,unsigned char *s);//字符串顯示
  9. void LCD_dsp_char( unsigned x,unsigned char y,unsigned char dat);     //字符顯示
  10. void write_com(unsigned char com);

  11. sbit lcden=P2^7;                                                        //讀寫控制輸入端
  12. sbit rw=P2^6;                                                                //讀寫控制端
  13. sbit rs=P2^5;                                                                //指令與數(shù)據(jù)選擇
  14. sbit busy=P0^7;                                                        //LCD忙碌標(biāo)識(shí)

  15. void delay(unsigned int i)                                        //延時(shí)程序
  16. {       
  17.         unsigned int n;
  18.         for(n=0;n<=i;n++);
  19. }

  20. void main()
  21. {
  22.         char idata temp[16];                                                //臨時(shí)存儲(chǔ)區(qū)
  23.         char i=0,j=0,fuhao;                                                //i,j分別為temp與LCD的數(shù)據(jù)指針
  24.         bit flag=0,dh=0,fh=0,xsd=0;
  25. //flag=0:操作數(shù)1,flag=1:操作數(shù)2;dh=1時(shí)表示已輸入等號(hào);fh負(fù)號(hào);xsd小數(shù)點(diǎn)
  26.         init();                                                                        //小數(shù)點(diǎn)
  27.         LCD_dsp_string(4,0,"Welcome!");                               
  28.         do
  29.         {
  30.                  key_scan();                                                                       
  31.         } while(n==17);                                                        //等待按鍵
  32.         write_com(0x01);                                                        //清屏
  33.         while(1)
  34.         {
  35.                 key_scan();                                                        //等待按鍵
  36.                 if((dh==1)&(flag==1)&(n!=17))                //一次計(jì)算完畢后執(zhí)行
  37.                 {
  38.                         write_com(0x01);                                        //清屏
  39.                         LCD_dsp_string(0,0,temp);                //輸出上次計(jì)算的結(jié)果
  40.                         j=0;                                                                                       
  41.                         i=0;
  42.                         flag=0;
  43.                         fh=0;                                                                                                                       
  44.                         while(temp[i++]!='\0') j++;                                    
  45. //將temp數(shù)據(jù)指針移向后一個(gè)空位,將LCD顯示指針移向下一個(gè)空位
  46.                 }
  47.                 if((i==0)&(n=='-')&(fh==0))                        //如果輸入的第一個(gè)數(shù)是負(fù)數(shù)則執(zhí)行
  48.                 {
  49.                         fh=1;                                                                //表示有負(fù)號(hào)
  50.                          temp[0]='-';                                                //保存負(fù)號(hào)
  51.                         i++;
  52.                         LCD_dsp_char(j++,0,n);                        //輸出減號(hào)
  53.                         if(flag==0) continue;                                                       
  54.                 }
  55.                 if(((n>='0')&(n<='9')|((n=='c')&(xsd==0)))&(dh==0))
  56.                 {
  57.                         if(n=='c')
  58.                         {       
  59.                                 n='.';
  60.                                 xsd=1;                                                        //防止再次按下c后繼續(xù)出現(xiàn)小數(shù)點(diǎn)
  61.                         }
  62.                         temp[i++]=n;                                        //保存輸入的數(shù)字
  63.                         LCD_dsp_char(j++,0,n);                //顯示并將光標(biāo)移至下一位(光標(biāo)未顯示)
  64.                
  65. }
  66.                 if(((n=='+')|(n=='-')|(n=='*')|(n=='/'))&((flag==0)|(dh==1)))
  67. //輸入完第一個(gè)操作數(shù)之后或者完成一次計(jì)算之后按下運(yùn)算符按鍵時(shí)執(zhí)行
  68.                 {
  69.                          flag=1;                                                //之后輸入的操作數(shù)是第二個(gè)操作數(shù)
  70.                         fuhao=n;
  71.                         temp[i]='\0';                                        //表示為字符串
  72.                         a=atof(temp);                                        //轉(zhuǎn)換為數(shù)據(jù)
  73.                         i=0;
  74.                         dh=0;
  75.                         xsd=0;                                                //之后第二個(gè)操作數(shù)中可以添加一個(gè)小數(shù)點(diǎn)
  76.                         switch(n)
  77.                         {
  78.                                  case '+': LCD_dsp_char(j++,0,n); break;
  79.                                 case '-': LCD_dsp_char(j++,0,n);
  80.                                                   fh=0;        break;
  81.                                 case '*': LCD_dsp_char(j++,0,n); break;
  82.                                 case '/': LCD_dsp_char(j++,0,n); break;
  83.                         }                                                                //顯示運(yùn)算符
  84.                 }
  85.                 if((n=='=')&(flag==1))                        //已輸入完第二個(gè)操作數(shù)并按下等號(hào)
  86.                 {
  87.                         dh=1;
  88.                         temp[i]='\0';
  89.                         b=atof(temp);
  90.                         i=0;
  91.                         xsd=0;
  92.                         LCD_dsp_char(j,0,'=');                //顯示等號(hào)
  93.                         switch(fuhao)
  94.                         {
  95.                                  case '+': a=a+b; break;
  96.                                 case '-': a=a-b; break;
  97.                                 case '*': a=a*b; break;
  98.                                 case '/': a=a/b; break;
  99.                         }                                                                //計(jì)算
  100.                         if(a>9999)
  101.                         {
  102.                                 sprintf(temp,"%s","Error");       
  103. //若計(jì)算結(jié)果超過四位數(shù)則輸出錯(cuò)誤信息
  104.                                 LCD_dsp_string(0,1,temp);
  105.                                 n=17;
  106.                                 do
  107.                                 {
  108.                                         key_scan();                                                                       
  109.                                 }while(n==17);                        //等待按鍵
  110.                                 write_com(0x01);                        //清屏
  111.                                 a=b=0;
  112.                                 fuhao=0;
  113.                                 flag=0;
  114.                                 i=0;
  115.                                 j=0;
  116.                                 dh=0;
  117.                                 xsd=0;
  118.                                 fh=0;                                                //恢復(fù)初始化
  119.                         }
  120.                         else
  121.                         {
  122.                                 sprintf(temp,"%g",a);        //輸出計(jì)算結(jié)果
  123.                                 LCD_dsp_string(0,1,temp);
  124.                         }
  125.                 }
  126.                 if(n=='c')                                                                        //按下清除鍵
  127.                 {
  128.                         write_com(0x01);                                                //清屏
  129.                         a=b=0;
  130.                         fuhao=0;
  131.                         flag=0;
  132.                         i=0;
  133.                         j=0;
  134.                         dh=0;
  135.                         xsd=0;
  136.                         fh=0;                                                                //恢復(fù)初始化
  137.                 }
  138.         }
  139. }


  140. void key_scan(void)
  141. {         
  142.         unsigned char temp;
  143.         P1=0xfe;
  144.         if(P1!=0xfe)
  145.         {
  146.                    delay(200);
  147.                    if(P1!=0xfe)
  148.                    {
  149.                     temp=P1&0xf0;
  150.                             switch(temp)
  151.                     {
  152.                              case 0xe0:n='c';break;
  153.                              case 0xd0:n='0';break;
  154.                              case 0xb0:n='=';break;
  155.                              case 0x70:n='+';break;
  156.                     }
  157.                    }
  158.                    while(P1!=0xfe);
  159.         }
  160.         else
  161.         {
  162.         P1=0xfd;
  163.         if(P1!=0xfd)
  164.         {
  165.                    delay(200);
  166.                    if(P1!=0xfd)
  167.                    {
  168.                     temp=P1&0xf0;
  169.                             switch(temp)
  170.                     {
  171.                              case 0xe0:n='1';break;
  172.                              case 0xd0:n='2';break;
  173.                              case 0xb0:n='3';break;
  174.                              case 0x70:n='-';break;
  175.                     }
  176.                    }
  177.                    while(P1!=0xfd);
  178.         }
  179.         else{
  180.         P1=0xfb;
  181.         if(P1!=0xfb)
  182.         {
  183.                    delay(200);
  184.                    if(P1!=0xfb)
  185.                    {
  186.                     temp=P1&0xf0;
  187.                             switch(temp)
  188.                     {
  189.                              case 0xe0:n='4';break;
  190.                              case 0xd0:n='5';break;
  191.                              case 0xb0:n='6';break;
  192.                              case 0x70:n='*';break;
  193.                     }
  194.                    }
  195.                    while(P1!=0xfb);
  196.         }
  197.         else{
  198.         P1=0xf7;
  199.         if(P1!=0xf7)
  200.         {
  201.                    delay(200);
  202.                    if(P1!=0xf7)
  203.                    {
  204.                     temp=P1&0xf0;
  205.                             switch(temp)
  206.                     {
  207.                              case 0xe0:n='7';break;
  208.                              case 0xd0:n='8';break;
  209.                              case 0xb0:n='9';break;
  210.                              case 0x70:n='/';break;
  211.                     }
  212.                    }
  213.                    while(P1!=0xf7);
  214.         }
  215.         else n=17;
  216.         }}}       
  217. }

  218. void check()                                                                 //判斷LCD是否忙碌
  219. {
  220.         do
  221.         {
  222.                 P0=0xff;
  223.                 rs=0;
  224.                 rw=1;
  225.                 lcden=0;
  226.                 delay(100);
  227.                 lcden=1;
  228.          }while(busy==1);                                                //當(dāng)busy=1,即LCD忙時(shí),等待
  229. }
  230. void write_com(unsigned char com)     //寫顯示命令
  231. {
  232.         P0=com;
  233.         rs=0;
  234.         rw=0;
  235.         lcden=0;
  236.         check();
  237.         lcden=1;
  238. }
  239. void write_data(unsigned char date) //寫顯示數(shù)據(jù)
  240. {
  241.         P0=date;
  242.         rs=1;
  243.         rw=0;
  244.         lcden=0;
  245.         check();
  246.         lcden=1;
  247. }
  248. void init()                                                                 //初始化LCD
  249. {
  250.         write_com(0x38);                                                //16x2行顯示,5x7點(diǎn)陣,8位數(shù)據(jù)接口
  251.         write_com(0x0c);                                                //開顯示,光標(biāo)不顯示、不閃爍
  252.         write_com(0x06);                                                //光標(biāo)自增,畫面不動(dòng)
  253.         write_com(0x80);                                                //選擇第一行
  254.         write_com(0x01);                                                //清屏
  255. }
  256. void LCD_set_xy( unsigned char x, unsigned char y )//設(shè)置LCD顯示的位置
  257. {
  258.         unsigned char address;
  259.         if (y == 0)                                                                                                                                                   //y=0為第一行
  260.              address = 0x80 + x;                                 //x=0為一行的第一個(gè)
  261.         else                                                                                                                                                                                  //第二行
  262.              address =0xc0+ x;
  263.         write_com(address);                                        //設(shè)置數(shù)據(jù)指針位置
  264. }
  265. void LCD_dsp_char( unsigned x,unsigned char y,unsigned char dat)
  266. //單個(gè)字符顯示函數(shù)
  267. {
  268.         LCD_set_xy( x, y );                                         //設(shè)置顯示位置
  269.         write_data(dat);                                                //寫入待顯示數(shù)據(jù)
  270. }
  271. void LCD_dsp_string(unsigned char X,unsigned char Y,unsigned char *s)
  272. //字符串顯示函數(shù)
  273. {
  274.          LCD_set_xy( X, Y );
  275.          while (*s)                                                          //當(dāng)字符串未到達(dá)結(jié)尾('\0')時(shí),循環(huán)輸出單個(gè)字符
  276.          {
  277.                  write_data(*s);  
  278.                  s ++;                                                       //指向下一個(gè)字符
  279.          }
  280. }
復(fù)制代碼

所有資料51hei提供下載:
計(jì)算器.zip (1.24 MB, 下載次數(shù): 65)

評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:684220 發(fā)表于 2020-1-10 13:52 | 顯示全部樓層
開關(guān)都沒有實(shí)現(xiàn)!坑比!大家別下載!
回復(fù)

使用道具 舉報(bào)

ID:657661 發(fā)表于 2019-12-7 09:38 | 顯示全部樓層
請(qǐng)問還能實(shí)現(xiàn)十進(jìn)制和二進(jìn)制互相轉(zhuǎn)換嗎
回復(fù)

使用道具 舉報(bào)

ID:732342 發(fā)表于 2020-5-9 22:26 | 顯示全部樓層
挺好的,有參考價(jià)值  想問問樓主他的工作原理是是嗎
回復(fù)

使用道具 舉報(bào)

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

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表