【蓝桥杯单片机组实战】2、高级计算器

微信搜索ReCclay,也可免费阅读博主蓝桥系列所有文章,后台回复“代码”即可获取蓝桥所有备赛代码!关注博主公众号,还可拥有加入博主粉丝群实时沟通技术难题、免费下载CSDN资源等多项福利,还在等什么呢?快快扫码关注,学习才不会迷路

在这里插入图片描述

这里再向各位同学推荐一个CSDN博主 ReRrain 的蓝桥备赛博客,博主秉持初学者思路,向你讲述自己蓝桥备赛的心路历程,娓娓道来蓝桥备赛经验,个人觉得非常不错,值得细细品读。


导读:《蓝桥杯单片机组》专栏文章是博主2018年参加蓝桥杯的单片机组比赛所做的学习笔记,在当年的比赛中,博主是获得了省赛一等奖,国赛二等奖的成绩。成绩虽谈不上最好,但至少问心无愧。如今2021年回头再看该系列文章,仍然感触颇多。为了能更好地帮助到单片机初学者,今年特地抽出时间对当年的文章逻辑和结构进行重构,以达到初学者快速上手的目的。需要指出的是,由于本人水平有限,如有错误还请读者指出,非常感谢。那么,接下来让我们一起开始愉快的学习吧。

不积跬步无以至千里,不积小流无以成江海。


一、前言

学习完毕基础模块后,接下来就是一系列的小项目实战了。在该系列实战中,希望读者可以仔细研究每个实战项目的代码细节,力求吃透每一个小知识点,这样之后做起来省赛题目会感觉非常的得心应手!

本节我们将基于1602液晶显示器实现一个整形加减乘除计算器,该计算器不考虑连续操作,不考虑被除数等复杂问题。

二、代码实战

详细代码下载可以到我的Github<传送门>,这里就只拉出main.c,说下主要实现思路:

/*
*******************************************************************************
* 文件名:main.c
* 描  述:
* 作  者:CLAY
* 版本号:v1.0.0
* 日  期: 
* 备  注:
*         
*******************************************************************************
*/

#include "config.h"
#include "lcd1602.h"
#include "keyboard.h"


long num1=0, num2=0, result=0;
u8 step=0, oprt=0;
u8 T0RH, T0RL;

void ConfigTimer0(u16 ms);

void main()
{
	EA = 1;
	ConfigTimer0(1);
	InitLcd1602();
	LcdShowStr(15, 1, "0");

	while(1)
	{
		KeyDriver();
	}

}

u8 LongToStr(u8 *str, long dat)
{
	u8 i=0;
	u8 len=0;
	u8 buf[12];
	
	if(dat < 0)
	{
	 	dat = -dat;
		len++;
		*str++ = '-';
	}
	do{
		buf[i++] = dat % 10;
		dat /= 10;
	}while(dat > 0);
	len += i;
	
	while(i-- > 0)
	{
		*str++ = buf[i] + '0';
	}		
	*str = '\0';

	return len;
}

void Reset()
{
	step = 0;
	num1 = 0;
	num2 = 0;
	result = 0;	
	LcdFullClear();
}

void NumKeyAction(u8 num)
{
	u8 buf[16];
	u8 len;

 	if(step > 1)
	{
	 	Reset();
	}
	if(step == 0)
	{
	 	num1 = num1 * 10 + num;
		len = LongToStr(buf, num1);
		LcdShowStr(16-len, 1, buf);
	}
	else
	{
	 	num2 = num2 * 10 + num;
		len = LongToStr(buf, num2);
		LcdShowStr(16-len, 1, buf);
	}
}

void ShowOprt(u8 y, u8 type)
{
 	switch(type)
	{
	 	case 0: LcdShowStr(0, y, "+"); break;
		case 1: LcdShowStr(0, y, "-"); break;
		case 2: LcdShowStr(0, y, "*"); break;
		case 3: LcdShowStr(0, y, "/"); break;
		default: break;
	}
	oprt = type;
}

void OprtKeyAction(u8 type)
{
	u8 len;
	u8 buf[12];

	if(step == 0)
	{
	 	step = 1;
		ShowOprt(1, type);
		len = LongToStr(buf, num1);
		LcdShowStr(16-len, 0, buf);
		LcdShowStr(15, 1, "0");
		LcdAreaClear(1, 1, 14);
	}
}



void GetResult()
{
	u8 len;
	u8 buf[12];
	
	if(step == 1) //最好加上这个!
	{
	 	switch(oprt)
		{
		 	case 0: result = num1 + num2; break;
			case 1: result = num1 - num2; break;
			case 2: result = num1 * num2; break;
			case 3: result = num1 / num2; break;
			default: break;
		}
		
		step = 2;
		ShowOprt(0, oprt);
		LcdShowStr(0, 1, "=");
		len = LongToStr(buf, result);
		LcdAreaClear(1, 1, 15-len);
		LcdShowStr(16-len, 1, buf);
	}
}

void KeyAction(u8 keycode)
{
	if((keycode >= '0') && (keycode <= '9'))
	{
	 	NumKeyAction(keycode - '0');	
	} 	
	else if(keycode == 0x26)
	{
	 	OprtKeyAction(0);
	}
	else if(keycode == 0x28)
	{
		OprtKeyAction(1);
	}
	else if(keycode == 0x25)
	{
	 	OprtKeyAction(2);
	}
	else if(keycode == 0x27)
	{
	 	OprtKeyAction(3);
	}
	else if(keycode == 0x1B)
	{
	 	Reset();
		LcdShowStr(15, 1, "0");
	}
	else if(keycode == 0x0D)
	{
		GetResult();	 	
	}
}

void ConfigTimer0(u16 ms)
{
	u32 tmp;

	tmp = 11059200 / 12;
	tmp = (tmp * ms) / 1000;
	tmp = 65536 - tmp;
	T0RH = (u8)(tmp >> 8);
	T0RL = (u8)tmp;
	TMOD &= 0xF0;
	TMOD |= 0x01;
	TH0 = T0RH;
	TL0 = T0RL;
	ET0 = 1;
	TR0 = 1;
}

void InterruptTimer0() interrupt 1
{
 	TH0 = T0RH;
	TL0 = T0RL;

	KeyScan();
}

KeyAction 引出的几个函数,NumKeyActionOprtKeyActionReset 以及 GetResult 分别实现即可。 总体来看也就那么回事,就是实现的细节一不留神就出错了,务必谨慎谨慎再谨慎!

另外,我定义了两个全部变量stepoprt 来标记当前的输入状态(第一个数还是第二个数)以及 所要进行的运算类型。(因为这里是一次运算,所以直接定义了全局,相对方便。)

step 的变化是在输入符号 加减乘除或者等于号变的!因为一次运算,一旦按完等号我么那就让step = 2 对应的操作是 Reset。 还有一次运算放置连续运算出错我们只在OprtKeyAction 中处理step == 1 的情形,其他都不管。

代码需要注意的也就这么多,这种模块化思想是不是又更深入你心了呢?

结语:以上就是本篇文章的全部内容啦,希望大家可以多多支持我的原创文章。如有错误,请及时指正,非常感谢。


微信搜索ReCclay,即可免费阅读博主蓝桥系列所有文章,后台回复“代码”即可获取蓝桥所有备赛代码!关注博主公众号,还可拥有加入博主粉丝群实时沟通技术难题、免费下载CSDN资源等多项福利,还在等什么呢?快快扫码关注,学习才不会迷路

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ReCclay

如果觉得不错,不妨请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值