单片机的串口是经常使用的功能之一,封装起来也相对简单一些,让我们慢慢体会c语言中封装的含义......
先看一下头文件的样子,如下:
里面出现了一个陌生的头文件"oscfrequencydef.h",不过从名字上应该能看出来是干什么用的,其实这个头文件里面就一句宏定义,不过可不要小看哦,以后的定时器封装中还会出现它的身影。
我写单片机程序的的原则很简单,就是要好看~_~不过这个“好看”的含义可是很广的,基本上可以概括为代码必须简洁、优美、高效。
有人也许会问,上来为什么先让看一个不知道函数内部细节的头文件,而不是直接给出具体实现?这个问题其实就需要用“封装”的本质来回答了:封装就是让调用端不用去关心具体的实现,从而达到信息的隐藏。注意:这里的“封装”是一种逻辑含义,是一种编程规范或准则。没有人可以约束你不去遵守。一看到头文件就能马上了解封装的这个功能模块提供了哪些功能,因为写程序就是需要通过合理的结构把各功能模块连接起来达到协调运作的过程。
好了,大道理说了不少了,看看具体的东西吧。.c文件如下:
又出现了一个新的头文件"chiptypedef.h",内容也是一句话,作用和"oscfrequencydef.h"一样强大。
注意:<at89x52.h>头文件是uvision3才有的,太早的keil版本没有。里面多了一些常量的定义,串口中断向量在里面已经有了宏定义SIO_VECTOR。
封装比较直观,代码里也有注释,就不多做解释了。下面说代码段是具体的用法。
让我们看一看把串口经过封装后main()函数的程序流程,是不是很清晰呢?更重要的是,从主函数中根本看不到单片机底层的实现,完全像是在写上位机程序,这样的好处是可以全身心地注重程序的实现流程,而不要关心具体的实现细节。否则,错综复杂的东西都搅和到一块很影响程序功能的实现。毕竟人的脑子同时思考的事情有限。
我的理解,程序就是通过抽象把易变的和不易改变的组合在一起。我们可以这样来思考程序:每一个单片机程序自身需要完成很多相对独立的功能。那么,什么是易变的呢?显然,各种功能的顺序流程是易变的,每个程序都不一样。那么,什么又是不易改变的呢?是各相对独立的功能模块,比如:串口功能、定时器功能、LDC显示功能......好了,现在我们已经把串口功能分离出来了,也就是把不易改变的功能分离了出来了。但仔细想想具体实现会发现,依然还有易变的因素在里面,比如:不同的波特率、晶振的频率。于是,我们想到了波特率可以作为函数的参数来适应不同的需求,把晶振频率分离出来单独的头文件以供该项目下所有的文件使用。最后,所有的易变因素都确定了下来,变成了为不易改变的因素,这样的功能封装基本上就达到可以“复用”的目的了。所以,我实现的这个串口封装可以适应所有51系列的单片机,原因也在于此。
通过一个小小的串口功能封装体会一下博大精深的“封装”思想还是很不错的嘛~_~