打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
模块化编程

---------单片机模块化编程初探

哈喽艾威玩,还记得上课时给大家讲到的单片机模块化编程的思想么?有些同学没有练习,有些同学一定也都忘却了。在这里我重新整理一下,作为我们进阶学习的第一弹内容给大家热热身咯~

俗话说,不会模块化编程的厨师不是好司机。那么如何进行单片机的模块化编程呢?且听我给大家慢慢说来。

   (一)What is单片机的模块化编程?

模块化编程是指将一个庞大的程序划分为若干个功能独立的模块,对各个模块进行独立开发,然后再将这些模块统一合并为一个完整的程序。举个栗子,大家都玩过七巧板,我们都知道,七巧板巧在七块板子随意组合,可以组成很多种形状。我让大家拼出一个小房子,大家能很轻易的做到,下次我又让大家用这些拼出来一个小钟楼,大家还是能够毫无鸭梨的完成任务。七块板还是这七块板,只不过进行了不同的排序罢了,但却收到了两种不同的产品。这就是模块化编程的优势,只要我“七块板”到手,任你魔高一尺,我则道高一丈。

在单片机程序里,程序比较小或者功能比较简单的时候,我们不需要采用模块化编程,但是,当程序功能复杂、涉及的资源较多的时候,模块化编程就能体现它的优越性了。如前面我们写过的DS18B20的驱动程序、独立按键扫描程序和12864程序,每一个程序都是只用一个源文件编写就能完成,但是,当您制作一个12864液晶日历的时候,需要用到DS18B20驱动程序、独立按键扫描程序和12864显示程序,如果把这三个程序全部集中在一个源文件里,将导致主体程序臃肿且杂乱,这样做并非不可取,只是降低了程序可读性、可维护性和代码的重用率。如果把这三个程序当做三个独立的模块放到你的主体工程进行模块化编程,效果就不一样了。

实际上,模块化编程就是模块合并的过程,就是建立每个模块的头文件和源文件并将其加入到主体程序的过程。主体程序调用模块的函数是通过包含模块的头文件来实现,模块的头文件和源文件是模块密不可分的两个部分,缺一不可。所以,模块化编程必须提供每个模块的头文件和源文件。

   (二)模块化编程的好处

想当年,我还是一枚单片机清新小菜的时候,记得大学的时候参加一个电子设计大赛,用单片机做了个点阵+数码管显示环境信息和万年历的程序,调试了几个星期,所有程序加起来小1000行,瘦长且杂乱的一个程序,编程的规范性也很差,从上浏览下来都要好半天。出了错误去问老师,见我这乱七八糟的程序,老师看都懒得看。于是自己调试,出了一些简单的语法错误还好定位,其它一些错误,找半天才能找的到。那个时候被自己挖的大坑折腾的够呛,那段岁月也不堪回首,每每回想起来(我先去吐会儿血),仍然会觉得脑袋里一团乱麻。

      生活就是这样,总是在你觉得“山穷水复疑无路”的时候让你“柳暗花明”“又一村”。一个偶然的机会,我接触到了模块化编程。于是开始了解,觉得这个是解决困扰我N久的问题的绝好机会。于是果断开始“模块化”。每天我都会写一些函数并调试,比如us级的延时函数,ms级的延时函数,I2C协议函数,串口通信函数,1602和12864液晶驱动函数,还有例如DS18B20等各种常用的传感器驱动函数等等。由于长期的积累,我收获了一大堆非常给力的函数,编程也渐渐变的规范起来,不再像以前那么难以阅读了。当然这都不是重点,重点是,我做单片机设计的速度和效率快了好几个数量级。

        那么具体是怎么实现的呢,敬请关注《第一弹---单片机模块化编程(二)》且听我慢慢道来。


--------单片机模块化编程再探

又有几天没有跟大家见面啦,真真是有点极为想念呢。在上一帖中,我向大家简单的讲解了使用单片机模块化编程给我们带来的好处。而在现实工作场合,不论是“攻城狮”们还是“程序猿”们,也不论是软件设计还是硬件设计,模块化的概念也是大家经常或者说是必须使用的思维了。下面针对大家的51单片机课程的学习,详细给大家讲讲如何将模块化编程这一概念运用到单片机实战当中去。还是以大家非常之熟悉的流水灯为例进行讲解吧。(版主下文中开启严肃教学模式,上课大家不要讲话,上厕所和有问题的请先举手示意。


(一)怎样使用模块化编程建立工程

下面以实现一个简单的LED流水灯作为实例进行详细讲解。我们都知道,要想实现简单的LED流水灯(这里使用延时函数,而不使用定时器中断法),我们必须要有以下函数:延时函数、LED初始化函数、和LED流水灯实现函数,这三大类函数。那么,我们怎样以模块的形式来使用这些函数呢。下文中作者采用了图文并茂的形式进行分析,这真真是极好的~

(二)LED流水灯例程

1、首先使用Keil uVision新建工程,这里我采用的是Keil uVision4

。(这个软件相信大家一定不会陌生)

2、保存创建的工程


3、选择所使用的芯片

4、点击ok后,在弹出的对话框中选择“否”


5、新建文件,用以编辑函数和头文件


6、将新建的这些文件分别重命名并保存

        

      7、将xxx.C的文件添加到工作组中。


8、当完成以上步奏之后,我们就可以进行具体的函数编写了。对于如何编写一个.C的C语言文件和一个.h的头文件,下面我来具体说明。首先以主函数main.c为例。如下图:


我们可以看到,这个流水灯的主函数main.c如果用模块化编程的方法来实现的话,干净整洁了很多。少了我们常见的相关的延时函数delay();以及对uint和uchar的宏定义。且在主函数中,直接使用了LED_init();和LED_display();这两个函数。而我们知道,要想在主函数中使用一个子函数,必须得在主函数的前面对这几个子函数进行声明,可是本段代码中并没有出现相关的语句。取而代之的是,在程序段第二行,多了一句#include “LED.h”,这一句话又有什么样的特殊功能呢?下面让我们来研究一下LED.c和LED.h的庐山真面目。

9、LED.c和LED.h的编写


       从LED.c这个C文件中,我们可以看出具体对LED_init();和LED_display();函数如何实现,在这个文件中有着具体的描述。那么问题来了~~LED.c和main.c之间是怎样产生联系的呢?换句话说,当我们在另外一个文件中需要调用其他文件当中的某个函数的时候,那么我们该如何做呢?要想搞清楚这个问题,是时候请出LED.h这位大神了。一般来讲xxx.h格式的文件为头文件,头文件提供了程序内函数被其他函数所调用的接口。我们也可以把他称为一份“接口描述文件”。

头文件的文件内部不应该包含任何实质性的函数代码。我们可以把这个头文件理解成为一份说明书,说明的内容就是我们的模块对外提供的接口函数或者是接口变量。同时该文件也包含了一些很重要的宏定义以及一些结构体的信息,离开了这些信息,很可能就无法正常使用接口函数或者是接口变量。但是总的原则是:不该让外界知道的信息就不应该出现在头文件里,而外界调用模块内接口函数或者是接口变量所必须的信息就一定要出现在头文件里,否则,外界就无法正确的调用我们提供的接口功能。因而为了让外部函数或者文件调用我们提供的接口功能,就必须包含我们提供的这个接口描述文件----即头文件。同时,我们自身模块也需要包含这份模块头文件(因为其包含了模块源文件中所需要的宏定义或者是结构体),好比我们平常所用的文件都是一式三份一样,模块本身也需要包含这个头文件。
下面我们来对LED.h这个头文件进行说明,一般来说,头文件的名字应该与源文件的名字保持一致,这样我们便可以清晰的知道哪个头文件是哪个源文件的描述。
   于是便得到了LED.c的头文件LED.h 其内容如下。
       #ifndef __LED_H__

       #define __LED_H__

       extern void LED_init();

extern void LED_display();

       #endif    

这与我们在源文件中定义函数时有点类似。不同的是,在其前面添加了extern 修饰符表明其是一个外部函数,可以被外部其它模块进行调用。

10、下面我们再来看delay.c和其头文件delay.h


我们发现了一点一样的地方和一点异样的地方(这句话读的我也是醉了)。

一样的是,对于头文件来讲,整体的框架似乎一点也没有发生改变,都是下列形式。

     #ifndef __DELAY_H__

           #define __DELAY_H__

           extern  ……

……    ……

           #endif 

 这是头文件的标准编写格式,其中__DELAY_H__这个是头文件的名字,必须大写,中间的横线不能少。一般来说,头文件的名字应该与源文件的名字保持一致,这样我们便可以清晰的知道哪个头文件是哪个源文件的描述。

而异样的是,我们在delay.c这个文件中,发现有”mytype.h”这么个头文件。那么这个是神马,又能做神马呢?下面我们来做一个简单的探讨。

11、工程中的mytype.h是个什么样的存在

      大家可能早就注意到了,这个mytype到底是何方神圣,在分析之前我们先来仔细的“打量一下”。


通过上图中的一段代码,我们能够发现,这好像是对字符串定义表达符号的宏定义,没错,你猜对了!!细心的小伙伴又发现了,我们通常在函数中的用法跟这并不完全一样啊,例如我们定义uint和uchar的时候,在程序中我们是这样写的:

#define uint unsigned int

#define uchar unsigned char

那么非常好,这就是两者不一样的地方啦。在写的时候注意一下就好啦。另外,在对unsigned int和unsigned char等进行宏定义的时候,我们分别采用了多种字符来对其进行定义,这样做的好处是,能够使得mytype.h这个头文件能够很好的适用于不同的芯片和不同编程风格的程序员,也能够起到方便程序进行移植的这么一个目的。由此可见,如果我们将模块化编程很好的运用在项目开发中,能够起到避免冗余工作量和一劳永逸的良好效果。

好了,以上几段代码都带着大家一一分析完毕,现在我们来进行一下编译,看看能不能一切顺利。

12、对编译输出选项进行简单设置



按照图中设置完成后,点击“OK”按钮即可。

13、点击编译按钮


    14、打开工程文件夹路径,我们可以查找到输出的test.hex文件



好了,大功告成了,第一弹宣布结束。。。

---------单片机模块化编程之  探之又探

大家好!由于前几天工作太忙的缘故,搁浅了《单片机模块化编程(三)》的创作,还望大家多多包涵和理解~!其实我想说的是:“码”字不易,且“码”且珍惜。很享受跟大家一起学习的乐趣。好了闲话不再多说,紧接着上一帖我们往下走起!

在开始之前我们先来看一下上一帖中的工程文件夹。。额。。。


上一帖中我们说到了,我是一个有着强迫症和密集恐惧症的双重“病症”的患者,当然这不是重点,重点是看到这样的工程文件夹。。。。我也是醉的一塌糊涂了。作为一个凡事都追求分类和条理性的“完美主义攻城狮”来说,这种混乱的状况是坚决不能出现在我们的世界里的。那么如何才能将这些文件进行有秩序的分门别类呢?

首先,让我们对文件夹中的文件进行解读。对于文件夹中的文件,想必大家最熟悉的就是上一帖中重点讲述的.c和.h两类文件了,那么我们就任性一次,不管三七二十一,新建四个文件夹将其分别放入相应的文件夹中。如下图:




例如文件夹“delay”所展示给大家的那样。

      这样一来,我们能够看到在工程文件夹中,文件是少了一些。但是问题来了,当我们再打开工程的时候,我们发现,工程中的.c文件成了这个样子:



而且再编译的话也会出现问题,那么怎么解决这个问题呢?我们接下来继续探讨:



在完成了以上步骤之后,我们可以发现工程中的三个.c文件的状态已经恢复了正常。但这还没完,由于.h的头文件也被移动到了新的位置,因此我们需要在编译软件中对其路径进行配置。配置方法如下:




之后再点击编译按钮进行编译,即可收到和之前一样的编译效果了。可是除了.c和.h之外,我们在文件夹里发现还有其他的很多文件,这些文件比.c和.h两类文件更乱更糟心。那么他们又是些什么文件呢?又该怎么处理呢?莱斯够昂go on!

这些文件绝大部分都是编译的过程中,产生的中间文件。为了更好的区分这些文件,我们采用以下办法。请大家读图:




      做完了以上步奏,我们发现虽然根文件夹下干净了不少,可是还有一些.lst和.bak等后缀的文件存在,这些文件又是哪儿来的呢?我们再来继续分析。请大家继续读图:


在完成了以上两个步奏之后,我们发现,我们的文件夹已经相对干净且有条理了。在完成了以上的步奏之后,我们也可以从中看出在编译过程中生成的文件主要有.obj、.lst、.hex以及其他文件,其中delay.obj、LED.obj等obj类型的文件是在对工程中的C文件编译时产生的二进制文件,大家可以不用理会;而delay.lst、LED.lst等lst类型的文件是在编译过程中生成的列表文件,些文件均属于中间文件,我们在学习过程中可以暂时将其忽略,不再做进一步的细究。我们要注意的文件是生成的 .hex格式的文件,这个文件是我们要用的着的文件,也是我们最终要往单片机内部烧写的文件。

而对于上面图中的.bak文件来讲,他们是在工程中所产生的备份文件,是可以删除的,在这里,为了更加美观我将其删除,同样不会影响再次编译的效果。好了,现在我们将没有进行处理的根文件夹与“分门别类”过的文件夹进行一下对比。下面是见证奇迹的时刻。。。。。请看下图:



看完了之后我的强迫症和密集恐惧症被自己的“机智”治愈了,这真是太疯狂啦!!原谅我的自恋,点评一下这样的好处吧。

当我们对函数文件进行分类之后,我们发现,当再需要建立一个新的工程的时候,又需要用到delay.c和delay.h这两个文件的时候,我们就能直接将这个“delay”文件夹拷贝到新的工程文件根目录下啦!不需要重新编写,仅仅需要按照上文的方法再次配置一下路径就好了!这真的是一劳永逸,坐享其成的好方法!!

好啦,文章写到这里,想必大家能够较好的认识模块化编程的思想了!这回第一弹真真的要结束了。我也真真的要和大家说再见了!!!站在教师的角度,还是希望大家多动手勤练习,争取学到有用的知识早日成才;站在创客的角度,楼主我在此抛砖引玉献丑啦,也希望各路大神能够将自己宝贵的经验分享出来,共同照亮我们大家学习的道路!谢谢大家~第一弹宣告结束,么~么~~哒~~~!!!


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
单片机C语言学习之模块化编程完结篇
C++中的接口的使用
C语言的头文件包含,竟然有那么多讲究!
请问什么是内核头文件(Kernel Headers)、工具链(Tool Chain)?
在KEIL中的模块化程序写法
手把手教您编写第一个单片机程序
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服