一个简单的加减乘除计算器/*注意上面头文件"bsp_GOG1.h"包含一个可选宏定义
若需使用扩展板请增加全局宏定义 _GOG1Plus
定义方式
菜单 Project->Options for Target->C51->Define
在此处填入 “_GOG1Plus”
在此代码完全兼容,第三次课的矩阵按键程序,在此感谢魏同学的帮助 */
/*
计算器功能实现:4位数字的加,减,乘法,除法没有做商的小数部分
1.对输入运算数的有效性检查,即超过9999时,显示错误;
2,用LED--》D3来指示系统的正常运行状态
3,运算的结果超过9999时,提示错误显示;
4,当系统运行错误时,或者显示乱码时,按A键清除数码管显示;
5,除法运算时,的二个运算数为0时,提示错误显示
6, 运算表达式不完整时,报错:
(1)无数 * 第二个数 = 报错
(2)第一个数 * 无数 = 报错
(3)直接按等号,报错
7,D3 LED灯实际是隔1ms 闪烁一次,
*/
/*矩阵按键 功能定义:
#define ADD 15 //'#':加法 S15
#define SUB 12 //'C':减法 S12
#define MUL 14 //'*':乘法 S13
#define DIV 11 //'B':除法 S8
#define EQU 13 //'D':等于 S16
#define CLE 10 //'A':清除 S4
仿真图:
单片机源程序如下:
- #include <REG52.H> //51单片机标准寄存器声明头文件
- #include "bsp_GOG1.h" //这个头文件用于映射GOG1学习板载硬件接口
- /*计算器的运算状态定义:*/
- #define NoKey 0xaa //没有按键按下的状态
- #define ErrKey 0xff //错误的按键状态/干扰
- #define DpyErr 0x0e //错误显示状态(码表数组第14个元素:'E')
- #define DpyCle 0x10 //清屏(码表数组第16个元素:0xff 关闭数码管)
- #define InCount 0xf0 //有运算符输入状态
- #define InErrEqu 0x0f //有等号输入状态
- #define NoCountFlag 0xa5 //没有运算符的状态
- /*矩阵按键 功能定义: */
- #define ADD 15 //'#':加法 S15
- #define SUB 12 //'C':减法 S12
- #define MUL 14 //'*':乘法 S13
- #define DIV 11 //'B':除法 S8
- #define EQU 13 //'D':等于 S16
- #define CLE 10 //'A':清除 S4
- /*相关子函数的声明:*/
- void delayms(unsigned int ms); //延时函数
- void SegDisplay(unsigned char casebit); //数码管显示函数
- unsigned char ReadKeyPad(void); //读取矩阵键盘函数
- void Timer0Init(void); //定时器0初始化函数
- unsigned char CheckInput(void); //计算器检查输入状态函数
- void DatUnpack(unsigned int dat); //计算器数据拆分函数
- bit CheckNum(unsigned int dat); //计算器数据有效性检查函数
- void WarmDpy(unsigned char err); //计算器错误显示函数
- void ComputeState(unsigned char dat); //计算器计算过程函数
-
- //数码管段码表 共阳 17个元素: 0~F & 0xff
- unsigned char code SegCode[17]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
- 0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff};
- unsigned int Ans; //运算结果
-
- bit AnsFlag=0; //运算结果存在标志
- bit InFlag1=0; //输入有效数字1标志
- bit InFlag2=0; //输入有效数字2标志
- unsigned char CountFlag; //运算符
- unsigned int temp1=0,temp2=0;//输入的2个运算的数字
- unsigned char DisBuff[4]={DpyCle,DpyCle,DpyCle,DpyCle};//数码管显示缓存
- /*******************************************************************************
- * @brief mian (简介)
- * @param 无 (参数)
- * @retval 无 (返回值)
- ******************************************************************************/
- void main(void) //程序从这里开始
- {
- unsigned char in; //保存单个按键值的变量
-
- CountFlag=NoCountFlag; //运算符初始状态
- Timer0Init(); //定时器0初始化
- while(1)
- {
- in=CheckInput();
- while(in == NoKey) in=CheckInput(); //没有按键按下,在此等待
- if(in !=ErrKey) //按键有效
- {
- ComputeState(in);
- }
-
- else WarmDpy(DpyErr); //按键无效,报错 'E'
-
- }
- }
- /*******************************************************************************
- * @brief ComputeState: 计算过程程序
- * @param unsigned char dat
- * @retval 无
- *******************************************************************************/
- void ComputeState(unsigned char dat)
- {
- unsigned int num; //保存运算操作数的变量
- if(AnsFlag == 1) //判断上一次运算结果完成标志
- {
- WarmDpy(DpyCle); //清屏
- AnsFlag=0; //清除有效运算完成标志
- }
- if((dat !=InCount)&(dat !=InErrEqu)&(dat <10)) //按下的键为数字
- {
-
- if(CountFlag == NoCountFlag) //没有运算符存在,保存第一个数
- {
- num = temp1;
- num *= 10; //输入的数字依次进高位
- num += dat;
- if( CheckNum(num)==1 ) //判断数据有效性
- { //有效在数字范围
- temp1 = num; //保存第一个数字
- InFlag1 = 1; //输入有效数字1标志
- DatUnpack(temp1); //拆分数据,更新显示缓存
- }
- else WarmDpy(DpyErr); //超出范围报错
- }
- else //运算符存在 ,保存第二个数
- {
- num = temp2;
- num *= 10;
- num += dat;
- if(CheckNum(num)==1)
- {
- temp2 = num;
- InFlag2 = 1; //输入有效数字2标志
- WarmDpy(DpyCle); //清除第一个数的显示,消除'余晖'
- DatUnpack(temp2);//更新显示缓存
- }
- else WarmDpy(DpyErr);
- }
- }
- else //按下的键为非数字(4则运算符被保存,这里考虑 清除键和 错误等号)
- {
- if(CLE == dat) //按下的为清除键
- {
- CountFlag = NoCountFlag; //清除运算符
- InFlag1 =0; //清除输入有效数字1标志
- InFlag2 =0; //清除输入有效数字2标志
- AnsFlag=0; //清除运算结果存在标志
- temp1=0,temp2=0; //清除输入的2个运算数
- WarmDpy(DpyCle); //清屏
- Ans=0; //清除上一次运算结果
- }
-
- if(InErrEqu == dat) //运算表达式不完整时,按下等号的情况
- WarmDpy(DpyErr); //报错 'E'
- }
- }
-
- /*******************************************************************************
- * @brief ReadKeyPad 用于读取矩阵键盘键值
- * @param 无
- * @retval 矩阵键盘键值
- * @note 键盘键值设置请修改case分支临时变量b的赋值
- 0xff 作为错误代码,表示读取出错
- ******************************************************************************/
- unsigned char ReadKeyPad(void)
- {
- unsigned char a,c,b=NoKey; //b 初始值为无按键的状态
- KeyPad = 0x0f; //初始状态,行号(P3^0~P3^3)高电平,列号(P3^4~P3^7)低电平
- if(KeyPad != 0x0f)
- {
- delayms(20); //按键消抖动(延时实现)
- if(KeyPad != 0x0f) //按键被按下,初始状态改变
- {
- a = KeyPad; //读取矩阵键盘的行号
- }
- KeyPad = 0xf0; //初始状态反转
- c = KeyPad; //读取矩阵键盘的列号
- a |= c; //按位'或',通过行号,列号唯一确定矩阵按键值
- switch (a) {
- case 0xee:
- b = 1; //S1
- break;
- case 0xed:
- b = 4; //S5
- break;
- case 0xeb:
- b = 7; //S9
- break;
- case 0xe7:
- b = MUL; //S13'MUL'
- break;
- case 0xde:
- b = 2; //S2
- break;
- case 0xdd:
- b = 5; //S6
- break;
- case 0xdb:
- b = 8; //S10
- break;
- case 0xd7:
- b = 0; //S14
- break;
- case 0xbe:
- b = 3; //S3
- break;
- case 0xbd:
- b = 6; //S7
- break;
- case 0xbb:
- b = 9; //S11
- break;
- case 0xb7:
- b = ADD; //S15 'ADD'
- break;
- case 0x7e:
- b = CLE; //S4 'CLE'
- break;
- case 0x7d:
- b = DIV; //S8 'DIV'
- break;
- case 0x7b:
- b = SUB; //S12 'SUB'
- break;
- case 0x77:
- b = EQU; //S16 '='
- break;
- default : //没有和 a 的匹配项
- b = ErrKey; //错误的按键值
- break;
- }
- KeyPad = 0xf0; //松手检测
- while (KeyPad != 0xf0); //当没有松手,将在此一直等待
- }
- return (b); //返回读取的按键值
- }
-
- /******************************************************************************
- * @brief delayms 毫秒级延时函数
- * @param ms 延时的毫秒数 允许值 unsigned int范围
- * @retval 无
- * @attention 这个函数只是用于12T 8051内核的单片机运行于12Mhz
- *****************************************************************************/
- void delayms(unsigned int ms) //延时子程序(晶振12Mhz)
- {
- unsigned char i;
- while(ms--)
- {
- for(i = 0; i < 120; i++);
- }
- }
-
- /******************************************************************************
- * @brief SegDisplay 数码管显示&定时器中断程序组成动态显示
- * @param casebit 用于选择数码管的位 允许值 0~4
- * @retval 无
- * @attention 这个函数需配合定时器中断服务程序
- *****************************************************************************/
- void SegDisplay(unsigned char casebit)
- {
- Seg7_Bits = 0xff; //关闭所有数码管
- Seg7_Data =SegCode[DisBuff[casebit]];//先把段码值赋给P1(段选端口)
- switch(casebit)
- {
- case 0:
- Seg7_Bit1 = 0;
- break;
- case 1:
- Seg7_Bit2 = 0;
- break;
- case 2:
- Seg7_Bit3 = 0;
- break;
- case 3:
- Seg7_Bit4 = 0;
- break;
- default :
- Seg7_Bits = 0xff; //关闭所有数码管
- Seg7_Data = 0xff;
- break;
- }
- }
- /************************************************************************************
- * @brief DatUnpack:数据拆分,同时把数据的千位,百位,十位,个位赋给显示缓存数组DisBuff[]
- * @param unsigned int dat
- * @retval 无
- ***********************************************************************************/
- void DatUnpack(unsigned int dat)
- {
-
- if((dat<10)) //1位数
- DisBuff[0]=dat;
- else if((dat<100)&&(dat>=10)) //2位数
- {
- DisBuff[1]=dat/10;
- DisBuff[0]=dat%10;
- }
- else if((dat<1000)&&(dat>=100)) //3位数
- {
- DisBuff[2]=dat/100;
- DisBuff[1]=dat%100/10;
- DisBuff[0]=dat%100%10;
- }
- else if ((dat<10000)&&(dat>=1000))//4位数
- {
- DisBuff[3]=dat/1000;
- DisBuff[2]=dat%1000/100;
- DisBuff[1]=dat%1000%100/10;
- DisBuff[0]=dat%1000%100%10;
- }
-
- }
- /*******************************************************************************
- * @brief unsigned char CheckInput(): 检查矩阵键盘输入按键的类型(简介)
- * @param 无 (参数)
- * @retval 数字,功能键(CLE,EQU,+,-,*,/),无按键的状态 (返回值)
- ******************************************************************************/
- unsigned char CheckInput(void)
- {
- unsigned char x;
- x=ReadKeyPad(); //调用读按键子程序
- if(x != ErrKey) //是否为错误按键值
- {
- if((x<10)|(x == NoKey)| (x == CLE))//按下的为数字,或没有按键按下,或清除键
- {
- return (x);
- }
- else //按下的为 运算符(四则运算 和 等号)
- {
- if(x == EQU) // 按下的为 等号"="
- {
- switch (CountFlag)
- {
- case ADD: Ans = temp1+temp2; break;
- case SUB: Ans = temp1-temp2; break;
- case MUL: Ans = temp1*temp2; break;
- case DIV: if (temp2 == 0) //除法分母为0,报错
- {
- WarmDpy(DpyErr);
- break;
- }
- else
- {
- Ans = temp1/temp2;//只计算除法商的整数,暂没有考虑小数
- break;
- }
- }
- if( CheckNum(Ans)&&(InFlag1 ==1)&&(InFlag2 ==1))//检测运算的有效性
- {
- DatUnpack(Ans); //运算结果拆分,更新显示缓存
- CountFlag = NoCountFlag; //清除运算符
- temp1=0,temp2=0; //清除运算数字
- AnsFlag = 1; //运算结果存在标志
- InFlag1 =0; //清除有效数字输入标志
- InFlag2 =0;
- Ans=0; //清除运算结果
- return (NoKey); //此次运算完成,返回无按键状态
- }
- else //WarmDpy(DpyErr) ;//运算表达式不完整或结果超出范围,报错
- return (InErrEqu); //返回有等号输入的状态
- }
- else //按下的为 4则 运算符(+ ,-,*, /)
- {
- CountFlag = x; //保存运算符
- return (InCount); //返回有运算符输入的状态
- }
-
- }
- }
- else return (ErrKey); //返回错误按键值状态
- }
- /*******************************************************************************
- * @brief CheckNum: 检查计算器运算数的有效性
- * @param dat
- * @retval bit 有效: 1,无效: 0
- ******************************************************************************/
- bit CheckNum(unsigned int dat)
- {
- if (dat < 10000)
- return 1; //数据有效
- else
- return 0;
-
- }
- /*******************************************************************************
- * @brief WarmDpy:数码管错误显示
- * @param err 实则:'E'的码段值元素的下标
- * @retval 无
- ******************************************************************************/
- ……………………
|