msp430实现串口计算器

工程下载链接:https://download.csdn.net/download/qq_45467083/12100424

本次实验实现了基于串口通信的表达式解析与计算功能,如下图所示,向单片机输入表达式:9*9*8 +9/3*6-3*8 * (1 * 5+4 * (2-2)+5)/(3-1 * 9)=;(空格会自动忽略); 返回计算结果:706,等等。msp430实现串口计算器_第1张图片
msp430实现串口计算器_第2张图片msp430实现串口计算器_第3张图片
msp430实现串口计算器_第4张图片
实验配置了一个波特率为115200的串口UART,在接受缓存满和发送缓存空的时候都会产生中断。在接受中断中调用oneCharProcess(revChar_temp);处理接受字符,在发送中断中发送待发送字符串。

中断服务程序如下:

/* ======== USCI A0/B0 TX Interrupt Handler Generation ======== */
#pragma vector = USCI_A1_VECTOR
__interrupt void USCI_A1_ISR(void){
    switch(__even_in_range(UCA1IV,4)){//user guide:36.4.14 UCAxIV Register
        case 0:break;
        case 2://接受数据
            revChar_temp = UCA1RXBUF;
            oneCharProcess(revChar_temp);
            break;                   //vector 2 : RXIFG
        case 4://发送数据
            if(sendstr[str_index] != '\0'){
                UCA1TXBUF = sendstr[str_index++];
            }else{
                str_index = 0;
            }
            break;                    //vector 4 : TXIFG
        default: break;
    }
}

在这里我们将用到如下变量作为表达式计算的中间变量缓存,这个和计算的算法相关,使用了两个栈,一个存储运算数,一个存储运算符:

int num[20] = {0};//运算数栈
int num_index = -1;//运算数栈栈顶指针
u8 sp[20] = {0};//运算符栈
int sp_index = -1;//运算符栈栈顶指针

在这个程序中我们封装了如下函数:

//使用的函数声明

//运算符优先级:数值越小优先级越高
u8 getPriority(u8 oneChar);

//中断处理函数,一次处理一个字符
void oneCharProcess(u8 oneChar);

/*
 * 字符解析函数
 * 说明:若输入字符0~9,返回数字0~9,其他返回-1
 * 返回值:
 *       0~9:数字字符解析为数字
 *       -1:四则运算符和括号和=
 *       -2:其他
 */
int analysis_char(u8 oneChar0);

/*
 * 发送最终结果
 * 参数:num 最终结果数字
 */
void sendResult(int num);

//b char0 a = ?
int calculate(char char0, int a, int b);

在我们看中断处理函数之前,我们先要简要讲解一下算法:

除了括号和等号之外,四则运算符本质上都是二元运算符,换言之运算数的数目是固定的,顺序也是固定的。因此我们使用两个栈,一个存储运算数,一个存储运算符。那么一个运算符必然代表着两个运算数,所以运算符堆栈里面的元素个数代表了运算数的读写次数。而由于栈先进后出,因此确保了二元运算数的顺序。

现在描述算法如下:

首先设置运算符优先级如下:
( > * > / > - > + > ) > =
计算时,
1 从左往右扫描表达式,
  • 如果SP栈空,则遇到运算符即入栈,此时如果NUM栈空,则在NUM栈补零入栈;
  • 如果遇到(,(入SP栈; 如果遇到数字即入NUM栈;
  • 如果遇到当前运算符优先级高于SP栈顶运算符,则运算符入SP栈;
  • 如果遇到当前运算符优先级低于或等于SP栈顶运算符,且SP栈顶运算符不是(。则依次弹出一个SP栈顶元素,并弹出两个NUM栈元素进行二元运算,将结果再入NUM栈。重复此过程直到运算符的优先级大于SP栈顶运算符优先级;
  • 如果遇到),则依次弹出一个SP栈顶元素,并弹出两个NUM栈元素进行二元运算,将结果再入NUM栈。重复此过程直到遇到(。然后弹出(,将其丢弃。
2 扫描结束后,即遇到=,则循环弹出依次弹出一个SP栈顶元素,并弹出两个NUM栈元素进行二元运算,将结果再入NUM栈。重复此过程直到SP栈空,此时弹出NUM栈顶元素即为最终结果。

具体代码如下:

//中断处理函数,一次处理一个字符
void oneCharProcess(u8 oneChar){
    int analysisChar = analysis_char(oneChar);//遇到操作数时,将其压入num
    if(analysisChar != -1 && analysisChar != -2){
        num_push(analysisChar);
    }else if(analysisChar == -1){
        if(oneChar=='='){//所有SP出栈,最后的计算结果在num栈中
            char temp1 = sp_pop();
            while(temp1 != 0){
                num_push(calculate(temp1, num_pop(), num_pop()));
                temp1 = sp_pop();
            }
            sendResult(num_pop());
        }else if((sp_index==-1) && (num_index==-1) && (oneChar == '-')){//第一个运算数是负数情况
            sp_push(oneChar);
            num_push(0);
        }else if((sp_index==-1) || (oneChar=='(') || (getPriority(oneChar)<getPriority(sp[sp_index]))){//三种情况下直接入SP栈①SP为空②运算符为‘(’③运算符优先级比SP栈顶运算符的高;
            sp_push(oneChar);
        }else if(oneChar==')'){//如果右括号“)”,则依次弹出SP栈顶的运算符,并压入num,直到遇到左括号为止,此时将这一对括号丢弃;
            char temp1 = sp_pop();
            while(temp1!='('){
                num_push(calculate(temp1, num_pop(), num_pop()));
                temp1 = sp_pop();//最后一次丢弃(
            }
        }else if((getPriority(oneChar)>=getPriority(sp[sp_index])) && (sp[sp_index]!='(')){//若运算符优先级小于或等于SP栈顶运算符的优先级,且栈顶运算符不是(,则依次弹出SP栈顶元素,直到运算符的优先级大于SP栈顶运算符优先级;
            while((getPriority(oneChar)>=getPriority(sp[sp_index])) && (sp[sp_index]!='(')){
                num_push(calculate(sp[sp_index], num_pop(), num_pop()));
                sp_pop();//移出使用过的运算符
            }
            sp_push(oneChar);
        }else{
            sp_push(oneChar);
        }
    }
}


· 关注公众号【技术斋】,发现更多精彩!

你可能感兴趣的:(tiva,msp430)