msp430实现串口计算器
程序员文章站
2022-06-09 19:36:35
...
工程下载链接:
本次实验实现了基于串口通信的表达式解析与计算功能,如下图所示,向单片机输入表达式:9*9*8 +9/3*6-3*8 * (1 * 5+4 * (2-2)+5)/(3-1 * 9)=
;(空格会自动忽略); 返回计算结果:706,等等。
实验配置了一个波特率为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);
}
}
}