找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2507|回复: 0
收起左侧

c51单片机答题计算器Proteus仿真+程序设计

[复制链接]
ID:512142 发表于 2019-4-15 07:48 | 显示全部楼层 |阅读模式
简易答题计算器
1)    采用LCD1602或者LCD12864液晶屏显示。
2)    预计20道简易加、减、乘、除的运算式,随机显示其中一道运算式进行答题。
3)    使用4*4矩阵键盘输入答案并显示。
4)    判断答案正确与否
5)    发挥部分: 其他创新功能。


单片机答题计算器仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
0.png

单片机源程序如下:
  1. #include <reg51.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include "key.h"
  6. #include "delay.h"
  7. #include "LCD1602.h"
  8. typedef unsigned char        u8;
  9. typedef unsigned short        u16;
  10. void  main()
  11. {
  12.         u8 key_down = 0;        //按键是否按下
  13.         u16 key_cnt = 0;        //持续按键计数
  14.         char key_bak = -1;        //上次扫描的按键信息
  15.         char key = -1;        //此次扫描的按键信息
  16.         LCD_Initial();//LCD初始化
  17.         new_q ();
  18.        
  19.         while(1)
  20.         {

  21.                 key = ScanKey();        //扫描键盘
  22.                 if(key)        //此次按键有效
  23.                 {
  24.                         if(!key_down)        //未曾按下键
  25.                         {
  26.                                 key_down = 1;
  27.                                 PressKey(key);// 处理按键值
  28.                         }
  29.                 }
  30.                 else        //无按键信息
  31.                 {
  32.                  key_down = 0;        //按下键标志清零
  33.                 }
  34.                 key_bak = key;        //保存此次按键值

  35.                 Render();        //刷新显示屏
  36.         }

  37. }
复制代码
  1. #include <reg51.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include "LCD1602.h"
  6. #include "key.h"
  7. #include "delay.h"
  8. #include "LCD1602.h"
  9. typedef unsigned char        u8;
  10. typedef unsigned short        u16;
  11. void Update();
  12. enum {PLUS = 1, MINUS, TIME, DIVIDE};

  13. float input;

  14. //矩阵键盘排列
  15. char code key_map[4][4] =
  16. {
  17.         '7', '8', '9', ' ',  //键盘对应顺序表
  18.         '4', '5', '6', ' ',
  19.         '1', '2', '3', ' ',
  20.         '0', 'C', '=', ' ',
  21. };

  22. u8 code disp_num[10] = {'0','1','2','3','4','5','6','7','8','9',};
  23. u8   disp_buf[16] = "                ";        //显示缓冲区
  24. u8   disp_buf2[16] = "                ";        //显示缓冲区
  25. //计算器操作
  26. float op_a = 0.0f;        //操作数A,数码管显示的都是op_a
  27. float op_b = 0.0f;        //操作数B
  28. u8 op_m = 0;        //运算方式

  29. //辅助操作
  30. u8 z;
  31. void new_q ();//数学运算


  32. float Calc(float a, float b, u8 op)
  33. {
  34.         float result = 0.0f;
  35.         switch(op)
  36.         {
  37.                 case 1: result = a + b; break;
  38.                 case 2: result = a - b; break;
  39.                 case 3: result = a * b; break;
  40.                 case 4: result = a / b;        break;
  41.         }

  42.         return result;
  43. }

  44. ////////////////////////////////////////////////////////////////////////////////

  45. //按下数字键
  46. void PressN(unsigned char  num)
  47. {
  48.         float tmp;
  49.         tmp = input * 10 + num;
  50.         input = tmp;        //保存当前数据
  51.        
  52. }



  53. //按下等于号,执行运算
  54. void PressEQ()
  55. {
  56.         if (input == Calc(op_a, op_b, op_m))        // 计算
  57.          {
  58.                  disp_buf[7]=' ';
  59.                  disp_buf[8]='Y';
  60.                  disp_buf[9]='E';
  61.                  disp_buf[10]='S';
  62.                  disp_buf[15]=' ';
  63.          }
  64.          else
  65.          {
  66.                  disp_buf[7]='N';
  67.                  disp_buf[8]='O';

  68.         }
  69. }


  70. //键盘扫描,无按键返回0
  71. char ScanKey()
  72. {
  73.         char ret = 0;
  74.         u8 key;
  75.         u8 line, row;//line行,row列

  76.         do
  77.         {
  78.                 P2 = 0x0f;        //扫描列
  79.                 key =P2;
  80.                 if(key == 0x0f) break;        //没有键按下
  81.                 //有键按下
  82.                 delay(10);        //延时消除抖动
  83.                 key = P2;        //再次读端口值
  84.                 if(key == 0x0f) break;        //没有键按下
  85.                 switch(key)        //有键按下,记录行值
  86.                 {
  87.                         case 0x07: line = 0; break;
  88.                         case 0x0b: line = 1; break;
  89.                         case 0x0d: line = 2; break;
  90.                         case 0x0e: line = 3; break;
  91.                 }

  92.                 P2 = 0xf0;        //扫描行
  93.                 key = P2;
  94.                 if(key == 0xf0) break;        //没有键按下
  95.                 //有键按下
  96.                 delay(10);        //延时消除抖动
  97.                 key = P2;        //再次读端口值
  98.                 if(key == 0xf0) break;        //没有键按下
  99.                 switch(key)        //有键按下,记录列值
  100.                 {
  101.                         case 0x70: row = 3; break;
  102.                         case 0xb0: row = 2; break;
  103.                         case 0xd0: row = 1; break;
  104.                         case 0xe0: row = 0; break;
  105.                 }
  106.                 //查找对应的键值
  107.                 ret = key_map[line][row];                        // 行列
  108.         } while(0);
  109.         return ret;
  110. }
  111. void clear ()
  112. {
  113.          u8 i;
  114.         input = 0.0f;
  115.         z=0;
  116.         for(i=0;i<16;i++)
  117.                 disp_buf[i] =' ';
  118. }


  119. //按键操作
  120. void PressKey(char key)
  121. {

  122.         if((key!='=') && (key!=' '))        // 数字键检测 用于在屏上显示 输入的数字
  123.         {
  124.         disp_buf[z++]=key; //加载显示值
  125.         }
  126.         switch(key)
  127.         {
  128.                 case '0': case '1': case '2': case '3': case '4':        //0-9 属于数字键进行数字处理
  129.                 case '5': case '6': case '7': case '8': case '9':
  130.                 PressN(key - '0');
  131.                 break;

  132.                 case '=': PressEQ();  break;
  133.                 case ' ': new_q();  break;
  134.                                                                                                                                                                                                                     
  135.                 case 'C': clear();  break;
  136.         }
  137. }



  138. ////////////////////////////////////////////////////////////////////////////////
  139. //把浮点数值转换成字符串形式放到s中,返回小数点位置
  140. void Format(float val, char *s)
  141. {
  142.         int dot = 0;
  143.         char *p = NULL;//NULL 表示未定义内容

  144.         //格式化字符串
  145.         sprintf(s, "%-8g", val);        //把ual 变成字符存放到S

  146. //        去掉后面的空格
  147.         p = strchr(s, ' ');
  148.         if(p) *p = 0;
  149. }


  150. //将当前操作数转换成字符形式放到显示缓冲区中
  151. void Update_question()
  152. {
  153.                 char idata s[16] = "";
  154.                 int len1,len2;
  155.                 int i;
  156.                  memset(disp_buf2, ' ', sizeof(disp_buf2));                //把DISP BUF 内存给' '                        sizeof(disp_buf)测量disp_buf 容量
  157.                 //当前操作数转换成可显示的字符串
  158.                 Format(op_a, s);        //计算小数点位置
  159.                 len1 = strlen(s);                        // 计算字符串长度
  160.                
  161.                 //可显示的字符串逆序放到显示缓冲区中
  162.                 for(i=0; i<len1; i++)
  163.                 {
  164.                  disp_buf2[i]=s[i];
  165.                 }
  166.                 switch (op_m)
  167.                 {
  168.                         case 1:
  169.                                 disp_buf2[len1] = '+';
  170.                         break;
  171.                         case 2:
  172.                                 disp_buf2[len1] = '-';
  173.                         break;
  174.                         case 3:
  175.                                 disp_buf2[len1] = '*';
  176.                         break;
  177.                         case 4:
  178.                                 disp_buf2[len1] = '/';
  179.                         break;
  180.                 }
  181.                 //当前操作数转换成可显示的字符串
  182.                 Format(op_b, s);        //计算小数点位置
  183.                 len2 = strlen(s);                        // 计算字符串长度

  184.                 for(i=len1+1; i<len2+len1+1; i++)
  185.                 {
  186.                  disp_buf2[i]=s[i-len1-1];
  187.                 }
  188.                 GotoXY(0,0);
  189.                 PrintLCD(disp_buf2);
  190. }

  191. //将显示缓冲区的内容显示到数码管上
  192. void Render()
  193. {
  194.         GotoXY(0,1);
  195.         PrintLCD(disp_buf);
  196. }

  197. int code question[20][3] =//题目
  198. {
  199.         2,3,PLUS,//+
  200.         6,8,PLUS,//+
  201.         36,24,PLUS,//+
  202.         32,2,PLUS,//+
  203.         16,20,PLUS,//+
  204.         20,15,MINUS,//-
  205.         40,5,MINUS,//-
  206.         10,5,MINUS,
  207.         30,6,MINUS,//-
  208.         50,25,MINUS,//-
  209.         12,2,TIME,//*
  210.         6,5,TIME,//*
  211.         7,7,TIME,//*
  212.         4,9,TIME,//*
  213.         12,8,TIME,//*
  214.         10,2,DIVIDE,//÷
  215.         16,4,DIVIDE,//÷
  216.         50,25,DIVIDE,//÷
  217.         99,33,DIVIDE,//÷
  218.         64,16,DIVIDE,//÷
  219. };

  220. void new_q ()
  221. {
  222.         char i = rand()%20;
  223.         op_a = question[i][0];
  224.         op_b = question[i][1];
  225.         op_m = question[i][2];
  226.         Update_question();

  227.         clear();
  228. }
复制代码

0.png

所有资料51hei提供下载:
基于单片机设计的答题计算器.rar (217.94 KB, 下载次数: 27)

评分

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

查看全部评分

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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