您好,欢迎访问三七文档
当前位置:首页 > 临时分类 > 单片机模块化编程方法
单片机模块化编程方法目前我们在学习和开发单片机时广泛采用c语言进行编程,当我们开发的单片机项目较小时,或者我们所写的练习程序很小时,我们总是习惯于将所有代码编写在同一个c文件下,由于程序代码量较少,通常为几十行或者上百行,此时这种操作是可行方便的,也没有什么问题。但如果要开发的项目较大,代码量上千行或者上万行甚至更大,如果你还继续将所有代码全部编写在仅有的一个c文件下,这种方式的弊病会凸显出来,它会给代码调试、更改及后期维护都会带来极大的不便。试想一下,当你尝试着从几千几万行代码中定位到某一位置或者去寻找某一错误点,上下拉动巨长的滚动条慢慢地、一点点地浏览整个c文件,是件多么令人眼花缭乱,头昏脑胀的事。模块化编程可解决这个问题,我们只要根据实际需要使用模块化编程的思维将具有不同功能的程序封装在不同模块中,将各个不同模块存放在不同的c文件中。模块化编程后的程序不但使整体的程序功能结构清晰明了,同时也提高程序代码的利用率,有些模块代码我们可以直接进行移植或者经简单修改就可另作他用,好比封装好的函数。那么什么是模块化呢?首先我们来简单来聊聊模块概念,我们可能听说过电源模块,通信模块,这些是硬件模块,它们都提供一些接口,譬如电源模块会有输出额定电压电流的接口,通信模块可能提供了RS232、USB等接口。那么对软件来说模块是怎样的呢?软件里的模块跟硬件模块类似,抽象地说就像一个黑盒子,盒子内部细节我们可以不予理会,我们只关心盒子给我们提供什么东西,即提供了什么接口,利用这些接口我们能实现什么功能。我们把相对独立,具有独立功能用代码编写在一个c文件下,把需要对外的函数或变量进行声明供外部使用,把不需要的细节尽可能对外部屏蔽起来,这就是软件模块化编程的思维。这样不同的模块占用不同c文件,一个个c文件将整个项目串接起来实现所有的功能。1.模块化编程的原则:模块化编程通常要遵循以下几个原则:每一个c文件对应一个同名的h头文件一个h文件伴随相应c文件存在,头文件是为了声明对外公开的接口。如果一个c文件不需要对外公布任何接口,则其就不应当存在,除非它是程序的入口,如main函数所在的文件,同时main函数所在文件可以没有对应的头文件。如有一个led.c,那应该同时制作一个led.h头文件。头文件中适合放置接口的声明,不适合放置实现头文件是模块的对外的接口,供外部程序调用。头文件中应放置对外部的声明,如对外提供的函数声明、宏定义、变量类型声明等。函数的实现、变量的赋值、语句的操作等决不能放在头文件中。因为头文件的功能是向外提供接口,譬如函数,变量,具体如何实现是在c文件中进行,头文件仅是进行了描述声明。任意一个c文件只要使用了其他c文件提供的接口,都要同时包含其对应的头文件,每个c文件应该头文件自包含任意一个c文件只要使用了其他c文件提供的接口,都要将其对应的头文件包含到该c文件中,没有使用到其他c文件的接口就不应该将其匹配的头文件包含,并且每个c文件都应该包含自己的头文件。防止头文件被重复包含避免一个头文件被重复包含,通常使用条件编译命令#ifndef--#endif,如下示例:示例1:#ifndefTIME_H#defineTIME_H……#endif示例2:#ifndefLED_H#defineLED_H……#endif其中#defineFILENAME_H为基本格式,FILENAME_H为头文件名称,但要全部使用大写形式,使用单下划线后紧跟一个H表明是头文件。不要在宏名最前面加上“_或“__”,即使用FILENAME_H代替_FILENAME_H_,因为一般以_和”__开头的标识符为系统保留或者标准库使用。2.模块化编程实例我们使用AT89C52单片机,在编程软件keil环境下实施一个工程,来说明模块化编程具体操作的方法和步骤。例子要实现的功能:和P1相连的8个LED灯每500ms亮灭交替闪烁,通过串口将数字0-9发送给单片机并显示在一个数码管上。LED闪烁的时间使用定时器0中断方式来控制,T0每50ms溢出产生中断,定义一个计数器,每次T0中断就计数一次,累计计数10次,那么时长为500ms,作为LED闪烁时间间隔。单片机的时钟为11.0592MHz。那么使用模块化编程的方法,整个项目将会有如下表中的文件。表1工程文件清单C文件H头文件描述main.c无Main文件可以没有对应的头文件timer0.ctimer0.h定时器0定时50ms中断led.cled.hLed闪烁实现uart.cuart.h串口通信配置实现digitron.cdigitron.h数码管显示2.1创建工程步骤2.1.1新建工程文件目录新建工程文件目录(如test),在工程目录下创建Project、Source、Output、Listing和Readme这5个文件夹,并在文件夹Readme下创建Readme.txt文件。这样做的目的是为了增强工程文件的可读性及结构化,便于维护和管理。Project存放工程文件Source存放用户编写的c文件及h头文件Output存放各种输出文件,如hex文件Listing存放编译过程中产生的各种中间文件Readme存放工程项目的说明文件2.1.2创建keil工程(1)启动软件KeilμVision,点击工具栏上的Project,选择NewμVisionProject,新建test工程到目录Project下。(2)选择目标器件,点击“OK”确认。(3)出现是否添加启动文件到工程中对话框,选择否。(4)目标选项设置,点击targetoption工具进入选项配置界面。(5)选中Target项,根据实际情况设置晶振频率。本例子频率为11.0592MHz。(6)选中output选项,点击“SelectFolderforObjects…”选择工程目录下的Output文件夹,将“CreateHEXFile”勾选中。(7)选中Listing选项,点击“SelectFolderforListings…”选择工程目录下的Listing文件夹。(8)最后点击“OK”保存各选项的设置,至此完成TargetOption的配置。(9)新建5个文件,以c为后缀名保存到工程目录的Source文件下,并分别命名为main.c、led.c、uart.c、timer0.c和digitron.c。右击“SourceGroup1”选择“AddExistingFliestoGroup‘SourceGroup1’”,将以上新建的5个文件添加到工程中。(10)至此,就完成整个keil工程的创建。(11)工程test目录文件结构3.程序代码编写3.1LED闪烁文件首先编写led.c文件代码,主要内容就是LED闪烁实现的函数,由于使用到timer0.c中TimeCounter变量,故需要包含timer0.h头文件。其程序代码如下:#includereg52.h#includeled.h#includetimer0.hvoidLight_LED(void){staticunsignedcharTickFlag=0;if(TimeCounter==0)//判断500ms定时是否到{TickFlag=1;TimeCounter=10;}if(TickFlag==1)//每间隔500msP1口取反{P1=~P1;TickFlag=0;}}这个文件中,仅有Light_LED()函数提供给外部使用,故在led.h仅声明该函数即可,声明时要使用关键字extern表明该函数可供外部模块使用,led.h头文件内容如下:#ifndefLED_H#defineLED_HexternvoidLight_LED(void);#endif3.2定时器0中断文件定时器0文件timer0.c代码如下:#includereg52.h#includetimer0.hunsignedcharTimeCounter=10;voidTimer0Config(void){TMOD|=0x01;//定时器0工作在方式2,即16位计数器TH0=0x3C;TL0=0xB0;//定时器0重赋初值ET0=1;//使能定时器0中断TR0=1;//开启定时器0}voidtimer0(void)interrupt1//定时器0中断函数{TH0=0x3C;TL0=0xB0;//定时器0重赋初值if(TimeCounter!=0){TimeCounter--;}}其对应的头文要向led.c文件提供TimeCounter变量,向main.c提Timer0Config函数,因此要在头文件中进行声明,具体内容如下:#ifndefTIMR0_H#defineTIMR0_HexternunsignedcharTimeCounter;externvoidTimer0Config(void);#endif3.3串口通信文件串口配置及中断服务程序uart.c文件,该文件的代码如下:#includereg52.h#includeuart.hunsignedchartem=0;voidUartConfig(void){SCON=0x50;//串口工作在方式1,即10位收发器模式PCON=0x00;//波特率不增倍TMOD|=0x20;//定时器1做波特率发生器,工作在方式2即8位自动重装初值模式TH1=0xFD;//定器1赋初值TL1=TH1;ES=1;//使能串口中断TR1=1;//开启定时器1}voidInterruptUart(void)interrupt4//串口中断服务函数{if(RI==1){RI=0;tem=SBUF;}}uart.h头文件向mian.c提供变量tem和函数UartConfig(),故要进行声明,内容如下:#ifndefUART_H#defineUART_HexternvoidUartConfig(void);externunsignedchartem;#endif3.4数码管显示文件数码管显示模块文件digitron.c代码如下:#includereg52.h#includedigitron.hunsignedcharcodetable[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};voidDigiShow(unsignedcharnum){P2=0xFE;//打开第一个数码管的位码P0=table[num];//将串口发送过来的数字送到数码上显示}文件main.c调用该文件的DigiShow()函数,因此digitron.h头文件要声明这个函数,其头文件内容如下:#ifndefDIGITRON_H#defineDIGITRON_HexternvoidDigiShow(unsignedcharnum);#endif3.5主函数所在文件mian.c文件是程序代码的入口文件,并且调用其他模块接口,实现所有功能的核心文件,故需要包含器其他4个头文件,其代码如下:#includereg52.h#includeled.h#includeuart.h#includetimer0.h#includedigitron.hvoidmain(void){Timer0Config();//初始化定时器0UartConfig();//初始化串口,设置波特率为9600EA=1;//使能全局中断while(1){Light_LED();DigiShow(tem);}}
本文标题:单片机模块化编程方法
链接地址:https://www.777doc.com/doc-4782594 .html