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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3511|回復: 1
打印 上一主題 下一主題
收起左側

單片機計算器出現問題

[復制鏈接]
跳轉到指定樓層
樓主
請各位大神看一下我的仿真電路應該沒問題吧  仿真的這個計算器按鍵不起作用 請各位大神幫我分析一下原因
  1. #include <reg51.h>

  2. #define LCD1602_DB   P0

  3. sbit LCD1602_RS = P1^0;
  4. sbit LCD1602_RW = P1^1;
  5. sbit LCD1602_E  = P1^5;

  6. void LcdWaitReady()  //等待液晶準備好
  7. {
  8.     unsigned char sta;

  9.     LCD1602_DB = 0xFF;
  10.     LCD1602_RS = 0;
  11.     LCD1602_RW = 1;
  12.     do
  13.     {
  14.         LCD1602_E = 1;
  15.         sta = LCD1602_DB; //讀取狀態字
  16.         LCD1602_E = 0;
  17.     } while (sta & 0x80); //bit7等于1表示液晶正忙,重復檢測直到其等于0為止
  18. }
  19. void LcdWriteCmd(unsigned char cmd)  //寫入命令函數
  20. {
  21.     LcdWaitReady();
  22.     LCD1602_RS = 0;
  23. LCD1602_RW = 0;
  24. LCD1602_DB = cmd;
  25.     LCD1602_E  = 1;
  26.     LCD1602_E  = 0;
  27. }
  28. void LcdWriteDat(unsigned char dat)  //寫入數據函數
  29. {
  30.     LcdWaitReady();
  31.     LCD1602_RS = 1;
  32.     LCD1602_RW = 0;
  33.     LCD1602_DB = dat;
  34.     LCD1602_E  = 1;
  35.     LCD1602_E  = 0;
  36. }
  37. void LcdShowStr(unsigned char x, unsigned char y, const unsigned char *str)  //顯示字符串,屏幕起始坐標(x,y),字符串指針str
  38. {
  39.     unsigned char addr;

  40.     //由輸入的顯示坐標計算顯示RAM的地址
  41.     if (y == 0)
  42.         addr = 0x00 + x; //第一行字符地址從0x00起始
  43.     else
  44.         addr = 0x40 + x; //第二行字符地址從0x40起始

  45.     //由起始顯示RAM地址連續寫入字符串
  46.     LcdWriteCmd(addr | 0x80); //寫入起始地址
  47.     while (*str != '\0')      //連續寫入字符串數據,直到檢測到結束符
  48.     {
  49.         LcdWriteDat(*str);
  50.         str++;
  51.     }
  52. }
  53. void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len)  //區域清除,清除從(x,y)坐標起始的len個字符位
  54. {
  55.     unsigned char addr;

  56.     //由輸入的顯示坐標計算顯示RAM的地址
  57.     if (y == 0)
  58.         addr = 0x00 + x; //第一行字符地址從0x00起始
  59.     else
  60.         addr = 0x40 + x; //第二行字符地址從0x40起始

  61.     //由起始顯示RAM地址連續寫入字符串
  62.     LcdWriteCmd(addr | 0x80); //寫入起始地址
  63.     while (len--)             //連續寫入空格
  64.     {
  65.         LcdWriteDat(' ');
  66.     }
  67. }
  68. void LcdFullClear()
  69. {
  70.     LcdWriteCmd(0x01);  //清屏
  71. }
  72. void LcdInit()  //液晶初始化函數
  73. {
  74.     LcdWriteCmd(0x38);  //16*2顯示,5*7點陣,8位數據接口
  75.     LcdWriteCmd(0x0C);  //顯示器開,光標關閉
  76.     LcdWriteCmd(0x06);  //文字不動,地址自動+1
  77.     LcdWriteCmd(0x01);  //清屏
  78.     LcdShowStr(15, 1, "0");
  79. }

  80. /***********************keyboard.c文件程序源代碼************************/

  81. #include <reg51.h>

  82. sbit KEY_IN_1  = P2^4;  //矩陣按鍵的掃描輸入引腳1
  83. sbit KEY_IN_2  = P2^5;  //矩陣按鍵的掃描輸入引腳2
  84. sbit KEY_IN_3  = P2^6;  //矩陣按鍵的掃描輸入引腳3
  85. sbit KEY_IN_4  = P2^7;  //矩陣按鍵的掃描輸入引腳4
  86. sbit KEY_OUT_1 = P2^3;  //矩陣按鍵的掃描輸出引腳1
  87. sbit KEY_OUT_2 = P2^2;  //矩陣按鍵的掃描輸出引腳2
  88. sbit KEY_OUT_3 = P2^1;  //矩陣按鍵的掃描輸出引腳3
  89. sbit KEY_OUT_4 = P2^0;  //矩陣按鍵的掃描輸出引腳4

  90. const unsigned char code KeyCodeMap[4][4] = { //矩陣按鍵編號到PC標準鍵盤鍵碼的映射表
  91.     { '1',  '2',  '3', 0x26 }, //數字鍵1、數字鍵2、數字鍵3、向上鍵
  92.     { '4',  '5',  '6', 0x25 }, //數字鍵4、數字鍵5、數字鍵6、向左鍵
  93.     { '7',  '8',  '9', 0x28 }, //數字鍵7、數字鍵8、數字鍵9、向下鍵
  94.     { '0', 0x1B, 0x0D, 0x27 }  //數字鍵0、ESC鍵、  回車鍵、 向右鍵
  95. };
  96. unsigned char pdata KeySta[4][4] = {  //全部矩陣按鍵的當前狀態
  97.     {1, 1, 1, 1},
  98.     {1, 1, 1, 1},
  99.     {1, 1, 1, 1},
  100.     {1, 1, 1, 1}
  101. };
  102. unsigned char step = 0;  //操作步驟
  103. unsigned char oprt = 0;  //運算類型
  104. signed long num1 = 0;    //操作數1
  105. signed long num2 = 0;    //操作數2
  106. signed long result = 0;  //運算結果

  107. extern void LcdFullClear();
  108. extern void LcdShowStr(unsigned char x, unsigned char y, const unsigned char *str);
  109. extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);

  110. unsigned char NumToString(unsigned char *str, signed long num) //整型數轉換為字符串,字符串指針str,待轉換數num,返回值為字符串長度
  111. {
  112.     unsigned char i, len;
  113.     unsigned char buf[12];

  114.     if (num < 0)  //如果為負數,則首先輸出符號到指針上,并取其絕對值
  115.     {
  116.         *str = '-';
  117.         str++;
  118.         num = -num;
  119.     }
  120.     i = 0;        //先轉換為低位在前的十進制數組
  121.     do {
  122.         buf[ i] = num % 10;
  123.         num /= 10;
  124.         i++;
  125.     } while (num > 0);
  126.     len = i;       //i最后的值就是有效字符的個數
  127.     while (i > 0)  //然后將數組值轉換為ASCII碼反向拷貝到接收指針上
  128.     {
  129.         i--;
  130.         *str = buf[ i] + '0';
  131.         str++;
  132.     }

  133.     return len;   //返回轉換后的字符串長度
  134. }
  135. void ShowOprt(unsigned char y, unsigned char type) //顯示運算符,顯示位置y,運算符類型type
  136. {
  137.     switch (type)
  138.     {
  139.         case 0: LcdShowStr(0, y, "+"); break;
  140.         case 1: LcdShowStr(0, y, "-"); break;
  141.         case 2: LcdShowStr(0, y, "*"); break;
  142.         case 3: LcdShowStr(0, y, "/"); break;
  143.         default: break;
  144.     }
  145. }
  146. void Reset()  //計算器復位函數
  147. {
  148.     num1 = 0;
  149.     num2 = 0;
  150.     step = 0;
  151.     LcdFullClear();
  152. }
  153. void NumKeyAction(unsigned char n) //數字鍵動作函數,按鍵輸入的數值n
  154. {
  155.     unsigned char len;
  156.     unsigned char str[12];

  157.     if (step > 1)  //如計算已完成,則重新開始新的計算
  158.     {
  159.         Reset();
  160.     }
  161.     if (step == 0)  //輸入第一操作數
  162.     {
  163.         num1 = num1*10 + n;           //輸入數值累加到原操作數上
  164.         len = NumToString(str, num1); //新數值轉換為字符串
  165.         LcdShowStr(16-len, 1, str);   //顯示到液晶第二行上
  166.     }
  167.     else            //輸入第二操作數
  168.     {
  169.         num2 = num2*10 + n;
  170.         len = NumToString(str, num2);
  171.         LcdShowStr(16-len, 1, str);
  172.     }
  173. }
  174. void OprtKeyAction(unsigned char type) //運算符按鍵動作函數,運算符類型type
  175. {
  176.     unsigned char len;
  177.     unsigned char str[12];

  178.     if (step == 0)  //第二操作數尚未輸入時響應,即不支持連續操作
  179.     {
  180.         len = NumToString(str, num1); //第一操作數轉換為字符串
  181.         LcdAreaClear(0, 0, 16-len);   //清除第一行左邊的字符位
  182.         LcdShowStr(16-len, 0, str);   //字符串靠右顯示在第一行
  183.         ShowOprt(1, type);            //在第二行顯示操作符
  184.         LcdAreaClear(1, 1, 14);       //清除第二行中間的字符位
  185.         LcdShowStr(15, 1, "0");       //在第二行最右端顯示0
  186.         oprt = type;                  //記錄操作類型
  187.         step = 1;
  188.     }
  189. }
  190. void GetResult() //計算結果
  191. {
  192.     unsigned char len;
  193.     unsigned char str[12];

  194.     if (step == 1) //第二操作數已輸入時才執行計算
  195.     {
  196.         step = 2;
  197.         switch (oprt)  //根據運算符類型計算結果,未考慮溢出問題
  198.         {
  199.             case 0: result = num1 + num2; break;
  200.             case 1: result = num1 - num2; break;
  201.             case 2: result = num1 * num2; break;
  202.             case 3: result = num1 / num2; break;
  203.             default: break;
  204.         }
  205.         len = NumToString(str, num2);   //原第二操作數和運算符顯示在第一行
  206.         ShowOprt(0, oprt);
  207.         LcdAreaClear(1, 0, 16-1-len);
  208.         LcdShowStr(16-len, 0, str);
  209.         len = NumToString(str, result); //計算結果和等號顯示在第二行
  210.         LcdShowStr(0, 1, "=");
  211.         LcdAreaClear(1, 1, 16-1-len);
  212.         LcdShowStr(16-len, 1, str);
  213.     }
  214. }

  215. void KeyAction(unsigned char keycode)  //按鍵動作函數,根據鍵碼執行相應動作
  216. {
  217.     if  ((keycode>='0') && (keycode<='9'))  //顯示輸入的字符
  218.     {
  219.         NumKeyAction(keycode - '0');
  220.     }
  221.     else if (keycode == 0x26)  //向上鍵,+
  222.     {
  223.         OprtKeyAction(0);
  224.     }
  225.     else if (keycode == 0x28)  //向下鍵,-
  226.     {
  227.         OprtKeyAction(1);
  228.     }
  229.     else if (keycode == 0x25)  //向左鍵,*
  230.     {
  231.         OprtKeyAction(2);
  232.     }
  233.     else if (keycode == 0x27)  //向右鍵,÷
  234.     {
  235.         OprtKeyAction(3);
  236.     }
  237.     else if (keycode == 0x0D)  //回車鍵,計算結果
  238.     {
  239.         GetResult();
  240.     }
  241.     else if (keycode == 0x1B)  //Esc鍵,清除
  242.     {
  243.         Reset();
  244.         LcdShowStr(15, 1, "0");
  245.     }
  246. }
  247. void KeyDrive()  //按鍵動作驅動函數
  248. {
  249.     unsigned char i, j;
  250.     static unsigned char pdata backup[4][4] = {  //按鍵值備份,保存前一次的值
  251.         {1, 1, 1, 1},
  252.         {1, 1, 1, 1},
  253.         {1, 1, 1, 1},
  254.         {1, 1, 1, 1}
  255.     };

  256.     for (i=0; i<4; i++)  //循環掃描4*4的矩陣按鍵
  257.     {
  258.         for (j=0; j<4; j++)
  259.         {
  260.             if (backup[ i][j] != KeySta[ i][j])  //檢測按鍵動作
  261.             {
  262.                 if (backup[ i][j] != 0)  //按鍵按下時執行動作
  263.                 {
  264.                     KeyAction(KeyCodeMap[ i][j]);  //調用按鍵動作函數
  265.                 }
  266.                 backup[ i][j] = KeySta[ i][j];
  267.             }
  268.         }
  269.     }
  270. }
  271. void KeyScan()  //按鍵掃描函數
  272. {
  273.     unsigned char i;
  274.     static unsigned char keyout = 0;  //矩陣按鍵掃描輸出計數器
  275.     static unsigned char keybuf[4][4] = {  //按鍵掃描緩沖區,保存一段時間內的掃描值
  276.         {0xFF, 0xFF, 0xFF, 0xFF},
  277.         {0xFF, 0xFF, 0xFF, 0xFF},
  278.         {0xFF, 0xFF, 0xFF, 0xFF},
  279.         {0xFF, 0xFF, 0xFF, 0xFF}
  280.     };

  281.     //將一行的4個按鍵值移入緩沖區
  282.     keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
  283.     keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
  284.     keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
  285.     keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;

  286.     //消抖后更新按鍵狀態
  287.     for (i=0; i<4; i++)  //每行4個按鍵,所以循環4次
  288.     {
  289.         if ((keybuf[keyout][ i] & 0x0F) == 0x00)
  290.         {   //連續4次掃描值為0,即16ms(4*4ms)內都只檢測到按下狀態時,可認為按鍵已按下
  291.             KeySta[keyout][ i] = 0;
  292.         }
  293.         else if ((keybuf[keyout][ i] & 0x0F) == 0x0F)
  294.         {   //連續4次掃描值為1,即16ms(4*4ms)內都只檢測到彈起狀態時,可認為按鍵已彈起
  295.             KeySta[keyout][ i] = 1;
  296.         }
  297.     }

  298.     //執行下一次的掃描輸出
  299.     keyout++;
  300.     keyout &= 0x03;
  301.     switch (keyout)
  302.     {
  303.         case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
  304.         case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
  305.         case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
  306.         case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
  307.         default: break;
  308.     }
  309. }

  310. /*************************main.c文件程序源代碼**************************/

  311. #include <reg51.h>

  312. void ConfigTimer0(unsigned int ms);
  313. extern void KeyScan();
  314. extern void KeyDrive();
  315. extern void LcdInit();

  316. unsigned char T0RH = 0;  //T0重載值的高字節
  317. unsigned char T0RL = 0;  //T0重載值的低字節

  318. void main(void)
  319. {
  320.     EA = 1;          //開總中斷
  321.     ConfigTimer0(1); //配置T0定時1ms
  322.     LcdInit();       //初始化液晶

  323.     while(1)
  324.     {
  325.         KeyDrive();
  326.     }
  327. }

  328. void ConfigTimer0(unsigned int ms)  //T0配置函數
  329. {
  330.     unsigned long tmp;

  331.     tmp = 11059200 / 12;      //定時器計數頻率
  332.     tmp = (tmp * ms) / 1000;  //計算所需的計數值
  333.     tmp = 65536 - tmp;        //計算定時器重載值
  334.     tmp = tmp + 18;           //修正中斷響應延時造成的誤差

  335.     T0RH = (unsigned char)(tmp >> 8);  //定時器重載值拆分為高低字節
  336.     T0RL = (unsigned char)tmp;
  337.     TMOD &= 0xF0;   //清零T0的控制位
  338.     TMOD |= 0x01;   //配置T0為模式1
  339.     TH0 = T0RH;     //加載T0重載值
  340.     TL0 = T0RL;
  341.     ET0 = 1;        //使能T0中斷
  342.     TR0 = 1;        //啟動T0
  343. }

  344. void InterruptTimer0() interrupt 1  //T0中斷服務函數
  345. {
  346.     TH0 = T0RH;  //定時器重新加載重載值
  347.     TL0 = T0RL;
  348.     KeyScan();   //按鍵掃描
  349. }
復制代碼


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:82765 發表于 2017-8-16 15:25 | 只看該作者
提示: 作者被禁止或刪除 內容自動屏蔽
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 黄色精品视频网站 | 精久久| 成人精品免费 | 久热国产精品视频 | 成人自拍视频 | 久热精品视频 | 888久久久 | 欧美国产视频 | 久久精品无码一区二区三区 | 亚洲一区高清 | 丁香五月缴情综合网 | 一区二区三区视频在线 | 精品日本中文字幕 | 999久久久久久久 | 国产精品一区二区不卡 | 久久国产一区二区三区 | 亚洲精品久久久久中文字幕二区 | 狠狠干美女 | 国产99视频精品免费视频7 | 精品乱码一区二区三四区视频 | 久久久久久91 | 狠狠做六月爱婷婷综合aⅴ 国产精品视频网 | 欧美成人a | 欧美一区二区免费电影 | 在线播放亚洲 | 精品国产乱码久久久久久a丨 | 中文字幕一区二区三 | 久久99精品久久久久久青青日本 | 色网站入口 | 在线看无码的免费网站 | 色综合久久88色综合天天 | 亚洲最大的成人网 | 国产亚洲精品成人av久久ww | 日韩欧美在线观看 | 一区二区免费看 | 欧美精品一区二区三 | 亚洲导航深夜福利涩涩屋 | 中文字幕一区二区三区四区五区 | 久久国产精品一区二区三区 | 精品一区在线看 | 蜜桃精品视频在线 |