当前位置: 首页 > article >正文

STM32简易计算机设计

运用 A0上拉按钮和 A1 A2下拉按钮设计按键功能     加上独特的算法检测设计,先计算()内在计算乘除在计算加减的值在计算乘除优先级最后计算加减优先级

#include "stm32f10x.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>#define EXPR_MAX_LEN 64
#define UART_BAUDRATE 115200/* 全局变量声明 */
char expr_buffer[EXPR_MAX_LEN] = {0};
char result_str[32] = {0};
volatile uint8_t expr_index = 0;
volatile uint8_t expr_ready = 0;
float calc_result = 0;
uint8_t result_available = 0;/* 函数原型声明 */
void GPIO_Configuration(void);
void USART1_Init(void);
void USART1_SendString(char *str);
void ProcessExpression(void);
float EvaluateExpression(char *expr);
int GetOperatorPriority(char op);int main(void) {
//    SystemInit();GPIO_Configuration();USART1_Init();USART1_SendString("Calculator Ready!\r\n");while(1) {/* 处理按键事件 */static uint8_t key1_state = 1, key2_state = 1, key3_state = 1;// KEY1 按下计算if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_SET && key1_state) {key1_state = 0;if(expr_ready) ProcessExpression();} else if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_SET) key1_state = 1;// KEY2 发送结果if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == Bit_RESET && key2_state) {key2_state = 0;if(result_available) USART1_SendString(result_str);} else if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == Bit_SET) key2_state = 1;// KEY3 清零if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) == Bit_RESET && key3_state) {key3_state = 0;expr_index = 0;expr_ready = 0;result_available = 0;memset(expr_buffer, 0, EXPR_MAX_LEN);USART1_SendString("Cleared\r\n");} else if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) == Bit_SET) key3_state = 1;}
}/* 处理接收到的表达式 */
void ProcessExpression(void) {expr_ready = 0;calc_result = EvaluateExpression(expr_buffer);if(isnan(calc_result)) {strcpy(result_str, "Error\r\n");} else {snprintf(result_str, sizeof(result_str), "Result: %.2f\r\n", calc_result);}result_available = 1;
}/* 支持多运算符和浮点数的表达式求值 */
float EvaluateExpression(char *expr) {float num_stack[EXPR_MAX_LEN] = {0};char op_stack[EXPR_MAX_LEN] = {0};int num_top = -1, op_top = -1;char *p = expr;float num = 0;int decimal = 0;float fraction = 1.0f;//进来保证不到最后一个字符不停止while(*p != '\0') {//如果是数字或者小数点就进行字符数字转换成真正的数字的操作if(isdigit(*p) || *p == '.') {if(*p == '.') {decimal = 1;} else {if(decimal) {fraction *= 0.1f;num += (*p - '0') * fraction;} else {num = num * 10 + (*p - '0');}}p++;} //如果是符号就判断这个elseelse {//将前面处理好的数字压入数字堆栈,如果遇到两次符号,也就是当+(..)就是(情况就会压入零代表当前数字,那就不会在主机算区算错因为0不管怎么样都零if(num != 0 || decimal) {num_stack[++num_top] = num;num = 0;   					//如果遇到两次符号,也就是当+(..)就是(情况就会压入零代表当前数字decimal = 0;fraction = 1.0f;}//若果判断到括号(那就记录一下碰到了括号,这样就会订掉一次计算,因为字符加减乘除和括号都是字符,这样加这一段可以防止误判断这里为计算时间上这里只是个括号if(*p == '(') {op_stack[++op_top] = *p;} //判断括号里卖你是不是有数字计算op_stack[op_top] != '('这句就是判断上一个符号如果还是)那就是括号里啥也没有,那就不判断计算else if(*p == ')') {while(op_top >= 0 && op_stack[op_top] != '(') {//那这一段只是处理)出现,代表此时的括号内算式已经结束,只需判断前面括号内的结果诚意最后一个数字的结果//处理两次符号区//如果遇到两次符号,也就是当+(..)就是(情况就会压入零代表当前数字/*辅助计算区*/char op = op_stack[op_top--];float b = num_stack[num_top--];float a = num_stack[num_top--];if(op == '+') num_stack[++num_top] = a + b;else if(op == '-') num_stack[++num_top] = a - b;else if(op == '*') num_stack[++num_top] = a * b;else if(op == '/') num_stack[++num_top] = a / b;/*辅助计算区*/}if(op_top >= 0) op_top--; // 弹出左括号} else {//时时刻刻在进行优先级判断计算运算式得出结果,为什么这里只判断后者与前者符号的差距呢,因为一个数字只要他前后符号优先级一样那就不具备优先级计算1*2*6==6*1*2但1+2*8!=1*8+2//所以有了这一段那你不管是不是括号内算式都可以具有优先级计算  /* 主计算区*/while(op_top >= 0 && GetOperatorPriority(op_stack[op_top]) >= GetOperatorPriority(*p)) {char op = op_stack[op_top--];float b = num_stack[num_top--];float a = num_stack[num_top--];if(op == '+') num_stack[++num_top] = a + b;else if(op == '-') num_stack[++num_top] = a - b;else if(op == '*') num_stack[++num_top] = a * b;else if(op == '/') num_stack[++num_top] = a / b;}/*主计算区*/op_stack[++op_top] = *p;}p++;}}if(num != 0 || decimal) {num_stack[++num_top] = num;}while(op_top >= 0) {char op = op_stack[op_top--];float b = num_stack[num_top--];float a = num_stack[num_top--];if(op == '+') num_stack[++num_top] = a + b;else if(op == '-') num_stack[++num_top] = a - b;else if(op == '*') num_stack[++num_top] = a * b;else if(op == '/') {if(fabs(b) < 1e-6) return NAN;num_stack[++num_top] = a / b;}}return num_top >= 0 ? num_stack[num_top] : NAN;
}/* 获取运算符优先级 */
int GetOperatorPriority(char op) {if(op == '+' || op == '-') return 1;if(op == '*' || op == '/') return 2;return 0;
}/* USART1中断处理 */
void USART1_IRQHandler(void) {if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {char ch = USART_ReceiveData(USART1);if(ch == '\r' || ch == '\n') {expr_buffer[expr_index] = '\0';expr_ready = 1;expr_index = 0;} else if(expr_index < EXPR_MAX_LEN-1) {expr_buffer[expr_index++] = ch;}USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}/* 初始化USART1 */
void USART1_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);// 配置TX(PA9)和RX(PA10)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;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_InitStructure.USART_BaudRate = UART_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);USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);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_Cmd(USART1, ENABLE);
}/* GPIO配置 */
void GPIO_Configuration(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// KEY1(PA0), KEY2(PA1), KEY3(PA2) 输入GPIO_InitStructure.GPIO_Pin =GPIO_Pin_1 | GPIO_Pin_2;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(GPIOA, &GPIO_InitStructure);
}/* 串口发送字符串 */
void USART1_SendString(char *str) {while(*str) {USART_SendData(USART1, *str++);while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);}
}

http://www.lryc.cn/news/2383280.html

相关文章:

  • GUI实验
  • 量子计算 | 量子密码学的挑战和机遇
  • linux系统查看硬盘序列号
  • 分享一些多模态文档解析思路
  • CSS 选择器入门
  • 【Django】Django DRF 中如何手动调用分页器返回分页数据(APIView,action场景)
  • AI知识梳理——RAG、Agent、ReAct、LangChain、LangGraph、MCP、Function Calling、JSON-RPC
  • Vue组件通信方式及最佳实践
  • 【实用教程】如何快速搭建一套私有的埋点系统?
  • 深入解析 Uniswap:自动做市商模型的数学推导与智能合约架构
  • spring配置并使用rabbitmq
  • Android开发——不同布局的定位属性 与 通用属性
  • React 19版本refs也支持清理函数了。
  • Python高效网络爬虫开发指南
  • Python爬虫实战:获取国家统计网最新消费数据并分析,为从业者做参考
  • Python中使用uv创建环境及原理详解
  • 阿尔泰科技助力电厂——520为爱发电!
  • 【Golang笔记02】函数、方法、泛型、接口学习笔记
  • C#语法篇 :基类子类转换,成员变化情况
  • 【漫话机器学习系列】264.内距(又称四分位差)Interquartile Range
  • 海外盲盒系统开发:重构全球消费体验的科技引擎
  • 高噪声下扩展边缘检测算子对检测边缘的影响
  • vuejs处理后端返回数字类型精度丢失问题
  • mysql数据库-中间件MyCat
  • 手搓四人麻将程序
  • PotPlayer 安装 madVR、LAV Filters 以提升解码能力和视频音频效果
  • 阿里云域名 绑定 华为云服务器ip
  • windows7安装node18
  • Maven配置安装
  • 小刚说C语言刷题—1153 - 查找“支撑数”