简易答题计算器
1) 采用LCD1602或者LCD12864液晶屏显示。
2) 预计20道简易加、减、乘、除的运算式,随机显示其中一道运算式进行答题。
3) 使用4*4矩阵键盘输入答案并显示。
4) 判断答案正确与否
5) 发挥部分: 其他创新功能。
单片机答题计算器仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include <reg51.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "key.h"
- #include "delay.h"
- #include "LCD1602.h"
- typedef unsigned char u8;
- typedef unsigned short u16;
- void main()
- {
- u8 key_down = 0; //按键是否按下
- u16 key_cnt = 0; //持续按键计数
- char key_bak = -1; //上次扫描的按键信息
- char key = -1; //此次扫描的按键信息
- LCD_Initial();//LCD初始化
- new_q ();
-
- while(1)
- {
- key = ScanKey(); //扫描键盘
- if(key) //此次按键有效
- {
- if(!key_down) //未曾按下键
- {
- key_down = 1;
- PressKey(key);// 处理按键值
- }
- }
- else //无按键信息
- {
- key_down = 0; //按下键标志清零
- }
- key_bak = key; //保存此次按键值
- Render(); //刷新显示屏
- }
- }
复制代码- #include <reg51.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "LCD1602.h"
- #include "key.h"
- #include "delay.h"
- #include "LCD1602.h"
- typedef unsigned char u8;
- typedef unsigned short u16;
- void Update();
- enum {PLUS = 1, MINUS, TIME, DIVIDE};
- float input;
- //矩阵键盘排列
- char code key_map[4][4] =
- {
- '7', '8', '9', ' ', //键盘对应顺序表
- '4', '5', '6', ' ',
- '1', '2', '3', ' ',
- '0', 'C', '=', ' ',
- };
- u8 code disp_num[10] = {'0','1','2','3','4','5','6','7','8','9',};
- u8 disp_buf[16] = " "; //显示缓冲区
- u8 disp_buf2[16] = " "; //显示缓冲区
- //计算器操作
- float op_a = 0.0f; //操作数A,数码管显示的都是op_a
- float op_b = 0.0f; //操作数B
- u8 op_m = 0; //运算方式
- //辅助操作
- u8 z;
- void new_q ();//数学运算
- float Calc(float a, float b, u8 op)
- {
- float result = 0.0f;
- switch(op)
- {
- case 1: result = a + b; break;
- case 2: result = a - b; break;
- case 3: result = a * b; break;
- case 4: result = a / b; break;
- }
- return result;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //按下数字键
- void PressN(unsigned char num)
- {
- float tmp;
- tmp = input * 10 + num;
- input = tmp; //保存当前数据
-
- }
- //按下等于号,执行运算
- void PressEQ()
- {
- if (input == Calc(op_a, op_b, op_m)) // 计算
- {
- disp_buf[7]=' ';
- disp_buf[8]='Y';
- disp_buf[9]='E';
- disp_buf[10]='S';
- disp_buf[15]=' ';
- }
- else
- {
- disp_buf[7]='N';
- disp_buf[8]='O';
- }
- }
- //键盘扫描,无按键返回0
- char ScanKey()
- {
- char ret = 0;
- u8 key;
- u8 line, row;//line行,row列
- do
- {
- P2 = 0x0f; //扫描列
- key =P2;
- if(key == 0x0f) break; //没有键按下
- //有键按下
- delay(10); //延时消除抖动
- key = P2; //再次读端口值
- if(key == 0x0f) break; //没有键按下
- switch(key) //有键按下,记录行值
- {
- case 0x07: line = 0; break;
- case 0x0b: line = 1; break;
- case 0x0d: line = 2; break;
- case 0x0e: line = 3; break;
- }
- P2 = 0xf0; //扫描行
- key = P2;
- if(key == 0xf0) break; //没有键按下
- //有键按下
- delay(10); //延时消除抖动
- key = P2; //再次读端口值
- if(key == 0xf0) break; //没有键按下
- switch(key) //有键按下,记录列值
- {
- case 0x70: row = 3; break;
- case 0xb0: row = 2; break;
- case 0xd0: row = 1; break;
- case 0xe0: row = 0; break;
- }
- //查找对应的键值
- ret = key_map[line][row]; // 行列
- } while(0);
- return ret;
- }
- void clear ()
- {
- u8 i;
- input = 0.0f;
- z=0;
- for(i=0;i<16;i++)
- disp_buf[i] =' ';
- }
- //按键操作
- void PressKey(char key)
- {
- if((key!='=') && (key!=' ')) // 数字键检测 用于在屏上显示 输入的数字
- {
- disp_buf[z++]=key; //加载显示值
- }
- switch(key)
- {
- case '0': case '1': case '2': case '3': case '4': //0-9 属于数字键进行数字处理
- case '5': case '6': case '7': case '8': case '9':
- PressN(key - '0');
- break;
- case '=': PressEQ(); break;
- case ' ': new_q(); break;
-
- case 'C': clear(); break;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- //把浮点数值转换成字符串形式放到s中,返回小数点位置
- void Format(float val, char *s)
- {
- int dot = 0;
- char *p = NULL;//NULL 表示未定义内容
- //格式化字符串
- sprintf(s, "%-8g", val); //把ual 变成字符存放到S
- // 去掉后面的空格
- p = strchr(s, ' ');
- if(p) *p = 0;
- }
- //将当前操作数转换成字符形式放到显示缓冲区中
- void Update_question()
- {
- char idata s[16] = "";
- int len1,len2;
- int i;
- memset(disp_buf2, ' ', sizeof(disp_buf2)); //把DISP BUF 内存给' ' sizeof(disp_buf)测量disp_buf 容量
- //当前操作数转换成可显示的字符串
- Format(op_a, s); //计算小数点位置
- len1 = strlen(s); // 计算字符串长度
-
- //可显示的字符串逆序放到显示缓冲区中
- for(i=0; i<len1; i++)
- {
- disp_buf2[i]=s[i];
- }
- switch (op_m)
- {
- case 1:
- disp_buf2[len1] = '+';
- break;
- case 2:
- disp_buf2[len1] = '-';
- break;
- case 3:
- disp_buf2[len1] = '*';
- break;
- case 4:
- disp_buf2[len1] = '/';
- break;
- }
- //当前操作数转换成可显示的字符串
- Format(op_b, s); //计算小数点位置
- len2 = strlen(s); // 计算字符串长度
- for(i=len1+1; i<len2+len1+1; i++)
- {
- disp_buf2[i]=s[i-len1-1];
- }
- GotoXY(0,0);
- PrintLCD(disp_buf2);
- }
- //将显示缓冲区的内容显示到数码管上
- void Render()
- {
- GotoXY(0,1);
- PrintLCD(disp_buf);
- }
- int code question[20][3] =//题目
- {
- 2,3,PLUS,//+
- 6,8,PLUS,//+
- 36,24,PLUS,//+
- 32,2,PLUS,//+
- 16,20,PLUS,//+
- 20,15,MINUS,//-
- 40,5,MINUS,//-
- 10,5,MINUS,
- 30,6,MINUS,//-
- 50,25,MINUS,//-
- 12,2,TIME,//*
- 6,5,TIME,//*
- 7,7,TIME,//*
- 4,9,TIME,//*
- 12,8,TIME,//*
- 10,2,DIVIDE,//÷
- 16,4,DIVIDE,//÷
- 50,25,DIVIDE,//÷
- 99,33,DIVIDE,//÷
- 64,16,DIVIDE,//÷
- };
- void new_q ()
- {
- char i = rand()%20;
- op_a = question[i][0];
- op_b = question[i][1];
- op_m = question[i][2];
- Update_question();
- clear();
- }
复制代码
所有资料51hei提供下载:
基于单片机设计的答题计算器.rar
(217.94 KB, 下载次数: 27)
|