STM32 串口计算器程序,支持基本运算、科学计算、括号运算、变量存储等功能,具有友好的交互界面和错误处理。
一、系统架构
STM32 串口计算器系统架构:
├── 硬件层
│ ├── STM32F103C8T6 微控制器
│ ├── USB-TTL 串口模块
│ ├── 按键输入(可选)
│ └── OLED 显示屏(可选)
├── 驱动层
│ ├── USART 串口驱动
│ ├── 定时器延时
│ ├── GPIO 控制
│ └── 中断管理
├── 计算引擎层
│ ├── 表达式解析器
│ ├── 词法分析器
│ ├── 语法分析器
│ ├── 计算执行器
│ └── 错误处理
├── 功能模块层
│ ├── 基本运算(+ - * / %)
│ ├── 科学计算(sin/cos/tan/log/exp/sqrt)
│ ├── 括号运算
│ ├── 变量存储(A-Z)
│ ├── 常量定义(π, e)
│ └── 历史记录
└── 用户界面层
├── 命令行交互
├── 帮助系统
├── 结果显示
└── 错误提示
二、硬件连接
2.1 硬件配置
STM32F103C8T6 USB-TTL模块 功能
PA9 (TX1) -----> RX 串口发送
PA10 (RX1) <----- TX 串口接收
GND -----> GND 地线
3.3V -----> VCC 电源(可选)
2.2 可选外设
OLED显示屏:I2C接口(PB6-SCL, PB7-SDA)
按键输入:PB0-PB3(数字0-9,运算符)
LED指示:PC13(计算状态指示)
三、核心代码实现
3.1 头文件定义 (calculator.h)
c
#ifndef CALCULATOR_H
#define CALCULATOR_H
#include "stm32f10x.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
// 计算器配置
#define MAX_EXPR_LEN 256 // 最大表达式长度
#define MAX_TOKEN_LEN 32 // 最大标记长度
#define MAX_STACK_SIZE 64 // 最大栈大小
#define MAX_HISTORY 10 // 历史记录数量
#define MAX_VARIABLES 26 // 变量数量(A-Z)
// 错误代码
#define CALC_OK 0
#define CALC_ERR_SYNTAX 1 // 语法错误
#define CALC_ERR_DIV_ZERO 2 // 除零错误
#define CALC_ERR_OVERFLOW 3 // 溢出错误
#define CALC_ERR_UNDEF_VAR 4 // 未定义变量
#define CALC_ERR_INVALID_OP 5 // 无效操作符
#define CALC_ERR_PAREN 6 // 括号不匹配
// 标记类型
typedef enum {
TOKEN_NUMBER = 0, // 数字
TOKEN_OPERATOR, // 运算符
TOKEN_FUNCTION, // 函数
TOKEN_VARIABLE, // 变量
TOKEN_CONSTANT, // 常量
TOKEN_LPAREN, // 左括号
TOKEN_RPAREN, // 右括号
TOKEN_END // 结束标记
} TokenType;
// 运算符优先级
typedef enum {
OPERATOR_PLUS = 1, // +
OPERATOR_MINUS, // -
OPERATOR_MULTIPLY, // *
OPERATOR_DIVIDE, // /
OPERATOR_MODULO, // %
OPERATOR_POWER // ^
} OperatorType;
// 函数类型
typedef enum {
FUNC_SIN = 1, // sin
FUNC_COS, // cos
FUNC_TAN, // tan
FUNC_LOG, // log
FUNC_LN, // ln
FUNC_EXP, // exp
FUNC_SQRT, // sqrt
FUNC_ABS // abs
} FunctionType;
// 标记结构
typedef struct {
TokenType type; // 标记类型
union {
double number; // 数字值
OperatorType op; // 运算符
FunctionType func; // 函数
char variable; // 变量名
double constant; // 常数值
} value;
char str[MAX_TOKEN_LEN]; // 字符串表示
} Token;
// 计算器状态
typedef struct {
double variables[MAX_VARIABLES]; // 变量存储(A-Z)
double constants[2]; // 常量存储(π, e)
char history[MAX_HISTORY][MAX_EXPR_LEN]; // 历史记录
int history_count; // 历史记录数量
int error_code; // 错误代码
char error_msg[128]; // 错误信息
int precision; // 显示精度
int angle_mode; // 角度模式(0=弧度,1=角度)
} CalculatorState;
// 栈结构
typedef struct {
Token items[MAX_STACK_SIZE];
int top;
} TokenStack;
// 函数声明
void Calculator_Init(void);
void Calculator_ProcessCommand(char *command);
double Calculator_EvaluateExpression(char *expression);
void Calculator_PrintResult(double result);
void Calculator_ShowHelp(void);
void Calculator_ShowVariables(void);
void Calculator_ShowHistory(void);
void Calculator_ClearAll(void);
// 表达式解析函数
int TokenizeExpression(char *expr, Token tokens[], int max_tokens);
int ParseTokens(Token tokens[], int token_count, Token postfix[]);
double EvaluatePostfix(Token postfix[], int count);
// 栈操作函数
void Stack_Init(TokenStack *stack);
void Stack_Push(TokenStack *stack, Token item);
Token Stack_Pop(TokenStack *stack);
Token Stack_Peek(TokenStack *stack);
int Stack_IsEmpty(TokenStack *stack);
int Stack_Size(TokenStack *stack);
// 工具函数
double CalculateFunction(FunctionType func, double arg);
double CalculateOperator(OperatorType op, double a, double b);
int GetOperatorPrecedence(OperatorType op);
int IsOperator(char c);
int IsFunction(char *str);
double GetConstant(char *str);
#endif // CALCULATOR_H
3.2 主程序实现 (main.c)
c
#include "stm32f10x.h"
#include "calculator.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
// 全局变量
CalculatorState calc_state;
char input_buffer[MAX_EXPR_LEN];
int input_index = 0;
// 系统初始化
void System_Init(void)
{
// 初始化系统时钟
SystemClock_Init();
// 初始化延时
Delay_Init();
// 初始化LED
LED_Init();
// 初始化串口
USART1_Init(115200);
// 初始化计算器
Calculator_Init();
printf("========================================\r\n");
printf(" STM32 串口计算器 v1.0\r\n");
printf("========================================\r\n");
printf("输入 'help' 查看帮助信息\r\n");
printf("输入 'vars' 查看变量\r\n");
printf("输入 'history' 查看历史记录\r\n");
printf("输入 'clear' 清除所有数据\r\n");
printf("========================================\r\n");
}
int main(void)
{
System_Init();
while(1)
{
printf("calc> ");
// 接收用户输入
input_index = 0;
memset(input_buffer, 0, sizeof(input_buffer));
while(1)
{
if(USART1_GetChar(&input_buffer[input_index]))
{
// 回显字符
USART1_SendChar(input_buffer[input_index]);
if(input_buffer[input_index] == '\r' ||
input_buffer[input_index] == '\n')
{
input_buffer[input_index] = '\0';
break;
}
input_index++;
if(input_index >= MAX_EXPR_LEN - 1)
{
printf("\r\n输入过长!\r\n");
break;
}
}
}
// 处理命令
if(strlen(input_buffer) > 0)
{
Calculator_ProcessCommand(input_buffer);
}
printf("\r\n");
}
}
3.3 计算器核心实现 (calculator.c)
c
#include "calculator.h"
CalculatorState calc_state;
// 初始化计算器
void Calculator_Init(void)
{
int i;
// 初始化变量
for(i = 0; i < MAX_VARIABLES; i++)
{
calc_state.variables[i] = 0.0;
}
// 初始化常量
calc_state.constants[0] = 3.14159265358979323846; // π
calc_state.constants[1] = 2.71828182845904523536; // e
// 初始化历史记录
for(i = 0; i < MAX_HISTORY; i++)
{
strcpy(calc_state.history[i], "");
}
calc_state.history_count = 0;
// 初始化其他参数
calc_state.error_code = CALC_OK;
calc_state.precision = 6;
calc_state.angle_mode = 0; // 默认弧度模式
}
// 处理命令
void Calculator_ProcessCommand(char *command)
{
char *args[4];
int arg_count = 0;
char *token;
char *rest = command;
// 解析命令参数
while((token = strtok_r(rest, " ", &rest)))
{
args[arg_count++] = token;
if(arg_count >= 4) break;
}
if(arg_count == 0) return;
// 处理命令
if(strcmp(args[0], "help") == 0)
{
Calculator_ShowHelp();
}
else if(strcmp(args[0], "vars") == 0)
{
Calculator_ShowVariables();
}
else if(strcmp(args[0], "history") == 0)
{
Calculator_ShowHistory();
}
else if(strcmp(args[0], "clear") == 0)
{
Calculator_ClearAll();
printf("已清除所有数据\r\n");
}
else if(strcmp(args[0], "deg") == 0)
{
calc_state.angle_mode = 1;
printf("已切换到角度模式\r\n");
}
else if(strcmp(args[0], "rad") == 0)
{
calc_state.angle_mode = 0;
printf("已切换到弧度模式\r\n");
}
else if(strchr(args[0], '=') != NULL)
{
// 变量赋值
char *eq_pos = strchr(args[0], '=');
char var_name = toupper(*args[0]);
char *expr = eq_pos + 1;
if(var_name >= 'A' && var_name <= 'Z')
{
double result = Calculator_EvaluateExpression(expr);
if(calc_state.error_code == CALC_OK)
{
calc_state.variables[var_name - 'A'] = result;
printf("%c = %.6f\r\n", var_name, result);
}
else
{
printf("错误: %s\r\n", calc_state.error_msg);
}
}
else
{
printf("错误: 变量名必须是A-Z\r\n");
}
}
else
{
// 计算表达式
double result = Calculator_EvaluateExpression(command);
if(calc_state.error_code == CALC_OK)
{
Calculator_PrintResult(result);
// 添加到历史记录
if(calc_state.history_count < MAX_HISTORY)
{
strcpy(calc_state.history[calc_state.history_count], command);
calc_state.history_count++;
}
else
{
// 移动历史记录
for(int i = 1; i < MAX_HISTORY; i++)
{
strcpy(calc_state.history[i-1], calc_state.history[i]);
}
strcpy(calc_state.history[MAX_HISTORY-1], command);
}
}
else
{
printf("错误: %s\r\n", calc_state.error_msg);
}
}
}
// 计算表达式
double Calculator_EvaluateExpression(char *expression)
{
Token tokens[MAX_STACK_SIZE];
Token postfix[MAX_STACK_SIZE];
int token_count;
double result;
// 重置错误状态
calc_state.error_code = CALC_OK;
// 词法分析
token_count = TokenizeExpression(expression, tokens, MAX_STACK_SIZE);
if(token_count <= 0)
{
calc_state.error_code = CALC_ERR_SYNTAX;
strcpy(calc_state.error_msg, "语法错误:无法解析表达式");
return 0.0;
}
// 语法分析(中缀转后缀)
int postfix_count = ParseTokens(tokens, token_count, postfix);
if(postfix_count <= 0)
{
calc_state.error_code = CALC_ERR_SYNTAX;
strcpy(calc_state.error_msg, "语法错误:表达式格式不正确");
return 0.0;
}
// 计算后缀表达式
result = EvaluatePostfix(postfix, postfix_count);
return result;
}
// 打印结果
void Calculator_PrintResult(double result)
{
if(fabs(result) < 1e-10) result = 0.0; // 处理负零
if(fabs(result - (int)result) < 1e-10)
{
printf("结果: %d\r\n", (int)result);
}
else
{
printf("结果: %.*f\r\n", calc_state.precision, result);
}
}
// 显示帮助
void Calculator_ShowHelp(void)
{
printf("========================================\r\n");
printf(" STM32 串口计算器帮助\r\n");
printf("========================================\r\n");
printf("基本运算:\r\n");
printf(" +, -, *, /, %% 加减乘除取模\r\n");
printf(" ^ 幂运算\r\n");
printf(" () 括号运算\r\n");
printf("\r\n科学函数:\r\n");
printf(" sin(x) 正弦函数\r\n");
printf(" cos(x) 余弦函数\r\n");
printf(" tan(x) 正切函数\r\n");
printf(" log(x) 常用对数\r\n");
printf(" ln(x) 自然对数\r\n");
printf(" exp(x) 指数函数\r\n");
printf(" sqrt(x) 平方根\r\n");
printf(" abs(x) 绝对值\r\n");
printf("\r\n常量:\r\n");
printf(" pi 圆周率 (%.10f)\r\n", calc_state.constants[0]);
printf(" e 自然常数 (%.10f)\r\n", calc_state.constants[1]);
printf("\r\n变量:\r\n");
printf(" A-Z 26个变量存储\r\n");
printf(" 赋值: A=10+5 将表达式结果赋给变量A\r\n");
printf("\r\n命令:\r\n");
printf(" help 显示此帮助\r\n");
printf(" vars 显示所有变量\r\n");
printf(" history 显示历史记录\r\n");
printf(" clear 清除所有数据\r\n");
printf(" deg 切换到角度模式\r\n");
printf(" rad 切换到弧度模式\r\n");
printf("\r\n示例:\r\n");
printf(" calc> 2+3*4\r\n");
printf(" calc> sin(pi/2)\r\n");
printf(" calc> A=10*5\r\n");
printf(" calc> B=A+sqrt(25)\r\n");
printf(" calc> (A+B)/2\r\n");
printf("========================================\r\n");
}
// 显示变量
void Calculator_ShowVariables(void)
{
int i;
printf("========================================\r\n");
printf(" 变量存储\r\n");
printf("========================================\r\n");
for(i = 0; i < MAX_VARIABLES; i++)
{
if(fabs(calc_state.variables[i]) > 1e-10)
{
printf(" %c = %.*f\r\n", 'A'+i, calc_state.precision, calc_state.variables[i]);
}
}
printf(" 角度模式: %s\r\n", calc_state.angle_mode ? "角度" : "弧度");
printf("========================================\r\n");
}
// 显示历史记录
void Calculator_ShowHistory(void)
{
int i;
printf("========================================\r\n");
printf(" 历史记录\r\n");
printf("========================================\r\n");
if(calc_state.history_count == 0)
{
printf(" 无历史记录\r\n");
}
else
{
for(i = 0; i < calc_state.history_count; i++)
{
printf(" %d: %s\r\n", i+1, calc_state.history[i]);
}
}
printf("========================================\r\n");
}
// 清除所有数据
void Calculator_ClearAll(void)
{
int i;
for(i = 0; i < MAX_VARIABLES; i++)
{
calc_state.variables[i] = 0.0;
}
for(i = 0; i < MAX_HISTORY; i++)
{
strcpy(calc_state.history[i], "");
}
calc_state.history_count = 0;
calc_state.error_code = CALC_OK;
}
// 词法分析
int TokenizeExpression(char *expr, Token tokens[], int max_tokens)
{
int token_idx = 0;
char *p = expr;
char token_str[MAX_TOKEN_LEN];
int token_len;
while(*p && token_idx < max_tokens)
{
// 跳过空格
if(isspace(*p))
{
p++;
continue;
}
// 数字(包括小数点)
if(isdigit(*p) || *p == '.')
{
token_len = 0;
while((isdigit(*p) || *p == '.') && token_len < MAX_TOKEN_LEN-1)
{
token_str[token_len++] = *p++;
}
token_str[token_len] = '\0';
tokens[token_idx].type = TOKEN_NUMBER;
tokens[token_idx].value.number = atof(token_str);
strcpy(tokens[token_idx].str, token_str);
token_idx++;
}
// 变量或函数
else if(isalpha(*p))
{
token_len = 0;
while(isalnum(*p) && token_len < MAX_TOKEN_LEN-1)
{
token_str[token_len++] = *p++;
}
token_str[token_len] = '\0';
// 检查是否是函数
if(IsFunction(token_str))
{
tokens[token_idx].type = TOKEN_FUNCTION;
if(strcmp(token_str, "sin") == 0) tokens[token_idx].value.func = FUNC_SIN;
else if(strcmp(token_str, "cos") == 0) tokens[token_idx].value.func = FUNC_COS;
else if(strcmp(token_str, "tan") == 0) tokens[token_idx].value.func = FUNC_TAN;
else if(strcmp(token_str, "log") == 0) tokens[token_idx].value.func = FUNC_LOG;
else if(strcmp(token_str, "ln") == 0) tokens[token_idx].value.func = FUNC_LN;
else if(strcmp(token_str, "exp") == 0) tokens[token_idx].value.func = FUNC_EXP;
else if(strcmp(token_str, "sqrt") == 0) tokens[token_idx].value.func = FUNC_SQRT;
else if(strcmp(token_str, "abs") == 0) tokens[token_idx].value.func = FUNC_ABS;
}
// 检查是否是常量
else if(strcmp(token_str, "pi") == 0 || strcmp(token_str, "PI") == 0)
{
tokens[token_idx].type = TOKEN_CONSTANT;
tokens[token_idx].value.constant = calc_state.constants[0];
}
else if(strcmp(token_str, "e") == 0 || strcmp(token_str, "E") == 0)
{
tokens[token_idx].type = TOKEN_CONSTANT;
tokens[token_idx].value.constant = calc_state.constants[1];
}
// 变量
else if(strlen(token_str) == 1 && token_str[0] >= 'A' && token_str[0] <= 'Z')
{
tokens[token_idx].type = TOKEN_VARIABLE;
tokens[token_idx].value.variable = token_str[0];
}
else
{
return -1; // 无效的标识符
}
strcpy(tokens[token_idx].str, token_str);
token_idx++;
}
// 运算符
else if(IsOperator(*p))
{
token_str[0] = *p++;
token_str[1] = '\0';
tokens[token_idx].type = TOKEN_OPERATOR;
if(token_str[0] == '+') tokens[token_idx].value.op = OPERATOR_PLUS;
else if(token_str[0] == '-') tokens[token_idx].value.op = OPERATOR_MINUS;
else if(token_str[0] == '*') tokens[token_idx].value.op = OPERATOR_MULTIPLY;
else if(token_str[0] == '/') tokens[token_idx].value.op = OPERATOR_DIVIDE;
else if(token_str[0] == '%') tokens[token_idx].value.op = OPERATOR_MODULO;
else if(token_str[0] == '^') tokens[token_idx].value.op = OPERATOR_POWER;
strcpy(tokens[token_idx].str, token_str);
token_idx++;
}
// 括号
else if(*p == '(')
{
tokens[token_idx].type = TOKEN_LPAREN;
tokens[token_idx].value.op = OPERATOR_PLUS; // 占位
strcpy(tokens[token_idx].str, "(");
token_idx++;
p++;
}
else if(*p == ')')
{
tokens[token_idx].type = TOKEN_RPAREN;
tokens[token_idx].value.op = OPERATOR_PLUS; // 占位
strcpy(tokens[token_idx].str, ")");
token_idx++;
p++;
}
else
{
return -1; // 无效字符
}
}
return token_idx;
}
// 解析标记(中缀转后缀)
int ParseTokens(Token tokens[], int token_count, Token postfix[])
{
TokenStack stack;
int postfix_idx = 0;
int i;
Stack_Init(&stack);
for(i = 0; i < token_count; i++)
{
Token token = tokens[i];
switch(token.type)
{
case TOKEN_NUMBER:
case TOKEN_CONSTANT:
case TOKEN_VARIABLE:
postfix[postfix_idx++] = token;
break;
case TOKEN_FUNCTION:
Stack_Push(&stack, token);
break;
case TOKEN_OPERATOR:
while(!Stack_IsEmpty(&stack) &&
Stack_Peek(&stack).type != TOKEN_LPAREN &&
GetOperatorPrecedence(Stack_Peek(&stack).value.op) >= GetOperatorPrecedence(token.value.op))
{
postfix[postfix_idx++] = Stack_Pop(&stack);
}
Stack_Push(&stack, token);
break;
case TOKEN_LPAREN:
Stack_Push(&stack, token);
break;
case TOKEN_RPAREN:
while(!Stack_IsEmpty(&stack) && Stack_Peek(&stack).type != TOKEN_LPAREN)
{
postfix[postfix_idx++] = Stack_Pop(&stack);
}
if(!Stack_IsEmpty(&stack) && Stack_Peek(&stack).type == TOKEN_LPAREN)
{
Stack_Pop(&stack); // 弹出左括号
}
else
{
calc_state.error_code = CALC_ERR_PAREN;
strcpy(calc_state.error_msg, "括号不匹配");
return -1;
}
// 如果函数栈顶是函数,弹出函数
if(!Stack_IsEmpty(&stack) && Stack_Peek(&stack).type == TOKEN_FUNCTION)
{
postfix[postfix_idx++] = Stack_Pop(&stack);
}
break;
}
}
// 弹出剩余运算符
while(!Stack_IsEmpty(&stack))
{
Token token = Stack_Pop(&stack);
if(token.type == TOKEN_LPAREN || token.type == TOKEN_RPAREN)
{
calc_state.error_code = CALC_ERR_PAREN;
strcpy(calc_state.error_msg, "括号不匹配");
return -1;
}
postfix[postfix_idx++] = token;
}
return postfix_idx;
}
// 计算后缀表达式
double EvaluatePostfix(Token postfix[], int count)
{
TokenStack stack;
Token token;
double a, b, result;
int i;
Stack_Init(&stack);
for(i = 0; i < count; i++)
{
token = postfix[i];
switch(token.type)
{
case TOKEN_NUMBER:
Stack_Push(&stack, token);
break;
case TOKEN_CONSTANT:
token.value.number = token.value.constant;
Stack_Push(&stack, token);
break;
case TOKEN_VARIABLE:
token.value.number = calc_state.variables[token.value.variable - 'A'];
Stack_Push(&stack, token);
break;
case TOKEN_OPERATOR:
if(Stack_Size(&stack) < 2)
{
calc_state.error_code = CALC_ERR_SYNTAX;
strcpy(calc_state.error_msg, "语法错误:缺少操作数");
return 0.0;
}
b = Stack_Pop(&stack).value.number;
a = Stack_Pop(&stack).value.number;
result = CalculateOperator(token.value.op, a, b);
if(calc_state.error_code != CALC_OK)
{
return 0.0;
}
token.type = TOKEN_NUMBER;
token.value.number = result;
Stack_Push(&stack, token);
break;
case TOKEN_FUNCTION:
if(Stack_IsEmpty(&stack))
{
calc_state.error_code = CALC_ERR_SYNTAX;
strcpy(calc_state.error_msg, "语法错误:函数缺少参数");
return 0.0;
}
a = Stack_Pop(&stack).value.number;
result = CalculateFunction(token.value.func, a);
if(calc_state.error_code != CALC_OK)
{
return 0.0;
}
token.type = TOKEN_NUMBER;
token.value.number = result;
Stack_Push(&stack, token);
break;
}
}
if(Stack_Size(&stack) != 1)
{
calc_state.error_code = CALC_ERR_SYNTAX;
strcpy(calc_state.error_msg, "语法错误:表达式格式不正确");
return 0.0;
}
return Stack_Pop(&stack).value.number;
}
// 计算函数
double CalculateFunction(FunctionType func, double arg)
{
double result;
switch(func)
{
case FUNC_SIN:
if(calc_state.angle_mode == 1) // 角度模式
result = sin(arg * 3.14159265358979323846 / 180.0);
else
result = sin(arg);
break;
case FUNC_COS:
if(calc_state.angle_mode == 1)
result = cos(arg * 3.14159265358979323846 / 180.0);
else
result = cos(arg);
break;
case FUNC_TAN:
if(calc_state.angle_mode == 1)
result = tan(arg * 3.14159265358979323846 / 180.0);
else
result = tan(arg);
break;
case FUNC_LOG:
if(arg <= 0)
{
calc_state.error_code = CALC_ERR_INVALID_OP;
strcpy(calc_state.error_msg, "对数函数的参数必须大于0");
return 0.0;
}
result = log10(arg);
break;
case FUNC_LN:
if(arg <= 0)
{
calc_state.error_code = CALC_ERR_INVALID_OP;
strcpy(calc_state.error_msg, "自然对数的参数必须大于0");
return 0.0;
}
result = log(arg);
break;
case FUNC_EXP:
result = exp(arg);
break;
case FUNC_SQRT:
if(arg < 0)
{
calc_state.error_code = CALC_ERR_INVALID_OP;
strcpy(calc_state.error_msg, "平方根的参数不能为负数");
return 0.0;
}
result = sqrt(arg);
break;
case FUNC_ABS:
result = fabs(arg);
break;
default:
calc_state.error_code = CALC_ERR_INVALID_OP;
strcpy(calc_state.error_msg, "不支持的函数");
return 0.0;
}
return result;
}
// 计算运算符
double CalculateOperator(OperatorType op, double a, double b)
{
double result;
switch(op)
{
case OPERATOR_PLUS:
result = a + b;
break;
case OPERATOR_MINUS:
result = a - b;
break;
case OPERATOR_MULTIPLY:
result = a * b;
break;
case OPERATOR_DIVIDE:
if(fabs(b) < 1e-10)
{
calc_state.error_code = CALC_ERR_DIV_ZERO;
strcpy(calc_state.error_msg, "除数不能为零");
return 0.0;
}
result = a / b;
break;
case OPERATOR_MODULO:
if(fabs(b) < 1e-10)
{
calc_state.error_code = CALC_ERR_DIV_ZERO;
strcpy(calc_state.error_msg, "取模运算的除数不能为零");
return 0.0;
}
result = fmod(a, b);
break;
case OPERATOR_POWER:
result = pow(a, b);
break;
default:
calc_state.error_code = CALC_ERR_INVALID_OP;
strcpy(calc_state.error_msg, "不支持的运算符");
return 0.0;
}
// 检查溢出
if(isinf(result) || isnan(result))
{
calc_state.error_code = CALC_ERR_OVERFLOW;
strcpy(calc_state.error_msg, "计算结果溢出");
return 0.0;
}
return result;
}
// 栈操作函数
void Stack_Init(TokenStack *stack)
{
stack->top = -1;
}
void Stack_Push(TokenStack *stack, Token item)
{
if(stack->top < MAX_STACK_SIZE - 1)
{
stack->items[++stack->top] = item;
}
}
Token Stack_Pop(TokenStack *stack)
{
Token empty_token;
empty_token.type = TOKEN_NUMBER;
empty_token.value.number = 0.0;
strcpy(empty_token.str, "");
if(stack->top >= 0)
{
return stack->items[stack->top--];
}
return empty_token;
}
Token Stack_Peek(TokenStack *stack)
{
Token empty_token;
empty_token.type = TOKEN_NUMBER;
empty_token.value.number = 0.0;
strcpy(empty_token.str, "");
if(stack->top >= 0)
{
return stack->items[stack->top];
}
return empty_token;
}
int Stack_IsEmpty(TokenStack *stack)
{
return stack->top == -1;
}
int Stack_Size(TokenStack *stack)
{
return stack->top + 1;
}
// 工具函数
int GetOperatorPrecedence(OperatorType op)
{
switch(op)
{
case OPERATOR_POWER: return 4;
case OPERATOR_MULTIPLY:
case OPERATOR_DIVIDE:
case OPERATOR_MODULO: return 3;
case OPERATOR_PLUS:
case OPERATOR_MINUS: return 2;
default: return 0;
}
}
int IsOperator(char c)
{
return (c == '+' || c == '-' || c == '*' || c == '/' || c == '%' || c == '^');
}
int IsFunction(char *str)
{
return (strcmp(str, "sin") == 0 || strcmp(str, "cos") == 0 ||
strcmp(str, "tan") == 0 || strcmp(str, "log") == 0 ||
strcmp(str, "ln") == 0 || strcmp(str, "exp") == 0 ||
strcmp(str, "sqrt") == 0 || strcmp(str, "abs") == 0);
}
3.4 串口驱动 (usart.c)
c
#include "usart.h"
// USART1初始化
void USART1_Init(uint32_t baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置USART1 TX (PA9) 和 RX (PA10)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART参数
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
// 配置中断
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 使能接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// 使能USART
USART_Cmd(USART1, ENABLE);
}
// 发送单个字符
void USART1_SendChar(char ch)
{
USART_SendData(USART1, (uint8_t)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
// 发送字符串
void USART1_SendString(char *str)
{
while(*str)
{
USART1_SendChar(*str++);
}
}
// 接收单个字符(非阻塞)
int USART1_GetChar(char *ch)
{
if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
{
*ch = (char)USART_ReceiveData(USART1);
return 1;
}
return 0;
}
// 重定向printf
int _write(int fd, char *ptr, int len)
{
int i;
for(i = 0; i < len; i++)
{
USART1_SendChar(ptr[i]);
}
return len;
}
3.5 测试程序 (test.c)
c
#include "calculator.h"
#include <assert.h>
// 测试函数
void RunCalculatorTests(void)
{
printf("========================================\r\n");
printf(" STM32 计算器测试\r\n");
printf("========================================\r\n");
// 测试基本运算
printf("测试基本运算:\r\n");
assert(fabs(Calculator_EvaluateExpression("2+3") - 5.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("10-4") - 6.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("3*7") - 21.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("15/3") - 5.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("17%5") - 2.0) < 1e-6);
printf(" 基本运算测试通过 ✓\r\n");
// 测试括号运算
printf("测试括号运算:\r\n");
assert(fabs(Calculator_EvaluateExpression("(2+3)*4") - 20.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("10/(2+3)") - 2.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("2*(3+4*(5-2))") - 30.0) < 1e-6);
printf(" 括号运算测试通过 ✓\r\n");
// 测试科学函数
printf("测试科学函数:\r\n");
assert(fabs(Calculator_EvaluateExpression("sin(pi/2)") - 1.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("cos(0)") - 1.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("sqrt(16)") - 4.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("log(100)") - 2.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("ln(e)") - 1.0) < 1e-6);
printf(" 科学函数测试通过 ✓\r\n");
// 测试变量
printf("测试变量存储:\r\n");
Calculator_EvaluateExpression("A=10");
Calculator_EvaluateExpression("B=20");
assert(fabs(Calculator_EvaluateExpression("A+B") - 30.0) < 1e-6);
assert(fabs(Calculator_EvaluateExpression("A*B") - 200.0) < 1e-6);
printf(" 变量存储测试通过 ✓\r\n");
// 测试错误处理
printf("测试错误处理:\r\n");
Calculator_EvaluateExpression("10/0"); // 除零错误
assert(calc_state.error_code == CALC_ERR_DIV_ZERO);
Calculator_EvaluateExpression("sqrt(-1)"); // 负数平方根
assert(calc_state.error_code == CALC_ERR_INVALID_OP);
printf(" 错误处理测试通过 ✓\r\n");
printf("========================================\r\n");
printf(" 所有测试通过!\r\n");
printf("========================================\r\n");
}
参考代码 STM32串口计算器 www.youwenfan.com/contentcsv/72257.html
四、编译与部署
4.1 Keil工程配置
Target: STM32F103C8
Device: STM32F103C8T6
C/C++:
Include Paths: .\inc; .\User; .\Hardware
Define: STM32F10X_MD, USE_STDPERIPH_DRIVER
Linker:
Scatter File: STM32_FLASH.sct
Debug:
Debugger: ST-Link Debugger
4.2 使用说明
-
连接硬件:将STM32通过USB-TTL连接到电脑
-
打开串口终端:使用PuTTY、SecureCRT等串口工具,设置115200波特率
-
基本计算:
calc> 2+3*4 结果: 14 -
科学计算:
calc> sin(pi/2) 结果: 1.000000 -
变量存储:
calc> A=10*5 A = 50.000000 calc> B=A+25 B = 75.000000 calc> (A+B)/2 结果: 62.500000 -
查看帮助:
calc> help
五、功能扩展建议
5.1 硬件扩展
- OLED显示:实时显示计算结果
- 矩阵键盘:物理按键输入
- SD卡存储:保存计算历史和配置
- RTC时钟:添加时间戳功能
5.2 软件扩展
- 复数运算:支持复数计算
- 矩阵运算:矩阵加减乘除
- 单位换算:长度、重量、温度等单位换算
- 编程模式:支持简单程序编写
- 图形显示:绘制函数图像