keil中的变量和常量定位问题_第1页
keil中的变量和常量定位问题_第2页
keil中的变量和常量定位问题_第3页
keil中的变量和常量定位问题_第4页
keil中的变量和常量定位问题_第5页
已阅读5页,还剩120页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

keil 中的变量和常量定位问题中的变量和常量定位问题 变量定位 char tab1 10 at 0 x200 赋值 在函数中赋值 如 tab1 0 0 x01 常量定位及初始化 新建一个 TABLE C 写入 char code table 初始值 KEIL 定位 选择 option BL51 Locate 在 CODE 栏中写入如 CO TABLE 0 x7000 这样 table 表就定位到了 0 x7000 开始的程序段 如何在 KEIL C51 v6 21 中调用汇编函数的一个示例 ycong kuang 有关 c51 调用汇编的方法已经有很多帖子讲到 但是一般只讲要点 很少有对整个过程作详细描述 对于 初学者是不够的 这里笔者 通过一个简单例子对这个过程进行描述 希望能对初学者有所帮助 几年来 在这个论坛里笔者得到很多 热心人指导 因此也希望 藉此尽一点绵薄之力 在这个例子里 阐述了编写 c51 程序调用汇编函数的一种方法 这个外部函数的入口参数是一个字符型变 量和一个位变量 返回值是 一个整型变量 例中 先用 c51 写出这个函数的主体 然后用 SRC 控制指令编译产生 asm 文件 进一步 修改这个 asm 文件就得到我们所 要的汇编函数 该方法让编译器自动完成各种段的安排 提高了汇编程序的编写效率 step1 按写普通 c51 程序方法 建立工程 在里面导入 main c 文件和 CFUNC c 文件 相关文件如下 main c 文件 include define uchar unsigned char define uint unsigned int extern uint AFUNC uchar v achr bit v bflag void main bit BFLAG uchar mav chr uint mvintrslt mav chr 0 xd4 BFLAG 1 mvintrslt AFUNC mav chr BFLAG CFUNC c 文件 define uchar unsigned char define uint unsigned int uint AFUNC uchar v achr bit v bflag uchar tmp vchr uint tp vint tmp vchr v achr tp vint uint v bflag return tmp vchr tp vint 8 step2 在 Project 窗口中包含汇编代码的 C 文件上右键 选择 Options for 点击右边的 Generate Assembler SRC File 和 Assemble SRC File 使检查框由灰色变成黑色 有效 状态 step3 根据选择的编译模式 把相应的库文件 如 Small 模式时 是 Keil C51 Lib C51S Lib 加入工程 中 该文件必须作为工 程的最后文件 step4 build 这个工程后将会产生一个 CFUNC SRC 的文件 将这个文件改名为 CFUNC A51 也可以通过 编译选项直接产生 CFUNC A51 文 件 然后在工程里去掉库文件 如 C51S Lib 和 CFUNC c 而将 CFUNC A51 添加到工程里 CFUNC SRC 文件如下 CFUNC SRC generated from CFUNC c NAME CFUNC PR AFUNC CFUNC SEGMENT CODE BI AFUNC CFUNC SEGMENT BIT OVERLAYABLE PUBLIC AFUNC BIT PUBLIC AFUNC RSEG BI AFUNC CFUNC AFUNC BIT v bflag 041 DBIT 1 define uchar unsigned char define uint unsigned int uint AFUNC uchar v achr bit v bflag RSEG PR AFUNC CFUNC AFUNC USING 0 SOURCE LINE 5 Variable v achr 040 assigned to Register R7 SOURCE LINE 6 uchar tmp vchr uint tp vint tmp vchr v achr SOURCE LINE 10 Variable tmp vchr 042 assigned to Register R5 MOV R5 AR7 tp vint uint v bflag SOURCE LINE 11 MOV C v bflag 041 CLR A RLC A Variable tp vint 043 assigned to Register R6 R7 return tmp vchr tp vint 8 SOURCE LINE 12 MOV R6 A MOV R4 00H CLR A ADD A R5 MOV R7 A MOV A R4 ADDC A R6 MOV R6 A SOURCE LINE 13 C0001 RET END OF AFUNC END step5 检查 main c 的 Generate Assembler SRC File 和 Assemble SRC File 是否有效 若是有效则点击使检 查框变成无效状 态 再次 build 这个工程 到此你已经得到汇编函数的主体 修改函数里面的汇编代码就得到你所需的汇 编函数了 参考文献 1 徐爱钧 彭秀华 单片机高级语言 C51windows 环境编程与应用 电子工业出版社 keil 中汇编函数调用 c51 函数 ycong kuang 第一步在工程里多了一个被汇编调用的 c51 的函数文件 c51func c 至于汇编函数还是先用 c51 编写出 主体 a51func c 这样汇编程序接口和段都交给编译器处理 你只管在编译成汇编代码后按你的要求改写汇编 代码就行了 例程如下 main c include define uchar unsigned char define uint unsigned int extern uint AFUNC uchar v achr bit v bflag void main bit BFLAG uchar mav chr uint mvintrslt mav chr 0 xd4 BFLAG 1 mvintrslt AFUNC mav chr BFLAG a51FUNC c define uchar unsigned char define uint unsigned int extern uint CFUNC uint uint AFUNC uchar v achr bit v bflag c51 写的汇编函数 最终要变成汇编代码 uchar tmp vchr uint tp vint tmp vchr v achr tp vint uint v bflag return CFUNC tp vint 这里调用一个 c51 函数 c51FUNC c define uchar unsigned char define uint unsigned int uint CFUNC uint v int 被汇编函数调用 c51 函数 return v int 2 第二步是按 89852 帖子的 step2 3 4 把用 c51 写的 汇编 函数变成 a51 文件 今天我试了一下 step3 可以不要 例程编译结果如 下 a51func SRC generated from a51func c NAME A51FUNC PR AFUNC A51FUNC SEGMENT CODE DT AFUNC A51FUNC SEGMENT DATA OVERLAYABLE BI AFUNC A51FUNC SEGMENT BIT OVERLAYABLE EXTRN CODE CFUNC PUBLIC AFUNC BIT PUBLIC AFUNC RSEG DT AFUNC A51FUNC AFUNC BYTE tmp vchr 042 DS 1 RSEG BI AFUNC A51FUNC AFUNC BIT v bflag 041 DBIT 1 a51FUNC c define uchar unsigned char define uint unsigned int extern uint CFUNC uint uint AFUNC uchar v achr bit v bflag RSEG PR AFUNC A51FUNC AFUNC c51 所写的函数产生的汇编代码从这里开始 USING 0 SOURCE LINE 8 Variable v achr 040 assigned to Register R7 SOURCE LINE 9 uchar tmp vchr uint tp vint tmp vchr v achr SOURCE LINE 13 MOV tmp vchr 042 R7 tp vint uint v bflag SOURCE LINE 14 MOV C v bflag 041 CLR A MOV R6 A RLC A MOV R7 A Variable tp vint 043 assigned to Register R6 R7 这里说明 R6 R7 内容就是 tp vint return CFUNC tp vint SOURCE LINE 16 LCALL CFUNC 这里调用了用 c51 写的函数 SOURCE LINE 17 C0001 RET END OF AFUNC END 这个文件就是你的汇编函数所在文件 把函数里面的汇编代码修改成你所需的汇编函数就 ok 了 建议参考 徐爱钧 彭秀华所写的 单片机高级语言 C51windows 环境编程与应用 或马忠梅所写的 单片机的 c 语言应用程序设计 有关混合语言编程有关章节 关于在 KEIL C51 中直接嵌入汇编 Youth 有时在 C51 程序中需要嵌入一些汇编代码 这时当然可以用通常的作法 按照 C51 与汇编的接口写一个汇编函数 然后在 C51 程序中调用该函数 此种方法可在论坛里搜索 以前有很多帖子讲到 不再 重复 下面介绍直接嵌入汇编代码的方法 1 在 C 文件中要嵌入汇编代码片以如下方式加入汇编代码 pragma ASM Assembler Code Here pragma ENDASM 2 在 Project 窗口中包含汇编代码的 C 文件上右键 选择 Options for 点击右边的 Generate Assembler SRC File 和 Assemble SRC File 使检查框由灰色变成黑色 有效 状态 3 根据选择的编译模式 把相应的库文件 如 Small 模式时 是 Keil C51 Lib C51S Lib 加入工程中 该 文件必须作为工程的最 后文件 4 编译 即可生成目标代码 在单片机的开发应用中 已逐渐开始引入高级语言 C 语言就是其中的一种 对用惯了汇编的人来说 总 觉得高级语言 可控性 不好 不如汇编那样随心所欲 但是只要我们掌握了一定的 C 语言知识 有些东西 还是容易做出来的 以下是笔者实际工作中遇到的几个问题 希望对初学 C51 者有所帮助 一 C51 热启动代码的编制 对于工业控制计算机 往往设有有看门狗电路 当看门狗动作 使计算机复位 这就是热启动 热启动时 一般不允许从头开始 这将导致现有的已测量到或计算到的值复位 导致系统工作异常 因而在程序必须 判断是热启动还是冷启动 常用的方法是 确定某内存单位为标志位 如 0 x7f 位和 0 x7e 位 启动时首先 读该内存单元的内容 如果它等于一个特定的值 例如两个内存单元的都是 0 xaa 就认为是热启动 否则 就是冷启动 程序执行初始化部份 并将 0 xaa 赋与这两个内存单元 根据以上的设计思路 编程时 设置一个指针 让其指向特定的内存单元如 0 x7f 然后在程序中判断 程 序如下 void main char data HotPoint char 0 x7f if HotPoint 0 xaa 冷启动的处进 HotPoint 0 xaa HotPoint 0 xaa 正常工作代码 然而实际调试中发现 无论是热启动还是冷启动 开机后所有内存单元的值都被复位为 0 当然也实现不 了热启动的要求 这是为什么呢 原来 用 C 语言编程时 开机时执行的代码并非是从 main 函数的第一 句语句开始的 在 main 函数的第一句语句执行前要先执行一段 起始代码 正是这段代码执行了清零的 工作 C 编译程序提供了这段起始代码的源程序 名为 CSTARTUP A51 打开这个文件 可以看到如下代 码 IDATALEN EQU 80H the length of IDATA memory in bytes STARTUP1 IF IDATALEN 0 MOV R0 IDATALEN 1 CLR A IDATALOOP MOV R0 A DJNZ R0 IDATALOOP ENDIF 可见 在执行到判断是否热启动的代码之前 起始代码已将所有内存单元清零 如何解决这个问题呢 好 在启动代码是可以更改的 方法是 修改 startup a51 源文件 然后用编译程序所附带的 a51 exe 程序对 startup a51 编译 得到 startup obj 文件 然后用这段代码代替原来的起始代码 具体步骤是 设 C 源程序 名为 HOTSTART C 修改 startup a51 源文件 这个文件在 C51 LIB 目录下 执行如下命令 A51 startup a51 得到 startup obj 文件 将此文件拷入 HOTSTART C 所在目录 将编好的 C 源程序用 C51 EXE 编译好 得到目标文件 HOTSTART OBJ 用 L51 HOTSTART STARTUP OBJ 命令连接 得到绝对目标文件 HOTSTART 用 OHS51 HOTSTART 得到 HOTSTART HEX 文件 即可 对于 startup a51 的修改 根据自已的需要进行 如将 IDATALEN EQU 80H 中的 80H 改为 70H 就可以使 6F 到 7F 的 16 字节内存不被清零 二 直接调用 EPROM 中已固化的程序 笔者用的仿真机 由 6 位数码管显示 在内存 DE00H 处放显示子程序 只要将要显示的数放入显示缓冲 区 然后调用这个子程序就可以使用了 汇编指令为 LCALL 0DEOOH 在用 C 语言编程时 如何实现这一功能呢 C 语言中有指向函数的指针这一概念 可以利用这种指针来实 现用函数指针调用函数 指向函数的指针变量的定义格式为 类型标识符 指针变量名 在定义好指针后就可以给指针变量赋值 使其指向某个函数的开始存地址 然后用 指针变量名 即可调用这个函数 如下例 void main void void DispBuffer 定义指向函数指针 DispBuffer 0 xde00 赋值 for Key DispBuffer 三 将浮点数转化为字符数组 笔者在编制应用程序时有这样的要求 将运算的结果 浮点数 存入 EEPROM 中 我们知道 浮点数在 C 语言中是以 IEEE 格式存储的 一个浮点数占用四个字节 例如浮点数 34 526 存为 160 26 10 66 这四个数 要将一个浮点数存入 EEPROM 实际上就是要存这四个数 那么如何在 程序中得到一个浮点数的组成数呢 浮点数在存储时 是存储连续的字节中的 只要设法找到存储位置 就可以得到这些数了 可以定义一个 void 的指针 将此指针指向需要存储的浮点数 然后将此指针强制转化为 char 型 这样 利用指针就可 以得到组成该浮点数的各个字节的值了 具体程序如下 define uchar unsigned char define uint unsigned intvoid FtoC void float a uchar i px uchar x 4 定义字符数组 准备存储浮点数的四个字节 void pf px x px 指针指向数组 x pf void 型指针指向浮点数首地址 a 34 526 for i 0 i 4 i px i char pf i 强制 void 型指针转成 char 型 因为 void 型指针不能运算 如果已将数存入 EEPROM 要将其取出合并 方法也是一样 可参考下面的程序 define uchar unsigned char define uint unsigned int void CtoF void float a uchar i px uchar x 4 56 180 150 73 void pf px x pf for i 0 i 出现 则当中断申请时 显示中断源信息 比如当中断发生 时会显示 interrupt Timer 0 occured 等 A D converter 显示 A D 转换器状态无时 则提示 无 Serial 串口信息显示 包括串口模式 波特产等 Other 其它器件 如为 8031 则显示 无 3 3 单步或 Go 执行 F8 单步执行 F5 全速执行到断点 或选主菜单中 Trace 单步执行 CPU 中的 Go 全速执行 4 4 存储器寄存器及变量访问 外部存储器管理 MAP 菜单 设置 set 取消 reset 显示 Display 处理可用存储空间 修改 Code 代码 ASM 命令 存储器显示命令 D 类别为 X D I B C 修改存储器命令 E 有以下几种命令 EB EC EI EL EF EP 复杂数据类型显示 Object 命令 用以显示结构或数组的内容 欲使此命令有效 C51 编译器必须有 DB 及 OBJECTEXTEND 两条 反汇编命令 U 5 5 Watch 表达式之值 在 View 菜单的 Watch 一栏中有四项 其中包括定义 Watch Point Define 删除 Watch Point remove kill all 及自动更新选项 也可用 WS WK 等命令代替 下面具体看 表达式 类型 dScope51 一次最多可设 16 个 WtchPoint 表达式 显示于 Watch Window 之中 表达式可以是简单变量 也可是复杂数据类型如结构 数组和指向结构的指针等 例如 WS ptime WS ptime hour WS some record o analog 等等 6 6 关于 IOF 文件 启动 DS51 后必须装入 IOF 文件才能使 CPU 及 Peripheral 各项起作用 这个函数的使用是依据 8051 系列 CPU 的不同特点 装入 8051 各 CPU 硬件设备模拟驱动文件 比如 8031CPU 就必须 load DS51 目录下的 8051 IOF 2 2 dScope for Windows dScope for windows 具有 dScope for dos 的全部功能 此外 它还具有以下明显的优点 1 标准的 Windows 界面 操作更容易更简单 2 常用操作多用对话框 而非 Dos 的行命令方式 3 窗口资源更加丰富 存储器窗口 覆盖率分析 运行状态分析窗口 加强了调试功能 因为 dScope for Windows 功能强大 具体操作在第八章详细介绍 3 第三节 Monitor51 及其使用 1 1 Monitor51 对硬件的要求 1 硬件系统为 51 系列 CPU 2 带 5K 外部程序存储器 从 O 地址开始 存放 Monitor51 程序 3 256Bytes 的外部数据存储器以及 5K 的跟踪缓冲区 此外 外部数据存储器必须足够容纳所有应用程 序代码及数据 且所有外部数据存储器必须为冯 诺伊曼存储器 即能一致访问 XDATA 与 Code 空间 4 一个定时器作为波特率发生器供串口使用 5 6 Bytes 的空余堆栈 2 2 Mon51 的使用 Mon51 的使用途径有三种方式 1 Dos 行命令方式 即先用 install 对 MON51 进行配置 然后用 MON51 进入 Monitor 状态 启用各种命令对 Monitor51 进行 调试 2 tScope51 方式 启动 tScope51 装入 TS51 目录下的 MON51 IOT 驱动文件 与目标板通信 3 dScope51 for Windows 方式 在选 CPU 驱动文件时 选 MON51 dll 则检查目标板并进入 MON51 状态 3 3 MON51 的配置 1 MON51 for Dos 的配置 运行 install 文件 在 MON51 目录下 不同的参数可以配置不同的硬件环境 INSTALL Serialtype xdstastart codestart bank PROMCHECK 具体说明见 MON51 帮助文件或使用手册 2 MON51 for Windows 的配置 在启用 MON51 dll 时 会使得系统自动检查目标板连接 如配置不对 则弹出 Configuration 对话框 设 置 PC 串口 波特率等 完毕单击 apply 有效 4 4 串口连接图 收发交叉互连 RTS CTS 直连 DSR DTR 直连 具体引脚排列参考串口资料 5 5 MON51 命令及使用 详细的 MON51 命令可参阅帮助 4 第四节 集成开发环境 IDE 的使用 1 1 Ishell for Dos 的使用 进入 Ishell 之后看到两个窗口 一个是文件窗口 一个是 Dos 命令行窗口 窗口上方是下拉式的命令菜单 其中的 Files 控制文件窗口的显隐 使用 Ishell 第一步就是配置系统 即要学习两个文件的修改与创建 1 1 Ishell CFG 文件 每一个 project 都有一个 Ishell CFG 其中存放有 Option 菜单和 Setup 菜单下的部分信息 Bell enabled Monochrome enabled Editor Selected CRT Lines target enviroment name of user edit Automatic load for configuration enabled file window enabled file specification for file window translate command line controls project name 等 对每个 project 都必须设置以上信息 然后存盘 setup 的的 save 这样才可正式开始下面工作 2 2 IShell col 文件 对 IDE 颜色设置 如不改动 可以缺省为主 3 3 CDF 文件 该文件位于 BIN 目录下 每一文件定义一组外部函数工具包 即定义外部环境如 8051 CDF USER CDF 等 开发者可修改 CDF 文件 供自己使用 至于 CDF 文件内容可查看一下 8051 CDF 即可知道 注意 CDF 文件是 Ishell 系统的核心所在 不同的 CDF 文件可使本 IDE 适用于不同的编译 连接系统 即本 IDE 并不仅适于 C51 下面谈一谈 Automake 工具 C51 的 Automake 是一个 project 管理器 在 8051 工具包中以 OBJECT 文件形式保留了一个 project 的信息 AutoMake 用这些信息来进行 project 管理 一旦手工建立一个 project Automake 可生成一个新的 OBJECT AutoMake 利用此文件来编译那些修改过的文件 Automake 支持 C51 A51 L51 BL51 C166 A166 L166 等编译连接器 点中主菜单中的 Automake 即 运行本工具 Ishell for Dos 使用比较繁琐 推荐使用 uVision for windows 2 2 uVision for windows 的使用 uVision 是一个标准的 windows 应用程序 其编译功能 文件处理功能 project 处理功能 窗口功能以及 工具引用功能 如 A51 C51 PL M41 BL51 dScope 等 等都较 Ishell for Dos 要强得多 uVision 采用 BL51 作连接器 因为 BL51 兼容 L51 所以一切能在 Dos 下工作的 project 都可以到 uVision 中进行连接调试 uVision 采用 dScope for windows 作调试器 该调试器支持 MON51 及系统模拟两种方式 功能较 for DOS 要强大好用 调试功能强大 注意 1 Option 菜单下的各项要会使用 其中 A51 C51 PL M51 BL51 定义各文件所使用的编译 连接控制 指令 dScope 定义一个 dScope 初始化文件 Make 则是定义一个 make 文件 2 进入调试是在 RUN 菜单下运行 dScope 3 project 中包括新建 打开 修改 更新 编译 连接等 poject 处理 具体使用可参考后面的例子 3 第三章 Keil C51 vs 标准 C 深入理解并应用 C51 对标准 ANSIC 的扩展是学习 C51 的关键之一 因为大多数扩展功能都是直接针对 8051 系列 CPU 硬件的 大致有以下 8 类 l 8051 存储类型及存储区域 l 存储模式 l 存储器类型声明 l 变量类型声明 l 位变量与位寻址 l 特殊功能寄存器 SFR l C51 指针 l 函数属性 具体说明如下 8031 为缺省 CPU 1 第一节 Keil C51 扩展关键字 C51 V4 0 版本有以下扩展关键字 共 19 个 at idata sfr16 alien interrupt small bdata large task Code bit pdata using reentrant xdata compact sbit data sfr 2 第二节 内存区域 Memory Areas 1 1 Pragram Area 由 Code 说明可有多达 64kBytes 的程序存储器 2 2 Internal Data Memory 内部数据存储器可用以下关键字说明 data 直接寻址区 为内部 RAM 的低 128 字节 00H 7FH idata 间接寻址区 包括整个内部 RAM 区 00H FFH bdata 可位寻址区 20H 2FH 3 3 External Data Memory 外部 RAM 视使用情况可由以下关键字标识 xdata 可指定多达 64KB 的外部直接寻址区 地址范围 0000H 0FFFFH pdata 能访问 1 页 25bBytes 的外部 RAM 主要用于紧凑模式 Compact Model 4 4 Speciac Function Register Memory 8051 提供 128Bytes 的 SFR 寻址区 这区域可位寻址 字节寻址或字寻址 用以控制定时器 计数器 串 口 I O 及其它部件 可由以下几种关键字说明 sfr 字节寻址 比如 sfr P0 0 x80 为 PO 口地址为 80H 后 H FFH 之间的常数 sfr16 字寻址 如 sfr16 T2 0 xcc 指定 Timer2 口地址 T2L 0 xcc T2H 0 xCD sbit 位寻址 如 sbit EA 0 xAF 指定第 0 xAF 位为 EA 即中断允许 还可以有如下定义方法 sbit 0V PSW 2 定义 0V 为 PSW 的第 2 位 sbit 0V 0XDO 2 同上 或 bit 0V 0 xD2 同上 3 第三节 存储模式 存储模式决定了没有明确指定存储类型的变量 函数参数等的缺省存储区域 共三种 1 1 Small 模式 所有缺省变量参数均装入内部 RAM 优点是访问速度快 缺点是空间有限 只适用于小程序 2 2 Compact 模式 所有缺省变量均位于外部 RAM 区的一页 256Bytes 具体哪一页可由 P2 口指定 在 STARTUP A51 文件 中说明 也可用 pdata 指定 优点是空间较 Small 为宽裕速度较 Small 慢 较 large 要快 是一种中间状态 3 3 large 模式 所有缺省变量可放在多达 64KB 的外部 RAM 区 优点是空间大 可存变量多 缺点是速度较慢 提示 存储模式在 C51 编译器选项中选择 4 第四节 存储类型声明 变量或参数的存储类型可由存储模式指定缺省类型 也可由关键字直接声明指定 各类型分别用 code data idata xdata pdata 说明 例 data uar1 char code array hello unsigned char xdata arr 10 4 4 5 第五节 变量或数据类型 C51 提供以下几种扩展数据类型 bit 位变量值为 0 或 1 sbit 从字节中定义的位变量 0 或 1 sfr sfr 字节地址 0 255 sfr16 sfr 字地址 0 65535 其余数据类型如 char enum short int long float 等与 ANSI C 相同 6 第六节 位变量与声明 1 1 bit 型变量 bit 型变量可用变量类型 函数声明 函数返回值等 存贮于内部 RAM20H 2FH 注意 1 用 pragma disable 说明函数和用 usign 指定的函数 不能返回 bit 值 2 一个 bit 变量不能声明为指针 如 bit ptr 是错误的 3 不能有 bit 数组如 bit arr 5 错误 2 2 可位寻址区说明 20H 2FH 可作如下定义 int bdata i char bdata arr 3 然后 sbit bito in0 sbit bit15 I 15 sbit arr07 arr 0 7 sbit arr15 arr i 7 7 第七节 Keil C51 指针 C51 支持一般指针 Generic Pointer 和存储器指针 Memory Specific Pointer 1 1 一般指针 一般指针的声明和使用均与标准 C 相同 不过同时还可以说明指针的存储类型 例如 long state 为一个指向 long 型整数的指针 而 state 本身则依存储模式存放 char xdata ptr ptr 为一个指向 char 数据的指针 而 ptr 本身放于外部 RAM 区 以上的 long char 等指针 指向的数据可存放于任何存储器中 一般指针本身用 3 个字节存放 分别为存储器类型 高位偏移 低位偏移量 2 2 存储器指针 基于存储器的指针说明时即指定了存贮类型 例如 char data str str 指向 data 区中 char 型数据 int xdata pow pow 指向外部 RAM 的 int 型整数 这种指针存放时 只需一个字节或 2 个字节就够了 因为只需存放偏移量 3 3 指针转换 即指针在上两种类型之间转化 l 当基于存储器的指针作为一个实参传递给需要一般指针的函数时 指针自动转化 l 如果不说明外部函数原形 基于存储器的指针自动转化为一般指针 导致错误 因而请用 include 说 明所有函数原形 l 可以强行改变指针类型 8 第八节 Keil C51 函数 C51 函数声明对 ANSI C 作了扩展 具体包括 1 1 中断函数声明 中断声明方法如下 void serial ISR interrupt 4 using 1 ISR 为提高代码的容错能力 在没用到的中断入口处生成 iret 语句 定义没用到的中断 define not used interrupt so generate IRET in their entrance void extern0 ISR interrupt 0 not used void timer0 ISR interrupt 1 not used void extern1 ISR interrupt 2 not used void timer1 ISR interrupt 3 not used void serial ISR interrupt 4 not used 2 2 通用存储工作区 3 3 选通用存储工作区由 using x 声明 见上例 4 4 指定存储模式 由 small compact 及 large 说明 例如 void fun1 void small 提示 small 说明的函数内部变量全部使用内部 RAM 关键的经常性的耗时的地方可以这样声明 以提高 运行速度 5 5 pragma disable 在函数前声明 只对一个函数有效 该函数调用过程中将不可被中断 6 6 递归或可重入函数指定 在主程序和中断中都可调用的函数 容易产生问题 因为 51 和 PC 不同 PC 使用堆栈传递参数 且静态 变量以外的内部变量都在堆栈中 而 51 一般使用寄存器传递参数 内部变量一般在 RAM 中 函数重入 时会破坏上次调用的数据 可以用以下两种方法解决函数重入 a 在相应的函数前使用前述 pragma disable 声明 即只允许主程序或中断之一调用该函数 b 将该函数说明为可重入的 如下 void func param reentrant KeilC51 编译后将生成一个可重入变量堆栈 然后就可以模拟通过堆栈传递变量的方法 由于一般可重入函数由主程序和中断调用 所以通常中断使用与主程序不同的 R 寄存器组 另外 对可重入函数 在相应的函数前面加上开关 pragma noaregs 以禁止编译器使用绝对寄存器寻址 可生成不依赖于寄存器组的代码 7 7 指定 PL M 51 函数 由 alien 指定 4 第四章 Keil C51 高级编程 本章讨论以下内容 l 绝对地址访问 l C 与汇编的接口 l C51 软件包中的通用文件 l 段名转换与程序优化 1 第一节 绝对地址访问 C51 提供了三种访问绝对地址的方法 1 1 绝对宏 在程序中 用 include 即可使用其中定义的宏来访问绝对地址 包括 CBYTE XBYTE PWORD DBYTE CWORD XWORD PBYTE DWORD 具体使用可看一看 absacc h 便知 例如 rval CBYTE 0 x0002 指向程序存贮器的 0002h 地址 rval XWORD 0 x0002 指向外 RAM 的 0004h 地址 2 2 at 关键字 直接在数据定义后加上 at const 即可 但是注意 1 绝对变量不能被初使化 2 bit 型函数及变量不能用 at 指定 例如 idata struct link list at 0 x40 指定 list 结构从 40h 开始 xdata char text 25b at 0 xE000 指定 text 数组从 0E000H 开始 提示 如果外部绝对变量是 I O 端口等可自行变化数据 需要使用 volatile 关键字进行描述 请参考 absacc h 3 3 连接定位控制 此法是利用连接控制指令 code xdata pdata data bdata 对 段 地址进行 如要指定某具体变量地址 则很有 局限性 不作详细讨论 2 第二节 Keil C51 与汇编的接口 1 1 模块内接口 方法是用 pragma 语句具体结构是 pragma asm 汇编行 pragma endasm 这种方法实质是通过 asm 与 ndasm 告诉 C51 编译器中间行不用编译为汇编行 因而在编译控制指令中有 SRC 以控制将这些不用编译的行存入其中 2 2 模块间接口 C 模块与汇编模块的接口较简单 分别用 C51 与 A51 对源文件进行编译 然后用 L51 将 obj 文件连接即 可 关键问题在于 C 函数与汇编函数之间的参数传递问题 C51 中有两种参数传递方法 1 通过寄存器传递函数参数 最多只能有 3 个参数通过寄存器传递 规律如下表 参数数目 char int long float 一般指针 123 R7R5R3 R6 This file is part of the C51 Compiler package Copyright KEIL ELEKTRONIK GmbH 1990 STARTUP A51 This code is executed after processor reset To translate this file use A51 with the following invocation A51 STARTUP A51 To link the modified STARTUP OBJ file to your application use the following L51 invocation L51 STARTUP OBJ User defined Power On Initialization of Memory With the following EQU statements the initialization of memory at processor reset can be defined the absolute start address of IDATA memory is always 0 IDATALEN EQU 80H the length of IDATA memory in bytes XDATASTART EQU 0H the absolute start address of XDATA memory XDATALEN EQU 0H the length of XDATA memory in bytes PDATASTART EQU 0H the absolute start address of PDATA memory PDATALEN EQU 0H the length of PDATA memory in bytes Notes The IDATA space overlaps physically the DATA and BIT areas of the 8051 CPU At minimum the memory space occupied from the C51 run time routines must be set to zero Reentrant Stack Initilization The following EQU statements define the stack pointer for reentrant functions and initialized it Stack Space for reentrant functions in the SMALL model IBPSTACK EQU 0 set to 1 if small reentrant is used IBPSTACKTOP EQU 0FFH 1 set top of stack to highest location 1 Stack Space for reentrant functions in the LARGE model XBPSTACK EQU 0 set to 1 if large reentrant is used XBPSTACKTOP EQU 0FFFFH 1 set top of stack to highest location 1 Stack Space for reentrant functions in the COMPACT model PBPSTACK EQU 0 set to 1 if compact reentrant is used PBPSTACKTOP EQU 0FFFFH 1 set top of stack to highest location 1 Page Definition for Using the Compact Model with 64 KByte xdata RAM The following EQU statements define the xdata page used for pdata variables The EQU PPAGE must conform with the PPAGE control used in the linker invocation PPAGEENABLE EQU 0 set to 1 if pdata object are used PPAGE EQU 0 define PPAGE number 3 3 标准输入输出文件 putchar c putchar c 是一个低级字符输出子程 开发人员可修改后应用到自己的硬件系统上 例如向 CLD 或 LEN 输 出字符 缺省 putchar c 是向串口输出一个字符 XON XOFF 是流控标志 换行符 n 自动转化为回车 换行 r n getkey c getkey 函数是一个低级字符输入子程 该程序可用到自己硬件系统 如矩阵键盘输入中 缺省时通过串口 输入字符 4 4 其它文件 还包括对 Watch Dog 有独特功能的 INIT A51 函数以及对 8 C751 适用的函数 可参考源代码 4 第四节 段名协定与程序优化 1 1 段名协定 Segment Naming Conventions C51 编译器生成的目标文件存放于许多段中 这些段是代码空间或数据空间的一些单元 一个段可以是可 重定位的 也可以是绝对段 每一个可重定位的段都有一个类型和名字 C51 段名有以下规定 每个段名包括前缀与模块名两部分 前缀表示存储类型 模块名则是被编译的模块的名字 例如 CO main1 表示 main1 模块中的代码段中的常数部分 PR function1 module 表 module 模块中函数 function1 的可执行段 具体规定参阅手册 2 2 程序优化 C51 编译器是一个具有优化功能的编译器 它共提供六级优化功能 确保生成目标代码的最高效率 代码 最少 运行速度最快 具体六级优化的内容可参考帮助 在 C51 中提供以下编译控制指令控制代码优化 OPTIMIZE SJXE 尽量采用子程序 使程序代码减少 NOAREGS 不使用绝对寄存器访问 程序代码与寄存器段独立 NOREGPARMS 参数传递总是在局部数据段实现 程序代码与低版本 C51 兼容 OPTIMIZE SIZE AK OPTIMIZE speed 提供 6 级优化功能 缺省为 OPTIMIZE 6 SPEED 5 第五章 Keil C51 库函数参考 C51 强大功能及其高效率的重要体现之一在于其丰富的可直接调用的库函数 多使用库函数使程序代码简

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论