|
单片机源程序如下:
#include //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 无
******************************************************************************/
……………………
|
|