【51单片机】简单四则运算


使用51单片机实现简单的四则运算(只包含+ - * / 和 =)


实验设备 : 普中科技 单片机开发试验仪

开发软件 : Keil uVision3

烧录软件 : PZ-ISP V1.48

设计思路

由于51单片机数据存储空间有限,所以不能开辟过多的数据空间,C语言处理四则运算的代码无法直接通过改写,编译烧录。故此次实验采用状态转换的方式实现计算器的简单四则运算。使用数据空间3个:a, b, c。即可实现。下图为状态转换图。
【51单片机】简单四则运算_第1张图片
在程序实现过程中,如果遇到’=’则需要显示结果到显示屏,这部分说明请看代码相应位置。对于错误输入在各自状态有相应处理过程,如不存储该错误输入等。此外,在程序实现过程中添加 状态11:用于清屏重置;状态12:ERROR状态。下面介绍接线及运行结果。

接线

Jp8连JP4 Jp9连Jp5 把1602液晶插入
【51单片机】简单四则运算_第2张图片

按键说明

【51单片机】简单四则运算_第3张图片

输入

【51单片机】简单四则运算_第4张图片

计算结果

【51单片机】简单四则运算_第5张图片

程序代码

/**************************************************************************************
*                     简易四则运算计算器                                           *
*                                                                                     *
*       仪器:普中科技 单片机开发实验仪                                                  *
*       连接方法:Jp8连JP4  Jp9连Jp5 把1602液晶插入                                   *
*                                                                                     *
***************************************************************************************/

#include      //此文件中定义了51的一些特殊功能寄存器

#define uchar unsigned char
#define uint unsigned int

#define MAXLEN 16

sbit EN=P2^7;  //LCD的使能引脚
sbit RS=P2^6;  //LCD数据命令选择端
sbit RW=P2^5;  //LCD的读写选择端

sbit K1=P3^0;
sbit K2=P3^1;
sbit K3=P3^2;
sbit K4=P3^3;
sbit K8=P3^7;   // 清屏,重置变量

bit flag = 0;   // + 或 - 标识符; 0:+;1:-;

uchar KEY_CODE[]={ 0xed,0xdd,0xbd,0x7d,//3X4矩阵键盘键值表
                   0xeb,0xdb,0xbb,0x7b,
                   0xe7,0xd7,0xb7,0x77};
//定义字符键值表
uchar CHAR_TABLE[]={0x30,0x31,0x32,0x33,//这四个会在液晶显示器中显示0 1 2 3
                    0x34,0x35,0x36,0x37,//这四个会显示4 5 6 7 
                    0x38,0x39,0x2b,0x3d,//这四个会显示8 9 + =
                    0x2b,0x2d,0x2a,0x2f,//这四个会显示+ - * /
                    0x45,0x52,0x4f};    //这三个会显示E R O

uchar QUEUE[2*MAXLEN]={' ',' ',' ',' ',' ',' '};        //定义一个队列

int count = 0;  

unsigned int state=0;
long a=0,b=0,c=0;


void mscanf(uchar *var);                //从矩阵键盘中获取值
void print(uchar *outStr,uint end);     //打印字符串

void delay5MS();            //短延时函数
void delay100MS();          //较长延时函数
void writeCMD(uchar com);       //写命令子程序
void showOneChar(uchar dat);    //写数据子程序

void init();        //初始化子程序,初始化液晶显示屏

void clear();       //清除显示屏上的显示
void clearInit();   //清屏,重置变量

void splitResultNum(long result);       // 分离数值

void number();                  //state0: 数字输入
void middle_add_sub();          //state:1:
void add_sub();                 //state:2:
void middle_add_sub_times();    //state:3;
void middle_add_sub_div();      //state:4;
void add_sub_times();           //state:5;
void add_sub_div();             //state:6;
void mulMidState();             //state7: *中间态
void divMidState();             //state8: /中间态
void mulState();                //state9: *计算态
void divState();                //state10: /计算态
void showError();               //state12:错误状态


/**************** 主函数 ******************/
void main()
{
    // state0:数字输入态
    // state1:+,-中间态
    // state2:+,-计算态
    // state3:+/-,*中间态
    // state4:+/-,/中间态
    // state5:+/-,*计算态
    // state6:+/-,/计算态
    // state7:*中间态
    // state8:/中间态
    // state9:*计算态
    // state10:/计算态
    // state11:清屏重置
    // state12:错误状态
    state = 0;
    init();
    while(1){
        switch(state){
            case 0:     // state0:数字输入态 
                number();
                break;
            case 1:     // state1:+,-中间态
                middle_add_sub();
                break;
            case 2:     // state2:+,-计算态
                add_sub();
                break;
            case 3:     // state3:+,-,*中间态
                middle_add_sub_times();
                break;
            case 4:     // state4:+,-,/中间态
                middle_add_sub_div();
                break;
            case 5:     // state5:+,-,*计算态
                add_sub_times();
                break;
            case 6:     // state6:+,-,/计算态
                add_sub_div();
                break;
            case 7:     // state7:*中间态
                mulMidState();
                break;
            case 8:     // state8:/中间态
                divMidState();
                break;
            case 9:     // state9:*计算态
                mulState();
                break;
            case 10:    // state10:/计算态
                divState();
                break;              
            case 11:    // state11:清屏重置
                clearInit();
                break;
            case 12:    // state12:错误状态
                showError();
                break;
        }
        // 错误状态不输出
        if(state != 12)
        {
            clear();
            print(QUEUE,count); 
        }

    }
}

/**************** 分离数值 ******************/
void splitResultNum(long result)
{
    long tmp;

    if(result > 2000000000) // 如果大于20亿则溢出报错
    {
        state = 12;
        return ;
    }

    tmp = result>0 ? result : -result;

    count = 0;
    while(tmp>0)
    {
        QUEUE[count++] = tmp%10;
        tmp /= 10;  
    }

    if(result < 0)
    {
        QUEUE[count++] = '-';
    }
    else if(result == 0)
    {
        QUEUE[count++] = 0;
    }

    for(tmp = count-1; tmp >= count/2; --tmp)
    {
        result = QUEUE[tmp];
        QUEUE[tmp] = QUEUE[count-1-tmp];
        QUEUE[count-1-tmp] = result;
    }   
}

/**************** state0的数字输入 ******************/
void number(){
    uchar num=0xff; 
    mscanf(&num);//获取字符
    QUEUE[count++]=num;
    if(num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9||num==0){
        a = a*10+num;
    }else if (num=='+'){    //调整状态 + 
        b = 0;  
        flag = 0;
        state = 1;
    }else if (num=='-'){    //调整状态 -
        b = 0;
        flag = 1;
        state = 1;
    }else if (num=='*'){    //调整状态 *中间态
        c = 0;
        state = 7;
    }else if (num=='/'){    //调整状态 /中间态
        c = 0;
        state = 8;
    }else if (num=='='){    //输出        
        splitResultNum(a);  //拆分
    }else if (num=='C'){
        state = 11;
    }else{
        //输入错误字符,启动报错程序
    }
}
/**************** state1:+,-中间态 ******************/
void middle_add_sub(){
    uchar num=0xff;
    mscanf(&num);
    QUEUE[count++]=num;
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        b=num;
        state=2;    
    }else if (num=='C'){    // K8 清屏
        state = 11;
    }else{
        // 错误输入不存储
        count--;
    }
}

/**************** state2:+,-计算态 ******************/
void add_sub(){
    uchar num=0xff;
    mscanf(&num);
    QUEUE[count++]=num;
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        b=num+b*10;
    }else if(num=='*'){  
        c=0;
        state=3;
    }else if (num=='/'){
        c=0;
        state=4;
    }else if(num=='+'){     // done
        if(flag == 1){
            a=a-b;
        }else{
            a=a+b;
        }
        b = 0;
        state = 1;
        flag= 0;
    }else if(num=='-'){     // done
        if(flag == 1){
            a=a-b;
        }else{
            a=a+b;
        }
        b = 0;
        state = 1;
        flag = 1;
    }else if(num=='='){
        state = 0;  //按=号之后回到状态0
        if(flag == 1){  // 1 : -        
            splitResultNum(a-b);
            a = a-b;    
        }else{          // 0 : +
            splitResultNum(a+b);
            a = a+b;
        }
        b = c = 0;                  
    }else if (num=='C'){
        state = 11;
    }
}
/**************** state3:+,-,*中间态 ******************/
void middle_add_sub_times(){
    uchar num=0xff;
    mscanf(&num);
    QUEUE[count++]=num;
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        c=num;
        state=5;
        return; 
    }else if (num=='C'){
        state = 11;
    }else{          //其他不符合规则的情况,不存储
        count--;
    }   
}
/**************** state4:+,-,/中间态 ******************/
void middle_add_sub_div(){
    uchar num=0xff;
    mscanf(&num);
    QUEUE[count++]=num;
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        c = num;
        if(c == 0){     //如果除数为0,则不存储
            count--;
        } else {
            state = 6;  //跳转到state6: +,-,/计算态   
        }   
    }else if (num=='C'){
        state = 11;
    }else{          //其他不符合规则的情况,不存储
        count--;
    }
}
/**************** state5:+,-,*计算态 ******************/
void add_sub_times(){
    uchar num=0xff;
    mscanf(&num);
    QUEUE[count++]=num;
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        c=num+c*10; 
    }else if(num=='+'){
        if(flag==1){
            a=a-b*c;
            b=0;
            c=0;
        }else{
            a=a+b*c;
            b=0;
            c=0;
        }
        flag=0;
        state=1;
    }else if(num=='-'){
        if(flag==1){
            a=a-b*c;
            b=0;
            c=0;
        }else{
            a=a+b*c;
            b=0;
            c=0;
        }
        flag=1;
        state=1;
    }else if(num=='*'){
        b=b*c;
        c=0;
        state=3;
    }else if(num=='/'){
        b=b*c;
        c=0;
        state=4;
    }else if(num=='='){
        state=0;
        if(flag == 1){
            //输出 a-b*c
            splitResultNum(a-b*c);
            a = a-b*c;
        }else{
            //计算 a+b*c
            splitResultNum(a+b*c);
            a = a+b*c;
        }
        b = c = 0;      
    }else if (num=='C'){
        state = 11;
    }
}
/**************** state6:+,-,/计算态 ******************/
void add_sub_div(){
    uchar num=0xff;
    mscanf(&num);
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        c=num+c*10; 
    }else if(num=='+'){
        if(flag == 1){
            a=a-b/c;
            b=0;
            c=0;
        }else{
            a=a+b/c;
            b=0;
            c=0;
        }
        flag=0;
        state=1;
    }else if(num=='-'){
        if(flag == 1){
            a=a-b/c;
            b=0;
            c=0;
        }else{
            a=a+b/c;
            b=0;
            c=0;
        }
        flag=1;
        state=1;
    }else if(num=='*'){
        b=b/c;
        c=0;
        state=3;
    }else if(num=='/'){
        b=b/c;
        c=0;
        state=4;
    }else if(num=='='){
        state=0;
        if(flag == 1){
            //计算 a-b/c
            splitResultNum(a-b/c);
            a = a-b/c;
        }else{
            //计算 a+b/c
            splitResultNum(a+b/c);
            a = a+b/c;
        }
        b = c = 0;      
    }else if (num=='C'){
        state = 11;
    }
}

/**************** state7:*中间态 ******************/
void mulMidState()
{
    uchar num=0xff;
    mscanf(&num);   //获取字符
    QUEUE[count++]=num; 
    if(num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9||num==0){
        c = num;
        state = 9;  //跳转到state9: *计算态
    }else if (num=='C'){
        state = 11;
    }else{          //其他不符合规则的情况,不存储
        //state = 12;
        count--;
    }   
}

/**************** state8:/中间态 ******************/
void divMidState()
{
    uchar num=0xff;
    mscanf(&num);   //获取字符
    QUEUE[count++]=num; 
    if(num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9||num==0){
        c = num;
        if(c == 0){     //如果除数为0,不存储    
            //state = 12;
            count--;
        } else {
            state = 10; //跳转到state10: /计算态  
        }

    }else if (num=='C'){
        state = 11;
    }else{          //其他不符合规则的情况,不存储
        //state = 12;
        count--;
    }
}   


/**************** state9:*计算态 ******************/
void mulState()
{
    uchar num=0xff;
    mscanf(&num);   //获取字符
    QUEUE[count++]=num; 
    if(num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9||num==0){
        c = c*10+num;
    }else if(num=='*'){
        a = a*c;
        c = 0;
        state = 7;  // 跳转到state7: *中间态
    }else if(num=='/'){
        a = a*c;
        c = 0;
        state = 8;  // 跳转到state8: /中间态
    }else if(num=='+'){
        a = a*c;
        c = 0;
        flag = 0;
        state = 1;  // 跳转到state1: +,-中间态
    }else if(num=='-'){
        a = a*c;
        c = 0;
        flag = 1;
        state = 1;  // 跳转到state1: +,-中间态
    }else if(num=='='){
        // 输出 a*c
        state = 0;  //按=号之后回到状态0
        splitResultNum(a*c);    //拆分
        a = a*c;
        b = c = 0;                      
    }else if (num=='C'){
        state = 11;
    }else{
        //输入错误字符,启动报错程序
    }   
}

/**************** state10:/计算态 ******************/
void divState()
{
    uchar num=0xff;
    mscanf(&num);   //获取字符
    QUEUE[count++]=num; 
    if(num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9||num==0){
        c = c*10+num;
    }else if(num=='/'){
        a = a/c;
        c = 0;
        state = 8;  // 跳转到state8: /中间态
    }else if(num=='*'){
        a = a/c;
        c = 0;
        state = 7;  // 跳转到state7: *中间态
        return ;
    }else if(num=='+'){
        a = a/c;
        c = 0;
        flag = 0;
        state = 1;  // 跳转到state1: +,-中间态
    }else if(num=='-'){
        a = a/c;
        c = 0;
        flag = 1;
        state = 1;  // 跳转到state1: +,-中间态
    }else if(num=='='){
        // 输出 a/c
        state = 0;     //按=号之后回到状态0
        splitResultNum(a/c);    //拆分
        a = a/c;
        b = c = 0;                      
    }else if (num=='C'){
        state = 11;
    }else{
        //输入错误字符,启动报错程序
    }
}
/********************* state11:清屏重置子程序 **********************/
void clearInit()
{
    a = b = c = 0;
    count = 0;
    state = 0;
    EN=0;
    writeCMD(0x01); 
}
/********************* state12:错误状态 **********************/
void showError()
{
    uchar num=0xff;
    a = b = c = 0;
    count = 5;
    state = 0;
    QUEUE[0] = 'E';
    QUEUE[1] = 'R';
    QUEUE[2] = 'R';
    QUEUE[3] = 'O';
    QUEUE[4] = 'R';
    clear();
    print(QUEUE,count);
    while(1)
    {
        mscanf(&num);   //  获取字符
        if(num == 'C')  //  只有按清屏 K8 才会退出 ERROR状态 
        {
            state = 11;
            return ;    
        }
        else
        {
            clear();
            print(QUEUE,count);
        }
    }


}
/**********从键盘获取值得函数类似于C语言的scanf()函数**************/             
void mscanf(uchar *var)
{
   uchar temp,num;
   int i=1;
   temp=i;
    while(1){
        P3=0xff;
        delay100MS(); //延时,软件消除抖动
        if(K1==0){
            *var = '+';
            break;
        }else if (K2==0){
            *var = '-';
            break;
        }else if (K3==0){
            *var = '*';
            break;
        }else if (K4==0){
            *var = '/';
            break;
        }else if (K8==0){
            *var = 'C';
            break;
        }

         P1=0x0f;//置行为高电平,列为低电平。这样用于检测行值。
         if(P1!=0x0f){
             delay100MS(); //延时,软件消除抖动。
             temp=P1;       //保存行值
             P1=0xf0;       //置行为低电平,列为高电平,获取列
               if(P1!=0xf0){
                  num=temp|P1; //获取了按键位置
                  //P2=1;
                  for(i=0;i<12;i++)
                   if(num==KEY_CODE[i]){
                   if(i==10)*var='+';//获取等号的值
                   else if(i==11)*var='=';//获取加号的值
                   else *var=i;//获取数值
                }
               break;   //跳出循环,为了只获取一个值
             }
         }   
     }
}
/*********************短延时函数*************************/
  void delay5MS()
  {
    int n=3000;
    while(n--);
  }

/*****************定义长点的延时程序**********************/
void delay100MS()
{
    uint n=10000;
    while(n--);
}

/*******************写命令子程序**************************/
void writeCMD(uchar com)
{
    P0=com;     //com为输入的命令码。通过P2送给LCD
    RS=0;       //RS=0 写命令
    RW=0;
    delay5MS();   
    EN=1;       //LCD的使能端E置高电平
    delay5MS();
    EN=0;       //LCD的使能端E置低电平
}
/*******************写数据子程序**************************/
void showOneChar(uchar dat)
{
    P0=dat;    //写入数据
    RS=1;       //RS=1写命令
    RW=0;
    EN=1;
    delay5MS();
    EN=0;
}
/*******************初始化函数**************************/
void init()
{
    EN=0;       
    writeCMD(0x38);//设置显示模式
    writeCMD(0x0e);//光标打开,不闪烁
    writeCMD(0x06);//写入一个字符后指针地址+1,写一个字符时整屏不移动
    writeCMD(0x01);//清屏显示,数据指针清0,所以显示清0
    writeCMD(0x80);//设置字符显示的首地址
}
/******************显示函数***************************/
void print(uchar arr[],uint end)
{    
    uint t=0,j=0;
    uint location;

    if(end==0 || end>MAXLEN){
        clear();
        return;
    }
    else {
        for(t=0;t//if(t>=MAXLEN){
                //writeCMD(0x40+0x80);  // 光标换行
            //}

            if(arr[t]=='=')         location=11;
            else if(arr[t]=='+')    location=10;
            else if(arr[t]=='+')    location=12;
            else if(arr[t]=='-')    location=13;
            else if(arr[t]=='*')    location=14;
            else if(arr[t]=='/')    location=15;
            else if(arr[t]=='E')    location=16;
            else if(arr[t]=='R')    location=17;
            else if(arr[t]=='O')    location=18;
            else{
                for(j=0;j<10;j++)
                    if(arr[t]==j)   location=j;
            }   
            showOneChar(CHAR_TABLE[location]);
        }
    }
}
/*********************清屏子程序**********************/
void clear()
{   
    EN=0;
    writeCMD(0x01);
}

四则运算C语言程序

以下是计算器四则运算的C语言程序,该程序可以包含( ) + - * / . 和 =

#include 
#include 
#include 
#include 
#include 

#define maxn 300

int priv[maxn];     // 运算符优先级数组
double value[maxn]; // 表达式中用到的变量的值

/**** 计算a op b的值并返回 ****/
double calc(double a, double b, char op)
{
    switch(op)
    {
    case '+':
        return a+b;
        break;
    case '-':
        return a-b;
        break;
    case '*':
        return a*b;
        break;
    case '/':
        return a/b;
        break;
    case '^':
        return exp(log(a)*b);
    }
    return 0;   // 默认状况
}

/*********** 运算符优先级赋值 *************/
void initPriv()
{
    // 数值越小优先级越高;数值相同,优先级相同
    priv['+'] = priv['-'] = 3;
    priv['*'] = priv['/'] = 2;
    priv['^'] = 1;
    priv['('] = 10;
}

/***********  字符变量映射数组  *************/
void initValue()
{
    // 表达式中变量初始化代码
    // e.g. : value['x'] = 10;
}

/*********** 计算器函数 ***************
    char str[] : 需要计算的合法表达式
    double val[] : 表达式中变量的值
*/
double calculate(char str[], double val[])
{
    double num[maxn];   // 存储数据的堆栈
    int numi = 0;       // 数据堆栈指针

    char oper[maxn];    // 存储运算符的堆栈
    int operi = 0;      // 运算符堆栈指针

    double x, y;
    int i;
    char last = 0;

    // 运算符优先级赋值
    initPriv();

    // 处理多项式字符串
    for(i = 0; i < strlen(str); ++i)
    {
        if(isalpha(str[i]))         // 如果是变量 'A'-'F' 或 'a'-'z' 则需要用 val 数组进行转换
        {
            num[numi++] = val[str[i]];
        }
        else if(isdigit(str[i]))    // 如果是数字字符 '0'-'9' 则需要
        {
            num[numi++] = atof(str+i);  // 将 str[i] 开头的数字字符串转换为浮点数类型压入栈
            // 将指针指向该数值之后的字符
            for(; i+1 < strlen(str) && isdigit(str[i+1]); ++i);
            if(i+1 < strlen(str) && str[i+1]=='.')
            {
                for(++i; i+1 < strlen(str) && isdigit(str[i+1]); ++i);
            }
        }
        else if(str[i]=='(')
        {
            oper[operi++] = str[i];
        }
        else if(str[i]==')')
        {
            // 计算 '(' 与 ')' 之间的表达式的数值
            while(oper[operi-1] != '(')
            {
                y = num[numi-1];    --numi;
                x = num[numi-1];    --numi;
                char op = oper[operi-1];    --operi;
                num[numi++] = calc(x,y,op);
            }
            --operi;
        }
        else if(str[i]=='-' && (last==0 || last=='('))
        {
            num[numi++] = 0.0;
            oper[operi++] = '-';
        }
        else if(priv[str[i]]>0)
        {
            while(operi>0 && priv[str[i]]>=priv[oper[operi-1]])
            {
                y = num[numi-1];    --numi;
                x = num[numi-1];    --numi;
                char op = oper[operi-1];    --operi;
                num[numi++] = calc(x,y,op);
            }
            oper[operi++] = str[i];
        }
        else
        {
            continue;
        }
        last = str[i];
    }

    // 计算剩余运算的多项式数值
    while(operi>0)
    {
        y = num[numi-1];    --numi;
        x = num[numi-1];    --numi;
        char op = oper[operi-1];    --operi;
        num[numi++] = calc(x,y,op);
    }
    return num[numi-1];
}


int main()
{
    // 初始化value数组
    initValue();

    char str[maxn] = "1+(3+4*5-2)/2+1200";

    printf("%lf", calculate(str,value));

    return 0;
}

你可能感兴趣的:(51单片机,四则运算)