自学单片机-8

第8章 函数进阶与按键

		用户与单片机之间的信息交互依赖两类设备:输入设备和输出设备。前边讲的LED小灯、数码管、点阵都是输出设备,本章就来学习一下最常用的输入设备-————按键,同时还会学到硬件电路的一些基础知识与C语言函数的一些进阶知识。

8.1 单片机最小系统

8.1.1 电源

	在学习过程中,很多指标都是概念指标,比如说+5V代表1,GND代表0等。但在实际电路中的电压值并不是完全精准的,那这些指标的允许范围是什么呢?随着所学内容的不断增多,大家要慢慢培养阅读数据手册的习惯。
	例如,要使用STC89C52RC单片机的时候,找到它的数据手册第11页,看第二项-------工作电压:3.4~5.5V(5V单片机),这说明这个单片机正常的工作电压是一个范围值,只要电源VCC在3.4~5.5V都可以正常工作,电压超过5.5V是绝对不允许的,会烧坏单片机,电压低于3.4V,单片机不会损坏,但是也不能正常工作。而在这个范围内,最典型、最常用的电压值就是5V,这就是后面括号里”5V单片机“这个名称的由来。除此之外,还有一种常用的工作电压是2.7~3.6V、典型值是3.3V的单片机,也就是所谓的”3.3V单片机”。随着接触更多的器件,对这点会有更深刻的理解。
	再顺便多了解一点,打开74HC138的数据手册,会发现74HC138手册的第二页也有一个表格,上边写了74HC138的工作电压范围,最小值是4.75V,额定值是5V,最大值是5.25V,可以得知它的工作电压是4.75~5.25V。这个地方讲这些目的是让大家清楚地了解,获取器件工作参数的一个重要、最权威的途径就是查阅该器件的数据手册。

8.1.2 晶振

	晶振通常分为无源晶振和有源晶振两种类型,无源晶振一般称为crystal(晶体),而有源晶振则叫作oscillator(振荡器)。
	有源晶振是一个完整的谐振振荡器,它是利用石英晶体的压电效应起振,所以有源晶振需要供电,当把有源晶振电路做好后,不需要外接其他器件,只要给它供电,它就可以主动产生振荡频率,并且可以提供高精度的频率基准,信号质量也比无源信号稳定。
	无源晶振自身无法振荡起来,它需要芯片内部的振荡电路一起工作才能振荡,它允许不同的电压,但是信号质量和精度较有源晶振差一些。相对价格来说,无源晶振要比有源晶振价格便宜得多。无源晶振两侧通常都会有一个电容,一般其容值为10~40pF,如果手册中有具体电容值的要求则要根据要求来选电容,如果手册没有要求,用20pF是比较好的选择, 这是一个长久以来的经验值,具有极其普遍的适用性。
	下面来认识一下比较常用的两种晶振,如图8-1和图8-2所示。

在这里插入图片描述
有源晶振通常有4个引脚,VCC、GND、晶振输出引脚和一个用不到的悬空引脚(有些晶振也把该引脚作为使能引脚)。无源晶振有2个或3个引脚,如果是3个引脚,则中间的引脚接晶振的外壳,使用时要接到GND,两侧的引脚就是晶体的两个引出脚了,这两个引脚作用是等同的,就像电阻的两个引脚一样,没有正负之分。对于无源晶振,用单片机上的两个晶振引脚接上即可,而有源晶振,只接到单片机晶振的输入引脚,输出引脚不需要连接,分别如图8-3和图8-4所示。
![在这里插入图片描述](https://img-blog.csdnimg.cn/067a9ed31a7d4a259a8c15a9e3f59c75.png#pic_cente
在这里插入图片描述

8.1.3 复位电路

	先来分析一下KST-51开发板上的复位电路,如图8-5所示。
	![在这里插入图片描述](https://img-blog.csdnimg.cn/9d7be0fb36b044e581844edf2c69cde3.png#pic_center)

在这里插入图片描述 当这个电路处于稳态时,电容起到隔离直流的作用,隔离了+5V,而左侧的复位按键是弹起状态,复位按键下面部分电路就不产生电压差,所以按键和电容C11以下部分的电位都是和GND相等的,也就是0V。这个单片机是高电平复位,低电平正常工作,所以正常工作的电压是0V。
再来分析从没有电到上电的瞬间,电容C11上方电压是5V,下方是0V,根据初中所学的知识,电容C11要进行充电,正离子从上往下充电,负电子从GND往上充电,这时电容对电路来说相当于一根导线,全部电压都加在R31这个电阻上,RST端口上的电压值等于电流乘以R31的阻值,因此也就会越来越小,一直到电容完全充满后,线路上不再有电流,这时RST和GND的电位就相等了,也就是0V。
从这个过程来看,加上这个电路,单片机系统上电后,RST引脚会先保持一小段时间的高电平而后变成低电平,这个过程就是上电复位的过程。这个“一小段时间”到底是多少才合适呢?每种单片机不完全一样,51单片机手册里写的是持续时间不少于两个机器周期。每种单片机的复位电压值不完全一样,按照通常值0.7VCC作为复位电压值,复位时间的计算比较复杂,这里只给大家一个结论,时间t=1.2RC,取R=4700欧,C=0.0000001法,那么计算出t就是0.000564s,即564微秒,远远大于两个机器周期(2微秒),在电路设计的时候一般留够余量就行。
按键复位(即手动复位)有两个过程,按下按键之前,RST的电压是0V,当按下按键后电路导通,同时电容也会在瞬间进行放电,RST电压值变为4700VCC/(4700+18),处于高电平复位状态。松开按键后和上电复位类似,先是电容充电,后电流逐渐减小直到RST电压变0V。按下按键的时间通常都会有几百毫秒,这个时间足够复位了。按下按键的瞬间,电容两端的5V电压(注意不是电源的5V和GND之间)会直接接通,此刻会有一个瞬间的大电流冲击,在局部范围内产生电磁干扰,为了抑制这个大电流所引起的干扰,这里在电容放电回路中串入一个18欧的电阻来限流。
如果有的读者已经想开始设计自己的电路板,那么单片机最小系统的设计现在已经有了足够的理论依据了,可以考虑尝试一下。基础比较薄弱的同学先不要着急,继续跟着往下学,把相关知识都学完了再动手操作也不迟。

8.2 函数的调用

		在一个程序的编写过程中,随着代码量的增加,如果把所有的语句都写到main函数中,一方面程序会显得比较乱,另一方面,当同一个功能需要在不同地方执行时,就得再重复写一遍相同的语句。此时,如果把一些零碎的功能单独写成一个函数,则在需要它们时只需要进行一些简单的函数调用,这样既有助于程序结构的清晰条理,又可以避免大量的代码重复。
	在实际工程项目中,一个程序通常都是由很多个子程序模块组成的, 一个模块实现一个特定的功能,在C语言中,这个模块用函数来表示。一个C程序一般由一个主函数和若干个其他函数构成。主函数可以调用其他函数,其他函数也可以相互调用,但其他函数不能调用主函数。在51单片机程序中,还有中断服务函数,在相应的中断到来后自动调用,不需要也不能由其他函数调用。
	函数调用的一般形式是:
	函数名(实参例表)
	函数名就是需要调用的函数的名称,实参列表就是根据实际需求调用函数要传递给被调用函数的参数列表,不需要传递参数时只保留括号就可以了,传递多个参数时参数之间要用逗号隔开。
	先举例看一下函数调用使程序结构更加条理清晰方面的作用。回顾一下图6-1所示的程序流程图和为实现它而编写的程序代码,相对来说这个主函数的结构就比较复杂了,很难一眼看清楚它的执行流程。如果把其中最重要的两件事----秒计数和数码管动态扫描功能一一都用单独的函数来实现会怎样呢?来看以下程序。
	![在这里插入图片描述](https://img-blog.csdnimg.cn/52e4d0ef13304552b5552090c6d5f20d.png#pic_center)

在这里插入图片描述
在这里插入图片描述 看一下,主函数的结构是不是清晰多了------每隔1ms就去干两件事, 至于这两件事是什么, 交由各自的函数去实现。还请大家注意一点:原来程序中的i、cnt、sec这三个变量在放到单独的函数中后,都加了static关键字而变成了静态变量。因为原来的main()永远不会结束,所以它们的值也总是得到保持,但它们在各自的功能函数内,如不加static修饰,那么每当函数被调用时它们的值就都成为初值,借此也对静态变量再加深一下理解吧。
当然,这是我们刻意把程序功能做了这样的划分,主要目的是讲解函数的调用,对于这个程序,即使不划分函数也复杂不到哪里去,但继续学下去你就能领会到划分功能函数的必要了。现在还是注意力放在学习函数调用上,有以下几点需要大家注意:
(1)函数调用的时候,不需要加函数类型。在主函数内调用SecondCount()和LedRefresh()时都没有加void。
(2)调用函数与被调用函数的位置关系。C语言规定:函数在被调用之前,必须先被定义或声明。意思就是说:在一个文件中,一个函数应该先定义,然后才能被调用,也就是调用函数应位于被调用函数的下方。但是作为一种通常的编程规范,一般推荐main函数写在最前面(因为它起到提纲挈领的作用),其后再定义各个功能函数,而中断函数则写在文件的最后。那么主函数要调用定义在它之后的函数怎么办呢?在文件开头(所有函数定义之前)开辟一块区域,叫作函数声明区,用来把被调用的函数声明一下,如此,该函数就可以被随意调用了。
(3)函数声明的时候必须加函数类型,函数的形式参数,最后加上一个分号表示结束。函数声明行与函数定义行的唯一区别就是最后的分号,其他的都必须保持一致。这点尤其注意,初学者很容易因粗心大意而搞错分号,或是修改了定义行中的形参却忘记了修改声明行中的形参,导致程序编译出错。

8.3 函数的形式参数与实际参数

		上一个例子中,在进行函数调用的时候,不需要任何参数传递,所以函数定义和调用时括号内都是空的,但是更多的时候需要在主调函数和被调用函数之间传递参数。在调用一个有参数的函数时,函数名后边括号中的参数叫作实际参数,简称实参。而被调用的函数在进行定义时,括号里的参数叫作形式参数,简称形参。下面用个简单程序例子说明。
		![在这里插入图片描述](https://img-blog.csdnimg.cn/c1422a6d7a6043deb20c5ff96b83c50e.png#pic_center)

在这里插入图片描述
这个演示程序虽然很简单,但是函数调用的全部内容都囊括在内了。主调函数main和被调用函数add之间的数据通过形参和实参发生了传递关系, 而函数运算完后把值传递给了变量c,函数只要不是void类型,就都会有返回值,返回值类型就是函数的类型。关于形参和实参,还有以下几点需要注意。
(1)函数定义中指定的形参,在未发生函数调用时不占内存,只有函数调用时,函数add中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放,形参是局部变量。
(2)实参可以是常量,也可以是简单或者复杂的表达式,但是要求它们必须有确定的值,在调用发生时将实参的值传递给形参。如上边这个程序也可以写成
c = add(1, a+b);
(3)形参必须指定数据类型,和定义变量一样,因为它本来就是局部变量。
(4)实参和形参的数据类型应该相同或者赋值兼容。和变量赋值一样,当形参和实参出现不同类型时,按照不同类型数值的赋值规则进行转换。
(5)主调函数在调用函数之前,应对被调函数做原型声明。
(6)实参向形参的数据传递是单身传递,不能由形参再回传给实参。也就是说,实参值传递给形参后,调用结束,形参单元被释放,而实参单元仍保留并且维持原值。

8.4 按键

8.4.1 独立按键

		常用的按键电路有两种形式:独立式按键和矩阵式按键。独立式按键比较简单,它们各自与独立输入线相连接,如图8-6所示。
		4条输入线接到单片机的I/O口上,当按下按键K1时, +5V依次通过电阻R1和按键K1最终进入GND形成一条通路,这条线路的全部电压都加到电阻R1上,引脚KeyIn1就是一个低电平。当松开按键后,线路断开,不会有电流通过,KeyIn1和+5V应该是等电位,是一个高电平。因此,可以通过引脚KeyIn1这个I/O口的高低电平来判断是否有按键按下。
		这个电路中按键的原理讲清楚了,但是实际上在单片机I/O口内部,也有一个上位电阻。按键是接到P2口上,P2口上电默认是准双向I/O口,下面来简单了解一下准双向I/O口的电路,如图8-7所示。
		![在这里插入图片描述](https://img-blog.csdnimg.cn/1685b2bcb0464923a0f646ac94f12d31.png#pic_center)

在这里插入图片描述
在这里插入图片描述 首先说明一点,就是现在绝大多数单片机的I/O口都是使用MOS管而非三极管,但用在这里的MOS管,其原理和三极管是一样的,因此用三极管替代它来进行原理讲解,把前面讲过的三极管的知识搬过来,一切都是适用的,有助于理解。
图8-7方框内的电路都是指单片机内部部分,方框外的就是外接的上拉电阻和按键。这个地方大家要注意一下,就是当要读取外部按键信号的时候,单片机必须先给该引脚写“1”,也就是高电平,这样才能正确读取到外部按键信号,下面来分析一下缘由。
当内部输出是高电平时,经过一个反向器变成低电平,NPN三极管不会导通,单片机I/O口从内部来看,由于上拉电阻R的存在,所以是一个高电平。当外部没有按键按下将电平拉低,VCC也是+5V,它们之间虽然有两个电阻,但是没有压差,就不会有电流,线上所有的位置都是高电平,这时就可以正常读取按键的状态了。
当内部输出是低电平时,经过一个反相器变成高电平,NPN三极管导通,单片机的内部I/O口就是一个低电平,这时,外部虽然也明上拉电阻的存在,但是两个电阻是并联关系,不管按键是否按下,单片机的I/O口上输入单片机内部的状态都是低电平,因此无法正常读取按键的状态。
这与水流很类似,内部和外部,只要有一边是低电位,电流就会顺流而下,由于只有上拉电阻,下边没有分压电阻,直接到GND上,所以不管另一边是高电位还是低电位,电平都是低电平。
从上面的分析可以得出一个结论,这种具有上拉的准双向 I/O口,如果要正常读取外部信号的状态,必须首先保证自己内部输出的是1,如果内部输出0, 则无论外部信号是1还是0, 这个引脚读进来 的都是0。

8.4.2 矩阵按键

	在某一个系统设计中,当需要使用很多按键时, 做成独立按键会大量占用I/O口,因此引入了矩阵按键的设计。如图8-8所示是KST-51开发板上的矩阵按键电路原理图,使用8个I/O口实现16个按键。
	![在这里插入图片描述](https://img-blog.csdnimg.cn/a7bab0709f884981b5f7dfbd3923dc70.png#pic_center)

在这里插入图片描述如果理解了独立按键,就不难理解矩阵按键,下面来分析一下。图8-8中,一共有4组按键,我们只看其中一组,如图8-9所示。大家认真看一下,如果KeyOut1输出一个低电平,则KeyOut1相当于GND,此时,K1、K2、K3、K4相当于4个独立按键。当然这时KeyOut2、KeyOut3、KeyOut4必须都输出高电平,才能保证与它们相连的3路按键不会对这一路产生干扰,大家可以对照两张原理图分析一下。
在这里插入图片描述

8.4.3 独立按键的扫描

了解了原理,下面编写一个独立按键的程序,把最基本的功能验证一下。

在这里插入图片描述
本程序固定在KeyOut1上输出低电平,而KeyOut2~KeyOut4保持高电平,相当于把矩阵按键的第一行即K1-K4作为4个独立按键来处理,然后把这4个按键的状态直接送给LED9-LED6这4个LED小灯,那么当按键按下时,对应按键的输入引脚是0,对应小灯控制信号也是0,于是灯亮,这说明上述关于按键检测的理论都是可以实现的。
绝大多数情况下,按键是不会一直按住的,所以通常检测按键的动作并不是检测一个固定的电平值,而是检测电平值的变化,即按键在按下和弹起这两种状态之间的变化,只要发生了这种变化就说明现在按键产生了动作。
程序上,可以把每次扫描到的按键状态都保存起来,当一次按键状态扫描进来的时候,与前一次的状态做比较,如果发现这两次按键状态不一致,则说明按键产生了动作。若上一次的状态是按下而现在是未按下,则此时按键的动作就是“弹起”。显然,每次按键动作都会包含一次“按下”和一次“弹起”,可以任选其一来执行程序,或者两个都用,以执行不同的程序也是可以的。下面就用程序来实现这个功能,程序只取按键K4为例。

在这里插入图片描述
在这里插入图片描述先来介绍出现在程序中的一个新知识点,就是变量类型-bit,这个在标准C语言中是没有的。51单片机有一种特殊的变量类型就是bit类型。比如unsigned char型是定义了一个无符号的8位的数据,它占用1字节(Byte)的内存,而bit型是1位数据,只占用1位(bit)内存,用法和标准C中其他的基本数据类型是一致的。它的优点就是节省内存空间,8个bit型变量才相当于1个char型变量所占用的空间。虽然它只有0和1两个值,但可以表示很多信息,例如,按键的按下和弹起,LED灯的亮和灭,三极管的导通与关断等,联想一下已经学过的内容,它是不是能用最小的内存代价来完成很多工作呢?
在这个程序中,以K4为例,按一次按键,就会产生“按下”和“弹起”两个动态的动作,选择在“弹起”时对数码管进行加1操作。理论是如此,大家可以在开发板上用K4按键做实验试试,多按几次,是不是会发生这样一种现象:有的时候明明只按了一下按键,数字却加了不止1,而是2或者更多?但是程序并没有任何逻辑上的错误,这是怎么回事呢?这就引出了按键抖动和消抖的问题。

8.4.4 按键消抖

通常按键所用的开关都是机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上就稳定接通,在断开时也不会一下子彻底断开,而是在闭合和断开的瞬间伴随了一连串的抖动,如图8-10所示。
按键稳定闭合时间长短是由操作人员决定的,通常都会在100ms以上,刻意快速按键达到40-50ms,很难再低了。抖动时间是由按键的机械特性决定的,一般都会在10ms以内,为了确保程序对按键的一次闭合或者一次断开只响应一次,必须进行按键的消抖处理。当检测到按键状态变化时,不是立即去响应动作,而是先等待闭合或断开稳定后再进行处理。按键消抖可分为硬件消抖和软件消抖。
硬件消抖就是在按键上并联一个电容,如图8-11所示,利用电容的充放电特性对抖动过程中产生的电压毛刺进行平滑处理,从而实现消抖。但实际应用中,这种方式的效果往往不是很好,而且还增加了成本和电路复杂度,所以实际中的应用并不多。
![在这里插入图片描述](https://img-blog.csdnimg.cn/6bdebc18b6894794ac1ae3c1bacdab39.png#pic_center)

在这里插入图片描述
在这里插入图片描述
在绝大多数情况下是用软件原理来实现消抖的。最简单的消抖原理,就是当检测到按键状态变化后,先等待10ms左右的延时,让抖动消失后再进行一次按键状态检测,如果与刚才检测到的状态相同,则可以确认按键已经稳定动作。将上一个程序稍加改动,得到新的带消抖功能的程序如下。
在这里插入图片描述

在这里插入图片描述
大家把这个程序下载到板子上再进行试验,只按一下按键却加了多次数字的问题是不是就解决了?把问题解决掉的感觉是不是很好呢?
这个程序用了一个简单的算法实现了按键的消抖。对于这种很简单的演示程序,可以这样来写,但是实际做项目开发的时候,程序量往往很大,各种状态值也很多,while(1)主循环要不停地扫描各种状态值是否发生变化,及时地进行任务调度,如果程序中间加了这种delay延时操作,则很可能某一事件发生了,但是程序还在进行delay延时操作中,当这个事件发生,程序还在delay操作中,delay完再去检查的时候,已经晚了,检测不到那个事件了。为了避免这种情况的发生,要尽量缩短while(1)循环一次所用的时间,而需要进行长时间延时的操作,必须用其他的办法来处理。
那么消抖操作所需要的延时该怎么处理呢?其实除了这种简单的延时,还有更优异的方法来处理按键抖动问题。举个例子:如果启用一个定时中断,每2ms进行一次中断,扫描一次按键状态并且存储起来,则连续扫描8次后,看看这连续8次的按键状态是否一致。8次按键的时间大概是16ms,这16ms内如果按键状态一直保持一致,那就可以确定现在按键处于稳定的阶段,而非处于抖动的阶段,如图8-12所示。
在这里插入图片描述
假如左边的时间是起始0,每经过2ms左移一次,每移动一次,判断当前连续的8次按键状态,如果是全1则判定为弹起,如果全是0则判定为按下,如果0和1交错,就认为是抖动,不做任何判定。想一下,这样是不是比简单的延时更加可靠。
利用这种方法,就可以避免通过延时消抖占用单片机执行时间,而是转化成一种按键状态判定而非按键过程判定,我们只对当前按键的连续16ms的8次状态进行判断,而不再关心它在这16ms内都做了什么事情,下面就按照这种思路用程序实现出来,同样只以K4为例。
在这里插入图片描述在这里插入图片描述
这个算法是在实际工程中经常使用按键所总结出来的一个比较好的消抖方法。当然,按键消抖还有其他的方法,程序实现更是多种多样,大家可以尝试其他的算法,拓展思路。

8.4.5 矩阵按键的扫描

我们讲独立按键扫描的时候,已经简单了解了矩阵按键。矩阵按键相当于4组,每组各4个独立按键,一共是16个按键。如何区分这些按键呢?想一下我们生活的地球,要想确定我们所在的位置,就要借助经纬线,而矩阵按键就是通过行线和列线来确定哪个按键被按下。在程序中如何进行这项操作呢?
	前边讲过,按键按下通常都会保持100ms以上,如果在按键扫描中断中,每次让矩阵按键的一个KeyOut输出低电平,其他三个输出高电平,判断当前所有KeyIn的状态,下次中断再让下一个KeyOut输出低电平,其他三个输出高电平,再次判断所有KeyIn,通过快速的中断不停地循环进行判断,就可以最终确定哪个按键按下了,这个原理是不是跟数码管动态扫描有点类似?数码管在动态赋值,而按键在动态读取状态。至于扫描间隔时间和消抖时间,因为现在有4个KeyOut输出,要中断4次才能完成一次全部按键的扫描,显然再采用2ms中断判断8次扫描值的方式时间就太长了(2X4X8=64ms),可改用1ms中断判断4次采样值,这样消抖时间还是16ms(1X4X4)。下面就用程序实现出来,程序循环扫描板子上的K1-K16这16个矩阵按键,分离出按键动作并在按键按下时把当前按键的编号显示在一位数码管上(用0-F表示,显示值=按键编号-1)。
	在这里插入图片描述

在这里插入图片描述在这里插入图片描述这个程序完成了矩阵按键的扫描、消抖、动作分离的全部内容,希望读者认真研究,彻底掌握矩阵按键的原理和应用方法。在程序中还有两点值得说明。
首先,可能读者已经发现了,中断函数中扫描KeyIn输入和切换KeyOut输出的顺序与前面提到的顺序不同,程序中首先对所有的KeyIn输入做了扫描、消抖,然后才切换到了下一次的KeyOut输出,也就是说中断每次扫描的实际是上一次输出选择的那行按键,这是为什么呢?因为任何信号从输出到稳定都需要一个时间,有时它足够快而有时却不够快,这取决于具体的电路设计,这里的输入输出顺序的颠倒就是为了让输出信号有足够的时间(一次中断间隔)来稳定,并有足够的时间来完成它对输入的影响,当按键电路中还有硬件电容沙拉时,这样处理就是绝对必要的了,虽然这样使得程序理解起来有点绕,但它的适应性是最好的,换个说法就是,这段程序足够“健壮”,足以应对各种恶劣情况。
其次,是一点小小的编程技巧。注意看keyout=keyou&0x03; 这一行,在这里要让keyout在0-3之间变化,加到4就自动归零,按照常规可以用前面讲过的if语句轻松实现,但是现在看一下这样程序是不是同样可以做到这一点呢?因为0、1、2、3这四个数值正好占用两个二进制的位,所以把一个字节的高6位一直清零,这个字节的值自然就是一种到4归零的效果了。这样一句代码比if语句更为简洁,而效果完全一样。

8.5 简易加法计算器

学到这里,我们已经掌握了一种显示设备和一种输入设备的使用,那么是不是可以来做点综合性的实验了。好吧,下面就来做一个简易的加法计算器,用程序实现从板子上标有0-9数字的按键输入相应的数字,该数字要实时显示到数码管上,用标有向上箭头的按键代替加号,按下加号后可以输入一串数字,然后回车键计算加法结果,并同时显示到数码管上。虽然这远不是一个完善的计算器程序,但作为初学者也足够你研究一阵子了。
首先,本程序相对于之前的例程要复杂得多,需要完成的工作也多得多,所以把各个子功能都作成独立的函数,以使程序便于编写和维护。分析程序的时候就从主函数和中断函数入手,随着程序的流程进行就可以了。可以体会体会划分函数的好处,想想如果还是只有主函数和中断函数来实现的话程序会是什么样子。
其次,大家可以看到再把矩阵按键扫描分离出动作以后,并没有直接使用行列数所组成的数值作为分支判断执行动作的依据,而是把抽像的行列数转换为了一种叫作标准键盘键码(就是计算机键盘的编码)的数据,然后用得到的这个数据作为下一步分支判断执行动作的依据,为什么多此一举呢?有两层含义:第一,尽量让自己设计的东西(包括硬件和软件)向已有的行业规范或标准看齐,这样有助于别人理解认可你的设计,也有助于你的设计与别人的设计相对接,毕竟标准就是为此而生的嘛。第二,有助于程序的层次化而方便维护与移植,比如用的按键是4X4,如果后续又增加了一行成了4X5,那么由行列数组成的编号可能就变了,就要在程序的各个分支中查找修改,稍不留神就会出错,而采用这种转换后,则只需要维护KeyCodeMap这样一个数组表格就行了,看上去就像是把程序的底层驱动与应用层的功能实现函数分离开了,应用层不用关心底层的实现细节,底层改变后也无须在应用层中做相应修改,两层程序之间是一种标准化的接口。这就是程序的层次化,而层次化是构建复杂系统的必备条件,现在就先通过简单的示例来学习一下吧。
作为初学者针对这种程序的学习方式是,先从头到尾读一到三遍,边读边理解,然后边抄边理解,彻底理解透彻后,自己尝试独立写出来。完全采用记忆模式来学习这种例程,一两个例程你可能感觉不到什么提高,当这种例程背过上百八十个的时候,厚积薄发的感觉就来了。同时,在抄读的过程中也要注意学习编程规范,这些可都是无形的财富,可以为日后的研发工作加分。
![在这里插入图片描述](https://img-blog.csdnimg.cn/2897d6becd144978871e4ae9c9ee3017.png#pic_center)

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

manyoftenvictory

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值