




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、高级语言在单片机设计中的应用C语言程序设计及基本技巧箴言 程序设计绝对是一门艺术,而不仅仅是一门技术 我们的工作应该不仅仅是把当前已有的功能实现而已,在程序设计期间要为以后的扩展和维护做好铺垫(这也许是目前很多工程师所忽略的)程序设计的出发点是,是给别人看,可读、易理解、好维护,如果你的程序只能自己来维护,到你离开这个程序时,你的程序也就与你一起离开了这个世界为了可读、易理解、好维护,你的程序要有好的设计,而不是一接手就进行东抄抄、西抄抄的写代码工作 C语言的发展简史和特点 1语言的诞生与发展语言的诞生与发展(1)在C语言诞生以前,系统软件主要是用汇编语言编写的。由于汇编语言程序依赖于计算机硬
2、件,其可读性和可移植性都很差;但一般的高级语言又难以实现对计算机硬件的直接操作(这正是汇编语言的优势),于是人们盼望有一种兼有汇编语言和高级语言特性的新语言。(2)语言是贝尔实验室于70年代初研制出来的,后来又被多次改进,并出现了多种版本。80年代初,美国国家标准化协会(ANSI),根据语言问世以来各种版本对语言的发展和扩充,制定了ANSI C标准(1989年再次做了修订)。(3) 与单片机有关的与单片机有关的C编译器基本上都是以编译器基本上都是以ANSIC为标准为标准的,但都会有些许的不同,比如在对位定义的处理上,中断的的,但都会有些许的不同,比如在对位定义的处理上,中断的处理上等。处理上等
3、。如何成为一个优秀的软件工程师会哪种语言不重要,重要的是如何将客户的零散无序的需求,迅速消化理解成程序逻辑,然后用自己熟悉的语言将其实现没有哪一个语言比其他语言更高级,我们需要的是高效(包括成本和开发周期考虑)的工具没有没有BUG的软件,没有最优化的软件精通语言不等于是一个好的软件开发人员最重要的,学习和总结的能力 逻辑分析能力一个好的软件开发人员应该具备哪些基本素质1 牢固掌握计算机软件的基本知识技能;2 善于分析和综合问题,具有严密的逻辑思维能力;3 工作踏实细致,遵循标准和规范,具有严格的科学作风;4 工作有耐心、有毅力、有责任心;5 善于听取别人的意见,善于与周围人员团结协作,建立良好
4、的人际关系;6 具有良好的书面和口头表达能力。逻辑分析能力训练对于事业部的人来说控制板就相当于黑匣子,只需要正确的结果,他们不会关心具体的实现方法而对于编程来说,需要将各个输入细化,最后给出一个输出,需要细心,考虑周全拿到项目后马上就开始写代码吗?不,首先分析流程熟悉系统可做到事半功倍事业部的产品需要扩展,同样我们的软件也不会只使用一次,只有把系统了解透彻,才可以将变量和过程定义的更加合理,这就是所谓的扩展性好很多的算法没有最好一说,只能说更适合这个系统C语言优点代码简练,可读性好易于合作:1+1 2 (Microsoft)可移植性(硬件无关性):模块代码可以很容易嵌入至任意一个系统易于模块化
5、:函数有输入输出的存在浮点数与长整型数已经由编译器处理位操作虽然繁琐,但好的编译器可以胜任需要速度快的地方可嵌入汇编语言趋势:编译器也在升级,芯片厂商都在推出更快的支持C语言的芯片(Toshiba, ST)不需掌握每种汇编语言,将更多经历集中程序流程和算法中站在巨人的肩膀上举例:可读性好C语言:If (a = b) & (c = d) e = f;对应汇编:CMP A, BJR Z, _STEP1_STEP1:LD A, CLD B, DCMP A, BJR Z, _STEP2_STEP2:LD E, F举例:硬件无关性与硬件有关的全部做成一个文件通常IO口操作可以调用与硬件有关的函数main
6、() f_MCU_InitSfr();f_MCU_DspLamp();a = f_MCU_ChkKey(1);中断操作可调用主文件中的相应函数或直接指向主文件中的中断函数_interrupt f_MCU_Int_1s(void)TCCS_IVF = 0;f_Int_1s();如何选择使用汇编或C语言程序量大小原则:建议4K以下汇编,以上用C语言与算法有关性:使用某种算法的用C,不需要算法的简单流程使用汇编是否使用浮点数或长整型C语言编译器是否稳定:当前16位机C语言编译器都比较稳定,8位机有待提高可扩展性与可移植性考虑最简单的C程序 当前芯片厂商都会有集成开发环境IDE,包括了工程的管理和代码
7、的编译连接在生成工程时会有一些与所用芯片有关的代码,先不要更改找到某个LED输出端口的定义,如p1_2将此端口设置为输出端口点亮LED灯main() while(1) pd1_2 = 1; P1_2 = 1; 加入时间中断的C程序 找到定义中断的地方,加入时间中断定义计算时间中断计数器,打开时间中断,编写中断函数:输出灯闪烁main(void)trbmr = 0 x10; / 时间中断模式, f8 trbpre = 0 x00; trbpr = 100 - 1;/ 500ms trbic = 0 x06;tstart_trbcr = 1;/ 启动定时器 #pragma interrupt_ti
8、mer_rb(vect=24)void _timer_rb(void) p1_2 = 1 p1_2;/ slpash 加入外部中断的C程序 找到定义中断的地方,加入外部中断定义 / int1(software int 25) /#pragma interrupt_int1(vect=25) /void _int1(void)打开外部中断使能int1en = 1;编写外部中断程序#pragma interrupt _int1(vect=25)void _int1(void)nPulseCnt+;C语言的特点1 语言简洁、紧凑,使用方便、灵活2 运算符丰富3 数据结构丰富4 具有结构化的控制语句5
9、 程序设计自由度大6 允许直接访问物理地址7 程序执行效率高8 可移植性好 结构特点 函数与主函数 程序由一个或多个函数组成 必须有且只能有一个主函数main() 程序执行从main开始,在main中结束,其它函数通过嵌套调用得以执行。 程序语句 C程序由语句组成 用“;”作为语句终止符 注释 /* */为注释,不能嵌套, C99之后可以用/注释 不产生编译代码, 老编译器编译时会选择注释消失,但ANSIC确认用空白代替 编译预处理命令:预处理命令不占用ROM空间 #ifdef DEBUG #else #endif数据类型C数据类型基本类型构造类型指针类型空类型void定义类型typedef数
10、值类型字符类型char枚举类型enum整 型浮点型单精度型float双精度型double字节型char长整型long整型int数组结构体struct共用体union占用内存字节数因内存有限,我们使用的单片机中最常使用的是unsigned char 和 unsigned int类型注意变量的自动类型转换变量都是有类型的,使用变量特别要注意它的类型。如下面的处理合适吗?例1 int i = 30; char c; c = i; 例2 还是上面的例子,下面处理还有问题吗? c = (char) i; C程序的结构 C语言的源程序要经过编译、连接以后,生成可执行文件,程序才能运行。其过程为:编译执行o
11、r解释执行?C语言编译与连接过程 1、源文件 .c和.h文件称为源文件,适合多人协作2、编译过程和目标文件 .o或.obj文件为编译后的文件 编译时只检查语法错误,不分配内存地址 对调用的外部函数只要有声明即可3、连接过程 将编译后的.o或.obj文件连接成一个可以烧写的文件 为RAM和ROM分配地址空间,超过则报错 连接时可能需要第三方函数库 无外部函数的实现则报错编程四步骤源文件的编辑:选择合适的编辑器 编译源文件:一般使用单片机厂家提供的编译器,第三方的通常收费。比较成功的第三方编译器:GCC, IAR 计算机把C的源程序翻译成计算机可以识别的二进制形式的目标代码文件,这个过程称为编译,
12、它由C的编译器的程序完成 C的编译程序在编译的同时,还对源程序的语法和程序的逻辑结构等进行检查。当发现错误时,将会列出错误的位置和种类,此时需要重新编辑修改源程序。如果编辑成功则生成目标文件,该文件包含了与源文件语句对应的机器语言指令,文件名同源程序文件名,扩展名为“.obj”。 编译生成的目标文件,不包含程序运行所需要的库函数等,计算机仍然不能直接执行。 这时不检测外部函数是否存在连接 连接程序以将目标程序和其它目标程序模块,以及系统提供的C库函数等进行连接生成可执行文件的过程,称为“连接”。连接生成的可执行文件的文件名同源程序文件名,扩展名为“.hex”,在计算机上则为”.exe”。 连接
13、生成的可执行文件,计算机可以直接执行。 模块化设计思想概述 模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块, 特点: 各模块相对独立、功能单一、结构清晰、接口简单 控制了程序设计的复杂性 提高元件的可靠性 缩短开发周期 避免程序开发的重复劳动 易于维护和功能扩充 开发方法: 自上向下,逐步分解,分而治之为什么程序需要模块化做到硬件无关,可移植性好黑匣子,除接口外,如何实现与外界无关,提高开发效率可以将不同功能的模块设计成小耦合度模块,使程序执行出错率降低,提高程序可靠性 可以大为提高源代码的复用率,降低代码占有空间,提高程序可靠性 可以提高了程序的可维修性,延长了程序生命周期
14、对于软硬结合的系统来说,软件性能和可靠性的提高,无疑也提升了系统的性能和可靠性。虽然,对于特定硬件来说,执行功能是一样的。但从系统角度看,仍然有其积极意义 如何才算做到好的模块化程序结构上,就像积木一样,到处都可调整的,很多东西不是写“死”的,很多可重复利用,程序模块间相互关系可调整,需求变动后,程序修改成本低的抽象点:高内聚,低耦合(这个口号很响)简单点:老大们提要求用了几分钟甚至几小时和你扯,你回去找到改几行就ok了。一般就是指这样的程序,偷懒系程序员的理想 人很难正确预料将来,所以一开始就“尽可能的多想”,往往会造成不必要的复杂度;与其一开始就“务求完美”,不若一开始时只用最简单的思想,
15、遭遇变化之后再改成灵活应对的方案。 摘自 - 敏捷软件开发。 模块分解的指导思想 (1)如果一个程序段被很多模块所公用,则它应是一个独立的模块。(2)如果若干个程序段处理的数据是公用的,则这些程序段应放在一个模块中。(3)若两个程序段的利用率差别很大,则应分属于两个模块。(4)一个模块既不能过大,也不能过小。过大则模块的通用性较差,过小则会造成时间和空间上的浪费。 (5)力求使模块具有通用性,通用性越强的模块利用性越高。 (6)各模块间应在功能上,逻辑上相互独立,尽量截然分开,特别应避免用转移语句的模块间转来转去。 (7)各模块间的接口应该简单,要尽量减少公共符号的个数,尽量不用共用数据存储单
16、元,在结构或编排上有联系的数据应放 在一个模块中,以免相互影响,造成查错困难。 (8)每个模块的结构应尽量设计成单入口,单出口的形式。这样的程序便于调试,阅读和理解且可靠性高。模块(文件)的划分原则 这是程序设计的第一步,会影响到整个代码的移植和效率问题,因此请不要怕浪费时间一般按功能来划分各个模块(文件),如按键检测,步进电机驱动,风机驱动,液晶驱动,蜂鸣器驱动等等尽量将模块黑匣子化:只需要知道其输入输出,而不用知道其实现方法尽量不使用全局变量:使用返回值或指针来完成功能模块(文件)的划分原则 为提高可移植性,模块的内容尽量与硬件无关,或使用外部函数来获取与硬件有关的内容 如温度检测模块:模
17、块内容只关注检测温度的AD值所对应的具体温度值,及滤波算法,至于如何获得AD值则由其他文件完成,这样在移植到另一芯片时此文件则不用更改主文件负责整体流程和各个模块间的调用尽量不要有交叉调用发生规范这是保证代码可读性的重要部分,如果没有规范,每人能保证永远记得住当时为什么取这样一个变量名的含义为资源共享、可读性与可移植性,需要一定的规范一般由公司来规定,但好的规范可以使使用者自己受益匪浅命名规范:注释规范:编程规范:模块划分:命名规范通则程序中变量名称 = 变量的前缀 + 代表变量含意的英文单词或单词缩写 + 后缀;为方便阅读,英文单词建议不多于3个应使用标准的英文单词或缩写;所有命名都应遵循达
18、意原则,即名称应含义清晰、明确;所有命名都不易过长,变量名应小于等于20字符,函数名和文件名应小于等于30字符;当名称由多个单词构成时,每一个单词的第一个字母必须大写;1.宏定义要求全部大写。文件名命名规范(建议)与硬件有关的文件:产品类型+产品型号+MCU厂家+MCU型号;通用函数文件:原则上以能说明此文件主要功能为宜,如RTC_HT1381.c表示文件命名不区分大小写,建议每个的单词的第一个字母大写,厂家缩写大写 函数名命名规范模块是实现不同功能的子程序,其以“f_”做为前缀,后面接模块功能名称。建议模块功能以“动-名”结构排列,即动词在前,名词在后,来表示处理某个事件。函数名应清晰反映函
19、数的功能、用途,不能引起歧异。与硬件有关的函数名以“f_MCU_”作为前缀中断函数以“f_Int_”作为前缀变量名命名规范原则上,变量名的命名遵从匈牙利记法。即:前缀 + 类型 + 变量名 unsigned char nSecondCnt;/秒级计数器变量名最长不得超过20个字符。类型缩写(type)bool bunsigned char, BYTE nWORD, int, long n, lpointer ptype tclass c建议使用结构来定义有关的变量 与高级语言命名中的区别注释规范 总体原则采用中文注释;如果某个模块或某个复合语句在5分钟内仍不能被其他编程人员看明白,则说明此处的
20、注释是不成功的;注释内容应简炼、清楚、明了;保持注释与代码完全一致,错误的注释还不如没有注释;每个源程序文件,都有文件注释每个函数(模块),都有函数头注释常量定义(DEFINE)有相应说明;文件注释内容 文件注释内容放在文件的最上端;文件注释需包含以下内容:文件名称、版权、包含文件、作者名称、修改时间、文件功能简介、使用芯片等,复杂的算法需要加上流程说明;文件结尾注释一律为:/* (c) 达峰科技有限公司* END OF FILE */举例 /*=* 文 件 名:SOLARMain.c* 版 权:达峰科技有限公司* 功能描述:主程序* 芯片名称:STM8105K4* 包含文件:SOLARMai
21、n.h* 编 译 器: ST Visual Develop* 修改日期修改人修改说明* 2010-06-08徐风飞 = */程序中的注释内容 对于基本数据类型,声明在一行内完成;unsigned char nSecCnt; /*秒级计数器*/unsigned char n1msCnt; /*毫秒级计数器*/一目了然的语句不加注释;算法语句需要添加注释来解释算法的实现方法;处理过程的每个阶段都有相关注释说明;空行和空白字符也是一种特殊注释,具体见下一节编程风格。结构体与共用体数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数
22、据结构可以带来更高的运行或者存储效率的算法。数据结构往往同高效的检索算法和索引技术有关。 数据结构在计算机科学界至今没有标准的定义。个人根据各自的理解而有不同的表述方法。 结构体可以用来表示数据结构结构体与共用体结构体&结构体是一种构造数据类型&用途:把不同类型的数据组合成一个整体-自定义数据类型 结构体类型定义struct 结构体名 类型标识符 成员名; 类型标识符 成员名; .;成员类型可以是基本型或构造型struct是关键字,不能省略合法标识符可省:无名结构体共用体&构造数据类型,也叫联合体&用途:使几个不同类型的变量共占一段内存(相互覆盖) 共用体类型定义定义形式:union 共用体名
23、 类型标识符 成员名; 类型标识符 成员名; .;例 union data int i; char ch; float f; ;fchi类型定义不分配内存形式一: union data int i; char ch; float f; a,b;形式二: union data int i; char ch; float f; ; union data a,b,c,*p,d3;形式三: union int i; char ch; float f; a,b,c; 共用体变量的定义fchifchiab共用体变量定义分配内存,长度=最长成员所占字节数共用体变量任何时刻只有一个成员存在我经常用到的结构体和
24、共用体typedef unionunsigned char byte;structunsigned char bMainValve : 1;unsigned char bSubValve : 1;unsigned char bSubValve2 : 1;unsigned char bFire : 1;bit;relay_def;typedef struct unsigned charhour;unsigned charminute;unsigned charsecond;time_def;结构体说明可以使用一条简单的赋值语句将一个结构体变量的值赋给另一个相同类型的结构体变量(数组是不可以直接赋
25、值的)books2 = books1;可以将一个结构体放入另一个结构体内。结构体不能嵌套它自身 struct issue char dt_of_issue8; struct cat books; issl; 结构体说明结构体变量可以作为参数传递给函数使用这种方式可以将一组逻辑上相关的数据项一起传递,而不是逐个传递变量的类型应该与参数的类型相匹配结构体内容比较多的话建议传形参结构体的一种常见用法是采用结构体数组的形式枚举型枚举类型的定义 enum 枚举类型名枚举类型名 取值表取值表;说明(1)枚举型仅适应于取值有限的数据。例如,根据现行的历法规定,周天,年个月。(2)取值表中的值称为枚举元素,其
26、含义由程序解释。一般会从上到下解释为到N的数值 (3) 好的编译器可以在调试的时候将其显示为枚举值,但现在用的编译器好像都没有这个功能。使用可以大大增加程序的可读性和可扩展性可扩展性:如在中间加一个值基本上原来的程序是不用更改的指针和数组引用数组中的任意一个元素的形式:引用数组中的任意一个元素的形式: 数组名下标表达式 1“下标表达式下标表达式”可以是任何非负整型数据,取值范可以是任何非负整型数据,取值范围是围是0(元素个数(元素个数-1)。)。 特别强调:在运行:在运行C语言程序过程中,系统并不自动检语言程序过程中,系统并不自动检验数组元素的下标是否越界。因此在编写程序时,验数组元素的下标是
27、否越界。因此在编写程序时,保证数组下标不越界是十分重要的。保证数组下标不越界是十分重要的。 21个数组元素,实质上就是个数组元素,实质上就是1个变量,它具有和相同个变量,它具有和相同类型单个变量一样的属性,可以对它进行赋值和参类型单个变量一样的属性,可以对它进行赋值和参与各种运算。与各种运算。 3在在C语言中,数组作为语言中,数组作为1个整体,不能参加数据运个整体,不能参加数据运算,只能对单个的元素进行处理。算,只能对单个的元素进行处理。最常用到的数组查表法根据查表法根据AD值求温度值求温度、离线计算出各、离线计算出各AD值所对应的温度值所对应的温度、直接用数组得到温度值、直接用数组得到温度值
28、通讯过程中的数据缓冲通讯过程中的数据缓冲、因占用中断,故希望中断里内容越少越好、因占用中断,故希望中断里内容越少越好、接收计数器、接收计数器、直接将接收到的内容通过计数器赋予数组、直接将接收到的内容通过计数器赋予数组、注意缓冲区的大小要满足要求、注意缓冲区的大小要满足要求指针1)指针即地址 一个变量的地址称为该变量的指针。通过变量的指针能够找到该变量。(2)指针变量专门用于存储其它变量地址的变量指针变量num_pointer的值就是变量num的地址。指针与指针变量的区别,就是变量值与变量的区别。(3)为表示指针变量和它指向的变量之间的关系,用指针运算符“*”表示。 例如,指针变量num_poi
29、nter与它所指向的变量num的关系,表示为:*num_pointer,即*num_pointer等价于变量num。因此,下面两个语句的作用相同:num=3; /*将3直接赋给变量num*/num_pointer=# /*使num_pointer指向num */*num_pointer=3; /*将3赋给指针变量num_pointer所指向的变量*/我们常用到的指针1)函数调用:为了利用被调用函数改变的变量值,应该使用指针(或指针变量)作函数实参。其机制为:在执行被调用函数时,使形参指针变量所指向的变量的值发生变化;函数调用结束后,通过不变的实参指针(或实参指针变量)将变化的值保留下来
30、。2) 当数组大小不能确定时,使用指针无疑要比数组方便的多3) 通过指针引用数组元素(注意注意:pointer+1指向数组的下一个元素,而不是简单地使指针变量 p o i n t e r 的 值 + 1 。 其 实 际 变 化 为pointer+1*size(size为一个元素占用的字节数)。 指针使用注意事项(1)指针变量的值是可以改变的,所以必须注意其当前值,否则容易出错。(2)指向数组的指针变量,可以指向数组以后的内存单元,虽然没有实际意义。(3)对指向数组的指针变量(px和py)进行算术运算和关系运算的含义 1)可以进行的算术运算,只有以下几种: pxn, px+/+px, px-/-
31、px, px-py pxn:将指针从当前位置向前(+n)或回退(-n)n个数据单位,而不是n个字节。显然,px+/+px和px-/-px是pxn的特例(n=1)。 px-py:两指针之间的数据个数,而不是指针的地址之差。2)关系运算 表示两个指针所指地址之间、位置的前后关系:前者为小,后者为大。例如,如果指针px所指地址在指针py所指地址之前,则pxpy的值为1。数组与指针的区别 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。 (1)修改内容上的差别char a = “hello”;a0 = X;char *p = “world”; / 注意p
32、指向常量字符串p0 = X; / 编译器不能发现该错误,运行时错误 (2) 用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C+/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。char a = hello world;char *p = a;cout sizeof(a) endl; / 12 字节cout sizeof(p) endl; / 4 字节 计算数组和指针的内存容量void Func(char a100)cou
33、t sizeof(a) endl; / 4 字节而不是100 字节编译预处理所谓编译预处理是指,在对源程序进行编译之前,先对源程序中的编译预处理命令进行处理;然后再将处理的结果,和源程序一起进行编译,以得到目标代码。 宏定义与符号常量宏定义与符号常量文件包含文件包含条件编译条件编译 宏的使用及命名规范宏是用来表示一些固定或可能会改变的参数的名称 宏不占用内存空间 (RAM)建议:在用到有意义的数值参数时应尽量使用建议:在用到有意义的数值参数时应尽量使用宏定义,而不是直接在程序中使用数值宏定义,而不是直接在程序中使用数值 需要使用宏定义的内容:芯片输入输出口:IN_RMC1.内部常量: BEEP
34、_SHORT_TIME无参宏定义无参宏定义1无参宏定义的一般格式无参宏定义的一般格式 #define 标识符标识符 语言符号字符串语言符号字符串其中:#define pi 3.142使用宏定义的优点使用宏定义的优点(1)可提高源程序的可维护性(2)可提高源程序的可移植性 (3)减少源程序中重复书写字符串的工作量说明说明(1)宏名一般用大写字母表示,以示与变量区别。但这并非是规定。 (2)宏定义不是语句,所以不能在行尾加分号。否则,宏展开时,会将分号作为字符串的1个字符,用于替换宏名。(3)在宏展开时,预处理程序仅以按宏定义简单替换宏名,而不作任何检查。如果有错误,只能由编译程序在编译宏展开后的
35、源程序时发现。(4)宏定义命令#define出现在函数的外部,宏名的有效范围是:从定义命令之后, 到本文件结束。通常,宏定义命令放在文件开头处。 (5)在进行宏定义时,可以引用已定义的宏名 。(6)对双引号括起来的字符串内的字符,即使与宏名同名,也不进行宏展开。 有参宏定义有参宏定义1带参宏定义的一般格式#define 宏名宏名(形参表形参表) 语言符号字符串语言符号字符串2带参宏的调用和宏展开(1)调用格式:宏名宏名(实参表实参表)(2)宏展开:用宏调用提供的实参字符串,直接置换宏定义命令行中、相应形参字符串,非形参字符保持不变。3说明(1)定义有参宏时,宏名与左圆括号之间不能留有空格。否则
36、,编译系统将空格以后的所有字符均作为替代字符串,而将该宏视为无参宏。(2)有参宏的展开,只是将实参作为字符串,简单地置换形参字符串,而不做任何语法检查。在定义有参宏时,在所有形参外和整个字符串外,均加一对圆括号。 有参宏定义有参宏定义3)虽然有参宏与有参函数确实有相似之处,但不同之处更多,主要有以下几个方面:1)调用有参函数时,是先求出实参的值,然后再复制一份给形参。而展开有参宏时,只是将实参简单地置换形参。2)在有参函数中,形参是有类型的,所以要求实参的类型与其一致;而在有参宏中,形参是没有类型信息的,因此用于置换的实参,什么类型都可以。有时,可利用有参宏的这一特性,实现通用函数功能。3)使
37、用有参函数,无论调用多少次,都不会使目标程序变长,但每次调用都要占用系统时间进行调用现场保护和现场恢复;而使用有参宏,由于宏展开是在编译时进行的,所以不占运行时间,但是每引用1次,都会使目标程序增大1次。 经常用到的有参宏定义经常用到的有参宏定义#define Bit(x) (1(x)#define bset(var, bitno) (var) |= (1 (bitno)#define bclr(var, bitno) (var) &= (1 (bitno)#define nop() asm(nop)#define clrwdt() asm(clrwdt)文件包含文件包含1文件包含的概念文件包
38、含是指,一个源文件可以将另一个源文件的全部内容包含进来。2文件包含处理命令的格式include “包含文件名包含文件名” 或 include 两种格式的区别仅在于:(1)使用双引号:系统首先到当前目录下查找被包含文件,如果没找到,再到系统指定的“包含文件目录”(由用户在配置环境时设置)去查找。(2)使用尖括号:直接到系统指定的“包含文件目录”去查找。一般地说,使用双引号比较保险。 文件包含优点文件包含优点一个大程序,通常分为多个模块,并由多个程序员分别编程。有了文件包含处理功能,就可以将多个模块共用的数据(如符号常量和数据结构)或函数,集中到一个单独的文件中。这样,凡是要使用其中数据或调用其中
39、函数的程序员,只要使用文件包含处理功能,将所需文件包含进来即可,不必再重复定义它们,从而减少重复劳动。文件包含说明文件包含说明(1)编译预处理时,预处理程序将查找指定的被包含文件,并将其复制到#include命令出现的位置上。 (2)常用在文件头部的被包含文件,称为“标题文件”或“头部文件”,常以“h”(head)作为后缀,简称头文件。在头文件中,除可包含宏定义外,还可包含外部变量定义、结构类型定义等。(3)一条包含命令,只能指定一个被包含文件。如果要包含n个文件,则要用n条包含命令。(4)文件包含可以嵌套,即被包含文件中又包含另一个文件。 理论上讲,包含.c文件是没有任何问题的条件编译条件编
40、译可有效地提高程序的可移植性,并广泛地应用在商业软件中,为一个程序提供各种不同的版本。#ifdef #endif和和#ifndef #endif命令命令#if #endif条件编译操作系统中使用的条件编译是最多的,操作系统中使用的条件编译是最多的,因为其要按照不同的版本和不同的因为其要按照不同的版本和不同的CPU来进行编译,基本上,我们不会用到多来进行编译,基本上,我们不会用到多个个CPU的情况的情况我们用的最多的应该是我们用的最多的应该是debug模式和模式和release模式模式要注意条件不满足的内容是不编译的,要注意条件不满足的内容是不编译的,即使有错误也不会报错,在连接的时候即使有错误
41、也不会报错,在连接的时候根本不占用根本不占用ROM区区请说出const与#define 相比,有何优点 1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。 2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。关于流程图流程图的好处方便地看到程序流向其他人帮你检查错误时容易发现错误方便与第三方厂家共享必要性太简单的程序不需要流程图当思绪理不清时需要画一下流程图1.文字说明有时比流程图更简洁有效C语言编写注意事项类型强制转换: unsigned
42、char x = unsigned int n; 取n的低8位赋给x char A = int b + char c; 将c转换为整形后与b相加,取b的低8位赋给x某些特定操作时各编译器可能实现结果不同,为安全起见最好强制转换,本身b为unsigned char 型,则相加后可能造成结果错误。 (int)A = (unsigned int)(b) + c;某些用来延时的语句可能会被编译器优化掉 尽量不要用;来延时,改用asm(“ nop”); 建议在RAM和ROM空间足够的情况下编译器选择不优化可以在线仿真的芯片一般会占用芯片部分资源C语言编写注意事项堆栈的使用 先进后出原则 注意调用函数层数
43、过多可能引起堆栈溢出,结果不可预料 尽量不使用嵌套中断 生成.hex文件后先查看下.map文件确认RAM使用量,避免堆栈溢出C语言编写注意事项注意如果使用unsigned char i 来定义变量,在判断过程中不要使用如下代码:if (i = 0) 或者 if (i)两个unsigned char 数相乘时需要类型强制 nSum = (unsigned char)(nCost) * nSum;使用数组时注意数组的大小为你认为永远不可能出现的地方填写一些代码外部函数有返回值时一定要事先声明后再使用C语言编写注意事项一般 在电源重置后(Power On Reset)所执行的第一个程序模块并不是使用
44、者的主程序main(),而是一个隐藏在 标准链接库中称为 startup.a 的程序模块(一般为汇编文件),具体启动文件可咨询芯片厂商。 startup.a的主要工作是把包含 idata、xdata、pdata 在内的内存区块清除为 0,并且初始化递归指针。接着 startup.a 被执行的仍然是一个隐藏在标准链接库 中称为 init.a的程序模块。而 init.a51 的主要工作则是初始化具有非零初始值设定的变量。 在完成上述的初始化程序之后,程序 的控制权才会交给 main() 开始执行使用者的程序。 也就是说,一般的C编译器都会在初始运行时将RAM清空,而这段程序我们在自己的代码中就可以
45、省略了。编程风格程序编码力求简洁,结构清晰,避免太多的分支结构及太过于技巧性的程序,尽量不采用递归模式(不容易理解);编写程序时,亦必须想好测试的方法,换句话说,“单元测试” 的测试方案应在程序编写时一并拟好;将大的复杂代码节分为较小的、易于理解的模块:一般一个模块的大小不超过100行;编程风格版本封存以后的修改一定要将老语句用/* */ 封闭,不能自行删除或修改,并要在文件及函数的修改记录中加以记录 预处理语句、全局数据、函数原型、标题、附加说明、函数说明等均顶格顶格书写;对齐:原则上关系密切的行应对齐,对齐包括类型、修饰、名称、参数等各部分对齐;空行空行:程序文件结构各部分之间空两行,若不
46、必要也可只空一行,各函数实现之间一般空两行; 一些常数和表格之类的应该放到code去中以节省RAM或编译器指定的方法;编程风格程序编完编译看有多少code多少data,注意留有足够的堆栈空间; 形参:在定义函数时,在函数名后面括号中直接进行形式参数说明,不再另行说明;形参使用“i_”作为前缀 禁止出现两条等价的支路; 禁止GOTO语句;避免从循环引出多个出口;即使对于可能仅出现在几个代码行中的生存期很短的变量,仍然使用有意义的名称。仅对于短循环索引使用单字母变量名,如 i 或 j;编程风格循环、分支代码,判断条件与执行代码不得在同一行上语句块的“”“”配对对齐,并与其前一行对齐;、应独占一行,
47、在该行内可有注释,但不许有可执行语句必须另起一行,之后的代码必须缩进一个Tab。与必须在同一列上。编程风格在所有两目、三目运算符的两边都必须有空格,在单目运算符两端不必空格。但在-、 .、等运算符前后,及&(取地址)、*(取值)等运算符之后不得有空格。 for、while、if 等关键词之后应有1个空格,再接(,之后无空格;在结尾的)前不得有空格。 调用函数、宏时,(、)前后不得有空格。 类型强制转换时,()前后不得有空格常用技巧1,防止一个头文件被重复包含#ifndef COMDEF_H#define COMDEF_H /头文件内容#endif高效编程的一些办法编写高效简洁的C语言代码,是软件工程师追求的目标。1:以空间换时间在数码管扫描过程中,假设需要2ms扫描一次for (i = 0; i 8; i+)OUT_595_CLK
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 管理者量化参数
- 工业互联网平台IPv6技术升级对工业设备生命周期管理的影响报告
- 工业互联网平台AR交互技术在设备维护保养中的应用前景报告
- 光通信技术在工业互联网平台中的光纤通信网络安全保障报告
- 工业互联网网络运维 课件 任务2.4-4 网络设备安装-任务训练
- 输血培训试题及答案
- 数电试题及答案
- 唐氏综合征试题及答案
- 体液失衡题目及答案
- 养牛日常管理办法
- 财务总监招聘笔试题与参考答案(某大型国企)2025年
- 2024首届全国红旗杯班组长大赛题库及答案(第1-200题)
- 人教版四年级上册数学第三单元《角的度量》测试卷含完整答案(各地真题)
- 隐匿性阴茎病人的护理
- 中小学校保安服务方案(技术方案)
- 【平台化物流模式运作存在的问题及优化建议探析:以菜鸟物流为例(论文)6700字】
- 万用表题库单选题100道及答案解析
- 《药品管理法》、《疫苗管理法》竞赛题库及答案
- DL-T5344-2018电力光纤通信工程验收规范
- 家具仪器设备搬迁服务投标方案(技术方案)
- 麓客社创中心(绿城分享)
评论
0/150
提交评论