【51单片机】矩阵键盘逐行扫描法仿真实验+超详细Proteus仿真和Keil操作步骤

  • 一、环境
  • 二、硬件部分
    • 1. Proteus新建工程
    • 2. 添加元件
    • 3.连接线路
    • 4、硬件效果
  • 三、软件部分
    • 1、Keil5新建工程
    • 2、代码:
      • (1 思路分析
      • (2 添加头文件
      • (3 延时程序
      • (4 键盘扫描程序
      • (5 配置按键功能
      • (6 补坑
      • (7 深度补坑
      • (8 程序入口
  • 四、让程序跑起来
    • 1、生成.hex文件
    • 2、单片机添加程序文件
  • 五、 总结

一、环境

我用的是Keil5做编译工具,用proteus仿真。除了Keil5不知道有没有其他好用的能生成.hex文件的软件(要单片机运行是需要生成.hex文件的),Proteus则是一款很好用的仿真软件,原件很多。当然,之前有试过multisim14,也是非常不错的软件,自带有可以编写代码的文本编辑器,但没找到我想要的原件。所以选择了Proteus。

二、硬件部分

我们可以先打开Proteus:

1. Proteus新建工程

点击开始界面的创建工程,先创建一个Proteus的工程。

(注意:最好每个项目单独一个文件夹,后期的文件很乱很杂)
工程名写好,选择好文件夹,后面的可以一直下一步。

2. 添加元件

可以直接点红色箭头或者先点击“元件模式”然后点击“P”进入元件库。

可以输入80C51进行筛选,我用的是第一个80C51。
再找到筛选keypad,我用的是keypad-smallcalc。
接着找LED,选择的是LED-BARGRAPH-GRN,作为输出,也方便调试。

选好的元件就在这了。然后点击就能放置元件。

3.连接线路

4、硬件效果

当然,红色和蓝色的点不是接上线就有的,这是仿真之后的效果。其中,红色是高电平,蓝色是低电平,无色是无电平或脉冲不稳定,黄色为短路。
注意:Proteus的部分原件默认接了电源和接地,所以找不到电源和接地管脚。比如T80C51就是默认了接电源接地,所以没有20、40管脚。

三、软件部分

刚刚完成了硬件部分,和真实的硬件一样,我们都需要有程序才能让单片机工作。现在我们来用Keil5编写程序。虽然课程是用的汇编,但由于个人不太习惯汇编的程序,所以我尝试的是C语言。目标是做成一个简单的计算器。

1、Keil5新建工程

菜单栏的project下的new uVision project,选择好芯片**T80C51,**选择好地址 (可以和Proteus的工程放一个文件夹)
然后新建一个.c源文件,并把源文件添加到工程的 Source Group内。

2、代码:

(1 思路分析

想要做一个计算器,其中有“+、-、*、/ ” 。最开始我想到的是数字和运算符分开存放,然后再处理。后来发现无法预测输入的数字位数(因为每次只能输入一位,也不能像在黑窗口那样回车)。于是我决定把数字变成字符,跟运算符存放在一个char数列里,再分析处理数列,找出数字和运算符。

(2 添加头文件

添加头文件,并设置全局变量。

#include<reg51.h>
int cro[4] = {0xFE,0xFD,0xFB,0xF7};//存放行值。分别表示是P2.0口低电平,P2.1低电平…………
char indata[50];//用于存放键盘输入的字符数列
int len=0;//数列的长度
int fnum=0;//用于存放第一个操作数(处理数列得到的数字)
int lnum=0;//用于存放第二个操作数(处理数字得到的数字)
int ans=0;//存放计算结果
char op;//存放运算符

这是51单片机的头文件,里面包含了51单片机的存储器、端口

(3 延时程序

在单片机中延时程序经常用到,延时的方法也很多,有硬件延时、软件延时,汇编中可能会用nop,或者

MOV R0,100
DJNZ R0,$

在C语言中可以通过空循环来延时,就像下面这样。当然也有其他方法。

void delay_ms(int n){int i,j;for(i = 0; i < n; i++)for(j = 0; j < 1000; j++);
}//这里的值只是大概写的,n==1时不一定真是1ms。也可以算准确值。

如果一个循环够用或者容易控制时间的话,可以不用嵌套。

(4 键盘扫描程序

最先尝试的是矩阵键盘的线路反转法,但是中间出了些问题,暂时放弃了,改用 逐行扫描法
根据书上的原理,结合以上面的电路图 写出程序。

可见,我们的键盘连接了P2端口,低4位为行,高四位为列LED则连接的P1端口。以此为例。

先使行端口(即P2端口低四位)输出低电平,读列值。若读入的列值不为0FFH,则有键按下

int keyscan(){int temp;P2 = 0xf0;//给P12口送入11110000Btemp = P2 & 0xf0;//读取列值
}

注意:在C语言里,二进制是前面加0b或0B,八进制是加0,十六进制加0x或0X。如十进制123,二进制0b123或0B123,八进制0123,十六进制0x123或0X123。

这样就能完成 行输出低电平,读取列值的操作。如果列值不为0xf0,表示有键按下,有一位变成低电平。

当有键按下时,可以加10毫秒延时去抖。再进行逐行扫描。

扫描的过程是第四位逐位输出低电平,读不为0xff 的列值

int keyscan(){int n;int row;int temp;P2 = 0xf0;temp = P2 & 0xf0;if(temp != 0xf0){delay_ms(10)//这里需要加10毫秒延时去抖,for(n = 0; n < 4; n++ ){//遍历,低4位逐位输出0,直到找到按下键的列值P2 = cro[n];//P2口低位输出0rol = P2 & 0xf0;//读高四维if(rol != 0xf0){return (row|(cro[n]&0x0f));//找到按下键的列值后合成键码,并返回break;}}}
}

这就是逐行扫描的主要程序。

(5 配置按键功能

这时候我们发现,键码找对了,该怎么让它执行特定的程序呢?比如现在按"1",它并不代表"1"这个数。这个时候我们就需要给键配置一个功能或者含义。
我是这样定义的:

void act(int key){switch(key){case 0x77:indata[len++] = '+';P1 = 0x80;break;//输入的是运算符,输出运算符按键对应的行。并存放到前面定义的数组里,长度+1case 0xB7: show();                        break;//”=“键的功能是展示运算结果case 0xD7:indata[len++] = '0';P1 = 0x00;break;//输入的是数字,输出对应的二进制数case 0xE7:clear();                      break;//清零键的功能是清零case 0x7B:indata[len++] = '-';P1 = 0x40;break;case 0xBB:indata[len++] = '3';P1 = 0x03;break;case 0xDB:indata[len++] = '2';P1 = 0x02;break;case 0xEB:indata[len++] = '1';P1 = 0x01;break;case 0x7D:indata[len++] = '*';P1 = 0x20;break;case 0xBD:indata[len++] = '6';P1 = 0x06;break;case 0xDD:indata[len++] = '5';P1 = 0x05;break;case 0xED:indata[len++] = '4';P1 = 0x04;break;case 0x7E:indata[len++] = '/';P1 = 0x10;break;case 0xBE:indata[len++] = '9';P1 = 0x09;break;case 0xDE:indata[len++] = '8';P1 = 0x08;break;case 0xEE:indata[len++] = '7';P1 = 0x07;break;default:break;}
}

到这里我们的基本要求已经完成。接下来是完善的部分。

(6 补坑

刚才用到而没有定义的函数,show()clear()。现在就让我们来把这两个函数写出来。
首先是"="号键的功能函数show()

void show(){decode();//这是一个把存放按键的字符数组变成可以运算的数字的函数。operat();//把字符型的数字变成int型的数字后,就该计算了。这是运算函数。P1 = ans;//最终要把运算结果输出到LED。由于之前定义的是全局变量,所以不需要传参数
}

接下来是清零按键的功能,清零。

void clear(){int i;for(i=0;i<len;i++){//清空数组。数组没清空可能会影响第二次计算。indata[i] = '\0';}len=0;fnum=0;lnum=0;ans=0;op = '\0';for(i=0;i<3;i++){//LED闪烁三次,作为提醒。P1 = 0xff;delay_ms(20);P1 = 0x00;delay_ms(20);}
}

(7 深度补坑

前面的确做到了按哪个键输出对应的值。但是!!!我们怎么会满足于此呢?说好的计算器呢?
对!下面就来把运算功能的坑填一填。
首先是把字符数组的数据变成可以数学运算的数字。

void decode(){int i;int j;for(i = 0; i<len;i++){//先找到第一个数if(indata[i] >= '0' && indata[i] <= '9')fnum = fnum*10 + (indata[i]-'0');else break;}if(indata[i] == '+' || indata[i]=='-'||indata[i]=='*'||indata[i]=='/'){//然后找到中间的运算符op = indata[i];i++;}for(j = i; j<len;j++){//再找到第二个操作数。lnum = lnum*10 + (indata[j]-'0');}
}

是不是so easy?确实,都是基础。可能我的算法还不够好。暂且这么看着吧,提供一个思路。
然后,然后的然后就是该运算了。这个也非常简单,用一个多分支语句就能搞定了。

void operat(){switch(op){case '+':ans = fnum + lnum;break;case '-':ans = fnum - lnum;break;case '*':ans = fnum * lnum;break;case '/':ans = fnum / lnum;break;}
}

这样就能实现运算功能了。

(8 程序入口

最后我们只差一个程序入口函数了。把main() 函数加进去我们的程序就大功告成了。

void main(){while(1){act(keyscan());delay_ms(70);}
}

以上就是我编写时的思路和实现。

四、让程序跑起来

现在我们硬件搭建好了,软件也实现了,接下来就是让软件在硬件中跑起来。

1、生成.hex文件

先点击这个"Option for target"。

然后找到"Output"里的"Creat HEX File",把复选框勾上,然后编译的时候就能生成.hex文件。
例如这个
当然,这个文件也可能生成在"Object"文件夹里。
记住.hex文件的地址。

2、单片机添加程序文件

在Proteus中双击51单片机,进入单片机的属性窗口

点击"ProgramFile"后面的框选择文件,把刚才得到的.hex文件添加进去。点击左下角的开始仿真按键就可以试试自己写的程序的运行效果了。

输入了12 * 2 ,输出的是11000B,即24D;按下清零,LED闪烁提醒。功能基本实现。

五、 总结

这次时第一次用C写单片机,先前学的C似乎又能发挥作用了。但是没目前这个程序还是比较粗糙,可以再改进一下,比如可以做个连续运算的计算器,或者增加其他不一样的功能,包括多义键,以及输出设备LED也可以优化。
在这个过程中,我也发现自己的算法比较朴实无华,都是些常规的逻辑。希望有其他的做法的小伙伴一起讨论。
第一篇文章,还有点小兴奋……

【51单片机】矩阵键盘逐行扫描法仿真实验+超详细Proteus仿真和Keil操作步骤相关推荐

  1. 矩阵键盘逐行扫描C语言,(原创)51单片机C语言程序设计--速学教程实例(入门篇)之矩阵键盘(逐行扫描法).pdf...

    (原创)51单片机C语言程序设计--速学教程实例(入门篇)之矩阵键盘(逐行扫描法).pdf /***************************************************** ...

  2. 51单片机 玩转按键加减切换+数码管+Proteus仿真

    51单片机 玩转按键加减切换+数码管+Proteus仿真 实例代码 /* 实验说明:实验接线:1,动态数码管模块-->单片机管脚2,独立按键模块-->单片机管脚 K1-->P10K2 ...

  3. 基于51单片机宠物自动投料喂食器控制系统仿真设计( proteus仿真+程序+讲解视频)

    基于51单片机宠物自动投料喂食器控制系统仿真设计( proteus仿真+程序+讲解视频) 仿真图proteus 7.8及以上 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S00 ...

  4. 【003】基于51单片机的宠物自动定时、喂食系统的proteus仿真设计

    一.压缩包资料(私信获取) (1). 包含基于51单片机的宠物自动定时.喂食系统的proteus仿真设计一份: (2).包含基于51单片机的宠物自动定时.喂食系统keil源代码工程文件一份: (3). ...

  5. 8255A红绿灯c语言程序,51单片机外接8255A做成的交通灯程序及PROTEUS仿真结果(附对应C语言程序).doc...

    51单片机外接8255A做成的交通灯程序及PROTEUS仿真结果(附对应C语言程序) 51单片机外接8255A做成的交通灯程序及PROTEUS仿真结果(附对应C语言程序)2010-04-21 22:0 ...

  6. 51单片机矩阵键盘的控制原理-扫描及使用方式

    矩阵键盘 矩阵键盘一般和之前学的LCD1602液晶屏一起控制,建议先看一下之前的博客学习一下液晶屏的使用. 当然矩阵键盘也可以和数码管和LED等一起操作,但是数码管需要扫描,很费CPU,LED又不能直 ...

  7. 51单片机矩阵键盘——LCD1602显示

    1.前言 本次的实验需要用到LCD1602液晶屏,需要用到LCD1602.c 与LCD1602.h文件链接: https://download.csdn.net/download/YLG_lin/86 ...

  8. c51单片机矩阵键盘1602计算器_基于51单片机矩阵键盘的简易计算器制作

    1. 运算过程.符号公式实时显示在显示屏上(I2C 1602). 2. 自带三角函数.开根号.平方运算. 3. 计算得出的结果可设置保存并用以下一次计算. 4. 所有运算结果精确到至少小数点后两位. ...

  9. 51单片机矩阵键盘——数码管显示

    1.前言 当我们熟悉了数码管的位选与段选,并了解的矩阵键盘的扫描之后就可以编写程序了. 1.1实验现象 按下矩阵键盘S1并松开,数码管第一位(LED8)显示0:按下矩阵键盘S2并松开,数码管第一位显示 ...

最新文章

  1. Ubuntu 下获得root权限
  2. Python元组介绍
  3. 友盟分享小程序_iOS分享微信小程序
  4. 最全的BAT大厂面试题整理,系列篇
  5. 【分享】一个集成tracert和ping的网络监测工具
  6. storm的数据源编程单元Spout学习整理
  7. 为什么软件最终都会变得很复杂?
  8. Hessian Spring相关使用的简单例子
  9. java循环取出word table表格中所有的值
  10. [cocos2dx]斗地主制作之洗牌算法
  11. Node Stream pipe的诞生
  12. java内网环境使用代理访问外网api
  13. phpnow php.ini,phpnow php探针环境检测代码
  14. 如何显示隐藏的 Chrome 扩展程序图标
  15. C语言--小学生计算机辅助教学系统
  16. list object has no attribute ZScan_【恋爱体验】No.112丨大二男生,河南南阳,身高178,喜欢篮球、羽毛球、兵乓球、足球.........
  17. 崩坏3服务器维护2月8号,《崩坏3》2月8日更新内容 符华月轮正式上线
  18. Linux中部分命令英语全拼
  19. 解决Rem的适配问题
  20. 中关村GHOSTXPSP3纯净装机自选CD版V2010.02(FAT32/NTFS) 首款整合“极光”漏洞补丁

热门文章

  1. python 读文件 如何从第二行开始
  2. 达摩院技术创新全景|懂你的语音AI
  3. 图像像素与数据量之间的关系
  4. 在win上下载安装CTex及其注意事项
  5. 微信公众号网页底部不带返回栏 或者想要隐藏微信的底部导航栏
  6. 微服务设计中关于服务组合和可视化编排的思考
  7. 孕妇不能吃哪些食物?(协和妇产权威版)
  8. 我与程思阳的2020
  9. ubuntu12.04 禁用访客
  10. Python 读书笔记4 反脆弱:从不确定中获益