当前位置:首页 > 单片机 > 单片机
[导读]  主要介绍Keil C51的预处理方法如宏定义、常用的预处理指令及文件包含指令,C51编译库的选择及代码优化原理,C51与汇编混合编程的方法与实现以及超过64KB空间的地址分页方法的C51实现。教学目标  1.了解Keil C5

  主要介绍Keil C51的预处理方法如宏定义、常用的预处理指令及文件包含指令,C51编译库的选择及代码优化原理,C51与汇编混合编程的方法与实现以及超过64KB空间的地址分页方法的C51实现。

教学目标

  1.了解Keil C51的预处理方法,主要有宏定义#define、常用的预处理指令#define、#error、#if 、#else、#elif、#endif、#ifdef、#ifndef 、#undef 、#line 、#pragma 及文件包含指令#include。

  2.了解small、compact、large三种编译模式信代码优化方法。

  3. 掌握C51模块内部调用汇编程序的三种方法,理解C51模块与汇编模块之间的接口规则,主要有C51函数名与汇编程序名的转换规则、C51函数及其相关段的命名规则、C51函数的参数传递规则。

  4.理解Keil C51的Bankswitch原理,了解Keil C51的三种分页方式、公共空间的概念,掌握BL51有关分页的配置,以PSD813F2为硬件基础,掌握Keil C51分页的实现过程,能进行分页的程序设计。

  一、预处理器

  1.1宏定义

宏定义格式如下:#define 名称 替换文字

宏是一种简单的替换,在程序中凡是出现“名称”之处均被“替换文字”替代,替换文字可以是数字,也可以是字符串。

  1.2预处理指令

由ANSI C的标准规定,预处理指令主要包括: #define、#error、#if 、#else、#elif、#endif、#ifdef、#ifndef 、#undef 、#line 、#pragma。

  #define 指令
  例如:#define PI 3.1415926凡是出现“PI”的地方均以“3.1415926”替换。宏的出现有助于提高程序的可读性及书写方便性,也有助于程序的调试。但是,出现在引号中的字符串是不能替换的。如printf(“PIn”);该语句运行后输出的是:PI而不是3.1415926。

  define注意事项:
1)在宏定义语名后没有“;”;
2)在C51程序中习惯上用大写字符作为宏替换名,常放在程序开头;
3)宏定义还有一个特点,就是宏替换名可以带有形式参数,在程序中用到时,实际参数会代替这些形式参数。
例如: #define MAX(x, y) (x>y)?x:y

main(){inti=10,j=15;printf("TheMaxmumis%d",MAX(i,j);}

上例宏定义语句的含义是用宏替换名MAX(x, y)代替x, y中较大者,同样也可定义:
#define MIN(x, y) (x表示用宏替换名MIN(x, y)代替x, y中较小者。
4)#define命令在程序之外,其有效范围为定义命令之后到源文件结束,但是可以用#undef命令终止宏定义的作用域。如:

#definePI3.1415926voidmain(void){……}#undefPI

PI的范围从#define 开始到#undef PI 结束。

  #if、#else、#endif指令
#if、#els和#endif指令为条件编择指令, 它的一般形式为:

#if常数表达式语句段;#else语句段;#endif

上述结构的含义是: 若#if指令后的常数表达式为真, 则编译#if到#else 之间的程序段; 否则编译#else到#endif之间的程序段。
例如:

#defineMAX200main(){#ifMAX>999printf("compiledforbiggern");#elseprintf("compiledforsmalln");#endif}

  #undef指令
#undef指令用来删除事先定义的宏定义, 其一般形式为:
#undef 宏替换名
例如:

#defineTRUE1...#undefTURE

#undef主要用来使宏替换名只限定在需要使用它们的程序段中。

  #include
文件包含是指用#include通常用来将一些常用的宏定义或变量定义所在的源文件包含到“#include”所在的文件中来。
通常格式如下:
#include“filename”或#include
在编译预处理时,将#include命令进行文件包含处理,即将filename中的全部内容复制插入到该指令处,减少重复劳动。通常引号包含的文件与现文件在同一个位置,否则用“<>”括起来。
在源文件开始处一般都要用一些#include指令,如

#include“stdio.h”#include“reg51.h”

如用户自定义了一个字库文件”kzk.h”,在源文件开始用#include “hzk.h”,之后,则可以在源程序中使用字库。

  二、C51编译库及代码优化技术

  2.1 C51编译库
  C51编译器包含6个不同的编译库,如表12-2-1可根据不同需要进行优化 , C51 编译器包含的库模块,都有源代码,对它们可作与硬件相关的修改。用户改变对于现有硬件输入和输出结构的两个模块,就可修改所有库函数,同样也可以重新很快地构造如“printf”和“puts”函数系统默认串口为输出设备,但用户可修改为LCD 显示。

  2.2 代码优化
C51可将即使有经验的程序员编制的代码进行优化,用户可选6个优化级,C51的所有优化方法如下:
  1)一般优化:
常数折迭:发生在一个表达式或地址计算中的几个常数值组合为一个常数;
跳转优化:跳转转到最终的目标地址,以提高程序效率;
死码消除:不可执行代码(死码)可从程序中去掉;
寄存器变量:只要有可能,自动变量和参量放入寄存器中;
通过寄存器传递参数:寄存器中可传递最多三个参数;
全局公共子式消除:相同的子表达式或地址计算(多次发生在同一函数中)将被识别出来,并且只要有可能,将只计算一次。
  2)基于8051 的优化
窥孔(PEEPHOLE)优化:只要能节省存贮空间或执行时间,复杂的运算都将化简。
访问优化:常数和变量直接包含在操作中。
数据覆盖:函数的数据和位移被标记为OVERLAYABLE,被L51 用其它数据和位覆盖。
CASE/SWITCH 优化:SWITCH/CASE 语句优化为一个跳转或一串跳转。
  3)代码生成选项:
OPTMIZE(SIZE):共同的“C”操作被子程序代替:程序码长被压缩。
NOAREGS:不使用绝对寄存器访问,程序代码在这种方式下独立于寄存器组。
NOREGPARMS:参数传递总是在本数据段完成,程序代码与早期C51 版本兼容。

  三、C51与ASM混合编程技术
  3.1 混合编程意义
通常用C51来编写主程序。然而,在一些时序要求严格的采用汇编程序设计具有更高的效率,因此要求在C程序中调用一些用汇编语言编写的子程序。
另一方面,在以汇编语言为主体的程序开发过程中,如果涉及到复杂的数学运算,往往需要借助C51提供的运算库函数和强大的数据处理能力,这就要求在汇编中调用C51函数。
  3.2 C51模块内的汇编接口
模块内接口通常是指在C函数内部插入汇编代码,也称内嵌汇编语句 。
在线汇编提供了能直接读写硬件的能力,如读写中断控制允许寄存器等,但编译器并不检查和分析在线汇编语言,插入在线汇编语言改变汇编环境或可能改变C变量的值可能导致严重的错误。
  方法一、直接在函数体内的每个汇编语句前加?“asm”预编译指令。

voidreset_data(void){asmMOVR1,#0AHasmLOOP:INCAasmDJNZR0,LOOPreturn;}

  方法二、把asm作为关键字后续汇编用大括号括起来即可。

voidreset_data(void){asm{MOVR1,#0AHLOOP:INCADJNZR0,LOOP}return;}

  方法三、在C模块内通过语句“#pragma”嵌入汇编代码。

voidreset(void){#pragmaasmMOVR1,#0AHLOOP:INCADJNZR0,LOOP#pragmaendasmreturn;}

  Keil C51编译环境相关设置
  将嵌有汇编语句源文件加入要编译的项目文件,将光标指向此文件,选择右键菜单“option?for?file?'asm.c'”,将属性单“properties”中的“Generate?Assembler?SRC?File”与“Assemble?SRC?File”两项设置成黑体的“√”,将“Link?Public?Only”的“√”去掉,再编译即可。用此方法可以在C51源代码的任意位置用#pragma?asm和#pragma?endasm嵌入汇编语句。如果编译时未用SRC指令,则C51中的汇编代码会被编译器忽略。

3.3 C51与汇编的模块间接口
1、C51函数名与汇编程序名的转换规则
C51程序模块编译成目标文件后,其中的函数名依据其定义的性质不同会转换为不同的函数名,因此在C51和汇编程序的相互调用时要求汇编程序必须服从这种函数名的转换规则。C51中函数名转换规则如表12-3-1所列。


2、C51函数及其相关段的命名规则
一个C51源程序模块被编译后,其中的每一个函数以“?PR?函数名?模块名”为名的命名规则被分配到一个独立的CODE段。
如:模块“FUNC51”内包含一个名为“func”的函数,则其CODE段的名字是“?PR?FUNC?FUNC51”。
如果一个函数包含有data和bit对象的局部变量,编译器将按“?函数名?BYTE和?函数名?BIT”命令规则建立一个data和bit段,它们代表所要传递参数的起始位置,其偏移值为零。这些段是公开的,因而它们的地址可被其它模块访问。另外,这些段被编译器赋予“OVERLAYABLE”标志,故可被L51连接/定位器作覆盖分析。
依赖于所使用的存储器模式,这些段的段名按表12-3-2所列规则命名,在相互调用时,汇编语言必须服从C51有关段名的命名规则。
各种存储器模式下函数相关段名的命名规则

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭