加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入

基于STM32的簡易計算器proteus仿真設(shè)計(仿真+程序+設(shè)計報告+講解視頻)

06/21 20:33
3638
服務(wù)支持:
技術(shù)交流群

完成交易后在“購買成功”頁面掃碼入群,即可與技術(shù)大咖們分享疑惑和經(jīng)驗、收獲成長和認同、領(lǐng)取優(yōu)惠和紅包等。

虛擬商品不可退

當前內(nèi)容為數(shù)字版權(quán)作品,購買后不支持退換且無法轉(zhuǎn)移使用。

加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論
放大
實物圖
相關(guān)方案
  • 方案介紹
    • 3. 程序
    • 4. 設(shè)計報告
  • 相關(guān)文件
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

基于STM32的簡易計算器proteus仿真設(shè)計(仿真+程序+設(shè)計報告+講解視頻)

仿真圖proteus 8.9

程序編譯器:keil 5

編程語言:C語言

設(shè)計編號:C0089

講解視頻:https://www.bilibili.com/video/BV1vn4y1Q7E2?t=30.3

1.主要功能
功能說明:

本次嵌入式課程設(shè)計綜合實驗的內(nèi)容為基于STM32單片機的簡易計算器仿真設(shè)計系統(tǒng)。完成LCD1602液晶顯示、矩陣按鍵掃描、LCD1602顯示等多項任務(wù)。

一、該簡易計算器設(shè)計硬件電路采用三部分電路模塊構(gòu)成:

1、鍵盤模塊電路,采用 4*4 矩陣式鍵盤作為輸入電路;

2、LCD1602 液晶顯示模塊;

3、以 STM32單片機作為控制核心。

二、軟件程序主要由三部分組成: 主程序、按鍵掃描程序和 LCD1602 顯示程序。

三、 性能指標

(1) 用STM32單片機設(shè)計一個簡易計算器, 并用 1602 液晶顯示相應(yīng)的數(shù)據(jù)。

(2) 可以進行簡單的整數(shù)加減乘除運算,具有清零功能。

(3) 最大可以 9999*9999。

(4) 可以通過 proteus 仿真。

主要硬件設(shè)備:STM32F103R6單片機 矩陣按鍵 LCD1602

2. 仿真
打開仿真工程,雙擊proteus中的單片機,選擇hex文件路徑,然后開始仿真。

然后開始仿真。

加法驗證:

減法驗證:

除法驗證:

乘法驗證:

3. 程序

程序是用keil5 mdk版本打開的,如果打開有問題,核實下keil的版本。程序是標準庫版本編寫的,有注釋可以結(jié)合講解視頻理解。

#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驅(qū)動程序段 ---
#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
/*********************************************************/
// 毫秒級的延時函數(shù),time是要延時的毫秒數(shù)
/*********************************************************/ 
void DelayMs(uint time) 
{
    uint i,j; // 定義兩個無符號整型變量i和j用于循環(huán)計數(shù)
    for(i=0;i<time;i++) // 外層循環(huán),根據(jù)time值進行迭代
        for(j=0;j<200;j++); // 內(nèi)層循環(huán),每次迭代執(zhí)行200次空操作,共同實現(xiàn)大約time毫秒的延遲
}

// 向LCD寫入數(shù)據(jù)或命令的函數(shù),rs為0時寫命令,rs為1時寫數(shù)據(jù),dat是要寫入的具體數(shù)據(jù)
void LCD_Write(char rs,char dat) 
{
//    for(int i=0;i<600;i++); // 這里原有一個延時循環(huán)被注釋掉了,現(xiàn)在使用下面的DelayMs函數(shù)替代
    DelayMs(1); // 引入一個1毫秒的延遲,可能是為了確保LCD有足夠的時間處理上一條指令
    if(0 == rs) LCD_RS(0); // 如果rs為0,則設(shè)置LCD的數(shù)據(jù)/命令選擇線為命令模式
    else LCD_RS(1); // 如果rs為1,則設(shè)置為數(shù)據(jù)模式
    LCD_EN(1); // 使能LCD寫入信號
    LCD_PORT(dat); // 通過LCD_PORT函數(shù)向LCD發(fā)送dat數(shù)據(jù)
    LCD_EN(0); // 寫入完成后,關(guān)閉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); // 設(shè)置LCD地址指針到第一列
    else if(1 == x) LCD_Write(COM,0xC0 + y); // 第二列
    else if(2 == x) LCD_Write(COM,0x90 + y); // 第三列(假設(shè)存在)
    else LCD_Write(COM,0xD0 + y); // 第四列(假設(shè)存在)
    LCD_Write(DAT,Data); // 在設(shè)定的位置寫入字符數(shù)據(jù)
}

// 在指定位置寫入字符串到LCD,x決定列,y決定行,*s是字符串的指針
void LCD_Write_String(char x,char y,char *s)
{
    if(0 == x) LCD_Write(COM,0x80 + y); // 設(shè)置LCD地址指針到第一列
    else if(1 == x) LCD_Write(COM,0xC0 + y); // 第二列
    else if(2 == x) LCD_Write(COM,0x90 + y); // 第三列(假設(shè)存在)
    else LCD_Write(COM,0xD0 + y); // 第四列(假設(shè)存在)
    while(*s) LCD_Write(DAT,*s++); // 循環(huán)寫入字符串中的每個字符直到結(jié)束
}

// 清除LCD顯示屏內(nèi)容的函數(shù)
void LCD_Clear(void) 
{
    LCD_Write(COM,0x01); // 發(fā)送特定命令(0x01)到LCD以清屏
//    for(int i=0;i<60000;i++); // 原有的延時循環(huán)被注釋,使用下面的DelayMs代替
    DelayMs(2); // 等待2毫秒讓LCD完成清屏操作
}

void LCD_Init(void) 
{
    LCD_Write(COM,0x38);                    //--- 顯示模式設(shè)置 ---
    LCD_Write(COM,0x08);                    //--- 顯示關(guān)閉 ---
    LCD_Write(COM,0x06);                    //--- 顯示光標移動設(shè)置 ---
    LCD_Write(COM,0x0C);                    //--- 顯示開及光標設(shè)置 ---
    LCD_Clear();
}

void MyGPIO_Init(void)
{
    GPIO_InitTypeDef MyGPIO;//定義GPIO結(jié)構(gòu)體初始化變量
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//打開GPIOC外設(shè)時鐘
    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;//設(shè)置響應(yīng)速度
    MyGPIO.GPIO_Mode = GPIO_Mode_Out_PP;//設(shè)置PC0~PC9為通用推挽輸出
    GPIO_Init(GPIOC,&MyGPIO);//調(diào)用GPIO初始化函數(shù)完成PC0~PC9引腳配置
}

unsigned char KEYTAB[] = 
{
	0xD7,					    //0
	0xEE,0xDE,0xBE,			    //1,2,3
	0xED,0xDD,0xBD,			    //4,5,6
	0xEB,0xDB,0xBB,			    //7,8,9
	0x7E,0x7D,0x7B,0x77,		//A,b,C,d
	0xE7,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;
    //讀取列線引腳電平狀態(tài)是否有鍵按下
    if((0xF0 != KEY_ROW) && (999999 != KeydlyCnt ) && (++KeydlyCnt  > 100))
    {
        if(0xF0 != KEY_ROW)//判斷是否真得有鍵按下
        {
            KeydlyCnt  = 999999;
					  Key = KEY_ROW;//獲取列線的狀態(tài)數(shù)值           KEY:1110 0000 0XE0
            ROWIN_COLOUT();//配置PB0~7為行線輸入列線輸出 KEY:0000 1110 0X0E
            Key |= KEY_COL; //獲取行線狀態(tài)并與列線狀態(tài)數(shù)值合并 Key 1110 1110 0xee
            for(i=0;i<sizeof(KEYTAB);i++)//查KEYTAB表是否存儲該按鍵編碼
            {
                if(KEYTAB[i] == Key)break;
            }
            //將編碼值轉(zhuǎn)換為數(shù)字代碼存儲到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模塊上顯示數(shù)字函數(shù) ---
char LCD_DisplayNum(int x, int y, int val)
{
    int i; // 循環(huán)計數(shù)器
    int m, nflag; // m為輔助計數(shù)器,nflag標記數(shù)值是否為負
    char buff[10 + 1]; // 用于存儲數(shù)字字符的緩沖區(qū),最大支持10位數(shù)字加上結(jié)束符'?'

    nflag = 0; // 初始化標志位,表示數(shù)值非負
    if (val < 0) nflag = 1; // 如果輸入的數(shù)值為負,則設(shè)置nflag為1
    val = abs(val); // 將輸入的數(shù)值轉(zhuǎn)換為其絕對值以便處理

    // 初始化緩沖區(qū),填充空格字符并設(shè)置結(jié)束符
    for (i = 0; i < sizeof(buff); i++) buff[i] = ' ';
    buff[sizeof(buff) - 1] = '?';

    i = sizeof(buff) - 2; // 設(shè)置緩沖區(qū)的起始寫入位置(從后向前)

    // 將數(shù)值轉(zhuǎn)換為字符形式存入緩沖區(qū)
    while (val)
    {
        buff[i--] = val % 10 + '0'; // 取當前數(shù)值的最后一位并轉(zhuǎn)換為字符
        val /= 10; // 數(shù)值除以10進入下一位
        if (0 == i) break; // 如果已到達緩沖區(qū)的最前端,則停止
    }

    // 如果原始數(shù)值是負數(shù),在適當位置插入負號
    if (nflag) buff[i--] = '-';

    // 移動緩沖區(qū)中的字符,去除前導空格
    for (m = 0; m <= i; m++)
    {
        for (nflag = 1; nflag < sizeof(buff); nflag++) 
            buff[nflag - 1] = buff[nflag]; // 緩沖區(qū)內(nèi)的字符向前移動
    }

    // 將處理后的數(shù)字字符串顯示在LCD上指定位置
    LCD_Write_String(x, y, buff);

    // 返回實際顯示的數(shù)字字符長度(不包括前導空格)
    return strlen(buff);
}


int ch,act,i,m;
long num1,num2,result;
char str1[12],str2[2];

int main(void)
{
    MyGPIO_Init(); // 初始化自定義的GPIO設(shè)置
    LCD_Init(); // 初始化LCD顯示屏
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 打開GPIOB端口的外設(shè)時鐘

    ROWOUT_COLIN(); // 配置GPIOB的0到7引腳為行輸出和列輸入,用于鍵盤掃描
	  LCD_Write_Char(1, 1, '0'); // 在LCD第一行顯示該數(shù)字鍵
    while(1) // 無限循環(huán),等待并處理按鍵事件
    {
        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); // 將之前輸入的數(shù)字字符串str1轉(zhuǎn)換為浮點數(shù)并賦值給num1
                memset(str1, 0, 12); // 清空str1準備接收新的輸入
                result += num1; // 累加結(jié)果
            }
            else if(ch == 'C') // 如果是清除鍵
            {
                i = act = 0; // 重置索引和當前運算符
                num1 = num2 = result = 0; // 重置所有數(shù)值
                memset(str1, 0, 12); // 清空輸入字符串
                LCD_Write(COM, 0x01); // 發(fā)送清屏指令給LCD
            }
            else if(ch == '=') // 如果是等于號
            {
                LCD_Write_Char(1, 0, ch); // 在LCD第二行顯示等于號
                
                num2 = atof(str1); // 將輸入的數(shù)字字符串轉(zhuǎn)換為浮點數(shù)num2
                // 根據(jù)之前記錄的運算符執(zhí)行相應(yīng)的計算
                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); // 清空輔助字符串
                // 處理并顯示計算結(jié)果
                i = 1;
                if(result < 1) LCD_Write_Char(1, i++, '0'); // 如果結(jié)果小于1,先顯示0
                else
                {
                    m = (int)result; // 取結(jié)果的整數(shù)部分
                    i += LCD_DisplayNum(1, i, m); // 顯示整數(shù)部分,并更新顯示位置
                    result -= m; // 從結(jié)果中減去已顯示的整數(shù)部分,保留小數(shù)部分(如果有的話)
                }
            }
            else // 對于其他數(shù)字鍵
            {
                LCD_Write_Char(0, i++, ch); // 在LCD第一行顯示該數(shù)字鍵
                sprintf(str2, "%c", ch); // 將按鍵字符格式化到str2
                strcat(str1, str2); // 將str2附加到str1,累積輸入的數(shù)字字符串
            }
        }
    }
}

4. 設(shè)計報告

8586字設(shè)計報告,內(nèi)容包括硬件設(shè)計、軟件設(shè)計、調(diào)試、結(jié)論等。

本方案以高性能STM32系列單片機為核心,巧妙融合了硬件電路的精妙設(shè)計與高效軟件編程技術(shù),旨在打造一款既實用又便捷的計算工具。計算器不僅實現(xiàn)了基礎(chǔ)的數(shù)學運算功能——包括加法、減法、乘法和除法運算,還貼心地加入了清零功能,使用戶在連續(xù)計算或需要重新開始時能夠快速重置,大大提升了使用的便捷性和效率。
設(shè)計的一大亮點在于其輸入系統(tǒng)采用了4x4矩陣式鍵盤,這種設(shè)計在有限的空間內(nèi)實現(xiàn)了豐富的功能輸入選項,用戶只需輕觸按鍵,即可快速錄入所需計算的數(shù)據(jù)或運算符號,極大地優(yōu)化了人機交互體驗。而運算結(jié)果顯示則依托于經(jīng)典的LCD1602液晶顯示屏,清晰直觀地展示每一步的運算過程及最終結(jié)果,使得計算過程一目了然,即便是復雜的運算序列也能輕松跟蹤。
軟件層面,設(shè)計團隊精心編寫了三大核心程序模塊:主程序、按鍵掃描程序和LCD1602顯示程序。主程序負責系統(tǒng)的整體調(diào)度與初始化,確保各組件協(xié)同工作;按鍵掃描程序通過高效的矩陣掃描算法,準確捕獲用戶的按鍵動作,實時響應(yīng)用戶指令;顯示程序則動態(tài)更新屏幕內(nèi)容,確保計算過程的每一步都得到及時反饋。這三大程序模塊的有機結(jié)合,確保了計算器功能的完整實現(xiàn)與流暢運行。
5. 資料清單&下載鏈接

0、常見使用問題及解決方法–必讀?。。。?/p>

1、程序代碼

2、Proteus仿真

3、功能要求

4、開題報告

5、設(shè)計報告

6、講解視頻

Altium Designer 安裝破解

KEIL+proteus 單片機仿真設(shè)計教程

KEIL安裝破解

Proteus元器件查找

Proteus安裝

Proteus簡易使用教程

單片機學習資料

相關(guān)數(shù)據(jù)手冊

答辯技巧

設(shè)計報告常用描述

鼠標雙擊打開查找嘉盛單片機51 STM32單片機課程畢業(yè)設(shè)計.url

資料下載鏈接:

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

  • 設(shè)計資料獲取聯(lián)系方式.doc

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風險等級 參考價格 更多信息
CC430F5137IRGZ 1 Texas Instruments 16-Bit ultra-low-power CC430 Sub 1 GHz wireless MCU with 12-Bit ADC, 32kB Flash and 4kB RAM 48-VQFN -40 to 85

ECAD模型

下載ECAD模型
$7.53 查看
S29AL016J70TFI020 1 Cypress Semiconductor Flash, 1MX16, 70ns, PDSO48, TSOP-48
$10.3 查看
LAN8720AI-CP-ABC 1 Microchip Technology Inc Ethernet Transceiver

ECAD模型

下載ECAD模型
$1.26 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜