STM32 串口计算器实现

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 使用说明

  1. 连接硬件:将STM32通过USB-TTL连接到电脑

  2. 打开串口终端:使用PuTTY、SecureCRT等串口工具,设置115200波特率

  3. 基本计算

    复制代码
    calc> 2+3*4
    结果: 14
  4. 科学计算

    复制代码
    calc> sin(pi/2)
    结果: 1.000000
  5. 变量存储

    复制代码
    calc> A=10*5
    A = 50.000000
    calc> B=A+25
    B = 75.000000
    calc> (A+B)/2
    结果: 62.500000
  6. 查看帮助

    复制代码
    calc> help

五、功能扩展建议

5.1 硬件扩展

  1. OLED显示:实时显示计算结果
  2. 矩阵键盘:物理按键输入
  3. SD卡存储:保存计算历史和配置
  4. RTC时钟:添加时间戳功能

5.2 软件扩展

  1. 复数运算:支持复数计算
  2. 矩阵运算:矩阵加减乘除
  3. 单位换算:长度、重量、温度等单位换算
  4. 编程模式:支持简单程序编写
  5. 图形显示:绘制函数图像
相关推荐
狂奔v蜗牛9 小时前
压敏电阻的使用
嵌入式硬件
科芯创展9 小时前
XZ4115B工作电压6-40V 输出电流1.2A 降压恒流LED驱动芯片
stm32·单片机·嵌入式硬件
涂山苏苏⁠10 小时前
stm32之SPI
stm32
求知喻11 小时前
KEIL5构建软件最小系统
单片机·嵌入式
MC_J11 小时前
STM32H7 串口 UART/USART从原理到实战
stm32·单片机·嵌入式硬件
学不懂飞行器12 小时前
电赛保姆级教程】从炸管到国一:电赛电源类(DC-DC/单相逆变)硬核避坑与拓扑全指南
stm32·单片机·嵌入式硬件·电赛·fft
大阳12313 小时前
ARM5.(beep,key,中断)
单片机·嵌入式硬件
崇山峻岭之间13 小时前
单片机RNG实验
单片机·嵌入式硬件
JNX_SEMI13 小时前
EG1160:600V半桥驱动,2.5A强驱带保护
stm32·单片机·嵌入式硬件