标题:
51单片机计算器程序状态图与Proteus仿真
[打印本页]
作者:
wmj123
时间:
2020-12-4 15:23
标题:
51单片机计算器程序状态图与Proteus仿真
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
51hei.png
(22.31 KB, 下载次数: 92)
下载附件
2020-12-4 16:45 上传
状态图.jpg
(97.45 KB, 下载次数: 72)
下载附件
2020-12-4 16:45 上传
单片机源程序如下:
#include "led_seg.h"
#include "key.h"
#include "mymath.h"
typedef enum
{
OPERATOR_EMPTY,
OPERATOR_PLUS,
OPERATOR_MINUS,
OPERATOR_MULTIPLY,
OPERATOR_DIVIDE,
OPERATOR_EQUAL
} OPERATOR;
typedef enum
{
STATE_INIT,
STATE_INPUT_FIRST_NUM,
STATE_INPUT_SECOND_NUM,
STATE_CALC_SIGN,
STATE_EQUAL
} STATE;
u8 timer = 0;
double show_number = 0;
// 用来标记小数点是否按下
bit is_dot_press = 0;
// 用来记录小数点按下后键盘按下的数的数量
u8 after_dot_press_number = 0;
// (float) 等价于 (double) 6位有效数字
void Timer0Init(void);
void Timer0Interrupt(void);
void update_show_number(u8);
void update_calc_sign(OPERATOR);
double first_number = 0;
double second_number = 0;
OPERATOR myoperator = OPERATOR_EMPTY;
STATE state = STATE_INIT;
void main()
{
Timer0Init();
while(1)
{
keyscan();
if(NO_KEY_PRESS != key_state)
{
switch(key_state)
{
// 1
case 0:
update_show_number(1);
break;
// 2
case 1:
update_show_number(2);
break;
// 3
case 2:
update_show_number(3);
break;
// +
case 3:
update_calc_sign(OPERATOR_PLUS);
break;
// 4
case 4:
update_show_number(4);
break;
// 5
case 5:
update_show_number(5);
break;
// 6
case 6:
update_show_number(6);
break;
// -
case 7:
update_calc_sign(OPERATOR_MINUS);
break;
// 7
case 8:
update_show_number(7);
break;
// 8
case 9:
update_show_number(8);
break;
// 9
case 10:
update_show_number(9);
break;
// ×
case 11:
update_calc_sign(OPERATOR_MULTIPLY);
break;
// .
case 12:
is_dot_press = 1;
break;
// 0
case 13:
update_show_number(0);
break;
// =
case 14:
switch(state)
{
case STATE_INIT:
case STATE_EQUAL:
case STATE_INPUT_FIRST_NUM:
first_number = show_number;
state = STATE_EQUAL;
myoperator = OPERATOR_EMPTY;
break;
case STATE_INPUT_SECOND_NUM:
second_number = show_number;
switch(myoperator)
{
case OPERATOR_PLUS:
show_number = first_number + second_number;
break;
case OPERATOR_MINUS:
show_number = first_number - second_number;
break;
case OPERATOR_MULTIPLY:
show_number = first_number * second_number;
break;
case OPERATOR_DIVIDE:
if(0.000000 != second_number)
{
show_number = first_number / second_number;
}
else
{
// warning
show_number = 0;
}
break;
default:
break;
}
is_dot_press = 0;
after_dot_press_number = 0;
first_number = 0;
second_number = 0;
state = STATE_EQUAL;
myoperator = OPERATOR_EMPTY;
break;
case STATE_CALC_SIGN:
break;
default:
break;
}
break;
// ÷
case 15:
update_calc_sign(OPERATOR_DIVIDE);
break;
//意外情况的处理
default:
break;
}
key_state = NO_KEY_PRESS;
}
}
}
void Timer0Init(void) //100微秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x02; //设置定时器模式
TL0 = 0x9C; //设置定时初值
TH0 = 0x9C; //设置定时重载值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
void Timer0Interrupt(void) interrupt 1
{
timer++;
if(10 == timer)
{
LedShowByNum(show_number);
timer = 0;
}
keyrescan();
}
void update_show_number(u8 number)
{
switch(state)
{
case STATE_INIT:
case STATE_EQUAL:
show_number = 0;
first_number = 0;
second_number = 0;
myoperator = OPERATOR_EMPTY;
state = STATE_INPUT_FIRST_NUM;
break;
case STATE_INPUT_FIRST_NUM:
break;
case STATE_INPUT_SECOND_NUM:
break;
case STATE_CALC_SIGN:
second_number = show_number = 0;
state = STATE_INPUT_SECOND_NUM;
break;
default:
break;
}
if(is_dot_press)
{
after_dot_press_number++;
show_number += number / ((double)mypow(10,after_dot_press_number));
}
else
{
show_number *= 10;
show_number += number;
}
switch(state)
{
case STATE_INPUT_FIRST_NUM:
first_number = show_number;
break;
case STATE_INPUT_SECOND_NUM:
second_number = show_number;
break;
default:
break;
}
}
void update_calc_sign(OPERATOR opr)
{
switch(state)
{
case STATE_INIT:
first_number = 0;
myoperator = opr;
state = STATE_CALC_SIGN;
break;
case STATE_EQUAL:
case STATE_INPUT_FIRST_NUM:
first_number = show_number;
state = STATE_CALC_SIGN;
myoperator = opr;
break;
case STATE_INPUT_SECOND_NUM:
second_number = show_number;
is_dot_press = 0;
after_dot_press_number = 0;
switch(myoperator)
{
case OPERATOR_PLUS:
show_number = first_number + second_number;
break;
case OPERATOR_MINUS:
show_number = first_number - second_number;
break;
case OPERATOR_MULTIPLY:
show_number = first_number * second_number;
break;
case OPERATOR_DIVIDE:
if(0.000000 != second_number)
{
show_number = first_number / second_number;
}
else
{
is_dot_press = 0;
after_dot_press_number = 0;
// warning
show_number = 0;
first_number = 0;
second_number = 0;
myoperator = OPERATOR_EMPTY;
state = STATE_INIT;
return;
}
break;
default:
break;
}
first_number = show_number;
state = STATE_CALC_SIGN;
myoperator = opr;
break;
case STATE_CALC_SIGN:
break;
}
}
复制代码
全部资料51hei下载地址(仿真+程序):
09-实现一个简便的计算器.7z
(116.72 KB, 下载次数: 47)
2020-12-4 15:23 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
泰兴电子
时间:
2023-4-9 16:29
第一次输入数不能带小数,否则运算符后的第二次输入数出错。比如7.1+2=9.2 。但是显示为7.1+0.02=7.12 。不知什么原因?楼主能不能查一下,更正后我再来下载一下。
作者:
泰兴电子
时间:
2023-4-13 15:57
已解决了第一次输入不能是小数的问题。但是出现了第二个问题,就是不能及时显示小数点及小数点后面的零,只有小数点后面是除零外的数才能及时显示。一直没有找到原因,楼主帮一下,谢谢!
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1