文档库 最新最全的文档下载
当前位置:文档库 › C51单片机编程基本知识

C51单片机编程基本知识

C51单片机编程基本知识
C51单片机编程基本知识

C51单片机编程基本知识

全文选段:该控制指令将C文件编译生成汇编文件(.SRC),该汇编文件可改名后,生成汇编.ASM文件,再用A51进行编译。

第三节 Keil C51软件包中的通用文件

在C51\LiB目录下有几个C源文件,这几个C源文件有非常重要的作用,对它们稍事修改,就可以用在自己的专用系统中。

1. 动态内存分配

init_mem.C:此文件是初始化动态内存区的程序源代码。它可以指定动态内存的位置及大小,只有使用了init_mem( )才可以调回其它函数,诸如malloc calloc,realloc等。

calloc.c:此文件是给数组分配内存的源代码,它可以指定单位数据类型及该单元数目。

malloc.c:此文件是malloc的源代码,分配一段固定大小的内存。

realloc.c:此文件是realloc.c源代码,其功能是调整当前分配动态内存的大小。

全文内容:

本章讨论以下内容:

l 绝对地址访问

l C与汇编的接口

l C51软件包中的通用文件

l 段名转换与程序优化

第一节绝对地址访问

C51提供了三种访问绝对地址的方法:

1. 绝对宏:

在程序中,用“#include〈absacc.h〉”即可使用其中定义的宏来访问绝对地址,包括:

CBYTE、XBYTE、PWORD、DBYTE、CWORD、XWORD、PBYTE、DWORD

具体使用可看一看absacc.h便知

例如:

rval=CBYTE[0x0002];指向程序存贮器的0002h地址

rval=XWORD [0x0002];指向外RAM的0004h地址

2. _at_关键字

直接在数据定义后加上_at_ const即可,但是注意:

(1)绝对变量不能被初使化;

(2)bit型函数及变量不能用_at_指定。

例如:

idata struct link list _at_ 0x40;指定list结构从40h开始。

xdata char text[25b] _at_0xE000;指定text数组从0E000H开始

提示:如果外部绝对变量是I/O端口等可自行变化数据,需要使用volatile关键字进行描述,请参考absacc.h。

3. 连接定位控制

此法是利用连接控制指令code xdata pdata \data bdata对“段”地址进行,如要指定某具体变量地址,则很有局限性,不作详细讨论。

第二节 Keil C51与汇编的接口

1. 模块内接口

方法是用#pragma语句具体结构是:

#pragma asm

汇编行

#pragma endasm

这种方法实质是通过asm与ndasm告诉C51编译器中间行不用编译为汇编行,因而在编译控制指令中有SRC以控制将这些不用编译的行存入其中。

2. 模块间接口

C模块与汇编模块的接口较简单,分别用C51与A51对源文件进行编译,然后用L51将obj文件连接即可,关键问题在于C函数与汇编函数之间的参数传递问题,C51中有两种参数传递方法。

(1) 通过寄存器传递函数参数

最多只能有3个参数通过寄存器传递,规律如下表:

参数数目

char

int

long,float

一般指针

1

2

3

R7

R5

R3

R6 & R7

R4 & R5

R2 & R3

R4~R7

R4~R7

R1~R3

R1~R3

R1~R3

(2) 通过固定存储区传递(fixed memory)

这种方法将bit型参数传给一个存储段中:

?function_name?BIT

将其它类型参数均传给下面的段:?function_name?BYTE,且按照预选顺序存放。

至于这个固定存储区本身在何处,则由存储模式默认。

(3) 函数的返回值

函数返回值一律放于寄存器中,有如下规律:

return type

Registev

说明

bit

标志位

由具体标志位返回

char/unsigned char 1_byte指针

R7

单字节由R7返回

int/unsigned int 2_byte指针

R6 & R7

双字节由R6和R7返回,MSB在R6

long&unsigned long

R4~R7

MSB在R4, LSB在R7

float

R4~R7

32Bit IEEE格式

一般指针

R1~R3

存储类型在R3 高位R2 低R1

(4) SRC控制

该控制指令将C文件编译生成汇编文件(.SRC),该汇编文件可改名后,生成汇编.ASM文件,再用A51进行编译。

第三节 Keil C51软件包中的通用文件

在C51\LiB目录下有几个C源文件,这几个C源文件有非常重要的作用,对它们稍事修改,就可以用在自己的专用系统中。

1. 动态内存分配

init_mem.C:此文件是初始化动态内存区的程序源代码。它可以指定动态内存的位置及大小,只有使用了init_mem( )才可以调回其它函数,诸如malloc calloc,realloc等。

calloc.c:此文件是给数组分配内存的源代码,它可以指定单位数据类型及该单元数目。

malloc.c:此文件是malloc的源代码,分配一段固定大小的内存。

realloc.c:此文件是realloc.c源代码,其功能是调整当前分配动态内存的大小。

2. C51启动文件STARTUP.A51

启动文件STARTUP.A51中包含目标板启动代码,可在每个project中加入这个文件,只要复位,则该文件立即执行,其功能包括:

l 定义内部RAM大小、外部RAM大小、可重入堆栈位置

l 清除内部、外部或者以此页为单元的外部存储器

l 按存储模式初使化重入堆栈及堆栈指针

l 初始化8051硬件堆栈指针

l 向main( )函数交权

开发人员可修改以下数据从而对系统初始化

常数名意义

IDATALEN 待清内部RAM长度

XDATA START 指定待清外部RAM起始地址

XDATALEN 待清外部RAM长度

IBPSTACK 是否小模式重入堆栈指针需初始化标志,1为需要。缺省为0

IBPSTACKTOP 指定小模式重入堆栈顶部地址

XBPSTACK 是否大模式重入堆栈指针需初始化标志,缺省为0

XBPSTACKTOP 指定大模式重入堆栈顶部地址

PBPSTACK 是否Compact重入堆栈指针,需初始化标志,缺省为0

PBPSTACKTOP 指定Compact模式重入堆栈顶部地址

PPAGEENABLE P2初始化允许开关

PPAGE 指定P2值

PDATASTART 待清外部RAM页首址

PDATALEN 待清外部RAM页长度

提示:如果要初始化P2作为紧凑模式高端地址,必须:PPAGEENAGLE=1,PPAGE为P2值,例如指定某页1000H-10FFH,则PPAGE=10H,而且连接时必须如下:

L51〈input modules〉 PDATA(1080H),其中1080H是1000H-10FFH中的任一个值。

以下是STARTUP.A51代码片断,红色是经常可能需要修改的地方:

;------------------------------------------------------------------------------

; 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 〈your object file list〉, STARTUP.OBJ 〈controls〉

;

;------------------------------------------------------------------------------

;

; 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. 标准输入输出文件

putchar.c

putchar.c是一个低级字符输出子程,开发人员可修改后应用到自己的硬件系统上,例如向CLD或LEN输出字符。

缺省:putchar.c是向串口输出一个字符XON|XOFF是流控标志,换行符“\*n”自动转化为回车/换行“\r\n”。getkey.c

getkey函数是一个低级字符输入子程,该程序可用到自己硬件系统,如矩阵键盘输入中,缺省时通过串口输入字符。 4. 其它文件

还包括对Watch-Dog有独特功能的INIT.A51函数以及对8×C751适用的函数,可参考源代码。

第四节段名协定与程序优化

1. 段名协定(Segment Naming Conventions)

C51编译器生成的目标文件存放于许多段中,这些段是代码空间或数据空间的一些单元,一个段可以是可重定位的,也可以是绝对段,每一个可重定位的段都有一个类型和名字,C51段名有以下规定:

每个段名包括前缀与模块名两部分,前缀表示存储类型,模块名则是被编译的模块的名字,例如:

?CO?main1 :表示main1模块中的代码段中的常数部分

?PR?function1?module 表module模块中函数function1的可执行段,具体规定参阅手册。

2. 程序优化

C51编译器是一个具有优化功能的编译器,它共提供六级优化功能。确保生成目标代码的最高效率(代码最少,运行速度最快)。具体六级优化的内容可参考帮助。

在C51中提供以下编译控制指令控制代码优化:

OPTIMIZE(SJXE):尽量采用子程序,使程序代码减少。

NOAREGS:不使用绝对寄存器访问,程序代码与寄存器段独立。

NOREGPARMS:参数传递总是在局部数据段实现,程序代码与低版本C51兼容。

OPTIMIZE(SIZE)AK OPTIMIZE(speed)提供6级优化功能,缺省为: OPTIMIZE(6,SPEED)。

三日学会Keil C51单片机开发系统基础教学课程

1. 第一节系统概述

Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。用过汇编语言后再使用C来开发,体会更加深刻。

Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。

下面详细介绍Keil C51开发系统各部分功能和使用。

2. 第二节Keil C51单片机软件开发系统的整体结构

C51工具包的整体结构,如图(1)所示,其中uVision与Ishell分别是C51 for Windows和for Dos的集成开发环境(IDE),可以完成编辑、编译、连接、调试、仿真等整个开发流程。开发人员可用IDE本身或其它编辑器编辑C或汇编源文件。然后分别由C51及A51编译器编译生成目标文件(.OBJ)。目标文件可由LIB51创建生成库文件,也可以与库文件一起经L51连接定位生成绝对目标文件(.ABS)。ABS文件由OH51转换成标准的Hex文件,以供调试器dScope51或tScope51使用进行源代码级调试,也可由仿真器使用直接对目标板进行调试,也可以直接写入程序存贮器如EPROM中。

图(1) C51工具包整体结构图

3. 第三节Keil C51工具包的安装

1. 1. C51 for Dos

在Windows下直接运行软件包中DOS\C51DOS.exe然后选择安装目录即可。完毕后欲使系统正常工作须进行以下操作(设C:\C51为安装目录):

修改Autoexec.bat,加入

path=C:\C51\Bin

Set C51LIB=C:\C51\LIB

Set C51INC=C:\C51\INC

然后运行Autoexec.bat

2. 2. C51 for Windows的安装及注意事项:

在Windows下运行软件包中WIN\Setup.exe,最好选择安装目录与C51 for Dos相同,这样设置最简单(设安装于C:\C51目录下)。然后将软件包中crack目录中的文件拷入C:\C51\Bin目录下。

4. 第四节Keil C51工具包各部分功能及使用简介

1. 1. C51与A51

1. (1) C51

C51是C语言编译器,其使用方法为:

C51 sourcefile[编译控制指令]

或者

C51 @ commandfile

其中sourcefile为C源文件(.C)。大量的编译控制指令完成C51编译器的全部功能。包控C51输出文件C.LST,.OBJ,.I和.SRC文件的控制。源文件(.C)的控制等,详见第五部分的具体介绍。

而Commandfile为一个连接控制文件其内容包括:.C源文件及各编译控制指令,它没有固定的名字,开发人员可根据自己的习惯指定,它适于用控制指令较多的场合。

2. (2) A51

A51是汇编语言编译器,使用方法为:

A51 sourcefile[编译控制指令]

或A51 @ commandfile

其中sourcefile为汇编源文件(.asm或.a51),而编译控制指令的使用与其它汇编如ASM语言类似,可参考其他汇编语言材料。

Commandfile同C51中的Commandfile类似,它使A51使用和修改方便。

2. 2. L51和BL51

1. (1) L51

L51是Keil C51软件包提供的连接/定位器,其功能是将编译生成的OBJ文件与库文件连接定位生成绝对目标文件(.ABS),其使用方法为:

L51 目标文件列表[库文件列表] [to outputfile] [连接控制指令]

或L51 @Commandfile

源程序的多个模块分别经C51与A51编译后生成多个OBJ文件,连接时,这些文件全列于目标文件列表中,作为输入文件,如果还需与库文件(.LiB)相连接,则库文件也必须列在其后。outputfile为输文件名,缺少时为第一模块名,后缀为.ABS。连接控制指令提供了连接定位时的所有控制功能。Commandfile为连接控制文件,其具体内容是包括了目标文件列表,库文件列表及输出文件、连接控制命令,以取代第一种繁琐的格式,由于目标模块库文件大多不止1个,因而第2种方法较多见,这个文件名字也可由使用者随意指定。

2. (2) Bl51

BL51也是C51软件包的连接/定位器,其具有L51的所有功能,此外它还具有以下3点特别之处:

a. 可以连接定位大于64kBytes的程序。

b. 具有代码域及域切换功能(CodeBanking & Bank Switching)

c. 可用于RTX51操作系统

RTX51是一个实时多任务操作系统,它改变了传统的编程模式,甚至不必用main( )函数,单片机系统软件向RTOS发展是一种趋势,这种趋势对于186和386及68K系列CPU更为明显和必须,对8051因CPU较为简单,程序结构等都不太复杂,RTX51作用显得不太突出,其专业版软件PK51软件包甚至不包括RTX51Full,而只有一个RTX51TINY版本的RTOS。RTX51 TINY适用于无外部RAM的单片机系统,因而可用面很窄,在本文中不作介绍。Bank switching技术因使用很少也不作介绍。

3. 3. DScope51,Tscope51及Monitor51

1. (1) dScope51

dScope51是一个源级调试器和模拟器,它可以调试由C51编译器、A51汇编器、PL/M-51编译器及ASM -51汇编器产生的程序。它不需目标板(for windows也可通过mon51接目标板),只能进行软件模拟,但其功能强大,可模拟CPU及其外围器件,如内部串口,外部I/O及定时器等,能对嵌入式软件功能进行有效测试。

其使用方法为:

DS51[debugfile][INIT(initfile)]

其中debugfile是一个Hex格式的8051文件,即待调试的文件其为可选的,可在进入dScope51后用load 命令装入。

Initfile为一个初使化文件,它在启动dScope51后,在debugfile装入前装入,装有一些dScope的初使化参数及常用调试函数等。下面是一个dScope.ini文件(for dos)的内容:

Load ..\..\ds51\8051.iof

Map 0,0xffff

dScope51 for Windows则直接用鼠标进入,然后用load装入待调文件。

2. (2) tScope51

与dScope51不同的是Scope51必须带目标板,目前它可以通过两种方式访问目标板。(1) 通过EMul51在线仿真器,tScope51为该仿真器准备了一个动态连接文件EMUL51.IOT,但该方法必须配合该仿真器。

(2) 通过Monitov51监控程序,这种方法是可行的,tScope51为访问Monitor51专门带有MON51.IOT连接程序,使用时可通过串口及监控程序来调试目标板。

其使用方法为:

TS51[INIT(file_name.ini)]

其中file_name.ini为一个初使化文件。

进入TS51后,必须装入IOT文件,可用的有MON51.IOT及EMUL51.IOT两种,如装入MON51.IOT:Load.C:\C51\TS51\MON51.IOT CPUTYPE(80517)

可惜的是tScope51只有for Dos的版本。

3. (3) Monitor 51

Monitor51是一个监控程序通过PC机的串口与目标板进行通信,Monitor操作需要MON51或dScope51 for Windows,后面部分将对Monitor51做较为详细的介绍。

4. 4. Ishell及uVision

1. (1) Ishell for Dos

这是一个for Dos的IDE,直接在命令行键入Ishell,则进入该环境,它使用简单方便。其命令行与DOS 命令行具有同样的功能,对单模块的Project直接由菜单进行编译连接,对多模块的project。则通过批处理,BAT文件进行编译连接,然后通过菜单控制由dScope51或tScope51对程序进行调试,因为是for dos 的,不做太详细介绍。

2. (2) uVision for Windows

uVision for Windows是一个标准的Windows应用程序,它是C51的一个集成软件开发平台,具有源代码

编辑、project管理、集成的make等功能,它的人机界面友好,操作方便,是开发者的首选,具体配置及使用见第五部分。

2. 第二章Keil C51软件使用详解

1. 第一节Keil C51编译器的控制指令

C51编译器的控制指令分为三类:源文件控制类,目标文件控制类及列表控制类。

1. 1. 源文件控制类

NOEXTEND:C51源文件不允许使用ANSI C扩展功能。

DEFINE(DF):定义预处理(在C51命令行)。

2. 2. 目标文件(Object)控制类:

COMPACT LARGE SMALL 选编译模式

DEBUG(DB) 包含调试信息,以供仿真器或dSCope51使用。

NOAMAKE(NOAM) 禁止AutoMake信息记录

NOREGPARMS 禁止用寄存器传递参数

OBJECTEXTEND(OE) Object文件包含附加变量类型信息

OPTIMIZE(OT) 指定优化级别

REGFILE(RF) 指定一个寄存器使用的文件以供整体优化用

REGISTERBANK(RB) 指定一个供绝对寄存器访问的寄存器区名

SRC 不生成目标文件只生成汇编源文件

其它控件不常用。

3. 3. 列表文件(listing)控制类:

CODE(CD):向列表文件加入汇编列表

LISTINCLUDE(LC):显示indude文件

SYMBOLS(SB):列表文件包括模块内所有符号的列表

WARNINGLEVEL(WL):选择“警告”级别

2. 第二节dScope51的使用

1. 1. dScope51 for Dos

总的来说dScope51具有以下特性:

l 高级语言显示模式

l 集成硬件环境模拟

l 单步或“GO”执行模式

l 存储器、寄存器及变量访问

l Watch表达式之值

l 函数与信号功能

下面,具体说明在进入dScope51 for Dos之后,如何实现上述功能,dScope51采用下拉菜单格式和窗口显示控制,共有language、serial、exe、register四个窗口,其中exe为命令行窗口,language为程序窗口,serial为串口窗,register为寄存器窗。

1. (1) 高级语言显示模式

单击主菜单中的“View”,第一栏中的三条命令“Highlevel”、“Mixed”、“Assembly”分别对所装入的程序按照“高级”、“混合级”及“汇编级”三种方式显示,以方便调试使用。

2. (2) 集成硬件环境模拟显示

主菜单中“Peripheral”各条能显示模拟硬件环境的状态,其中:

i/o Port:显示各I/O口之值,对8031而言SFR中的P1、P2、P3、P0与引脚之值分别列出:Interrupt:显示5个中断源的入口模式是否允许,优先级等中断状态。

Timer:显示各定时/计数器的模式,初始值状态等。

int Message:中断信息允许,如为允许(“>>”出现),则当中断申请时,显示中断源信息。比如当中断发生时会显示:

“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=0x80;为PO口地址为80H,“=”后H~FFH之间的常数。

sfr16:字寻址,如sfr16 T2=0xcc;指定Timer2口地址T2L=0xcc T2H=0xCD

sbit:位寻址,如sbit EA=0xAF;指定第0xAF位为EA,即中断允许

还可以有如下定义方法:

sbit 0V=PSW^2;(定义0V为PSW的第2位)

sbit 0V=0XDO^2;(同上)

或bit 0V-=0xD2(同上)。

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[0x0002];指向程序存贮器的0002h地址

rval=XWORD [0x0002];指向外RAM的0004h地址

2. 2. _at_关键字

直接在数据定义后加上_at_ const即可,但是注意:

(1)绝对变量不能被初使化;

(2)bit型函数及变量不能用_at_指定。

例如:

idata struct link list _at_ 0x40;指定list结构从40h开始。

xdata char text[25b] _at_0xE000;指定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 & R7R4 & R5R2 & R3 R4~R7R4~R7 R1~R3R1~R3R1~R3

< p>

(2) 通过固定存储区传递(fixed memory)

这种方法将bit型参数传给一个存储段中:

?function_name?BIT

将其它类型参数均传给下面的段:?function_name?BYTE,且按照预选顺序存放。

至于这个固定存储区本身在何处,则由存储模式默认。

(3) 函数的返回值

函数返回值一律放于寄存器中,有如下规律:

return type Registev 说明

bit 标志位由具体标志位返回

char/unsigned char 1_byte指针R7 单字节由R7返回

int/unsigned int 2_byte指针R6 & R7 双字节由R6和R7返回,MSB在R6

long&unsigned long R4~R7 MSB在R4, LSB在R7

float R4~R7 32Bit IEEE格式

一般指针R1~R3 存储类型在R3 高位R2 低R1

(4) SRC控制

该控制指令将C文件编译生成汇编文件(.SRC),该汇编文件可改名后,生成汇编.ASM文件,再用A51进行编译。

3. 第三节Keil C51软件包中的通用文件

在C51\LiB目录下有几个C源文件,这几个C源文件有非常重要的作用,对它们稍事修改,就可以用在自己的专用系统中。

1. 1. 动态内存分配

init_mem.C:此文件是初始化动态内存区的程序源代码。它可以指定动态内存的位置及大小,只有使用了init_mem( )才可以调回其它函数,诸如malloc calloc,realloc等。

calloc.c:此文件是给数组分配内存的源代码,它可以指定单位数据类型及该单元数目。

malloc.c:此文件是malloc的源代码,分配一段固定大小的内存。

realloc.c:此文件是realloc.c源代码,其功能是调整当前分配动态内存的大小。

2. 2. C51启动文件STARTUP.A51

启动文件STARTUP.A51中包含目标板启动代码,可在每个project中加入这个文件,只要复位,则该文件立即执行,其功能包括:

l 定义内部RAM大小、外部RAM大小、可重入堆栈位置

l 清除内部、外部或者以此页为单元的外部存储器

l 按存储模式初使化重入堆栈及堆栈指针

l 初始化8051硬件堆栈指针

l 向main( )函数交权

开发人员可修改以下数据从而对系统初始化

常数名意义

IDATALEN 待清内部RAM长度

XDATA START 指定待清外部RAM起始地址

XDATALEN 待清外部RAM长度

IBPSTACK 是否小模式重入堆栈指针需初始化标志,1为需要。缺省为0

IBPSTACKTOP 指定小模式重入堆栈顶部地址

XBPSTACK 是否大模式重入堆栈指针需初始化标志,缺省为0

XBPSTACKTOP 指定大模式重入堆栈顶部地址

PBPSTACK 是否Compact重入堆栈指针,需初始化标志,缺省为0

PBPSTACKTOP 指定Compact模式重入堆栈顶部地址

PPAGEENABLE P2初始化允许开关

PPAGE 指定P2值

PDATASTART 待清外部RAM页首址

PDATALEN 待清外部RAM页长度

提示:如果要初始化P2作为紧凑模式高端地址,必须:PPAGEENAGLE=1,PPAGE为P2值,例如指定某页1000H-10FFH,则PPAGE=10H,而且连接时必须如下:

L51 PDATA(1080H),其中1080H是1000H-10FFH中的任一个值。

以下是STARTUP.A51代码片断,红色是经常可能需要修改的地方:

;------------------------------------------------------------------------------

; 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.

2. 第二节几类重要库函数

1. 1. 专用寄存器include文件

例如8031、8051均为REG51.h其中包括了所有8051的SFR及其位定义,一般系统都必须包括本文件。

2. 2. 绝对地址include文件absacc.h

该文件中实际只定义了几个宏,以确定各存储空间的绝对地址。

3. 3. 动态内存分配函数,位于stdlib.h中

4. 4. 缓冲区处理函数位于“string.h”中

其中包括拷贝比较移动等函数如:

memccpy memchr memcmp memcpy memmove memset

这样很方便地对缓冲区进行处理。

5. 5. 输入输出流函数,位于“stdio.h”中

流函数通8051的串口或用户定义的I/O口读写数据,缺省为8051串口,如要修改,比如改为LCD显示,可修改lib目录中的getkey.c及putchar.c源文件,然后在库中替换它们即可。

3. 第三节Keil C51库函数原型列表

1. 1. CTYPE.H

bit isalnum(char c);

bit isalpha(char c);

bit iscntrl(char c);

bit isdigit(char c);

bit isgraph(char c);

bit islower(char c);

bit isprint(char c);

bit ispunct(char c);

bit isspace(char c);

bit isupper(char c);

bit isxdigit(char c);

bit toascii(char c);

bit toint(char c);

char tolower(char c);

char __tolower(char c);

char toupper(char c);

char __toupper(char c);

2. 2. INTRINS.H

unsigned char _crol_(unsigned char c,unsigned char b);

unsigned char _cror_(unsigned char c,unsigned char b);

unsigned char _chkfloat_(float ual);

unsigned int _irol_(unsigned int i,unsigned char b);

unsigned int _iror_(unsigned int i,unsigned char b);

unsigned long _irol_(unsigned long l,unsigned char b);

unsigned long _iror_(unsigned long L,unsigned char b);

void _nop_(void);

bit _testbit_(bit b);

3. 3. STDIO.H

char getchar(void);

char _getkey(void);

char *gets(char * string,int len);

int printf(const char * fmtstr[,argument]…);

char putchar(char c);

int puts (const char * string);

int scanf(const cha r * fmtstr.[,argument]…);

int sprintf(char * buffer,const char *fmtstr[;argument]);

int sscanf(char *buffer,const char * fmtstr[,argument]);

char ungetchar(char c);

void vprintf (const char *fmtstr,char * argptr);

void vsprintf(char *buffer,const char * fm tstr,char * argptr);

4. 4. STDLIB.H

float atof(void * string);

int atoi(void * string);

long atol(void * string);

void * calloc(unsigned int num,unsigned int len);

void free(void xdata *p);

void init_mempool(void *data *p,unsigned int size);

void *malloc (unsigned int size);

int rand(void);

void *realloc (void xdata *p,unsigned int size);

void srand (int seed);

5. 5. STRING.H

void *memccpy (void *dest,void *src,char c,int len);

void *memchr (void *buf,char c,int len);

char memcmp(void *buf1,void *buf2,int len);

void *memcopy (void *dest,void *SRC,int len);

void *memmove (void *dest,void *src,int len);

void *memset (void *buf,char c,int len);

char *strcat (char *dest,char *src);

char *strchr (const char *string,char c);

char strcmp (char *string1,char *string2);

char *strcpy (char *dest,char *src);

int strcspn(char *src,char * set);

int strlen (char *src);

char *strncat (char 8dest,char *src,int len);

char strncmp(char *string1,char *string2,int len);

char strncpy (char *dest,char *src,int len);

char *strpbrk (char *string,char *set);

int strpos (const char *string,char c);

char *strrchr (const char *string,char c);

char *strrpbrk (char *string,char *set);

int strrpos (const char *string,char c);

int strspn(char *string,char *set);

6. 第六章Keil C51例子:Hello.c

Hello位于\C51\excmples\Hello\目录,其功能是向串口输出“Hello,world”整个程序如下:#pragma DB OE CD

相关文档