




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、下面让我们揭开模块化神秘面纱,一窥其真面目。C语言源文件*.c提到C语言源文件,大家都不会陌生。因为我们平常写的程序代码几乎都在这个XX.C文件里面。编译器也是以此文件来进行编译并生成相应的目标文件。作为模块化编程的组成基础,我们所要实现的所有功能的源代码均在这个文件里。理想的模块化应该可以看成是一个黑盒子。即我们只关心模块提供的功能,而不管模块内部的实现细节。好比我们买了一部手机,我们只需要会用手机提供的功能即可,不需要知晓它是如何把短信发出去的,如何响应我们按键的输入,这些过程对我们用户而言,就是是一个黑盒子。在大规模程序开发中,一个程序由很多个模块组成,很可能,这些模块的编写任务被分配到
2、不同的人。而你在编写这个模块的时候很可能就需要利用到别人写好的模块的借口,这个时候我们关心的是,它的模块实现了什么样的接口,我该如何去调用,至于模块内部是如何组织的,对于我而言,无需过多关注。而追求接口的单一性,把不需要的细节尽可能对外部屏蔽起来,正是我们所需要注意的地方。C语言头文件*.h谈及到模块化编程,必然会涉及到多文件编译,也就是工程编译。在这样的一个系统中,往往会有多个C文件,而且每个C文件的作用不尽相同。在我们的C文件中,由于需要对外提供接口,因此必须有一些函数或者是变量提供给外部其它文件进行调用。假设我们有一个LCD.C文件,其提供最基本的LCD的驱动函数LcdPutChar(c
3、harcNewValue);/在当前位置输出一个字符而在我们的另外一个文件中需要调用此函数,那么我们该如何做呢?头文件的作用正是在此。可以称其为一份接口描述文件。其文件内部不应该包含任何实质性的函数代码。我们可以把这个头文件理解成为一份说明书,说明的内容就是我们的模块对外提供的接口函数或者是接口变量。同时该文件也包含了一些很重要的宏定义以及一些结构体的信息,离开了这些信息,很可能就无法正常使用接口函数或者是接口变量。但是总的原则是:不该让外界知道的信息就不应该出现在头文件里,而外界调用模块内接口函数或者是接口变量所必须的信息就一定要出现在头文件里,否则,外界就无法正确的调用我们提供的接口功能因
4、而为了让外部函数或者文件调用我们提供的接口功能,就必须包含我们提供的这个接口描述文件-即头文件。同时,我们自身模块也需要包含这份模块头文件(因为其包含了模块源文件中所需要的宏定义或者是结构体),好比我们平常所用的文件都是一式三份一样,模块本身也需要包含这个头文件。下面我们来定义这个头文件,一般来说,头文件的名字应该与源文件的名字保持一致,这样我们便可以清晰的知道哪个头文件是哪个源文件的描述。于是便得到了LCD.C的头文件LCD.h其内容如下。#ifndef_LCD_H_#define_LCD_H_externLcdPutChar(charcNewValue);#endif这与我们在源文件中定义
5、函数时有点类似。不同的是,在其前面添加了extern修饰符表明其是一个外部函数,可以被外部其它模块进行调用。#ifndef_LCD_H_#define_LCD_H_#endif这个几条条件编译和宏定义是为了防止重复包含。假如有两个不同源文件需要调用LcdPutChar(charcNewValue)这个函数,他们分别都通过#includeLcd.h”把这个头文件包含了进去。在第一个源文件进行编译时候,由于没有定义过_LCD_H_因此#ifndef_LCD_H_条件成立,于是定义_LCD_H_并将下面的声明包含进去。在第二个文件编译时候,由于第一个文件包含时候,已经将_LCD_H_定义过了。因此#
6、ifndef_LCD_H_不成立,整个头文件内容就没有被包含。假设没有这样的条件编译语句,那么两个文件都包含了externLcdPutChar(charcNewValue);就会引起重复包含的错误。不得不说的typedef很多朋友似乎了习惯程序中利用如下语句来对数据类型进行定义#defineuintunsignedint#defineucharunsignedchar然后在定义变量的时候直接这样使用uintg_nTimeCounter=0;不可否认,这样确实很方便,而且对于移植起来也有一定的方便性。但是考虑下面这种情况你还会这么认为吗?#definePINTunsignedint*定义unsi
7、gnedint指针类型PINTg_npTimeCounter,g_npTimeState;那么你到底是定义了两个unsignedint型的指针变量,还是一个指针变量,一个整形变量呢?而你的初衷又是什么呢,想定义两个unsignedint型的指针变量吗?如果是这样,那么估计过不久就会到处抓狂找错误了。庆幸的是C语言已经为我们考虑到了这一点。typedef正是为此而生。为了给变量起一个别名我们可以用如下的语句typedefunsignedintuint16;给指向无符号整形变量起一个别名uint16typedefunsignedint*puint16;给指向无符号整形变量指针起一个别名puint1
8、6在我们定义变量时候便可以这样定义了:uint16g_nTimeCounter=0;/定义一个无符号的整形变量puint16g_npTimeCounter;/定义一个无符号的整形变量的指针32在我们使用51单片机的C语言编程的时候,整形变量的范围是16位,而在基于32的微处理下的整形变量是位。倘若我们在8位单片机下编写的一些代码想要移植到32位的处理器上,那么很可能我们就需要在源文件中到处修改变量的类型定义。这是一件庞大的工作,为了考虑程序的可移植性,在一开始,我们就应该养成良好的习惯,用变量的别名进行定义。如在8位单片机的平台下,有如下一个变量定义uint16g_nTimeCounter=0
9、;如果移植32单片机的平台下,想要其的范围依旧为16位。可以直接修改uint16的定义,即typedefunsignedshortintuint16;这样就可以了,而不需要到源文件处处寻找并修改。将常用的数据类型全部采用此种方法定义,形成一个头文件,便于我们以后编程直接调用。文件名MacroAndConst.h其内容如下:#ifndef_MACRO_AND_CONST_H_#define_MACRO_AND_CONST_H_typedefunsignedintuint16;typedefunsignedintUINT;typedefunsignedintuint;typedefunsigned
10、intUINT16;typedefunsignedintWORD;typedefintint16;typedefintINT16;typedefunsignedlonguint32;typedefunsignedlongUINT32;typedefunsignedlongDWORD;typedefunsignedlongdword;typedeflongint32;typedeflongINT32;typedefsignedcharint8;typedefsignedcharINT8;typedefunsignedcharbyte;typedefunsignedcharBYTE;typedef
11、unsignedcharuchar;typedefunsignedcharUINT8;typedefunsignedcharuint8;typedefunsignedcharBOOL;#endif至此,似乎我们对于源文件和头文件的分工以及模块化编程有那么一点概念了。那么让我们趁热打铁,将上一章的我们编写的LED闪烁函数进行模块划分并重新组织进行编译。在上一章中我们主要完成的功能是P0口所驱动的LED以1Hz的频率闪烁。其中用到了定时器,以及LED驱动模块。因而我们可以简单的将整个工程分成三个模块,定时器模块,LED模块,以及主函数对应的文件关系如下main.cTimer.c-?Timer.hL
12、ed.c-?Led.h在开始重新编写我们的程序之前,先给大家讲一下如何在KEIL中建立工程模板吧,这个模板是我一直沿用至今。希望能够给大家一点启发。卜面的内容就主要以图片为主了。同时辅以少量文字说明。我们以芯片AT89S52为例。FileEditViewProjectDebugFlashferiphersisTo&lsSVCSTTindawHelpM史冒1¥isignProject.#t新建一个工程HewFrojectWorkspace.Inkport禺ViwionlProject.OpenProj&ct.Mil图静单击project选择NewuVisionProje
13、ctEileEdityievprojectFlashPetipheralsloolsgVCSWindowHelp窗东Q0XRa®二看承|舞泰|3,珞僚ProjectWorkspacex=)»蔻Workspace>(Target1Iioiyc<CPU在子项中选中AT89s52Vendor:Atmded(inket(LX51)irvsteadofBL51Devic©:ATToofcetDesjnption:QaUbaseveviAT89LV55AT89S2O51AT89S4O51AT89S4OAT89S51rU$eExtendedmWer(AX51)ins
14、teadofA51AT89S53AI8958252AT89S8253AT8xC5122T8OC31T8OC31X2T8OC32)然后单击OK按钮8051basedFullStaticCMOSconlrolferwithThree-LevelProgramMemoryLock,32I/Olines,31rr»er$/Counter$,8InterruptsSources.WatchdogTim82DPTRs,SKRashMemory,256BytesOn-chipRAMDeviceDatabase.LicenseManagement.PrintSetup.rrintPrintPrevx
15、ewProjectDebugFlashPeripheralsToolsSVCSWindowHelp窗New.Ctrl+NOpenCtrl+Oj3CloseProjSaveCtrl+SSaveAs.DeviceDatabase.LicenseManagement.文件新建之后,再次点击File菜单并选择SaveAs菜单PrintSetup.昌PrintPrintPreviewCtrl+P尽Target1二我最近的文档ave,保存在(X):testSTARTUP.A51testtestk新建文件夹文件名如:保存类型(T):在弹出的保存文件对话框中,单击新建文件夹按钮,新建一个空的文件夹打开)|A1
16、1Files(*.*)取消ILJtestSTARTUP选定CL)ecxirityNortonInternet重命名也)保存在(X):回由国、*/AQJ我的文档I我最近的文档康我的电脑句网上邻居发送到®剪切(1)复制C)indinFiles创建快捷方式)删除也)共享和安全但).II6SnagItI常添加到压缩文件&).Il添加到“新建文件夹.rar")/常压缩并E-mail.H文件名国逢压缩到"新建文件夹.rar"并#-mail保存类型QGrooveFolderSynchronization打开(Q)资源管理器Q()授索3.在On/ote中作为笔记
17、本打开千千播放任)千千播放列表1)取消3桌面在新建文件夹上右键单击,选择重命-名文件夹arget1因STARTUPons在SourceGroupl上单击鼠标右键,在弹出的菜单中选择AddFilestoGroup*SourceourceProjectWorkspace-有Target1Opeit源|RebuildalltargetfilesStopbullAddFilestoGroup*SourceGroup1?ManageComponentsRemoveGroup?SourceGroupanditsFilesIncludeDependencieseehom<roupFileEditVie
18、wProjectDebugFlashPeripheralsToolsSVCSWindowHelpTarget1ProjectWorkspace-三曰Target1一、SourceGroup1在main,c文件中编写我们的主函数代码窗百S3解X电(8q;舂;a>&%聃iHA富DeviceTargetIOutputSelectFolderforListings.ser|C51A51BL51Locate:BL51MiseDebugIUtilities|卜CCompilerListing:.V.lstVConcStional一SymbolsPageWidth:|12OPageLength
19、:|65切换到Listing选项卡,并单击SelectFolderforListinasrT曲nckideRles'AssertftlyCodeCPreprocessorListing:Ax.i3AssemblerListing:.V.lst歹Condtional3SymbolsMacros:Finalexpansiononly!Cro$Reference3LirkerListing:Ate5t.m51“MemoryMap-CrossReferencevGeneratedSymbols3LibrarySymbfifc7PublicSymbols3LocalSymbolsvLineNum
20、bersJCommentRecordsOKCancelDefaultsaelxHelpEnrollOptionsforTarget*Target1'Xrorseleret1-|A然-Target1F6Source|START+国main,cProjectWorks010203040506070809#include<reg52h>voidmain(void)while(1)单击此按钮,编举生程隹1.詈y%啰=)main,cBuildtarget1Tarcjet11assemblingSTARTUP.Apilingmain.c.linking.ProgramSize:data
21、=9.0xdata=Ocode=17Fr.outputtestr,-0Error(s),0Warning(s).BuildCommandFindinFiles/testSTAETW.A51A51女件7KBLEisiciiFroject目来看看我们的tftst.OptOPT女件组织形式口output文件夹里面保存的是编译过程中的输出文件以及列表和目标文件E而5IX文件夹里则是我们的源代文件(*-c及*h文绢OK,到此一个简单的工程模板就建立起来了,以后我们再新建源文件和头文件的时候,就可以直接保存到文件目录下面了。下面我们开始编写各个模块文件。首先编写Timer.c这个文件主要内容就是定时器初始
22、化,以及定时器中断服务函数。其内容如下。#include<reg52.h>bitg_bSystemTime1Ms=0;/IMS系统时标srcvoidTimer0Init(void)TMOD&=0xf0;TMOD|=0x01;TH0=0xfc;TL0=0x66;TR0=1;ET0=1;定时器0工作方式1/定时器初始值)voidTime0Isr(void)interrupt1TH0=0xfc;/定时器重新赋初值TL00x66;g_bSystemTime1Ms=1;/IMS时标标志位置位由于在Led.c文件中需要调用我们的g_bSystemTime1Ms变量。同时主函数需要调用T
23、imer0Init()初始化函数,所以应该对这个变量和函数在头文件里作外部声明。以方便其它函数调用。Timer.h内容如下。#ifndef_TIMER_H_#define_TIMER_H_externvoidTimer0Init(void);externbitg_bSystemTime1Ms;#endif完成了定时器模块后,我们开始编写LED驱动模块。Led.c内容如下:#include<reg52.h>#include"MacroAndConst.h"#include"Led.h"#include"Timer.h"sta
24、ticuint16g_u16LedTimeCount=0;/LED计数器staticuint8g_u8LedState=0;/LED状态标志,0表示亮,1表示熄灭#defineLEDP0/定义LED接口#defineLED_ON()LED=0x00;所有LED亮#defineLED_OFF()LED=0xff;所有LED熄灭voidLedProcess(void)if(0=g_u8LedState)如果LED的状态为亮,则点亮LEDelseLED_ON();否则熄灭LEDLED_OFF();)voidLedStateChange(void)(if(g_bSystemTime1Ms)系统IMS时
25、标到(g_bSystemTime1Ms=0;g_u16LedTimeCount+;/LED计数器加一if(g_u16LedTimeCount>=500)/计数达到500,即500Ms到了,改变LED的状态。(g_u16LedTimeCount=0;g_u8LedState=!g_u8LedState;)这个模块对外的借口只有两个函数,因此在相应的Led.h中需要作相应的声明。Led.h内容:#ifndef_LED_H_#define_LED_H_externvoidLedProcess(void);externvoidLedStateChange(void);#endif这两个模块完成后,我们将其C文件添加到工程中。然后开始编写主函数里的代码。如下所示:#include<
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 煤矿安装综掘机施工方案
- 辽宁管道防腐施工方案
- 新乡停车场照明施工方案
- 全面提高云杉育苗质量和成活率的栽培技术研究
- 新未来大学英语 视听说教程1(智慧版) 听力脚本汇 Unit 1 -6
- 新未来大学英语 视听说教程1(智慧版) 听力脚本 Unit 2
- 变电站无人机智能识别技术
- 任务型教学法在高中语文教学中的应用研究
- 基于问题链的高中英语阅读教学实践探究
- 加强污染防治和生态建设的策略及实施路径
- 幼儿园开学教职工安全教育培训
- 小学生双拥活动国防教育
- 酒店建设项目施工总承包合同
- 《得胜的基督新妇》课件
- 烟囱拆除工程施工方案设计及安全措施
- 2025年湖南省烟草专卖局系统招聘336人高频重点提升(共500题)附带答案详解
- 交通安全劝导讲座课件
- 洞库安全隐患
- 协助患者翻身扣背
- 2024解析:第二章声现象-基础练(解析版)
- 扬尘防治(治理)监理实施细则(范本)
评论
0/150
提交评论