ImageVerifierCode 换一换
格式:DOCX , 页数:14 ,大小:39.26KB ,
资源ID:7286300      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/7286300.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(模块化编程.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

模块化编程.docx

1、模块化编程两年前,那时的我还是个学生,虽然平时也写一些代码,但没有经过正规项目的训练,对程序的可移植性根本没有太多的考虑,当心情不错时,洋洋洒洒写个几百行,满足一下自己的编程欲,然后在朋友面前显摆一下,得到几句夸奖、赞叹后,把写好的代码扔到一个文件夹或直接删掉,随着时间的推移,这段代码就像石沉大海,再也不会有重见天日的机会。同样是两年前,一个高手在我面前很是强调了程序的模块化编程,对我说了N多模块化编程的好处,我恁是没听进去一句,只知道他在我面前唾沫飞溅的说了关于模块化编程的很多东西。 两个月前,现在的我已经不是学生,摇身变成了一个专职代码编写器,每天面对的都是一大堆设备的驱动程序,面堆一堆驱

2、动程序并不可怕,最让人郁闷的是每天面对的是相同的设备的不同驱动程序,我就纳闷了,相同的设备为什么需要好几套驱动呢,为什么不能用一套呢,这些还不是最郁闷的,一个设备有多套驱动就有吧,最让人郁闷的是在你写同一设备的新驱动时,以前那些驱动就是派不上什么用场,里面有N多的不知道出处的头文件,还有一堆不知道在哪定义的数据结构,把以前的这些垃圾程序都弄懂,比重新写一份都难,现在才真正体会到了以前那个高手重复强调的模块化编程的重要性。 模块化编程意味着什么?对于设备驱动来说,难道仅仅是一个设备对应一套驱动吗?其实这些,在上学时老师早已告诉了我们,那就是我们听的都有点厌烦的”高内聚,低偶合“,这才是模块化编程

3、的本质。对于设备驱动,最理想的是应该做到跟其他程序没有任何关系,整个驱动只有一两个C文件和一个头文件组成,不需要任何其他程序的支持就可以单独编译,只有做到这样,才能够重复利用代码,即使要修改,也比较容易,不需要为找一个数据结构而搞的心情很是郁闷,我们写代码的也是人,也需要一个好心情,你说呢!第一次模块化编程2010-8-4 7:49:00最近在使用一款工业用单片机,作为四通红外遥控器的控制IC,从编写控制程序到初步调试结束,差不多用了四天时间。值得一提的是,着手编程之前,花了整整一个上午来分析功能要求及程序结构,已保证满足所有要求的同时,有良好的维护性。事实上,这并不是第一次使用模块化编程。早

4、在离校之前(一个月前,呵呵),做过一个项目,当时把这个项目分成几个模块,每个模块有自己独立的功能,并保存在单独的文件中。但结果是并没有看出这样做有什么特别之处,除去一点一个程序有一大堆文件。但这次不同,I promise!这款遥控器大致有以下功能:1、读取遥控指令(电位器,按键等)2、读取e2prom(保存着以前的指令,断电不会消失)3、将上述两组指令重新按要求编码,存储4、发射只看上述功能,思路简单,没什么特别之处,只需要按步骤编程就可以了。然而,还有以下要求:1、开机蜂鸣400ms,频率是1khz;指示灯闪烁,频率510hz。2、系统初始化,主要是读取油门,确定一个上下限,同时在油门最小之

5、前,屏蔽其功能。(难以表述)简单说,避免遥控器刚打开时,油门不为零,造成飞机(此遥控器是控制飞机的,玩具)突然起飞,失控。3、按键每按一次蜂鸣器响40ms,1khz;若按键次数达到某一数值,蜂鸣器响400ms,2khz。4、红外发射时载波是38khz,码长22位(不含头码)。看完以上功能要求,再说下控制用ic的可用资源:1、系统时钟,最大8M。时钟周期为晶振周期2分频,指令周期等于时钟周期。2、片内RAM 32bytes3、ROM 1k4、定时器一个5、四路复用12位AD转换器顺便扯一句,谁知道这款单片机都少钱一片?到目前为止,遥控器功能要求及IC资源都有个大概的了解。接下来,就该考虑如何实现

6、了。说实话,最令人恼火的就是IC只有一个定时器,然而系统中用到时间控制的地方却有好多,比如蜂鸣器需要1k或2khz载波,同时要连续蜂鸣400ms;红外发射必须有38khz载波,22位码,每个码又包括数据位和间隔位,每个位长度不定。除此之外,遥控器还包括低压保护,电量不足时,指示灯闪烁。.不是我故意把简单的事情说的复杂,而是很多时候,我想,应该把一些陌生的七七八八的部分理出一个头绪。制定一个步骤,先做什么、后做什么,各部分如何协调。只有这样,才能适应每天变化的生活。.接着说遥控器。我是这样做的:首先,确定系统的功能模块。读电位器、读按键、e2prom读写、蜂鸣器、红外发射等其次,确定系统框架。对

7、整个系统来说,应该先干什么,后干什么。再次,对模块封装,定义接口及消息。消息是指模块执行后返回的标志位,供主程序使用。最后,解耦合。如多个模块复用同一个标志位,或者定时器有限的中断时间内需处理多件事情,应如何分配。昨天初步测试了遥控器,发现蜂鸣器有问题。本来需使用有源蜂鸣器,但拿到的却是一个无源的。从使用的角度看,前者,只要导通,就能蜂鸣;后者,需有载波驱动。而程序中,蜂鸣器的某个声音是按有源方式控制的。这样以来,我需要使用定时器产生特定频率的载波,修改这段程序。比较幸运的是,使用模块化编程。如前所述,我已将蜂鸣部分进行了封装,现在只需找到不符合要求的代码块,在满足其接口的前提下,重写就可以了

8、,简单十几行代码。其它的所有程序,不需要任何改变。这就是模块化编程的好处。其实,还有另一个突出的特点,复用。简单说,当我再编写另一款遥控器的时候,可以直接把红外发射部分的代码复制过去,或者只需改下接口。写到最后,需感谢一个人。很久很久以前(一年前吧),我喜欢把上千行代码(汇编)写在一个文件里面,若需改动,要翻来翻去很是麻烦,更不知模块化编程为何物。某一天,半路遇到一陌生人,他说,“模块化编程,要不要跟我学?”“你是哪个,躲一边去!”我这样回答。呵呵,开玩笑一个大的DSP程序往往包含很多模块,养成良好的编程习惯,学会模块化编程,下次用到类似功能程序就能直接调用。1、每一个C源程序都要建立一个与之

9、名字一样的H文件(头文件),里面仅仅包括该C文件的函数的声明,其他的什么也不会有,比如变量的定义啊等等不应该有。 -格式参见另一篇:条件编译的#ifndef,#define,#endif的用法2、建立一个所有文件都要共同使用的头文件,里面当然就是DSP的管脚使用的定义,还有里面放那些需要的系统的头文件,比如 include等等,把这个文件命名为global.h。3、每个C源文件都应包含自己的头文件以及那个共同的使用的头文件(global.h),里面还放自己本文件内部使用的全局变量或者以extern定义的全局变量4、main.c里包含所有的头文件(global.h和其他C的头文件),main.c

10、里面的函数可以再做一个头文件,也可以直接放在文件的开头部分声明就可以了,里面一般还有中断服务程序也放在main.c里面5、对于贯穿工程的全局变量,可以放在global.h里面,也可以用extern关键字在某个C源文件里面定义,哪个文件要使用就重复定义一下,对于全局变量用大写字母以示区别(习惯,非规定)详细的工程文件例程在我的另一篇-2407编程模板中有下载一个大的单片机程序往往包含很多模块,我是这样组织的1。每一个C源文件都要建立一个与之名字一样的H文件,里面仅仅包括该C文件的函数的声明,其他的什么也不会有,比如变量的定义啊等等不应该有。2。建立一个所有的文件都要共同使用的头文件,里面当然就是

11、单片机的管脚使用的定义,还有里面放那些需要的KEIL系统的头文件,比如 #include,#include等等,把这个文件命名为common.h,或者干脆就叫main.h3,每个C源文件应该包含自己的头文件以及那个共同的使用的头文件,里面还放自己本文件内部使用的全局变量或者以extern定义的全局变量4。主文件main.c里面包含所有的头文件包括那个共同使用的文件,main.c里面的函数可以再做一个头文件,也可以直接放在文件的开头部分声明就可以了,里面一般还有中断服务程序也放在main.c里面5。对于那些贯穿整个工程的变量,可以放在那个共同的使用的头文件里面,也可以用extern关键字在某个C

12、源文件里面定义,哪个文件要使用就重复定义一下6.建立工程的时候,只要把C源文件加到工程中,把H文件直接放到相应的目录下面就可以了,不需要加到工程里面。AVR c语言优秀编程风格 作为一个初学者如何具有良好的程序设计风格呢?我想引用一个关于初学者请教编程大师的故事让读者自己去领悟。有一位编程大师,他写非结构化的程序,一位初学者刻意模仿他,也写非结构化的程序。当他让大师看他的进步时,大师批评了他的非结构化程序:“ 对一位编程大师合适的东西未必对一个初学者同样合适,在超越结构化之前,你必须理解编程之道。” 我个人认为作为一个初学者应该踏踏实实的打好程序设计的基础,不要急功近利,舍本逐末。我走过不少弯

13、路,希望大家能和我一样能牢记编程大师的忠告:“对编程大师合适的东西未必对一个初学者同样合适”。 本文所描述的优秀编程风格适合于大部分语言,文章中可能提到你不是很了解的概念,没有关系,你放心的读下去,当你使用AVR一个月之后,你什么都明白了。AVR c语言优秀编程风格 文件结构模块化的程序应该是有一个很好的程序结构的。AVR C语言程序有两种用户文件,.c程序文件,.h头文件,程序中编写过程中需要在.c文件中包含.h头文件。初学者往往出现重复包含或者头文件包含错误的问题,我当时也时常为这种错误而发愁。下面我以我写的电机驱动例程来给大家说明一下,优秀的编程文件结构。这个工程中有8个文件,一个说明文

14、件,如下图:下载程序例子 电机控制案例 。 我写的成型的程序的文件个数基本上都是偶数,因为每一个结构化的函数定义.c文件都会对应一个.h文件。main.c对应config.h。我们来看看各文件的包含关系。下面我们看看这些文件的包含关系与内容:推荐的文件包含顺序与关系 所有.c文件都包含了config.h文件。如: #include config.h 在config.h 中有如下代码: #include delay.h #include device_init.h#include motor.h 这样做就不容易出现错误的包含关系,为了预防万一,我们还引入了宏定义与预编译。如下: #ifndef

15、_UNIT_H_ #define _UNIT_H_ 1 /100us extern void Delay100us(uint8 n); /1s extern void Delay1s(uint16 n); / n = 6 ,when n=7, it is 1. /1ms extern void Delay1ms(uint16 n); #endif 第一次包含本文件的时候正确编译,并且#define _UNIT_H_ 1,第二次包含本文件#ifndef _UNIT_H_就不再成立,跳过文件。 预编译还有更多的用途,比如可以根据不同的值编译不同的语句,如下: /#pragma REGPARMS #

16、if CPU_TYPE = M128 #include #endif #if CPU_TYPE = M64 #include #endif #if CPU_TYPE = M32 #include #endif #if CPU_TYPE = M16 #include #endif #if CPU_TYPE = M8 #include #endif #include 与 #include filename 的区别 :前者是包含系统目录include下 的文件,后者是包含程序目录下的文件。 变量名与函数名变量以及函数命名应该按照尽量短,按需长,具有实际意义。可以通过下划线或者大小写结合的方法组合动词

17、和名词组成变量函数名。下面对比好的命名方法与不好的命名方法:1. 好的:Delay100us();不好的:Yanshi(); 2. 好的:init_devices();不好的:Chengxuchushihua(); 3. 好的:int temp;不好的:int dd; 外部调用1. 首先在模块化程序的.h文件中定义extern2. /端口初始化3. extern void port_init(void);4. 5. /T2初始化6. void timer2_init(void);7. 8. /各种参数初始化extern void init_devices(void);9. 模块化程序的.c文件

18、中定义函数,不要在模块化的程序中调用程序,及不要出现向timer2_init();这样函数的使用,因为你以后不知道你到底什么地方调用了函数,导致程序调试难度增加。可以在定义函数的过程中调用其他函数作为函数体。10. /*采用timer2 产生波形*/11. / PWM频率 = 系统时钟频率/(分频系数*2*计数器上限值) 12. void timer2_init(void)13. 14. TCCR2 = 0x00; /stop15. TCNT2= 0x01; /set count16. OCR2 = 0x66; /set compare17. TCCR2 = (1WGM20)|(1WGM21)

19、|(1COM21)|0x06; / start timer 快速pwm模式,匹配清零,溢出置位 256分频18. /占空比高比低为:(OCR2-0X01)/(0XFF-OCR2) OX01+(OCR2)_OXFF (+表示输出高,_表示输出低)19. /即OCR2越大,输出越大20. 在少数几个文件中调用函数,在main.c中调用大部分函数,在interupts.c中根据不同的中断调用服务函数。21. void main(void)22. 23. 24. /*/25. /初始工作26. /*/27. init_devices();28. 29. while(1)30. 31. for_ward

20、(0); /默认速度运转 正32. Delay1s(5); /延时5s33. motor_stop(); /停止34. Delay1s(5); /延时5s35. back_ward(0); /默认速度运转 反36. Delay1s(5); /延时5s37. speed_add(20); /加速38. Delay1s(5); /延时5s39. speed_subtract(20); /减速40. Delay1s(5); /延时5s41. 42. 宏定义宏定义主要用于两个地方:1. 一是用得非常多的命令或语句,利用宏将其简化。2. #ifndef TRUE3. #define TRUE 14. #

21、endif5. #ifndef FALSE6. #define FALSE 07. #endif8. #ifndef NULL9. #define NULL 010. #endif11. #define MIN(a,b) (ab)?(a):(b)13. #define ABS(x) (x)?(x):(-x)14. typedef unsigned char uint8; /* 定义可移植的无符号8位整数关键字 */15. typedef signed char int8; /* 定义可移植的有符号8位整数关键字 */16. typedef unsigned int uint16; /* 定义可

22、移植的无符号16位整数关键字 */17. typedef signed int int16; /* 定义可移植的有符号16位整数关键字 */18. typedef unsigned long uint32; /* 定义可移植的无符号32位整数关键字 */19. typedef signed long int32; /* 定义可移植的有符号32位整数关键字 */20. 二是利用宏定义方便的进行硬件接口操作,再程序需要修改时,只需要修改宏定义即可,而不需要满篇去找命令行,进行修改。21. /PD4,PD5 电机方向控制 如果更改管脚控制电机方向,更改PORTD |= 0x10即可。22. #def

23、ine moto_en1 PORTD |= 0x1023. #define moto_en2 PORTD |= 0x2024. #define moto_uen1 PORTD &= 0x1025. #define moto_uen2 PORTD &= 0x2026. /启动TC2定时比较和溢出27. #define TC2_EN TIMSK |= (1OCIE2)|(1TOIE2)28. /禁止TC2再定时比较和溢出#define TC2_DIS TIMSK &= (1OCIE2)|(1TOIE2)关于注释为了增加程序的可读性,方便合作者读动程序,或者程序作者在一段时间之后还能看懂程序,我们需

24、要在程序中写 注释。1. 在比较特殊的函数使用或者命令调用的地方加单行注释。使用方法为:2. Tbuf_putchar(c,RTbuf); / 将数据加入到发送缓冲区并开中断extern void Delay1s(uint16 n); / n = 6 ,when n=7, it is 1. 3. 在模块化的函数中使用详细段落注释:4. /*5. * 函数名称: Com_putchar6. * 功能描述: 从串行口输出一个字符c7. * 输入: c:输出字符8. * 输出 : 0:失败 1:成功9. * 全局变量: 无10. * 调用模块: 11. * 说明:12. * 注意:*/13. 在文件

25、头上加文件名,文件用途,作者,日期等信息。14. /*15. * serial driver 16. * (c) Copyright 2005-2006, limaokui17. * All Rights Reserved18. *19. * V1.1.020. *21. *22. *-文件信息-23. *文 件 名:sio.c24. *创 建 人: 李茂奎25. *最后修改日期: 2005年7月13日26. *描 述: serial driver 27. *28. *-历史版本信息-29. * 创建人: 李茂奎30. * 版 本: V1.0031. * 日期: 2005年7月13日32. *

26、 描述: 原始版本33. * */要清楚,注释是为了方便阅读,增强程序的可度性,不要本末倒置,不要给很简单大家都能看明白的程序加注释,不要让注释淹没了你的程序结构。对于函数,变量等尽量使用文件名自注释的方法,及通过文件名就可以知道意思。本文结束了,新手教程也结束了,希望我们教程能让你轻松进入AVR的世界。原文出处:Using typedef to Curb Miscreant Code摘要:Typedef 声明有助于创建平台无关类型,甚至能隐藏复杂和难以理解的语法。不管怎样,使用 typedef 能为代码带来意想不到的好处,通过本文你可以学习用 typedef 避免缺欠,从而使代码更健壮。ty

27、pedef 声明,简称 typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。所谓美观,意指 typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。本文下面将竭尽全力来揭示 typedef 强大功能以及如何避免一些常见的陷阱。如何创建平台无关的数据类型,隐藏笨拙且难以理解的语法? 使用 typedefs 为现有类型创建同义字。 定义易于记忆的类型名typedef 使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。类型出现在所声明的变量名字中,位于 typedef 关键字右边。例如:typedef int size;此声明定义了一个 int 的同义字,名字为 size。注意 typedef 并不创建新的类型。它仅仅为现有类型添加一个同义字。你可以在任何需要 int 的上下文中使用 size:void measure(size * psz); size array4;size len = file.getlength();std:vector vs;typedef 还可以掩饰符合类型,如指针和数组。例如,你不用象下面这样重复定义有 81 个字符元素的数组:char line81;char text81;定义一个 typedef,每当要用到相

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1