基于STM32的简易计算器proteus仿真设计(仿真+程序+设计报告+讲解视频)

基于STM32的简易计算器proteus仿真设计

  • 讲解视频
  • 1.主要功能
  • 2. 仿真
  • 3. 程序
  • 4. 设计报告
  • 5. 资料清单&下载链接

基于STM32的简易计算器proteus仿真设计(仿真+程序+设计报告+讲解视频)

仿真图proteus 8.9

程序编译器:keil 5

编程语言:C语言

设计编号:C0089

讲解视频

基于STM32的简易计算器proteus仿真+程序+设计报告+讲解视频

1.主要功能

功能说明:

本次嵌入式课程设计综合实验的内容为基于STM32单片机的简易计算器仿真设计系统。完成LCD1602液晶显示、矩阵按键扫描、LCD1602显示等多项任务。

一、该简易计算器设计硬件电路采用三部分电路模块构成:

1、键盘模块电路,采用 4*4 矩阵式键盘作为输入电路;

2、LCD1602 液晶显示模块;

3、以 STM32单片机作为控制核心。

二、软件程序主要由三部分组成: 主程序、按键扫描程序和 LCD1602 显示程序。

三、 性能指标

(1) 用STM32单片机设计一个简易计算器, 并用 1602 液晶显示相应的数据。

(2) 可以进行简单的整数加减乘除运算,具有清零功能。

(3) 最大可以 9999*9999。

(4) 可以通过 proteus 仿真。

主要硬件设备:STM32F103R6单片机 矩阵按键 LCD1602

2. 仿真

打开仿真工程,双击proteus中的单片机,选择hex文件路径,然后开始仿真。

然后开始仿真。

加法验证:

img

img

减法验证:

img

img

除法验证:

img

img

乘法验证:

img

img

3. 程序

程序是用keil5 mdk版本打开的,如果打开有问题,核实下keil的版本。程序是标准库版本编写的,有注释可以结合讲解视频理解。

img

#include "stm32f10x.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define uchar unsigned char		// 以后unsigned char就可以用uchar代替
#define uint  unsigned int		// 以后unsigned int 就可以用uint 代替
//=============================================================
//--- 1604 LCD驱动程序段 ---
#define   LCD_RS(x)   (x)?(GPIOC->ODR |= (1 << 8)):(GPIOC->ODR &=~(1 << 8))
#define   LCD_EN(x)   (x)?(GPIOC->ODR |= (1 << 9)):(GPIOC->ODR &=~(1 << 9))
#define   LCD_PORT(x) GPIOC->ODR = (GPIOC->ODR & 0xFF00) | x
#define   COM 0
#define   DAT 1
/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/ 
void DelayMs(uint time) 
{uint i,j; // 定义两个无符号整型变量i和j用于循环计数for(i=0;i<time;i++) // 外层循环,根据time值进行迭代for(j=0;j<200;j++); // 内层循环,每次迭代执行200次空操作,共同实现大约time毫秒的延迟
}// 向LCD写入数据或命令的函数,rs为0时写命令,rs为1时写数据,dat是要写入的具体数据
void LCD_Write(char rs,char dat) 
{
//    for(int i=0;i<600;i++); // 这里原有一个延时循环被注释掉了,现在使用下面的DelayMs函数替代DelayMs(1); // 引入一个1毫秒的延迟,可能是为了确保LCD有足够的时间处理上一条指令if(0 == rs) LCD_RS(0); // 如果rs为0,则设置LCD的数据/命令选择线为命令模式else LCD_RS(1); // 如果rs为1,则设置为数据模式LCD_EN(1); // 使能LCD写入信号LCD_PORT(dat); // 通过LCD_PORT函数向LCD发送dat数据LCD_EN(0); // 写入完成后,关闭LCD使能信号
}// 在指定位置写入单个字符到LCD,x决定列位置(0-3),y决定行位置。Data是要写入的字符
void LCD_Write_Char(char x,char y,char Data)
{if(0 == x) LCD_Write(COM,0x80 + y); // 设置LCD地址指针到第一列else if(1 == x) LCD_Write(COM,0xC0 + y); // 第二列else if(2 == x) LCD_Write(COM,0x90 + y); // 第三列(假设存在)else LCD_Write(COM,0xD0 + y); // 第四列(假设存在)LCD_Write(DAT,Data); // 在设定的位置写入字符数据
}// 在指定位置写入字符串到LCD,x决定列,y决定行,*s是字符串的指针
void LCD_Write_String(char x,char y,char *s)
{if(0 == x) LCD_Write(COM,0x80 + y); // 设置LCD地址指针到第一列else if(1 == x) LCD_Write(COM,0xC0 + y); // 第二列else if(2 == x) LCD_Write(COM,0x90 + y); // 第三列(假设存在)else LCD_Write(COM,0xD0 + y); // 第四列(假设存在)while(*s) LCD_Write(DAT,*s++); // 循环写入字符串中的每个字符直到结束
}// 清除LCD显示屏内容的函数
void LCD_Clear(void) 
{LCD_Write(COM,0x01); // 发送特定命令(0x01)到LCD以清屏
//    for(int i=0;i<60000;i++); // 原有的延时循环被注释,使用下面的DelayMs代替DelayMs(2); // 等待2毫秒让LCD完成清屏操作
}void LCD_Init(void) 
{LCD_Write(COM,0x38);                    //--- 显示模式设置 ---LCD_Write(COM,0x08);                    //--- 显示关闭 ---LCD_Write(COM,0x06);                    //--- 显示光标移动设置 ---LCD_Write(COM,0x0C);                    //--- 显示开及光标设置 ---LCD_Clear();
}void MyGPIO_Init(void)
{GPIO_InitTypeDef MyGPIO;//定义GPIO结构体初始化变量RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//打开GPIOC外设时钟MyGPIO.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 |GPIO_Pin_8 | GPIO_Pin_9;MyGPIO.GPIO_Speed = GPIO_Speed_50MHz;//设置响应速度MyGPIO.GPIO_Mode = GPIO_Mode_Out_PP;//设置PC0~PC9为通用推挽输出GPIO_Init(GPIOC,&MyGPIO);//调用GPIO初始化函数完成PC0~PC9引脚配置
}unsigned char KEYTAB[] = 
{0xD7,					    //00xEE,0xDE,0xBE,			    //1,2,30xED,0xDD,0xBD,			    //4,5,60xEB,0xDB,0xBB,			    //7,8,90x7E,0x7D,0x7B,0x77,		//A,b,C,d0xE7,0xB7,				    //E,F
};
#define ROWOUT_COLIN()  {\GPIOB->CRL = 0x44443333;\GPIOB->ODR = 0xF0;\}
#define ROWIN_COLOUT()  {\GPIOB->CRL = 0x33334444;\GPIOB->ODR = 0x0F;\}
#define KEY_PORT()      GPIOB->IDR
#define KEY_ROW         (KEY_PORT() & 0xF0)
#define KEY_COL         (KEY_PORT() & 0x0F)
int KeydlyCnt ;
int KeyBoard4X4_Scan(void)
{int i,Key = 0xFF;//读取列线引脚电平状态是否有键按下if((0xF0 != KEY_ROW) && (999999 != KeydlyCnt ) && (++KeydlyCnt  > 100)){if(0xF0 != KEY_ROW)//判断是否真得有键按下{KeydlyCnt  = 999999;Key = KEY_ROW;//获取列线的状态数值           KEY:1110 0000 0XE0ROWIN_COLOUT();//配置PB0~7为行线输入列线输出 KEY:0000 1110 0X0EKey |= KEY_COL; //获取行线状态并与列线状态数值合并 Key 1110 1110 0xeefor(i=0;i<sizeof(KEYTAB);i++)//查KEYTAB表是否存储该按键编码{if(KEYTAB[i] == Key)break;}//将编码值转换为数字代码存储到Key变量中if(i >= sizeof(KEYTAB))i = 0xFF;else Key = i;//key =1 if(Key < sizeof(KEYTAB)){if(Key < 10)Key += '0';else if(10 == Key)Key = '+';else if(11 == Key)Key = '-';else if(12 == Key)Key = '*';else if(13 == Key)Key = '/';else if(14 == Key)Key = 'C';else if(15 == Key)Key = '=';}ROWOUT_COLIN();//配置PB0~7为行线输出列线输入引脚}}else if(0xF0 == KEY_ROW){if(999999 == KeydlyCnt )KeydlyCnt  = 0;}return Key;// key =1
}//--- LCD模块上显示数字函数 ---
char LCD_DisplayNum(int x, int y, int val)
{int i; // 循环计数器int m, nflag; // m为辅助计数器,nflag标记数值是否为负char buff[10 + 1]; // 用于存储数字字符的缓冲区,最大支持10位数字加上结束符'\0'nflag = 0; // 初始化标志位,表示数值非负if (val < 0) nflag = 1; // 如果输入的数值为负,则设置nflag为1val = abs(val); // 将输入的数值转换为其绝对值以便处理// 初始化缓冲区,填充空格字符并设置结束符for (i = 0; i < sizeof(buff); i++) buff[i] = ' ';buff[sizeof(buff) - 1] = '\0';i = sizeof(buff) - 2; // 设置缓冲区的起始写入位置(从后向前)// 将数值转换为字符形式存入缓冲区while (val){buff[i--] = val % 10 + '0'; // 取当前数值的最后一位并转换为字符val /= 10; // 数值除以10进入下一位if (0 == i) break; // 如果已到达缓冲区的最前端,则停止}// 如果原始数值是负数,在适当位置插入负号if (nflag) buff[i--] = '-';// 移动缓冲区中的字符,去除前导空格for (m = 0; m <= i; m++){for (nflag = 1; nflag < sizeof(buff); nflag++) buff[nflag - 1] = buff[nflag]; // 缓冲区内的字符向前移动}// 将处理后的数字字符串显示在LCD上指定位置LCD_Write_String(x, y, buff);// 返回实际显示的数字字符长度(不包括前导空格)return strlen(buff);
}int ch,act,i,m;
long num1,num2,result;
char str1[12],str2[2];int main(void)
{MyGPIO_Init(); // 初始化自定义的GPIO设置LCD_Init(); // 初始化LCD显示屏RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 打开GPIOB端口的外设时钟ROWOUT_COLIN(); // 配置GPIOB的0到7引脚为行输出和列输入,用于键盘扫描LCD_Write_Char(1, 1, '0'); // 在LCD第一行显示该数字键while(1) // 无限循环,等待并处理按键事件{ch = KeyBoard4X4_Scan(); // 扫描4x4键盘并获取按键值if(0xFF != ch) // 如果获取到了有效的按键(0xFF表示未按下键){if((ch == '+') || (ch == '-') || (ch == '*') || (ch == '/')) // 检查是否为运算符{LCD_Write_Char(0, i++, ch); // 在LCD的第一行显示获取到的运算符act = ch; // 记录当前运算符num1 = atof(str1); // 将之前输入的数字字符串str1转换为浮点数并赋值给num1memset(str1, 0, 12); // 清空str1准备接收新的输入result += num1; // 累加结果}else if(ch == 'C') // 如果是清除键{i = act = 0; // 重置索引和当前运算符num1 = num2 = result = 0; // 重置所有数值memset(str1, 0, 12); // 清空输入字符串LCD_Write(COM, 0x01); // 发送清屏指令给LCD}else if(ch == '=') // 如果是等于号{LCD_Write_Char(1, 0, ch); // 在LCD第二行显示等于号num2 = atof(str1); // 将输入的数字字符串转换为浮点数num2// 根据之前记录的运算符执行相应的计算switch(act){case '+': result += num2; break;case '-': result -= num2; break;case '*': result *= num2; break;case '/': result /= num2; break;}memset(str1, 0, 12); // 清空输入字符串memset(str2, 0, 2); // 清空辅助字符串// 处理并显示计算结果i = 1;if(result < 1) LCD_Write_Char(1, i++, '0'); // 如果结果小于1,先显示0else{m = (int)result; // 取结果的整数部分i += LCD_DisplayNum(1, i, m); // 显示整数部分,并更新显示位置result -= m; // 从结果中减去已显示的整数部分,保留小数部分(如果有的话)}}else // 对于其他数字键{LCD_Write_Char(0, i++, ch); // 在LCD第一行显示该数字键sprintf(str2, "%c", ch); // 将按键字符格式化到str2strcat(str1, str2); // 将str2附加到str1,累积输入的数字字符串}}}
}

4. 设计报告

8586字设计报告,内容包括硬件设计、软件设计、调试、结论等。

img

本方案以高性能STM32系列单片机为核心,巧妙融合了硬件电路的精妙设计与高效软件编程技术,旨在打造一款既实用又便捷的计算工具。计算器不仅实现了基础的数学运算功能——包括加法、减法、乘法和除法运算,还贴心地加入了清零功能,使用户在连续计算或需要重新开始时能够快速重置,大大提升了使用的便捷性和效率。

设计的一大亮点在于其输入系统采用了4x4矩阵式键盘,这种设计在有限的空间内实现了丰富的功能输入选项,用户只需轻触按键,即可快速录入所需计算的数据或运算符号,极大地优化了人机交互体验。而运算结果显示则依托于经典的LCD1602液晶显示屏,清晰直观地展示每一步的运算过程及最终结果,使得计算过程一目了然,即便是复杂的运算序列也能轻松跟踪。

软件层面,设计团队精心编写了三大核心程序模块:主程序、按键扫描程序和LCD1602显示程序。主程序负责系统的整体调度与初始化,确保各组件协同工作;按键扫描程序通过高效的矩阵扫描算法,准确捕获用户的按键动作,实时响应用户指令;显示程序则动态更新屏幕内容,确保计算过程的每一步都得到及时反馈。这三大程序模块的有机结合,确保了计算器功能的完整实现与流畅运行。

5. 资料清单&下载链接

img

0、常见使用问题及解决方法–必读!!!!

1、程序代码

2、Proteus仿真

3、功能要求

4、开题报告

5、设计报告

6、讲解视频

Altium Designer 安装破解

KEIL+proteus 单片机仿真设计教程

KEIL安装破解

Proteus元器件查找

Proteus安装

Proteus简易使用教程

单片机学习资料

相关数据手册

答辩技巧

设计报告常用描述

鼠标双击打开查找嘉盛单片机51 STM32单片机课程毕业设计.url

资料下载链接:

https://pan.baidu.com/s/1eiEeurqSY2hBktaMKal3GQ?pwd=6vam

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/860456.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入JVM:详解JIT即时编译器

文章目录 深入JVM&#xff1a;详解JIT即时编译器一、序言二、基础概念1、何为JIT即时编译2、热点代码 三、HotSpot内置的即时编译器1、C1编译器2、C2编译器3、分层编译3.1 协作流程 四、常见JIT优化技术1、方法内联2、逃逸分析&#xff08;1&#xff09;同步锁消除&#xff08;…

数据结构:栈和队列详解

栈 栈的概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守先进后出LIFO&#xff08;Last In First Out&#xff09;的原则。大家可以理解为…

Day60 代码随想录打卡|回溯算法篇---组合

题目&#xff08;leecode T77&#xff09;&#xff1a; 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 方法&#xff1a;本题最直观的解法是使用暴力for循环遍历法&#xff0c;根据k的大小定for循环的嵌套次数&…

Posix消息队列使用总结

Posix在线文档&#xff1a; The Single UNIX Specification, Version 2 (opengroup.org) Linux系统中提供了两种不同接口的消息队列&#xff1a; POSIX消息队列。POSIX为可移植的操作系统接口。System V消息队列。System V 是 AT&T 的第一个商业UNIX版本(UNIX System III)的…

[Python人工智能] 四十六.PyTorch入门 (1)环境搭建、神经网络普及和Torch基础知识

从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前文讲解合如何利用keras和tensorflow构建基于注意力机制的CNN-BiLSTM-ATT-CRF模型,并实现中文实体识别研究。这篇文章将介绍PyTorch入门知识。前面我们的Python人工智能主要以TensorFlow和Keras为主,…

【Linux】进程间通信_4

文章目录 七、进程间通信1. 进程间通信分类systeam V共享内存消息队列信号量 未完待续 七、进程间通信 1. 进程间通信分类 systeam V共享内存 进程间通信的本质就是让不同进程看到同一份资源。而systeam V是通过让不同的进程经过页表映射到同一块内存空间&#xff08;操作系…

LED显示屏中什么是静态驱动?什么是扫描驱动?两者的区别是什么?

随着科技的飞速发展&#xff0c;LED显示屏作为现代信息显示技术的重要组成部分&#xff0c;正以其独特的优势引领着显示行业的革新。近日&#xff0c;LED显示屏市场呈现出蓬勃的发展态势&#xff0c;技术创新不断推动行业向前发展&#xff0c;让LED显示屏无论是在商场的广告牌、…

苏东坡传-读书笔记一

太守的官衙位于杭州中心&#xff0c;但是苏东坡却喜欢在较为富有诗意的地方办公。他往往在葛岭下面有十三间房子的寿星院办公&#xff0c;因为那里风光如画。看公文不在寒碧轩&#xff0c;就在雨奇堂。我们记得雨奇堂是从苏东坡西湖诗“山色空濛雨亦奇”而得名的。在这里&#…

04-Shell编程之正则表达式与文本处理器

4.1 正则表达式 4.1.1正则表达式概述 1.正则表达式的定义 正则表达式又称正规表达式&#xff0c;常规表达式。在代码中常简写为regex&#xff0c;regexp&#xff0c;或RE。正则表达式是使用一个字符来描述&#xff0c;匹配一系列符合某个句法规则的字符串&#xff0c;简单的…

【现代操作系统】什么是操作系统

1.前言 现代计算机系统由一个或多个处理器、主存、磁盘、打印机、键盘、鼠标、显示器、网络接口以及各种其他输入/输出设备组成。一般而言&#xff0c;现代计算机系统是一个复杂的系统。如果每位应用程序员都不得不掌握系统的所有细节&#xff0c;那就不可能再编写代码了。而且…

音视频入门基础:H.264专题(5)——FFmpeg源码中 解析NALU Header的函数分析

音视频入门基础&#xff1a;H.264专题系列文章&#xff1a; 音视频入门基础&#xff1a;H.264专题&#xff08;1&#xff09;——H.264官方文档下载 音视频入门基础&#xff1a;H.264专题&#xff08;2&#xff09;——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…

SpringBoot-在配置文件中使用Profile

Profile&#xff0c;译为“配置文件” 在这里的Spring Boot也是一样&#xff0c;我们可以配置很多个Profile&#xff0c;每个Profile都对应一整个完整的全局配置&#xff0c;激活哪个&#xff0c;那个对应的全局配置就生效&#xff0c;具体的配置&#xff1a; 1、properties格…

漏洞挖掘 | 记一次edusrc--轻松拿下中危信息泄露

1.前言 也是一次漏洞挖掘的思路分享 上次我们讲过了关于小程序方面的一些小思路&#xff0c;即关于抓包更改id号造成的一个信息泄露&#xff0c;但是在小程序上的信息泄露很难涉及到公民三要素这是一个痛点&#xff0c;今天就来分享一下一次edu挖掘时挖到的一个涉及公民三要素…

【讲师招募】PowerData 2024数字经济开源行

【讲师招募】PowerData 2024数字经济开源行 活动信息讲师招募往期活动回顾 活动信息 2023&#xff0c;社区经过一年的发展&#xff0c;凝聚起了一批热爱数据、热爱开源的伙伴。 2024&#xff0c;社区计划在全国十个城市举办"数字经济-城市开源行"活动&#xff0c;连…

2024年最新中级会计职称考试题库。

46.甲将一汇票背书转让给乙&#xff0c;但该汇票上未记载乙的名称。其后&#xff0c;乙在该汇票被背书人栏内记载了自己的名称。根据《票据法》的规定&#xff0c;下列有关该汇票背书与记载效力的表述中&#xff0c;正确的是&#xff08;&#xff09;。 A.甲的背书无效&#x…

Qt案例-ApplicationExamples-Calqlatr

项目 一个Qt Quick应用程序设计的横向和纵向设备&#xff0c;使用自定义组件&#xff0c;响应式布局和JavaScript的应用程序逻辑。 项目路径&#xff1a; Qt\Examples\Qt-6.7.1\demos 环境&#xff1a;Qt6.7.1 MSVC 2019 64位 项目目录&#xff1a; calqlatr--CMakeList.txt…

三、用户中心项目笔记----后端多环境实战+原始部署

后端多环境主要是修改&#xff1a; 依赖的环境地址 数据库地址 缓存地址 消息队列地址 项目端口号 服务器配置 后端怎么去区分不同的环境&#xff1f; 我们后端的SpringBoot项目&#xff0c;通过application.yml添加不同后缀来区分配置文件 application.yml就是公共的配置&a…

Sam Altman:从少儿奇才到OpenAI掌舵人

自2022年底发布了ChatGPT以来&#xff0c;OpenAI及其首席执行官Sam Altman迅速成为科技界的焦点人物。Altman的崛起并非偶然&#xff0c;而是长期以来不断追求权力和创新的结果。本文将回顾Altman的成长历程&#xff0c;探索他如何一步步走向OpenAI的顶峰。 童年与教育背景 S…

乌班图Ubuntu 24.04初始化MySQL报错error while loading shared libraries: libaio.so.1

由于乌班图24.04 LTS已经发布了&#xff0c;因此准备新业务逐步往这上面迁移&#xff0c;毕竟支持有效期比22.04更长 准备在24.04上进行MySQL的初始化&#xff0c;因为习惯自定义安装存储目录&#xff0c;所以使用mysql-8.0.37-linux-glibc2.28-x86_64.tar.xz这个最新的二进制版…

7款三维地球软件/框架:Google Earth SkylineGlobe,Cesium等

可视化大屏已经不满足于2D和3D展示了&#xff0c;开始向着星辰大海迈进了&#xff0c;本文介绍7款三维地球软件/开发框架&#xff0c;带各位老铁入个门。 1. Google Earth: 大名鼎鼎&#xff0c;Google Earth 是由 Google 开发的一款免费的虚拟地球软件。它提供了全球范围内的…