0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于STM32設(shè)計(jì)的計(jì)算器(實(shí)現(xiàn)基本運(yùn)算)

DS小龍哥-嵌入式技術(shù) ? 來源:DS小龍哥-嵌入式技術(shù) ? 作者:DS小龍哥-嵌入式技 ? 2022-05-18 10:56 ? 次閱讀

1. 項(xiàng)目介紹

計(jì)算器是最常見的工具了,現(xiàn)在不管是手機(jī)、電腦都帶有計(jì)算器功能,支持強(qiáng)大的科學(xué)運(yùn)算等。

當(dāng)前文章介紹的是STM32+LCD觸摸屏設(shè)計(jì)的一個(gè)觸摸計(jì)算器功能,實(shí)現(xiàn)基本的加減乘除,二進(jìn)制轉(zhuǎn)換顯示等功能。LCD屏使用的是3.5寸帶觸摸屏的顯示屏,方便操作屏幕,MCU采用STM32F103ZET6。

設(shè)計(jì)的這個(gè)計(jì)算器用到的硬件不多,主要是LCD屏和觸摸屏,用到了一個(gè)W25Q64存儲(chǔ)芯片,保存觸摸屏校準(zhǔn)后的一些配置數(shù)據(jù),這個(gè)可有可無,只是方便不需要每次斷電后重新校準(zhǔn)。

運(yùn)行效果圖如下:

poYBAGKEYFCAV0K3AAPhQx3jhMM240.pngpYYBAGKEYFCAKRxRAAPEWu9G_vY637.pngpoYBAGKEYFGANMhuAAO4DDiiwn4153.png

完整項(xiàng)目源碼下載地址: https://download.csdn.net/download/xiaolong1126626497/63976226

視頻演示地址: https://live.csdn.net/v/182604

2. 項(xiàng)目實(shí)現(xiàn)

2.1 運(yùn)算實(shí)現(xiàn)思路

功能介紹:

pYYBAGKEYFGAeMWtAARrvkNjfbQ189.png

在除法計(jì)算過程中,如果商是小數(shù),計(jì)算器得到的結(jié)果也是精準(zhǔn)的,是double類型。 在計(jì)算過程中,可以實(shí)現(xiàn)連續(xù)運(yùn)算。過程中是逐步計(jì)算出數(shù)據(jù)來的。

觸摸校準(zhǔn)流程:

poYBAGKEYFGADnEuAABnV-JMlig461.png

計(jì)算器算法:

poYBAGKEYFGADnEuAABnV-JMlig461.png

LCD的驅(qū)動(dòng)芯片是NT35310,支持8080時(shí)序讀寫寄存器,當(dāng)前項(xiàng)目采用模擬時(shí)序控制LCD屏,移植性較高。

核心代碼如下:

#include "lcd.h"
#include "stdlib.h"
#include "usart.h"	 
#include "delay.h"
#include "math.h"
#include "timer.h"
#include "spi.h"
#include "usart.h"
#include 
#include "key.h"
#include "rtc.h"
#include "wannianli.h"
#include "touch.h"
#include "led.h"
#include 
#include "shuzimo.h"
#include 
#include "calculator.h"

/*
函數(shù)功能:寫LCD數(shù)據(jù)
函數(shù)參數(shù):data:要寫入的值	
*/
void LcdWriteData(u16 data)
{	 
	 LCD_RS=1; //寫數(shù)據(jù)
	 LCD_CS=0; //選中LCD屏
	 
	 //輸出數(shù)據(jù)
	 LCD_DATA0=(data>>0&0x01);
	 LCD_DATA1=(data>>1&0x01);
	 LCD_DATA2=(data>>2&0x01);
	 LCD_DATA3=(data>>3&0x01);
	 LCD_DATA4=(data>>4&0x01);
	 LCD_DATA5=(data>>5&0x01);
	 LCD_DATA6=(data>>6&0x01);
	 LCD_DATA7=(data>>7&0x01);
	 LCD_DATA8=(data>>8&0x01);
	 LCD_DATA9=(data>>9&0x01);
	 LCD_DATA10=(data>>10&0x01);
	 LCD_DATA11=(data>>11&0x01);
	 LCD_DATA12=(data>>12&0x01);
	 LCD_DATA13=(data>>13&0x01);
	 LCD_DATA14=(data>>14&0x01);
	 LCD_DATA15=(data>>15&0x01);
	
	 LCD_WR=0; //表示準(zhǔn)備寫數(shù)據(jù)
	 LCD_WR=1; //表示數(shù)據(jù)寫完成
	 LCD_CS=1; //取消LCD屏片選
}


/*
函數(shù)功能:寫寄存器
參    數(shù):regval:寄存器值
*/	 
void LcdWriteReg(u16 data)
{
	 LCD_RS=0; //寫命令
	 LCD_CS=0; //選中LCD屏
	 
	 //輸出數(shù)據(jù)
	 LCD_DATA0=(data>>0&0x01);
	 LCD_DATA1=(data>>1&0x01);
	 LCD_DATA2=(data>>2&0x01);
	 LCD_DATA3=(data>>3&0x01);
	 LCD_DATA4=(data>>4&0x01);
	 LCD_DATA5=(data>>5&0x01);
	 LCD_DATA6=(data>>6&0x01);
	 LCD_DATA7=(data>>7&0x01);
	 LCD_DATA8=(data>>8&0x01);
	 LCD_DATA9=(data>>9&0x01);
	 LCD_DATA10=(data>>10&0x01);
	 LCD_DATA11=(data>>11&0x01);
	 LCD_DATA12=(data>>12&0x01);
	 LCD_DATA13=(data>>13&0x01);
	 LCD_DATA14=(data>>14&0x01);
	 LCD_DATA15=(data>>15&0x01);
	
	 LCD_WR=0; //表示準(zhǔn)備寫數(shù)據(jù)
	 LCD_WR=1; //表示數(shù)據(jù)寫完成
	 LCD_CS=1; //取消LCD屏片選
}


/*
函數(shù)功能:設(shè)置光標(biāo)位置
函數(shù)參數(shù):
         Xpos:橫坐標(biāo)
         Ypos:縱坐標(biāo)
*/
void LcdSetCursor(u16 Xpos, u16 Ypos)
{	 
	  LcdWriteReg(0X2A); 
		LcdWriteData(Xpos>>8);
	  LcdWriteData(Xpos&0XFF); 			 
		LcdWriteReg(0X2B); 
		LcdWriteData(Ypos>>8);
	  LcdWriteData(Ypos&0XFF); 
}



/*
功  能: 初始化LCD屏幕
說  明: 用于3.5寸屏幕的初始化。 
         LCD ID:5310
硬件連接:
硬件連接:
FSMC_D0 ------PD14
FSMC_D1 ------PD15
FSMC_D2 ------PD0
FSMC_D3 ------PD1
FSMC_D4 ------PE7
FSMC_D5 ------PE8
FSMC_D6 ------PE9
FSMC_D7 ------PE10
FSMC_D8 ------PE11
FSMC_D9 ------PE12
FSMC_D10 -----PE13
FSMC_D11 ------PE14
FSMC_D12 ------PE15
FSMC_D13 ------PD8
FSMC_D14 ------PD9
FSMC_D15 ------PD10

LCD_BL(背光) ----PB0
FSMC_NE4(CS) --->PG12
FSMC_NWE(WR/CLK)--->PD5 
FSMC_NOE(RD) --->PD4
FSMC_A10(RS) --->PG0
*/
void LcdInit(void)
{ 										    
		RCC->APB2ENR|=1<<3;     	//使能PORTB時(shí)鐘
		RCC->APB2ENR|=1<<5;     	//使能PORTD時(shí)鐘
		RCC->APB2ENR|=1<<6;     	//使能PORTE時(shí)鐘
		RCC->APB2ENR|=1<<8;      	//使能PORTG時(shí)鐘	 

		/*1. 初始化控制IO口*/
		GPIOB->CRL&=0xFFFFFFF0;  //LCD_BL(背光)
		GPIOB->CRL|=0x0000000B;
	
	  GPIOG->CRH&=0xFFF0FFFF;  //FSMC_NE4(CS)
		GPIOG->CRH|=0x00030000;
		
		GPIOD->CRL&=0xFF00FFFF;  //FSMC_NWE(WR/CLK)\FSMC_NOE(RD)
		GPIOD->CRL|=0x00330000;
	
		GPIOG->CRL&=0xFFFFFFF0;  //FSMC_A10(RS)
		GPIOG->CRL|=0x00000003;
	
		/*2. 初始化數(shù)據(jù)線*/
		GPIOD->CRL&=0xFFFFFF00;
		GPIOD->CRL|=0x00000033;
		GPIOD->CRH&=0x00FFF000;
		GPIOD->CRH|=0x33000333;
		GPIOE->CRL&=0x0FFFFFFF;
		GPIOE->CRL|=0x30000000;
		GPIOE->CRH&=0x00000000;
		GPIOE->CRH|=0x33333333;
}

/*
函數(shù)功能:畫點(diǎn)
函數(shù)形參:x,y:坐標(biāo)
*/
void LcdDrawPoint(u16 x,u16 y,u16 color)
{
	LcdSetCursor(x,y);		  //設(shè)置光標(biāo)位置 
	LcdWriteReg(0X2C);		  //開始寫入GRAM
	LcdWriteData(color);
}

/*
函數(shù)功能:顯示一個(gè)漢字
*/
 void LcdShowFont(u8 *font,u16 x,u16 y,u16 size,u16 high,u16 color1,u16 color2)
{
		u8 data;
	  u16 i,j,k;
		for(i=0;i;i++)>

2.3 觸摸屏代碼

觸摸屏采用XPT2046芯片,一個(gè)24位的ADC芯片,支持SPI接口。

代碼里主要完成兩個(gè)操作: 1. 讀取XPT2046檢測(cè)到的數(shù)據(jù) 2. 實(shí)現(xiàn)觸摸屏校準(zhǔn)算法

代碼如下:

#include "touch.h"
#include "delay.h"
#include "lcd.h"
#include "spi.h"
#include 

#define T_MOSI1 GPIOF->ODR|=1<<9;
#define T_MOSI0 GPIOF->ODR&=~(1<<9);
#define T_SCK1  GPIOB->ODR|=1<<1;
#define T_SCK0  GPIOB->ODR&=~(1<<1);
#define T_CS1   GPIOF->ODR|=1<<11;
#define T_CS0   GPIOF->ODR&=~(1<<11);

extern struct kxy
{
	float kx;
	float ky;
	u16 x1;
	u16 y1;
	u16 x2;
	u16 y2;
	u16 x3;
	u16 y3;
	u16 x4;
	u16 y4;
	u16 xx;
	u16 yy;
}xielv;

void touch_lint(void)
{
	RCC->APB2ENR|=1<<3;  //打開PB口時(shí)鐘
	RCC->APB2ENR|=1<<7;  //打開PF口時(shí)鐘
	
	GPIOB->CRL&=0XFFFFF00F; //配置PB口
	GPIOB->CRL|=0X00000830;
	
	GPIOF->CRH&=0XFFFF000F; //配置PF口
	GPIOF->CRH|=0X00003830;
	
	T_SCK1
	GPIOF->IDR|=1<<10;
	T_CS1;
	
}



void touch_write(u8 data) //往XPT2046中寫入命令
{
	u8 i;
	T_CS0
	T_SCK0
	T_MOSI0
	for(i=0;i<8;i++)
	{
		if(data&0x80) T_MOSI1
		else T_MOSI0
		T_SCK0
		T_SCK1
		data=data<<1;
	}
}

u16 touch_read(u8 data)  //從XPT2046中讀取數(shù)據(jù)
{
	u16 i,dat=0;
	touch_write(data);
	delay_us(6);
	for(i=0;i<16;i++)
	{
		dat=dat<<1;
		T_SCK0
		T_SCK1
		if(GPIOB->IDR&1<<2)
		{
			dat|=1<<0;
		}
	}
	T_CS1
	dat=dat>>4;
	return dat;
}

void si_shizi(u16 color)
{
	
		Draw_line(0,10,20,10,color); 
	  Draw_line(10,0,10,20,color); 
	  Draw_line(300,10,320,10,color);
	  Draw_line(310,0,310,20,color);
		Draw_line(0,470,20,470,color);
	  Draw_line(10,460,10,480,color);
	  Draw_line(300,470,320,470,color);
	  Draw_line(310,460,310,480,color);	
}

void jiaozhun(u16 x1,u16 y1,u16 x2,u16 y2,u16 x3,u16 y3,u16 x4,u16 y4)
{
	xielv.kx=(300.0/(x1-x2)+300.0/(x3-x4))/2;
	xielv.ky=(460.0/(y1-y3)+460.0/(y2-y4))/2;
}

void lcd_jiaozhun(void)
{
	 read_data((u8*)&xielv,791920,sizeof(struct kxy));
	 if(xielv.kx<0)
	 {
		 u8 *buff=malloc(100);
		 u8 *bufi=malloc(50);
		 u8 i=0;
		 u16 x0,y0;
		lcd_clear(0,0,YELLOW);
		si_shizi(BLUE);
		lcd_string((u8*)"校準(zhǔn)開始",buff,16,130,220,767600,32,64);
		delay_ms(3000);
		juxing_tianchong(80,220,160,16,YELLOW);
		lcd_string((u8*)"請(qǐng)點(diǎn)擊第一個(gè)十字中心",bufi,16,80,220,767600,32,64);
		while(1)
		{
			if(!(GPIOF->IDR&1<<10))
			{
				delay_ms(20);
				if(!(GPIOF->IDR&1<<10))
				{
					x0=touch_read(0xD0);
					y0=touch_read(0X90);
					i++;
					if(i==1)
					{
						Draw_line(0,10,20,10,YELLOW); 
						Draw_line(10,0,10,20,YELLOW);
						juxing_tianchong(80,220,160,16,YELLOW);
						lcd_string((u8*)"請(qǐng)點(diǎn)擊第二個(gè)十字中心",bufi,16,80,220,767600,32,64);
						xielv.x1=x0;
						xielv.y1=y0;
					}
					if(i==2)
					{
						Draw_line(300,10,320,10,YELLOW);
						Draw_line(310,0,310,20,YELLOW);
						juxing_tianchong(80,220,160,16,YELLOW);
						lcd_string((u8*)"請(qǐng)點(diǎn)擊第三個(gè)十字中心",bufi,16,80,220,767600,32,64);
						xielv.x2=x0;
						xielv.y2=y0;				
					}
					if(i==3)
					{
						Draw_line(0,470,20,470,YELLOW);
						Draw_line(10,460,10,480,YELLOW); 
						juxing_tianchong(80,220,160,16,YELLOW);
						lcd_string((u8*)"請(qǐng)點(diǎn)擊第四個(gè)十字中心",bufi,16,80,220,767600,32,64);
						xielv.x3=x0;
						xielv.y3=y0;
					}
					if(i==4)
					{
						Draw_line(300,470,320,470,YELLOW);
						Draw_line(310,460,310,480,YELLOW);
						juxing_tianchong(80,220,160,16,YELLOW);	
						lcd_string((u8*)"校準(zhǔn)完畢",buff,16,130,220,767600,32,64);
						delay_ms(3000);	
						juxing_tianchong(80,220,160,16,YELLOW);					
						xielv.x4=x0;
						xielv.y4=y0;
						jiaozhun(xielv.x1,xielv.y1,xielv.x2,xielv.y2,xielv.x3,xielv.y3,xielv.x4,xielv.y4);
						break;
					}
					delay_ms(40);
				}
			}
		}
		clear_shanqu(761920);
		write_every((u8*)&xielv,sizeof(struct kxy),791920);
	}
}

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • mcu
    mcu
    +關(guān)注

    關(guān)注

    146

    文章

    16664

    瀏覽量

    347726
  • STM32
    +關(guān)注

    關(guān)注

    2257

    文章

    10826

    瀏覽量

    352428
  • 計(jì)算器
    +關(guān)注

    關(guān)注

    16

    文章

    434

    瀏覽量

    37026
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    HarmonyOS開發(fā)案例:【計(jì)算器

    基于基礎(chǔ)組件、容器組件,實(shí)現(xiàn)一個(gè)支持加減乘除混合運(yùn)算計(jì)算器
    的頭像 發(fā)表于 05-07 15:31 ?963次閱讀
    HarmonyOS開發(fā)案例:【<b class='flag-5'>計(jì)算器</b>】

    編制程序實(shí)現(xiàn)計(jì)算器功能,包含加減乘除運(yùn)算

    編制程序實(shí)現(xiàn)計(jì)算器功能,包含加減乘除運(yùn)算。
    發(fā)表于 04-15 22:38

    STM32有關(guān)計(jì)算器的問題如何解決

    用板子STM32F103RB做了一個(gè)計(jì)算器,在運(yùn)算的時(shí)候按鍵會(huì)出錯(cuò),比如先按“3”,再按“4”的時(shí)候,有時(shí)候還會(huì)顯示“3”,按所有的按鍵有時(shí)候都會(huì)出現(xiàn)前一個(gè)按鍵按的字符,這是為什么啊?我是新手,各位大神幫忙解釋一下,謝謝!
    發(fā)表于 06-10 04:35

    計(jì)算器是怎么實(shí)現(xiàn)的呢

    大家都用過計(jì)算器,有沒有想過它是怎么實(shí)現(xiàn)的呢?這里我不詳述計(jì)算器的原理,而只對(duì)思路進(jìn)行簡(jiǎn)單介紹。等我們學(xué)會(huì)了單片機(jī),也可以親手制作一個(gè)計(jì)算器。
    發(fā)表于 11-09 09:07

    如何去實(shí)現(xiàn)基于單片機(jī)的四則運(yùn)算計(jì)算器設(shè)計(jì)

    基于單片機(jī)四則運(yùn)算計(jì)算器設(shè)計(jì)設(shè)計(jì)要求硬件設(shè)計(jì)設(shè)計(jì)要求使用keil c軟件基于單片機(jī)系統(tǒng)設(shè)計(jì)一個(gè)“簡(jiǎn)單的計(jì)算器”。要求設(shè)計(jì)的模擬計(jì)算器必須從按鈕輸入0~9組成一個(gè)數(shù),再從按鈕輸入加、減、乘和除運(yùn)
    發(fā)表于 11-19 08:04

    基于FDSJ86/FDSJ88實(shí)現(xiàn)的電子計(jì)算器

    基于FDSJ86/88實(shí)現(xiàn)的電子計(jì)算器 摘要: 本文旨在介紹一種用FDSJ86/88電子實(shí)驗(yàn)箱實(shí)現(xiàn)的能夠進(jìn)行加減乘除運(yùn)算的簡(jiǎn)易電子計(jì)算器
    發(fā)表于 06-21 09:29 ?26次下載

    應(yīng)用AutoCAD幾何計(jì)算器實(shí)現(xiàn)快速定位

    應(yīng)用AutoCAD幾何計(jì)算器實(shí)現(xiàn)快速定位    幾何計(jì)算器是AutoCAD R12提供的一個(gè)十分有用的工具。和普通的計(jì)算器一樣,幾何計(jì)算器
    發(fā)表于 02-14 17:08 ?1443次閱讀

    實(shí)用數(shù)制轉(zhuǎn)換及邏輯運(yùn)算計(jì)算器

    軟件介紹 二進(jìn)制,十進(jìn)制數(shù)值轉(zhuǎn)換,取余,取模,位或等邏輯運(yùn)算計(jì)算器
    發(fā)表于 03-04 16:54 ?228次下載
    實(shí)用數(shù)制轉(zhuǎn)換及邏輯<b class='flag-5'>運(yùn)算計(jì)算器</b>

    簡(jiǎn)易計(jì)算器

    計(jì)算器基于51單片機(jī)實(shí)現(xiàn)加減乘除四則運(yùn)算,資料附有調(diào)試運(yùn)行成功的源代碼。
    發(fā)表于 03-03 16:12 ?8次下載

    計(jì)算器-復(fù)數(shù)的計(jì)算方法

    利用不同的科學(xué)計(jì)算器計(jì)算復(fù)數(shù)運(yùn)算的步驟,幫你輕松解決復(fù)數(shù)運(yùn)算的煩惱
    發(fā)表于 03-22 11:26 ?0次下載

    LABVIEW簡(jiǎn)易計(jì)算器設(shè)計(jì)

    用于Labview實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器,可以簡(jiǎn)單計(jì)算四則運(yùn)算,比較一目了然和容易理解。
    發(fā)表于 03-28 16:14 ?159次下載

    基于FPGA的計(jì)算器設(shè)計(jì)(源碼)

    這是一個(gè)基于FPGA設(shè)計(jì)的四則運(yùn)算簡(jiǎn)易計(jì)算器??梢?b class='flag-5'>實(shí)現(xiàn)定點(diǎn)小數(shù)運(yùn)算和負(fù)數(shù)運(yùn)算。
    發(fā)表于 08-23 16:23 ?31次下載

    計(jì)算器復(fù)數(shù)運(yùn)算方法

    計(jì)算器上面復(fù)數(shù)轉(zhuǎn)換
    發(fā)表于 01-22 13:20 ?4次下載

    科學(xué)計(jì)算器價(jià)錢是多少_科學(xué)計(jì)算器使用方法_科學(xué)計(jì)算器使用注意事項(xiàng)

    科學(xué)型計(jì)算器是電子計(jì)算器的一種,可進(jìn)行乘方、開方、指數(shù)、對(duì)數(shù)、三角函數(shù)、統(tǒng)計(jì)等方面的運(yùn)算,又稱函數(shù)計(jì)算器??茖W(xué)型帶有所有普通的函數(shù),所有的函數(shù)都分布在鍵盤上以致于你可以不用通過菜單列表
    發(fā)表于 12-11 09:24 ?3411次閱讀

    電阻衰減網(wǎng)絡(luò)計(jì)算器設(shè)計(jì)與實(shí)現(xiàn)

    電阻衰減網(wǎng)絡(luò)計(jì)算器設(shè)計(jì)與實(shí)現(xiàn)
    發(fā)表于 06-22 09:58 ?22次下載