0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于STM32设计的计算器(实现基本运算)

DS小龙哥-嵌入式技术 来源:DS小龙哥-嵌入式技术 作者:DS小龙哥-嵌入式技 2022-05-18 10:56 次阅读

1. 项目介绍

计算器是最常见的工具了,现在不管是手机电脑都带有计算器功能,支持强大的科学运算等。

当前文章介绍的是STM32+LCD触摸屏设计的一个触摸计算器功能,实现基本的加减乘除,二进制转换显示等功能。LCD屏使用的是3.5寸带触摸屏的显示屏,方便操作屏幕,MCU采用STM32F103ZET6。

设计的这个计算器用到的硬件不多,主要是LCD屏和触摸屏,用到了一个W25Q64存储芯片,保存触摸屏校准后的一些配置数据,这个可有可无,只是方便不需要每次断电后重新校准。

运行效果图如下:

poYBAGKEYFCAV0K3AAPhQx3jhMM240.pngpYYBAGKEYFCAKRxRAAPEWu9G_vY637.pngpoYBAGKEYFGANMhuAAO4DDiiwn4153.png

完整项目源码下载地址: https://download.csdn.net/download/xiaolong1126626497/63976226

视频演示地址: https://live.csdn.net/v/182604

2. 项目实现

2.1 运算实现思路

功能介绍:

pYYBAGKEYFGAeMWtAARrvkNjfbQ189.png

在除法计算过程中,如果商是小数,计算器得到的结果也是精准的,是double类型。 在计算过程中,可以实现连续运算。过程中是逐步计算出数据来的。

触摸校准流程:

poYBAGKEYFGADnEuAABnV-JMlig461.png

计算器算法:

poYBAGKEYFGADnEuAABnV-JMlig461.png

LCD的驱动芯片是NT35310,支持8080时序读写寄存器,当前项目采用模拟时序控制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"

/*
函数功能:写LCD数据
函数参数:data:要写入的值	
*/
void LcdWriteData(u16 data)
{	 
	 LCD_RS=1; //写数据
	 LCD_CS=0; //选中LCD屏
	 
	 //输出数据
	 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; //表示准备写数据
	 LCD_WR=1; //表示数据写完成
	 LCD_CS=1; //取消LCD屏片选
}


/*
函数功能:写寄存器
参    数:regval:寄存器值
*/	 
void LcdWriteReg(u16 data)
{
	 LCD_RS=0; //写命令
	 LCD_CS=0; //选中LCD屏
	 
	 //输出数据
	 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; //表示准备写数据
	 LCD_WR=1; //表示数据写完成
	 LCD_CS=1; //取消LCD屏片选
}


/*
函数功能:设置光标位置
函数参数:
         Xpos:横坐标
         Ypos:纵坐标
*/
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时钟
		RCC->APB2ENR|=1<<5;     	//使能PORTD时钟
		RCC->APB2ENR|=1<<6;     	//使能PORTE时钟
		RCC->APB2ENR|=1<<8;      	//使能PORTG时钟	 

		/*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. 初始化数据线*/
		GPIOD->CRL&=0xFFFFFF00;
		GPIOD->CRL|=0x00000033;
		GPIOD->CRH&=0x00FFF000;
		GPIOD->CRH|=0x33000333;
		GPIOE->CRL&=0x0FFFFFFF;
		GPIOE->CRL|=0x30000000;
		GPIOE->CRH&=0x00000000;
		GPIOE->CRH|=0x33333333;
}

/*
函数功能:画点
函数形参:x,y:坐标
*/
void LcdDrawPoint(u16 x,u16 y,u16 color)
{
	LcdSetCursor(x,y);		  //设置光标位置 
	LcdWriteReg(0X2C);		  //开始写入GRAM
	LcdWriteData(color);
}

/*
函数功能:显示一个汉字
*/
 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芯片,一个24位的ADC芯片,支持SPI接口

代码里主要完成两个操作: 1. 读取XPT2046检测到的数据 2. 实现触摸屏校准算法

代码如下:

#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口时钟
	RCC->APB2ENR|=1<<7;  //打开PF口时钟
	
	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中读取数据
{
	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*)"校准开始",buff,16,130,220,767600,32,64);
		delay_ms(3000);
		juxing_tianchong(80,220,160,16,YELLOW);
		lcd_string((u8*)"请点击第一个十字中心",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*)"请点击第二个十字中心",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*)"请点击第三个十字中心",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*)"请点击第四个十字中心",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*)"校准完毕",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);
	}
}

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • mcu
    mcu
    +关注

    关注

    145

    文章

    15885

    浏览量

    342777
  • STM32
    +关注

    关注

    2232

    文章

    10649

    浏览量

    347876
  • 计算器
    +关注

    关注

    16

    文章

    424

    浏览量

    36456
收藏 人收藏

    评论

    相关推荐

    基于matlab的多功能计算器(转)

    是显示0,但是在按下数字之后,初始状态的0应该 被覆盖掉,而不随之左移。 3.现实中的计算器是有电源启动按钮的,如何仿真实现。 4.特别要注意的是从显示框中取到的数是字符,不能直接用于数值运算,一定
    发表于 12-19 14:31

    【作品分享】计算器

    `利用状态机编写的计算器小程序能力不足程序还有很多不足:不能连续运算、没有括号改变运算顺序等实现了基本功能算是抛砖引玉希望大神晒出自己的神作让楼主学习学习`
    发表于 10-12 11:42

    编制程序实现计算器功能,包含加减乘除运算

    编制程序实现计算器功能,包含加减乘除运算
    发表于 04-15 22:38

    简单计算器实现

    简单计算器实现
    发表于 05-13 17:22

    基于LabVIEW的科学计算器设计

    基于LabVIEW的科学计算器设计 。 功能:(1) 可以实现对于两个数据的加、减、乘、除等四则运算; (2) 可以实现开方、三角函数、对数、指数等
    发表于 10-17 19:31

    STM32有关计算器的问题如何解决

    用板子STM32F103RB做了一个计算器,在运算的时候按键会出错,比如先按“3”,再按“4”的时候,有时候还会显示“3”,按所有的按键有时候都会出现前一个按键按的字符,这是为什么啊?我是新手,各位大神帮忙解释一下,谢谢!
    发表于 06-10 04:35

    labview实现的中级计算器

    包含20个运算按键,能够求多个输入的计算器
    发表于 09-18 21:03

    怎样去设计一种基于STM32计算器

    文章目录前言一、开发步骤二、项目实现1.STM32实现串口通信2.STM32计算逻辑3.Qt界面设计3.1 界面的
    发表于 08-16 08:14

    如何去实现一基于51单片机的计算器设计

    进行多位的加减乘除运算。它主要由51单片机的数码管,键盘等模块组成。本计算器是将键盘输入信息经处理通过缓存,送入数码管显示,数码管采用动态扫描方式,计算功能通过软件实现,用C语言对单片
    发表于 11-09 06:43

    计算器是怎么实现的呢

    大家都用过计算器,有没有想过它是怎么实现的呢?这里我不详述计算器的原理,而只对思路进行简单介绍。等我们学会了单片机,也可以亲手制作一个计算器
    发表于 11-09 09:07

    如何实现基于FPGA的电子计算器设计

    今天给大侠带来基于FPGA的电子计算器设计,由于篇幅较长,分三篇。今天带来第二篇,中篇,话不多说,上货。导读本篇介绍了一个简单计算器的设计,基于 FPGA 硬件描述语言 Verilog HDL,系统
    发表于 11-11 08:31

    如何去实现基于单片机的四则运算计算器设计

    基于单片机四则运算计算器设计设计要求硬件设计设计要求使用keil c软件基于单片机系统设计一个“简单的计算器”。要求设计的模拟计算器必须从按钮输入0~9组成一个数,再从按钮输入加、减、乘和除
    发表于 11-19 08:04

    51单片机LCD1602显示四则混合运算计算器怎么实现

    51单片机LCD1602显示四则混合运算计算器怎么实现
    发表于 09-27 06:06

    应用AutoCAD几何计算器实现快速定位

    应用AutoCAD几何计算器实现快速定位    几何计算器是AutoCAD R12提供的一个十分有用的工具。和普通的计算器一样,几何计算器
    发表于 02-14 17:08 1378次阅读

    基于FPGA的计算器设计(源码)

    这是一个基于FPGA设计的四则运算简易计算器。可以实现定点小数运算和负数运算
    发表于 08-23 16:23 30次下载