送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。

计算器简介计算器是现代人发明的可以进行数字运算的电子机器。现代的电子计算器能进行数学运算的手持电子机器,拥有集成电路芯片,但结构简单,功能弱,但较为方便与廉价,

大家好,关于送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。很多朋友都还不太明白,今天小编就来为大家分享关于的知识,希望对各位有所帮助!

简单计算器

为了帮助单片机爱好者学习单片机,本计算器是以STC89C51RC系列单片机为核心组成的简易计算器系统。该系统由单片机控制,实现4*4键盘扫描的实时按键检测,并将过程和结果显示在LCD1602显示屏上。硬件比较简单,主要由四部分组成。第一部分是最小单片机系统;第二部分是4*4矩阵键盘;第三部分是LCD1602显示屏;第四部分是系统+5V供电。先说一下制作过程:

第一步,画电路原理图

以单片机为主控芯片的简易计算器示意图

第二步,根据设计绘制的原理图采购电子元件

所用电子元件详细清单

单片机主控芯片——-STC89C52RC 1片

LCD液晶显示模块——LCD1602 1片

点击按钮BUTTON — — 17

自锁开关按钮—— 1个

10K可调电阻—–1个

晶振—– 1

10K电阻—–9个

10UF电解电容—–1个

稳频电容30PF—-2个

PCB通用实验板—-1块

第三步,万能实验板的焊接

由于使用的原厂零件相对较少,因此焊接也相对简单。焊接时主要要注意的是,最好使用单片机芯片的插座,以方便编程。另外,LCD1602的引脚必须焊接正确,不能焊错。另一种是焊接16X16矩阵按钮时。还要注意。其他的则更容易焊接。

简单计算器电路板正面

简单计算器焊接反面

下面主要讲一下LCD1602液晶显示模块。大的通常在第一行显示16个小黑块,第二行不显示任何内容。这是1602液晶屏。 1602 LCD 的主显示容量为16 x 2 个字符。该芯片工作电压为4.5~5.5V,工作电流为2.0mA(5.0V),模块的最佳工作电压为5.0V 1602 LCD,从它的名字我们可以看出它的显示能力,即可以显示2行,每行16 个字符LCD。其工作电压为4.5V5.5V。我们可以直接将其连接到5V电源上,但是要保证我们的5V系统不能低于4.5V。 5V工作电压下测得其工作电流为2mA。请注意,这个2mA只是指液晶,其黄色和绿色背光都是由LED制成的,所以功耗一般为一到二十毫安。 1602 LCD共有16个引脚。每个引脚的功能在下面的注释中解释。

1.VSS—电源地

2. VDD—-电源正极

3、VL—-液晶偏置信号

4、RS—-数据/命令选择端子(H/L)

5. R/W—-读/写选择端(H/L)

6.E—-使能信号端

7、D0——数据I/O(输入输出口)

8.D1—数据I/O(输入输出口)

9.D2—数据I/O(输入输出口)

10、D3—数据I/O(输入输出口)

11.D4—数据I/O(输入输出口)

12、D5—数据I/O(输入输出口)

13、D6—数据I/O(输入输出口)

14、D7—数据I/O(输入输出口)

15、BLA——背光源正极(输入输出口)

16. BLK—-背光负极(输入输出口)

LCD1602正面

LCD1602背面

第四部分是程序编写部分

我们制作的最简单的计算器可以由两个部分组成:按钮和液晶。下面我们一起来学习一个简单的整数计算器。为了不让程序过于复杂,我们的计算器不考虑连续加减等连续计算,也不考虑小数。有加号键、减号键、乘号键、除号键、0-9键、等号键、清除键等16个键组成矩阵键盘。我们采用模块化编程,程序分为三部分。第一部分是主要功能模块,第二部分是1602液晶模块,第三部分是按键动作和扫描模块。我们先来说一下主程序模块。必要的陈述后添加注释,以方便大家理解。

主要功能模块

#包括reg52.h

无符号字符步=0; //操作步骤

无符号字符oprt=0; //操作类型

有符号长num1=0; //操作数1

有符号长num2=0; //操作数2

有符号长结果=0; //操作结果

无符号字符T0RH=0; //T0重载值的高字节

无符号字符T0RL=0; //T0重载值的低字节

extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);//清屏

无效主(无效)

{

EA=1; //使能总中断

配置定时器0(1); //配置T0时序1ms

InitLcd1602(); //初始化液晶屏

LcdShowStr(15, 1, ‘0’); //初始显示数字0

而(1)

{

密钥驱动程序(); //调用按键驱动

}

}

/* 将长整型转换为字符串,str – 字符串指针,dat – 需要转换的数字,返回值- 字符串长度*/

无符号char LongToString(无符号char *str, 有符号长dat)

{

有符号字符i=0;

无符号字符长度=0;

无符号字符buf[12];

if (dat 0) //如果是负数,先取绝对值,然后给指针加上负号

{

数据=-数据;

*str++=’-‘;

伦++;

}

do { //先转换为低位十进制数组

buf[i++]=dat % 10;

数据/=10;

而(数据0);

len+=i; //i的最后一个值是有效字符的个数

while (i– 0) //将数组值转换为ASCII码并反向复制到接收指针

{

*str++=buf[i] + ‘0’;

}

*str=’\0′; //添加字符串终止符

返回长度; //返回字符串的长度

}/* 显示运算符,显示位置y,运算符类型type */

void ShowOprt(unsigned char y, unsigned char 类型)

{

开关(类型)

{

案例0: LcdShowStr(0, y, ‘+’);休息; //0代表+

案例1: LcdShowStr(0, y, ‘-‘);休息; //1代表-

案例2: LcdShowStr(0, y, ‘*’);休息; //2代表*

案例3: LcdShowStr(0, y, ‘/’);休息; //3代表/

默认:中断;

}

}

/* 重置计算器,清除变量值,并清除屏幕显示*/

无效重置()

{

数字1=0;

数字2=0;

步长=0;

LcdFullClear();

}

/* 数字键动作函数,按键输入的n个数值*/

void NumKeyAction(无符号字符n)

{

无符号字符长度;

无符号字符str[12];

if (step 1) //如果计算完成,则重新开始新的计算

{

重置();

}

if (step==0) //输入第一个操作数

{

num1=num1*10 + n; //输入值累加到原操作数

len=LongToString(str, num1); //将新值转换为字符串

LcdShowStr(16-len, 1, str); //显示在LCD的第二行

}

else //输入第二个操作数

{

num2=num2*10 + n; //输入值累加到原操作数

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。

len=LongToString(str, num2); //将新值转换为字符串

LcdShowStr(16-len, 1, str); //显示在LCD的第二行

}

}

/* 操作员按键动作函数,操作员类型type */

void OprtKeyAction(无符号字符类型)

{

无符号字符长度;

无符号字符str[12];

if (step==0) //第二个操作数尚未输入时的响应,即不支持连续运算

{

len=LongToString(str, num1); //第一个操作数转换为字符串

LcdAreaClear(0, 0, 16-len); //清除第一行左边的字符位

LcdShowStr(16-len, 0, str); //字符串显示在第一行右侧

ShowOprt(1, 类型); //在第二行显示运算符

LcdAreaClear(1, 1, 14); //清除第二行中间的字符位

LcdShowStr(15, 1, ‘0’); //第二行最右端显示0

oprt=类型; //记录操作类型

步骤=1;

}

}

/* 计算结果函数*/

无效GetResult()

{

无符号字符长度;

无符号字符str[12];

if (step==1) //仅当第二个操作数输入后才进行计算

{

步骤=2;

switch (oprt) //根据运算符类型计算结果,不考虑溢出问题

{

案例0: 结果=num1 + num2;休息;

案例1: 结果=num1 – num2;休息;

案例2: 结果=num1 * num2;休息;

案例3: 结果=num1/num2;休息;

默认:中断;

}

len=LongToString(str, num2); //原来的第二个操作数和运算符显示在第一行

ShowOprt(0, oprt);

LcdAreaClear(1, 0, 16-1-len);

LcdShowStr(16-len, 0, str);

len=LongToString(str, 结果); //第二行显示计算结果和等号

LcdShowStr(0, 1, ‘=’);

LcdAreaClear(1, 1, 16-1-len);

LcdShowStr(16-len, 1, str);

}

}

/* 按键动作函数,根据按键码执行相应操作,keycode-key键码*/

void KeyAction(无符号字符键码)

{

if ((keycode=’0′) (keycode=’9′)) //输入字符

{NumKeyAction(键码- ‘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==0x0D) //输入按键,计算结果

{ 获取结果();}

else if (keycode==0x1B) //Esc键,清除

{

重置();

LcdShowStr(15, 1, ‘0’);

}

}

/* 配置并启动T0,ms-T0定时时间*/

void ConfigTimer0(无符号整数毫秒)

{

无符号长tmp; //临时变量

tmp=11059200/12; //定时器计数频率

tmp=(tmp * 毫秒)/1000; //计算需要的计数值

tmp=65536 – tmp; //计算定时器重载值

tmp=tmp + 28; //补偿中断响应延迟造成的错误

T0RH=(无符号字符)(tmp8); //定时器重载值分为高字节和低字节

T0RL=(无符号字符)tmp;

TMOD=0xF0; //清除T0的控制位

TMOD |=0x01; //配置T0为模式1

TH0=T0RH; //加载T0重载值

TL0=T0RL;

ET0=1; //使能T0中断

TR0=1; //开始T0

}

/* T0中断服务函数,执行按键扫描*/

void InterruptTimer0() 中断1

{

TH0=T0RH; //重新加载重载值

TL0=T0RL;

键盘扫描(); //按键扫描

}

1602液晶模组

#包括reg52.h

#定义LCD1602_DB P0

位LCD1602_RS=P1^0;

位LCD1602_RW=P1^1;

位LCD1602_E=P1^5;

/*等待LCD准备好*/

无效LcdWaitReady()

{

未签名的char sta;

LCD1602_DB=0xFF;

LCD1602_RS=0;

LCD1602_RW=1;

做{

LCD1602_E=1;

sta=LCD1602_DB; //读取状态字

LCD1602_E=0;

while (sta0x80); //bit7等于1,表示LCD忙,重复检测,直到等于0

}

/* 向LCD1602液晶写入一字节命令,cmd-要写入的命令值*/

void LcdWriteCmd(无符号字符cmd)

{

LcdWaitReady();

LCD1602_RS=0; LCD1602_RW=0; LCD1602_DB=cmd;

LCD1602_E=1; LCD1602_E=0;

}

/* 向LCD1602液晶写入一字节数据,dat-要写入的数据值*/

void LcdWriteDat(无符号字符数据)

{

LcdWaitReady();

LCD1602_RS=1; LCD1602_RW=0; LCD1602_DB=数据;

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。

LCD1602_E=1; LCD1602_E=0;

}

/* 设置显示RAM起始地址,即光标位置,(x,y)——对应屏幕上的字符坐标*/

void LcdSetCursor(无符号字符x,无符号字符y)

{

无符号字符地址;

if (y==0) //根据输入的屏幕坐标计算显示RAM的地址

地址=0x00 + x; //第一行的字符地址从0x00开始

别的

地址=0x40 + x; //第二行的字符地址从0x40开始

LcdWriteCmd(地址|0x80); //设置RAM地址

}

/* 在LCD上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针*/

void LcdShowStr(无符号字符x,无符号字符y,无符号字符*str)

{

LcdSetCursor(x, y); //设置起始地址

while (*str !=’\0′) //不断写入字符串数据,直到检测到终止符

{

LcdWriteDat(*str++);

}

}

/* 区域清除,清除从(x,y)坐标开始的len个字符位*/

void LcdAreaClear(无符号字符x,无符号字符y,无符号字符len)

{

LcdSetCursor(x, y); //设置起始地址

while (len–) //连续写空格

{

LcdWriteDat(”);

}

}

/* 清空整个屏幕*/

无效LcdFullClear()

{

LcdWriteCmd(0x01);

}

/* 初始化1602 LCD */

无效InitLcd1602()

{

LcdWriteCmd(0x38); //16*2显示,5*7点阵,8位数据接口

LcdWriteCmd(0x0C); //显示打开,光标关闭

LcdWriteCmd(0x06); //文字不动且地址自动+1

LcdWriteCmd(0x01); //清屏

}

在Lcd1602.c文件中,根据上层应用的需要,添加了两个清屏函数:区域清屏——LcdAreaClear,

清除整个屏幕——LcdFullClear。

按键操作及扫描模块

#包括reg52.h

sbit KEY_IN_1=P2^4; sbit KEY_IN_2=P2^5; sbit KEY_IN_3=P2^6;

sbit KEY_IN_4=P2^7;//定义输入端口

sbit KEY_OUT_1=P2^3;sbit KEY_OUT_2=P2^2;sbit KEY_OUT_3=P2^1;

sbit KEY_OUT_4=P2^0;//定义输出端口

unsigned char code KeyCodeMap[4][4]={ //矩阵键号到标准键盘键码的映射表

{ ‘1’, ‘2’, ‘3’,0x26 }, //数字键1,数字键2,数字键3,加号键

{ ‘4’, ‘5’, ‘6’,0x25 }, //数字键4、数字键5、数字键6、乘号键

{ ‘7’, ‘8’, ‘9’,0x28 }, //数字键7、数字键8、数字键9、减号键

{ ‘0’,0x1B,0x0D,0x27 } //数字键0、清除键、等号键、除号键

};

unsigned char pdata KeySta[4][4]={ //所有矩阵按键当前状态

{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}

};

extern void KeyAction(unsigned char keycode);

/* 关键驱动函数,检测关键动作并调度相应的动作函数。需要在主循环中调用*/

voidKeyDriver()

{

无符号字符i, j;

static unsigned char pdata backup[4][4]={ //键值备份,保存之前的值

{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}

};

for (i=0; i4; i++) //循环检测4*4矩阵按钮

{

对于(j=0; j4; j++)

{

if (backup[i][j] !=KeySta[i][j]) //检测按键动作

{

if (backup[i][j] !=0) //执行按钮按下时的动作

{

KeyAction(KeyCodeMap[i][j]); //调用按键动作函数

}

备份[i][j]=KeySta[i][j]; //刷新之前的备份值

}

}

}

}

/* 按键扫描函数,需要在定时中断中调用。建议调用间隔为1ms */

无效KeyScan()

{

无符号字符i;

静态无符号字符keyout=0; //矩阵按键扫描输出索引

static unsigned char keybuf[4][4]={ //矩阵按键扫描缓冲区

{0xFF,0xFF,0xFF,0xFF}, {0xFF,0xFF,0xFF,0xFF},

{0xFF,0xFF,0xFF,0xFF}, {0xFF,0xFF,0xFF,0xFF}

};

//将一行的4个键值移入缓冲区

keybuf[keyout][0]=(keybuf[keyout][0] 1) | keybuf[keyout][0]=(keybuf[keyout][0] 1) | KEY_IN_1;

keybuf[keyout][1]=(keybuf[keyout][1] 1) | keybuf[keyout][1]=(keybuf[keyout][1] 1) | KEY_IN_2;

keybuf[keyout][2]=(keybuf[keyout][2] 1) | keybuf[keyout][2]=(keybuf[keyout][2] 1) | KEY_IN_3;

keybuf[keyout][3]=(keybuf[keyout][3] 1) | keybuf[keyout][3]=(keybuf[keyout][3] 1) | KEY_IN_4; //去抖后更新按键状态

for (i=0; i4; i++) //每行有4个按钮,所以循环4次

{

if ((keybuf[keyout][i]0x0F)==0x00)

{ //当连续4次扫描值为0时,即4*4ms内按下按钮时,可以认为按钮已经稳定按下。

KeySta[keyout][i]=0;

}

否则if ((keybuf[keyout][i]0x0F)==0x0F)

{ //当连续4次扫描值为1时,即4*4ms内按钮处于弹出状态时,可以认为按钮已稳定弹起。

KeySta[keyout][i]=1;

}

} //执行下一次扫描输出

按键输出++; //输出索引递增

按键输出=0x03; //将索引值加4并返回零

switch (keyout) //根据索引,释放当前输出引脚,并将下一个输出引脚拉低

{

情况0: KEY_OUT_4=1; KEY_OUT_1=0;休息;

情况1: KEY_OUT_1=1; KEY_OUT_2=0;休息;

情况2: KEY_OUT_2=1; KEY_OUT_3=0;休息;

情况3: KEY_OUT_3=1; KEY_OUT_4=0;休息;

默认:中断;

}

}

Keyboard.c是对之前多次使用过的矩阵按键驱动的封装,具体是某个按键要执行的动作。

操作函数均在上层main.c中实现。该按键驱动文件只负责调用上层实现的按键动作函数。 main.c文件实现了所有应用层操作功能,即计算器功能所需的信息显示、按键动作响应等,还包括主循环的调度和定时中断。通过这样的程序,我们一方面可以学习如何对多个.c文件进行编程,另一方面可以学习如何灵活调用多个函数。您可以将此程序视为一个简单的练习小项目。

第五部分调试

调试完成的结果界面3795X593

用户评论

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
七级床震

我刚买了第一个单片机想尝试自己做一个简单的计算器,这个教程看起来很合适!之前对单片机的概念了解不多,希望能跟着学习掌握一些基础知识。感谢分享!

    有14位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
封心锁爱

太赞了!我一直很喜欢动手做东西,看到这篇文章立马跃跃欲试。打算周末动手试试看,希望能够顺利完成制作,到时候一定会分享成果!

    有14位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
安之若素

单片机确实很强大,很多功能都可以实现!我之前也做一个简单的计时器,这个计算器的教程看着更有难度,需要好好学习一下电路和编程知识。感谢作者的详细讲解!

    有12位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
丢了爱情i

做计算器的思路很简单,关键就在于逻辑程序的设计吧?我是初学单片机的小白一枚,这方面还不太熟练,希望能多多关注类似的文章学习经验,期待自己也能打造出功能完善的计算器!

    有12位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
↘▂_倥絔

制作一个简易计算器虽然难度不高,但需要对单片机的各个部分功能了解透彻,以及算法设计能力。文章讲解清晰易懂,相信能让初学者快速上手!

    有9位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
肆忌

我有一个想法,这个基础的计算器可以进行改进,例如支持更精细的操作,或者加入其他功能比如单位转换等等。作者可以在接下来的博文里分享一下这些改进方案吗?我很期待看到更多惊喜!

    有19位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
稳妥

说实话,我还蛮喜欢用现成的智能手机计算器,毕竟操作简单、功能强大啊!自己做的单片机计算器虽然很有挑战性,但似乎实用性有限。不过还是感谢作者的分享,让我对单片机的开发有了一些基本了解。

    有13位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
青衫故人

这个教程太棒了!我已经开始学习了,一步步跟着做,感觉渐渐掌握了其中的诀窍。等项目完成之后一定要分享我的成果!

    有11位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
£烟消云散

文章写的很棒,能够清晰地解释复杂的知识点,并且用简洁的语言描述电路图和程序代码。对于初学者来说非常友好,能够让我快速入门单片机开发!

    有14位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
各自安好ぃ

这个教程确实适合初学者学习,但我觉得可以添加一些更详细的例子和实践环节,这样会更加生动有趣!

    有12位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
有一种中毒叫上瘾成咆哮i

我之前也有试过用单片机制作计算器,但是遇到了很多问题,例如数字显示不正确等等。不知道作者有没有遇到类似的问题,以及如何解决呢?

    有15位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
那伤。眞美

这篇教程虽然不错,但感觉缺少一些趣味性要素,例如可以加入一些音乐或灯效的控制,让计算器更生动有趣!

    有16位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
涐们的幸福像流星丶

我已经做了一个简单的计算器,但是显示屏只有两行,想增加更多行,该如何修改代码呢?希望作者能提供一些建议!

    有7位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
眷恋

佩服作者的动手能力!这种从零开始自己制作工具的体验真的很棒!我以后也要学习一下单片机编程知识,实现自己的创意!

    有5位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
﹎℡默默的爱

看到这么详细的教程,我更有信心来尝试制作简易计算器了!感谢作者分享经验!期待更多关于单片机的干货内容!

    有16位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
忘故

这个想法很棒,但我觉得可以考虑使用更加便捷的编程工具,例如Arduino IDE,这样会更容易上手!希望作者可以在后续文章中介绍这些工具的使用方法!

    有18位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
毒舌妖后

制作自己计算器的过程很有趣,也能够加深我对单片机硬件和软件的理解。感谢作者分享这个动手实践的机会! 我要赶紧动手试试了!

    有13位网友表示赞同!

送给刚接触微控制器的朋友的礼物。使用微控制器制作一个简单的计算器。
雪花ミ飞舞

对于像我这样初学电工的小白来说,这种教程太棒了!既能学习到单片机的知识,又能制作出实用的工具,简直是一举两得!

    有14位网友表示赞同!

原创文章,作者:小su,如若转载,请注明出处:https://www.sudun.com/ask/132295.html

(0)
小su's avatar小su
上一篇 2024年9月17日 下午11:53
下一篇 2024年9月17日 下午11:55

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注