余巧书
摘 要:本文从实际应用出发,探讨一种通用精确延时程序设计方法,并给出使用的详细步骤,以便开发者能很好的理解和掌握。
关键词:Keil C51;精确延时;C语言与汇编语言混合编程
单片机因具有体积小、功能强、成本低以及便于实现分布式控制而有非常广泛的应用领域。单片机开发者在编制各种应用程序时经常会遇到实现精确延时的问题。用汇编语言编制程序时,这种问题比较容易解决,而目前开发单片机应用系统的主流工具为C语言。相对汇编语言来说,C语言有很多优点,但缺点就是实时性没有保证,因而在实时性要求高的场合,还需要汇编语言和C语言的联合应用。
使用C语言编写单片机程序时,生成的机器代码、代码大小和效率,除了与C语言代码本身有关外,还与编译器有非常重要的关系。本文以Keil C51為例,探讨如何编制通用精确的延时程序。为获得通用精确的延时程序,可通过编译器合理配置和优化代码编写两方面来达到目的。
一、模块化编程
采用模块化编程,将常用延时函数程序封装为独立模块。项目中需要时仅需调用延时程序头文件并将C语言源文件添加到项目中即可,便于修改和维护。同时模块化也有利于在配置编译器时有针对性对该模块进行相应配置。
二、合理配置编译器
对于Keil C51编译器来说,可以从“存储器类型及存储器模型、代码优化”两方面来配置。
(一)存储器类型
Keil C51编译器提供对所有8051内存区域的访问。变量可以显式地分配给特定的内存空间(通过在声明中包含存储器类型说明符)或隐式地分配(基于存储器模型)。
(二)存储器模型
存储器模型用于确定函数参数、自动变量和不包含显式存储器类型的声明的默认存储器类型。Keil C51编译器提供三种存储器模型。
Keil C51编译器在CPU寄存器中最多可传递三个函数自变量。参数的传递可通过“REGPARMS”和“NOREGPARMS”控制命令进行控制。如果没有寄存器可用于参数传递或包含的参数太多,使用固定存储器位置传递超出部分的参数。
(三)代码优化
Keil C51编译器提供了多层次、多种类的优化配置,高级别优化包含低级别优化。优化配置作用范围有项目级(全局)、文件级(私有)和函数级(私有)。优化设置包括优化级别(用数字表示,数字越大级别越高)和优化偏好(关键字为“SIZE”和“SPEED”)。
项目级优化可在项目选项的“C51”标签中进行配置,具有全局性,若项目中的文件或函数没有进行单独优化配置,则继承项目级优化。
文件级优化可在该文件选项的“C51”标签中进行配置,配置后不受项目级优化的影响;若选择“Default”表示文件继承项目级优化。另外,也可以在文件的头部使用“#pragma OPTIMIZE(9,SPEED)”指定文件级优化。
函数级优化是在函数前使用“#pragma OT(9,SPEED)”指定函数的优化。
三、优化代码编写
对于短暂延时(通常10微秒以下),可以直接调用Keil C51头文件“Intrins.h”,使用“_nop_();”函数获得一个机器周期的延时时间。
为保证延时的精确性,代码采用汇编语言编写,这样每一条指令都有固定的机器周期。为了使延时程序具有一定的通用性和使用方便,采用C语言函数封装。在Keil C51中通过预处理指令“#pragma asm”和“#pragma endasm”可以嵌套汇编语言语句。也可以采用“__asm”进行汇编的嵌入。为计算延时时间方便,函数参数数据类型选择“unsigned char”。
四、程序编写范例
五、仿真及实践检验
使用Proteus进行仿真,编写测试程序如下:
对测试程序进行反汇编,从汇编代码中可以看出,测试程序IO端口电平的变化时间比延时时间多了3个机器周期(测试程序本身引入的时间),即一个脉冲周期多了6个机器周期时间。
使用高精度示波器测量脉冲周期为206微秒,延时时间实际为(206微秒-6微秒),误差为0,符合设计预期目的。
六、归纳总结
保障延时程序延时精确性和程序的通用性的关键:
(1)采用模块化编程并指定模块私有优化级,不受编译器全局优化级影响;
(2)指定变量、函数存储模式,避免因编译器编译模式影响;
(3)延时程序核心采用汇编语言编写,每条指令有确定的指令周期;
(4)为保证程序通用、方便性,采用C语言函数封装。