好文档就是一把金锄头!
欢迎来到金锄头文库![会员中心]
电子文档交易市场
安卓APP | ios版本
电子文档交易市场
安卓APP | ios版本

(VR虚拟现实)AVR学习笔记十四、模块化程序设计2.doc

8页
  • 卖家[上传人]:管****问
  • 文档编号:118933798
  • 上传时间:2019-12-30
  • 文档格式:DOC
  • 文档大小:51.04KB
  • / 8 举报 版权申诉 马上下载
  • 文本预览
  • 下载提示
  • 常见问题
    • AVR学习笔记十四、模块化程序设计(二)14.1 程序模块化设计(二)14.1.1、实例功能在前面一讲里,我们已经初步了解了模块化程序设计的简单知识,今天我们再深入探讨一下模块化程序设计我们先回顾一下前面一讲的主要内容:模块化程序设计是指将实现同一功能的程序整合起来,封装到一个程序模块中,这样在使用该功能的时候,可以直接调用该模块中的相关函数进行操作我们在单片机编程中经常用到的按键检测、液晶显示、数码管显示、串口通信、DS18B20温度检测、DS1302实时时钟等经常用到的程序都可以实现模块化模块化编程的最大优点是:思路清晰、移植方便、程序简化通常的做法是将某一模块中所有用到的端口定义,函数声明,函数定义等一起写到一个“.h”或者“.c”文件中,然后在主程序里面使用“#include”预编译指令将这些内容包含到主程序中,这样做调用虽然简单,但是对于模块化程序设计来说还是显得有些不太直观,因为我们调用模块中的函数的时候,需要在这一个模块文件中很费劲的找出需要的函数同样对于移植到别的单片机系统中的时候,需要遍历该模块文件,然后一一更改如果不小心,很容易造成错误更为标准的做法是我们将某一个功能模块的端口定义,函数声明这些内容放在一个“.h”文件中,而把具体的函数实现(执行具体操作的函数)放在一个“.c”文件中。

      这样我们在编写主程序文件的时候,可以直接使用“#include”预编译指令将“.h”文件包含进主程序文件中,而在编译的时候将“.c”文件和主程序文件一起编译这样做的优点是,我们可以直接在“.h”文件中查找到我们需要的函数名称,从而在主程序里面直接调用,而不用去关心“.c”文件中的具体内容如果我们要将该程序移植到不同型号的单片机上,我们同样只需在“.h”文件中修改相应的端口定义即可在这一讲中,我们继续学习一下模块化程序设计本实例有两个功能模块:● 继续了解模块化程序设计的思路和方法● 编写串口通信的模块化程序通过本实例的学习,掌握以下知识点:● 初步掌握模块化程序设计的方法● 了解模块化程序设计中需要注意的一些问题14.2 模块化程序设计需要注意的两点14.2.1 模块化程序设计中的重复声明 在编写模块程序的过程中,我们在编写具体函数实现的“.c”文件时,需要调用包含相关的端口定义和函数声明的“.h”文件,调用时,我们使用使用“#include”预编译指令来调用“.h”文件 同样的,在编写主程序文件时,我们仍然需要将需要调用模块的“.h”文件包含到主程序中,这样就出现了一个单片机系统程序中同一个文件被多次调用的情况,这在很多编译系统中进行编译的时候会有“某某.h”文件被重复调用的编译警告或错误提示。

      事实上,再同一个单片机系统程序中,在编译的时候出现任何的警告或者错误提示都表示我们的程序编写的有问题,虽然有些警告信息不会影响程序的最终运行结果,但我们希望编译程序的时候不出现任何的警告或者错误提示 那这种重复调用的情况该怎么避免呢?一种解决方法是,当我们在调用某一个程序文件时,先判断一下在前面的程序里面是否已经定义或者调用了这个文件,如果这个文件没有被定义或者调用,那么我们就执行调用指令,否则我们就略过调用指令要实现这种判断,我们需要用到条件预编译指令ifndef”,“#define”,“#endif” 这三条指令使用格式如下: #ifndef xxxxx 语句块1#define xxxxxx 语句块2#endif 具体作用是: //如果没有定义文件xxxxxx以及语句块1; #ifndef xxxxx(该处可以为文件名) 语句块1 //定义文件xxxxxx以及语句块2#define xxxxxx 语句块2//结束文件xxxxxx以及语句块的定义#endif 举例如下:下面是文件“usart.h”的避免重复定义的书写方法,具体作用是,先判断是否定义了文件“usart.h”,如果没有定义(#ifndef)文件“usart.h”,则定义文件“usart.h”,并且填写文件“usart.h”的具体内容(即需要定义的内容);填写完需要定义的内容后,使用#endif结束定义。

      ifndef __USART_H__ //如果usart.h没有定义#define __USART_H__ //则定义usart.h//下面是usart.h的内容#include #include //中断函数头文件//常量声明#define BAUD 9600//函数声明void Port_Init(void); //端口初始化配置void Usart_Init(void); //USART寄存器设置void Usart_PutChar(unsigned char cTXData); //字节发送函数void Usart_PutString(unsigned char *pcString);// usart.h的内容写完后,结束条件编译#endif //结束判断条件指示符可以防止头文件的重复处理标准格式如下#define 表达式#ifndef 表达式执行语句1#else执行语句2#enddef意思:在执行#ifdef时如果在前面使用define定义了“表达式”的话就执行“执行语句1”否则执行“执行语句2”例如:#include#define DEBUGvoid main(){#ifdef DEBUGcout<<"run it!"<

      在编写模块化程序的时候,我们经常会遇到一种情况,即:一个函数在不同的模块之间都会用到,最常见的就是延时函数,一般的程序中都需要调用延时函数出现这种情况该怎么办?难道需要在每个模块中都定义相同的函数?那程序编译的时候会提示我们有重复定义的函数那我们只好在不同的模块中为相同功能的函数起不同的名字,这样岂不是做了很多重复劳动,这样的重复劳动还会造成程序的可读性变得很差怎么办?同样的情况也会出现在不同模块程序之间传递数据变量的时候在这样的情况下,一种解决办法是:使用文件包含命令“#include”将一个模块的文件包含到另一个模块文件中,这种方法在只包含很少的模块文件的时候是很方便的,对于比较大的、很复杂的包含很多模块文件的单片机应用程序中,在每一个模块里面都是用包含命令就很麻烦了,并且很容易出错出现这种情况的原因是我们在编写单片机程序的时候,我们所定义的函数和变量都被默认为是局部函数和变量,那么它们的作用范围当然是在调用他们的程序之间了如果我们将这些函数和变量定义为全局的函数和变量,那么,在整个单片机系统程序中,所有的模块之间都可以使用这些函数和变量最好的解决方法是:将需要在不同模块之间互相调用的文件声明为外部函数、变量(或者全局函数、变量)。

      将函数和变量声明为全局函数和变量的方法是:在该函数和变量前面加“extern”修饰符extern”的英文意思就是“全局”,这样我们就可以将加了“extern”修饰符的函数和变量声明为全局函数和变量,那么在整个单片机系统程序的任何地方,我们都可以随意调用这些全局函数和变量例如:extern void Port0_Init(void); //端口初始化配置extern void Usart0_Init(void); //USART寄存器设置extern void Usart0_PutChar(unsigned char cTXData); //字节发送函数extern void Usart0_PutString(unsigned char *pcString);在这里,我们将这4个函数都定义成为全局函数,那么,在一个单片机系统中,在整个程序的任何地方,我们都可以直接调用这写函数注意:在调用的之后直接调用函数名称即可,“extern”这个修饰符不必再调用的时候写上同样的,对于变量的定义我们可以使用同样的方法:extern int second; 在这里,我们定义了一个全局的整形变量second;14.3 串口通信模块化程序的实现1)usart.h 文件的编写 在这里,我们使用了条件编译指令,对于函数,我们使用“extern”关键字,将函数声明为全局函数/*************************************************ATmega16异步串行通信模块化头文件,usart.h变量以及函数声明**********************************************/#ifndef __USART_H__#define __USART_H__#include #include //中断函数头文件//常量声明#define BAUD 9600//函数声明extern void Port_Init(void); //端口初始化配置extern void Usart_Init(void); //USART寄存器设置extern void Usart_PutChar(unsigned char cTXData); //字节发送函数extern void Usart_PutString(unsigned char *pcString);#endif2)usart.c 文件的编写/*************************************************ATmega16异步串行通信模块化头文件,usart.c函数定义部分**********************************************/#include #include "usart.h"//端口状态初始化设置函数void Port_Init(){ PORTD = 0X00; //USART的发送接收端口分别为PD0和PD1 DDRD |= (1 << PD1); //PD0为接收端口,置为输入口;PD1为发送端口,置为输出口}//USART寄存器配置函数void Usart_Init(){ UCSRA = 0X00; 。

      点击阅读更多内容
      关于金锄头网 - 版权申诉 - 免责声明 - 诚邀英才 - 联系我们
      手机版 | 川公网安备 51140202000112号 | 经营许可证(蜀ICP备13022795号)
      ©2008-2016 by Sichuan Goldhoe Inc. All Rights Reserved.