XBYTE
The XBYTE macro accesses individual bytes in the external data memory of the 8051. You may use this macro in your programs as follows:
#include
/* Include Macro Definitions */
.
.
.
rval = XBYTE [0x0002];
XBYTE [0x0002] = 57;
.
.
.
This example reads and writes the contents of the byte in external data memory at address 0002h.
The range of valid index values for this macro is 0-65535.
http://www.keil.com/support/man/docs/c51/c51_xbyte.htm
上面的是在keil的help里ctrl+c来的,以前在论坛里看到过有人问如何用c语言实现定位存储,呵呵,当时还说不可能呢!现在在查找using的时候,无意中看到了XBYTE,点中看看,居然有大发现啊!
百度结果:这个主要是在用C51的P0,P2口做外部扩展时使用,其中XBYTE [0x0002],P2口对应于地址高位,P0口对应于地址低位。一般P2口用于控制信号,P0口作为数据通道。
如:P2.7接WR,P2.6接RD,P2.5接CS,那么就可以确定个外部RAM的一个地址,想往外部RAM的一个地址写一个字节时,地址可以定为XBYTE [0x4000],其中WR,CS为低,RD为高,那就是高位的4,当然其余的可以根据情况自己定,然后通过
XBYTE [0x4000] = 57。这赋值语句,就可以把57写到外部RAM的0x4000处了,此地址对应一个字节。
一下摘自论坛网友的问答:
问:
在一般的读写外部RAM的程序中,经常看到这样的句子:
XBYTE[address]=data 写数据
data=XBYTE[address] 读数据
但是我想问的是,为什么用了XBYTE后,就不用顾及其时序了呢?
就是说,读写数据的时候,WR和RD怎么都不用用程序去控制了呢?
参考了很多读写外部RAM的程序,都找不到其控制WR和RD控制线的语句
哪位大侠能帮忙解释一下这是为什么嘛?
最好还能说说XBYTE具体的用法.....
答:
外部总线,
1外部总线由3组总线组成,数据 地址 控制,我们常常一般就叫他外部总线,既然是有3组不同的信号,那么他们是怎么协调工作的呢?一般情况CPU有特殊的外部数据访问指令如你这里讲51的MOVX指令(在C语言中他会编译成这个指令)在执行这个指令的时候3组线是协调工作
mov dptr,#1000h
mov a,#55h
movx @dptr,a
上面3调语句的C语言可以表示如下
#define W_DATA XBYTE[0x1000]
W_DATA=0X55;
在使用外部总线的时候,数据 地址和控制信号是直接按照规定的时序输出高低电平的,所以不用你管,当然你必须要满足时序工作
一下摘自网友博客文章:
如何理解#define XBYTE ((unsigned char volatile xdata *
8051 特有的内存型态
code 以 MOVC @A+DPTR 读取的程序内存
data 可以直接存取的内部数据存储器
idata 以 Mov @Rn 存取的内部数据存储器
bdata 可以位寻址(Bit Addressable)的内部存储器
xdata 以 MOVX @DPTR 存取的外部数据存储器
pdata 以 MOVX @Rn 存取的外部数据存储器
特殊资料型态
bit 一般位(bit)变量
sbit 绝对寻址的位(bit)变量
语法
sbit my_flag = location; (location 范围从 0x00 ~ 0x7F)
范例
sbit EA = 0xAF;
或是配合 bdata 宣告的位(bit)变量
char bdata my_flags;
sbit flag0 = my_flags ^ 0;
(注意 sbit 前不可以加 static)
sfr 特殊功能缓存器(Special Function Register)
语法
sfr my_sfr = location; (location 范围从 0x80 ~ 0xFF)
范例
sfr P0 = 0x80;
指定绝对地址的变量
在单一模块内可以使用下面的语法宣告
[memory_space] type variable_name _at_ location
范例
pdata char my_pdata _at_ 0x80;
如果该变量必须为多个模块所使用(Global Variable)则以
抽象指针(Abstract Pointer)的方式在标头档(Header File)定义较为方便。
#define variable_name *((data_type *) location)
范例
#define my_pdata *((char pdata *) 0x80)
(注意 char 与 pdata 的顺序)
ABSACC.H 提供了下列方便的宏(Macro)定义。
#define CBYTE ((unsigned char volatile code *) 0)
#define DBYTE ((unsigned char volatile data *) 0)
#define PBYTE ((unsigned char volatile pdata *) 0)
#define XBYTE ((unsigned char volatile xdata *) 0)
#define CWORD ((unsigned int volatile code *) 0)
#define DWORD ((unsigned int volatile data *) 0)
#define PWORD ((unsigned int volatile pdata *) 0)
#define XWORD ((unsigned int volatile xdata *) 0)
隐藏的初始化程序
80C51 在电源重置后(Power On Reset)所执行的第一个程序模块并不是使用者的主程序
main(),而是一个隐藏在 KEIL-C51 链接库中称为 startup.a51 的程序模块。
startup.a51 的主要工作是把包含 idata、xdata、pdata 在内的内存区块清除为 0,并
且初始化递归指针。接着 startup.a51 被执行的仍然是一个隐藏在 KEIL-C51 标准链接库
中称为 init.a51 的程序模块。而 init.a51 的主要工作则是初始化具有非零初始值设定的
变量。
在完成上述的初始化程序之后,80C51 的控制权才会交给 main() 开始执行使用者的程序。
#define XBYTE ((unsigned char volatile xdata *) 0)
定义 XBYTE 为 指向 xdata 地址空间unsigned char 数据类型的指针,指针值为0
这样,可以直接用XBYTE[0xnnnn]或*(XBYTE+0xnnnn)访问外部RAM了
XBYTE
XBYTE 宏允许访问51 外部数据区的单个字节可以如下使用
rval = XBYTE[0x0002];
XBYTE[0x002] = 57;
读或写外部数据存储区地址0002h 的字节内容
XWORD
XWORD 宏允许访问51 外部数据区的单个字可以如下使用
rval = XWORD[0x0002];
XWORD[0x002] = 57;
读或写外部数据存储区地址0004h 2×sizeof(unsigned int)=4 的字内容
1. 绝对宏:
在程序中,用“#include”即可使用其中定义的宏来访问绝对地址,包括CBYTE、XBYTE、PWORD、DBYTE、CWORD、XWORD、PBYTE、DWORD
具体使用可看一看absacc.h便知,例如:
rval=CBYTE[0x0002];指向程序存贮器的0002h地址
rval=XWORD[0x0002];指向外RAM的0002h地址
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。
查看文章
51单片机C语言编程中对单片机绝对地址访问的两种方法
2009-04-17 14:27
在进行8051单片机应用系统程序设计时,编程都往往少不了要直接操作系统的各个存储器地址空间。C51程序经过编译之后产生的目标代码具有浮动地址,其绝对地址必须经过BL51连接定位后才能确定。为了能够在C51程序中直接对任意指定的存储器地址进行操作,可以采用扩展关键字“at”、指针、预定义以及连接定位控制命令。
在这些方法中,本人认为最简单而有效的方法是用“ _at_ ”关键字来对指定变量存储器空间绝对地址来指定。一般格式如下:
[存储器类型] 数据类型 标识符 _at_ 地址常数
其中:
存储器类型 为idata、data、xdata等C51能够识别的所有类型,最好不要省略。
数据类型 可以用int、long、float等基本类型,当然也可以用数组、结构等复杂数据类型 , 本人认为一般用unsigned int 就可以解决很多问题了。
标识符 就是要定义的变量名,编程者自己决定
地址常数 就是要直接操作的存储器的绝对地址,必须位于有效的存储器空间之内。
注意:不能对变量进行初始化,只能是全局变量,一般不要轻易用,免得出错。
举例:
xdata unsigned int addr1 _at_ 0x8300;
另有一种方法就是要用到一个头文件absacc.h,也不是很难,举个例说明一下就会明白:
#include
XBYTE[0x8300]=0; /*向外部存储器(XDATA)地址0x8300写0
本人强烈建议用at,这样可能会更好些,还有一点就是不能乱用,因为有些存储器空间不能随便占用,C51编译器已经做其它的用了,而且有些空间单片机本身就做了很重要的作用,如果乱用,很容易出错.
类别:c语言 |
| 添加到搜藏 | 分享到i贴吧 | 浏览(64) | 评论 (0)
上一篇:C语言嵌入式系统编程修炼之软件... 下一篇:C程序的优化
相关文章:
•
51单片机输出PWM的两种方法
最近读者:
登录后,您就出现在这里。
转自网络)关于C51的XBYTE
工作 2009-07-14 17:38:05 阅读196 评论0 字号:大中小
XBYTE
The XBYTE macro accesses individual bytes in the external data memory of the 8051. You may use this macro in your programs as follows:
#include /* Include Macro Definitions */
.
.
.
rval = XBYTE [0x0002];
XBYTE [0x0002] = 57;
.
.
.This example reads and writes the contents of the byte in external data memory at address 0002h.
The range of valid index values for this macro is 0-65535.
http://www.keil.com/support/man/docs/c51/c51_xbyte.htm
上面的是在keil的help里ctrl+c来的,以前在论坛里看到过有人问如何用c语言实现定位存储,呵呵,当时还说不可能呢!现在在查找using的时候,无意中看到了XBYTE,点中看看,居然有大发现啊!
百度结果:这个主要是在用C51的P0,P2口做外部扩展时使用,其中XBYTE [0x0002],P2口对应于地址高位,P0口对应于地址低位。一般P2口用于控制信号,P0口作为数据通道。
如:P2.7接WR,P2.6接RD,P2.5接CS,那么就可以确定个外部RAM的一个地址,想往外部RAM的一个地址写一个字节时,地址可以定为XBYTE [0x4000],其中WR,CS为低,RD为高,那就是高位的4,当然其余的可以根据情况自己定,然后通过
XBYTE [0x4000] = 57。这赋值语句,就可以把57写到外部RAM的0x4000处了,此地址对应一个字节。
一下摘自论坛网友的问答:
问:
在一般的读写外部RAM的程序中,经常看到这样的句子:
XBYTE[address]=data 写数据
data=XBYTE[address] 读数据
但是我想问的是,为什么用了XBYTE后,就不用顾及其时序了呢?
就是说,读写数据的时候,WR和RD怎么都不用用程序去控制了呢?
参考了很多读写外部RAM的程序,都找不到其控制WR和RD控制线的语句
哪位大侠能帮忙解释一下这是为什么嘛?
最好还能说说XBYTE具体的用法.....
答:
外部总线,
1外部总线由3组总线组成,数据 地址 控制,我们常常一般就叫他外部总线,既然是有3组不同的信号,那么他们是怎么协调工作的呢?一般情况CPU有特殊的外部数据访问指令如你这里讲51的MOVX指令(在C语言中他会编译成这个指令)在执行这个指令的时候3组线是协调工作
mov dptr,#1000h
mov a,#55h
movx @dptr,a
上面3调语句的C语言可以表示如下
#define W_DATA XBYTE[0x1000]
W_DATA=0X55;
在使用外部总线的时候,数据 地址和控制信号是直接按照规定的时序输出高低电平的,所以不用你管,当然你必须要满足时序工作
一下摘自网友博客文章:
如何理解#define XBYTE ((unsigned char volatile xdata *
8051 特有的内存型态
code 以 MOVC @A+DPTR 读取的程序内存
data 可以直接存取的内部数据存储器
idata 以 Mov @Rn 存取的内部数据存储器
bdata 可以位寻址(Bit Addressable)的内部存储器
xdata 以 MOVX @DPTR 存取的外部数据存储器
pdata 以 MOVX @Rn 存取的外部数据存储器
特殊资料型态
bit 一般位(bit)变量
sbit 绝对寻址的位(bit)变量
语法
sbit my_flag = location; (location 范围从 0x00 ~ 0x7F)
范例
sbit EA = 0xAF;
或是配合 bdata 宣告的位(bit)变量
char bdata my_flags;
sbit flag0 = my_flags ^ 0;
(注意 sbit 前不可以加 static)
sfr 特殊功能缓存器(Special Function Register)
语法
sfr my_sfr = location; (location 范围从 0x80 ~ 0xFF)
范例
sfr P0 = 0x80;
指定绝对地址的变量
在单一模块内可以使用下面的语法宣告
[memory_space] type variable_name _at_ location
范例
pdata char my_pdata _at_ 0x80;
如果该变量必须为多个模块所使用(Global Variable)则以
抽象指针(Abstract Pointer)的方式在标头档(Header File)定义较为方便。
#define variable_name *((data_type *) location)
范例
#define my_pdata *((char pdata *) 0x80)
(注意 char 与 pdata 的顺序)
ABSACC.H 提供了下列方便的宏(Macro)定义。
#define CBYTE ((unsigned char volatile code *) 0)
#define DBYTE ((unsigned char volatile data *) 0)
#define PBYTE ((unsigned char volatile pdata *) 0)
#define XBYTE ((unsigned char volatile xdata *) 0)
#define CWORD ((unsigned int volatile code *) 0)
#define DWORD ((unsigned int volatile data *) 0)
#define PWORD ((unsigned int volatile pdata *) 0)
#define XWORD ((unsigned int volatile xdata *) 0)
隐藏的初始化程序
80C51 在电源重置后(Power On Reset)所执行的第一个程序模块并不是使用者的主程序
main(),而是一个隐藏在 KEIL-C51 标准链接库中称为 startup.a51 的程序模块。
startup.a51 的主要工作是把包含 idata、xdata、pdata 在内的内存区块清除为 0,并
且初始化递归指针。接着 startup.a51 被执行的仍然是一个隐藏在 KEIL-C51 标准链接库
中称为 init.a51 的程序模块。而 init.a51 的主要工作则是初始化具有非零初始值设定的
变量。
在完成上述的初始化程序之后,80C51 的控制权才会交给 main() 开始执行使用者的程序。
#define XBYTE ((unsigned char volatile xdata *) 0)
定义 XBYTE 为 指向 xdata 地址空间unsigned char 数据类型的指针,指针值为0
这样,可以直接用XBYTE[0xnnnn]或*(XBYTE+0xnnnn)访问外部RAM了
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xb_crazyman/archive/2008/10/15/3081731.aspx
知道的:
问:
请大家看下面这段程序# define ADCOM XBYTE[ 0xff7c ] /* 使A0=0 ,R/C=0, CS=0 */# define ADLO XBYTE [ 0xff7f ] /* 使 R/C =1,A0=1, CS=0 */# define ADHI XBYTE [ 0xff7d ] /* 使R/C=1,A0=0,CS =0 */本人一直理解是ADCOM是一个指针,指针指向的地址为0xff7c,完事可以通过对ADCOM的操作来更改地址0xff7c内变量的值,但是为何同时在宏定义后,相应的注释里会是同时初始化某值的作用呢?
问题补充:
那在问下像0xff7c这些地址,是应该怎样和外部电路相配合呢?是说地址可以随便写么?
答:XBYTE定义的是外部地址,这样才能和接到你的IO口上的器件通信
关于你的不充问题:
你把0xff7c展开成二进制形式就全明白了,0xff7c的二进制是:1111,1111,0111,1100
再结合后面的注释可知外部电路管脚的对应关系为:
CS——P1.7
A0——P1.1
R/C——P1.0
用XBYTE定义的目的是将外部电路不同的功能编程不同的地址而已
这样就可以在程序里面通过直接对地址附置,就能使外部电路实现需要的功能,这样做还有一个好处就是在编译的时候会产生 MOVX 指令,这样可以操作WR和RD引脚,以实现特定的功能
至于用XBYTE定义的地址是多少就得根据实际的外围电路的连接来确定,不是随便写的
如何理解XBYTE(转载)
(2009-11-05 17:04:46)
转载
标签:
单片机
it
8051 特有的内存型态
code 以 MOVC @A+DPTR 读取的程序内存
data 可以直接存取的内部数据存储器
idata 以 Mov @Rn 存取的内部数据存储器
bdata 可以位寻址(Bit Addressable)的内部存储器
xdata 以 MOVX @DPTR 存取的外部数据存储器
pdata 以 MOVX @Rn 存取的外部数据存储器
特殊资料型态
bit 一般位(bit)变量
sbit 绝对寻址的位(bit)变量
语法
sbit my_flag = location; (location 范围从 0x00 ~ 0x7F)
范例
sbit EA = 0xAF;
或是配合 bdata 宣告的位(bit)变量
char bdata my_flags;
sbit flag0 = my_flags ^ 0;
(注意 sbit 前不可以加 static)
sfr 特殊功能缓存器(Special Function Register)
语法
sfr my_sfr = location; (location 范围从 0x80 ~ 0xFF)
范例
sfr P0 = 0x80;
指定绝对地址的变量
在单一模块内可以使用下面的语法宣告
[memory_space] type variable_name _at_ location
范例
pdata char my_pdata _at_ 0x80;
如果该变量必须为多个模块所使用(Global Variable)则以
抽象指针(Abstract Pointer)的方式在标头档(Header File)定义较为方便。
#define variable_name *((data_type *) location)
范例
#define my_pdata *((char pdata *) 0x80)
(注意 char 与 pdata 的顺序)
ABSACC.H 提供了下列方便的宏(Macro)定义。
#define CBYTE ((unsigned char volatile code *) 0)
#define DBYTE ((unsigned char volatile data *) 0)
#define PBYTE ((unsigned char volatile pdata *) 0)
#define XBYTE ((unsigned char volatile xdata *) 0)
#define CWORD ((unsigned int volatile code *) 0)
#define DWORD ((unsigned int volatile data *) 0)
#define PWORD ((unsigned int volatile pdata *) 0)
#define XWORD ((unsigned int volatile xdata *) 0)
隐藏的初始化程序
80C51 在电源重置后(Power On Reset)所执行的第一个程序模块并不是使用者的主程序
main(),而是一个隐藏在 KEIL-C51 标准链接库中称为 startup.a51 的程序模块。
startup.a51 的主要工作是把包含 idata、xdata、pdata 在内的内存区块清除为 0,并
且初始化递归指针。接着 startup.a51 被执行的仍然是一个隐藏在 KEIL-C51 标准链接库
中称为 init.a51 的程序模块。而 init.a51 的主要工作则是初始化具有非零初始值设定的
变量。
今天在51的头文件中碰到了如下语句:
#define Page XBYTE[0X7000]
查相关资料:
answer:
xbyte[地址]=数据;
对XBYTE的解释:
The XBYTE macro accesses individual bytes in the external data memory of the 8051. You may use this macro in your programs as follows:
#include /* Include Macro Definitions */
.
.
.
rval = XBYTE [0x0002];
XBYTE [0x0002] = 57;
.
.
.
This example reads and writes the contents of the byte in external data memory
at address 0002h.
The range of valid index values for this macro is 0-65535.
其中利用宏定义文件absacc.h可以方便的对任何内存空间进行操作。
原来是对外部RAM的操作,XBYTE[0x7000]相当于一个地址而已
#define Page XBYTE[0X7000] 就是相当于定义外部寄存器Page,搞定!!!
C语言之一
软件学习 2009-05-19 22:39:48 阅读8 评论0 字号:大中小
1、带参数与不带参数的宏定义
带参数: #define NIL 0x80
不带参数:#define SQ(a,b) a*b
2、文件包含 #include
/*在C中用双引用形式更保险,在C51中常用物是尖括弧形式*/
3、条件编译:#if #elif #else #endif #ifdef #ifndef
/*一般源程序中的所有程序行都参加编译,但有时希望对其中一部分内容在满足一定条件下才进行编译;选择不同的编译范围,产生不同的代码,提供通用性*/
4、#error:捕捉不可预料的编译条件
#if (myv!=0&&myv!=1)/*假定其值必为0或1*/
#error myv must be 1 or 0/*出错时显示*/
#endif
5、#pragma:用于在程序中向编译器传送各种编译控制命令
#pragma 编译命令序列
/*例:想按如下命令编译ex.c c51 ex.c debug cod large可用:*/
#pragma DB CD LA
#pragma disable
6、数据类型及长度:
char int long
1:unsinged 0~255 0~65535 0~4294967295
2:signed -128~127 -32768~32767 -2147483648~2147483647
指针:*
3字节位标量: sbit
7、特殊功能寄存器:sfr
16位特殊功能寄存器:sfr16 占2个内存单元,0~65535
可寻址位:sbit利用他可访问51单片机的内部RAM中的可寻址位或特殊功能寄存器中的可寻址位
sfr P0=0x80; /*将P0口的口地址定义为80H*/
sbit P0_1=P1^1; /*将P0.1位定义为P1_1*/
8、数据存储类型
表1. C51数据存贮类型
━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━
数据存贮类型 ┃ 与存贮空间的对应关系
━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━
data ┃ 直接寻址片内数据存贮区,访速度快
bdata ┃ 可位寻址片内数据存贮区,允许位与字节混合访问
idata ┃ 间接寻址片内数据存贮区,可访问片内全部RAM地址空间
pdata ┃ 分页寻址片外数据存贮区(256字节)由MOVX @R0访问
xdata ┃ 片外数据存贮区(64K),由MOVX @DPTR访问
code ┃ 代码存贮区(64K),由MOVC @DPTR访问
━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━
9、变量的存储类型定义
char data var
/*字符变量var被定义为data存贮类型,C51编译器将把该变量定位在51单片机片内数据区存贮区中*/
bit bdata flag
/*位变量flag被定义为bdata存贮类型,C51编译器将把该变量定位在51单片机片内数据区存贮区(RAM)中的位寻址区:20H--2FH*/
10、typedef:重新定义数据类型 typedef 已有数据类型 新的数据类型
typedef int word; /*将word定义为整型*/
word i,j; /*将i,j定义为整型*/
11、数组作为函数的参数
例:用数组作为函数的参数,计算两个不同长度的数组中所有元素的平均值
float average(array,n)
{
int N;
float array[ ];
int I;
float aver,sum=array[0];
for(I=1;I要求精度达到5%%,大于这个值将认为无效。主要来自于随机干扰,下面就各种干扰的方法给出简单的去除方法:
1、白噪声:最重要的统计特性为平均值为0,可采取每路数据采集几次求平均的方法;
2、随机干扰:该点明显高于或低于附近正常采样值,故采取中值滤波法,即对被测信号连续采样M次,进行大小排序,取大小居中的1/3个采样值进行算术平均;
3、电源干扰:特点是有固定周期,故可采用定时采样求平均的方法。
13、 指针:可对内存地址直接操作
基于存贮器的指针以存贮器类为参量,它在编译时才被确定。因此为指针选择存贮器的方法可以省掉,这些指针的长度可为1个字节(idata *,data *,pdata *)或2个这节(code *,xdata *)。
char xdata *address; ADC0809具有8个模拟量输入通道,采用中断方式,在中断函数中读取8个通道的A/D转换值,分别存储在外部RAM的1000H~1007H单元。ADC0809端口地址为00F0H。 程序定义了两个指针变量* ADC和* ADCdata,分别指向ADC0809端口地址(00F0H)和外部RAM单元地址(1000H~1007H)
由*ADC=I送入通道数,启动ADC0809进行A/D转换,转换结束时产生INT1中断。在中断服务函数int1()中通过temp=*ADC和*ADCdata=temp;读取A/D转换结果并存到外部RAM中。
#include
unsigned int xdata *ADC; /*定义ADC0809端口指针*/
unsigned int xdata *ADCdata; /*定义ADC0809数据缓冲器指针*/
unsigned char I;
void main( )
{
ADC=0x00f0; /*定义端口地址和数据缓冲器地址*/
ADCdata=0x1000;
I=8; /* ADC0809有8个模拟输入通道*/
EA=1; EX1=1;IT1=1; /*开中断*/
*ADC=I; /*启动ADC0809*/
WHILE(I); /*等待8个通道A/D转换完*/
}
void int1() interrupt 2
{
unsigned char tmp;
temp=*ADC; /*读取A/D转换结果*/
*ADCdata=temp; /*结果值存到数据缓冲区*/
ADCdata++; /*数据缓冲区地址加1*/
i—;
*ADC=I; /*启动下一个模拟输入通道A/D转换*/
}
除了用指针变量来实现对内存地址的直接操作外,c51编译器还提供一组宏,该宏定义文件为:“absacc.h”,利用它可十分方便地实现对任何内存空间的直接操作,改写上面的程序:
#include
#include /*包含绝对地址操作预定义头文件*/
#define ADC 0x00f0; /*定义ADC0809端口地址*/
#define ADCdata 0X1000 /*定义数据缓冲器地址*/
unsigned char I;
void main( )
{
I=8; / *ADC0809有8个模拟输入通道*/
EA=1;ex1=1;it1=1; / *开中断*/
XBYTE[ADC]=I; /*启动0809 */
While(i); /*等待8个通道转换完毕*/
}
void int1() interrupt2
{
unsigned char tmp;
tmp=XBYTE[ADC]; /*读取A/D转换结果*/
i--;
XBYTE[ADCdata+I]=tmp; /**结果值存储到数据缓冲器*/
XBYTE[ADC]=I; /*启动下一个模拟输入通道A/D转换*/
}
两指针相减-----计算字符串的长度
#include
main()
{
char *s=”abcdef”;
int strlen(char *s);
printf(“\n length of ‘%%s’=%%d\n”,s,strlen(s));
}
int strlen(char *s)
{
char *p=s;
while(*p!=’\0’)p++;
return(p-s);
}
结果为:length of ‘abcdef’=6注:不允许指针之间进行加,乘,除,移位,或屏蔽运算,也不允许用float类型数据与指针做加,减运算!抽象型指针:
ANSI新标准增加了一种“void * ”的指针类型,这是一种抽象型指针,即可以定义一个指针变量,但不指定该指针是指向哪种类型的数据的。在赋值时需进行强制类型转换:
Char *p1;
Void *p2;
P1=(char*)p2;
传统51MCU--AT89C51扩展ROM,RAM实验
默认分类 2009-08-07 13:10:01 阅读89 评论0 字号:大中小
51MCU内部有RAM,ROM,不同于8031。尽管如今的增强行51MCU的内部RAM,ROM可能已经很大的空间。但就技术而言,扩展RAM,ROM还是需要学会的。
对于不同的设计方案需求,扩展可能基于以下任何一种设计:
A,只扩展RAM
B,只扩展ROM
C,扩展ROM,RAM
****************************总线扩展时,P2口是否可用做普通IO口************************************
这种扩展是基于总线扩展的,所以,P0P2口就已经不可以再做它用了(有网友提供信息,总线扩展P2还可以做普通IO口用,有两种可能:1,P2口复用,如同P1利用373锁存器。2,在总线扩展时,只用到了低地址总线,P2口未用到。就作为普通IO口应用。由于技术还不到位,不做评论。)
*******************************************扩展RAM****程序************************************************
扩展RAM,在程序中定义的xdata类型 XBYTE类型等地址范围在外部RAM的变量,对其读写的过程。用C51语言编写程序,且使用总线扩展的RAM,则时序电路不用考虑,WR RD等信号由编译器/硬件自动完成。
**************************************编译器设置*****************************************
内部RAM:0x00~~0xFF
外部RAM:0x0000~~0xFFFF
RAM的地址虽重复,但是两个RAM是没有关系的,所以不会造成干扰
使用了外部RAM,就在工程选项---off-chip xdata memory中设置 start:0x0000 size:0xFFFF(根据具体的RAM大小设置size)。
*******************************扩展RAM时的变量定位及连续读取问题*********************************
ROM,RAM的扩展时,需要用到变量的绝对地址定位,函数定位等。
变量的绝对地址定位,是由于在程序中可能需要即时读取某个变量,但变量的类型可能是XDATA,存储在外部RAM中。这里有两个方法:
1,用 _at_ 定位 关键字定位
unsigned char xdata xxx _at_ 0x1100 //定义变量XXX数据类型xdata,位置0x1100
[memory_space]tepe variable_name _at_ constant;
***绝对地址的变量不可以被初始化;函数或BIT类型的变量是不可以被定义为绝对地址;
2,用 XBYTE 定位 宏定义 绝对地址访问
#define CBYTE((unsigned char volatile code*)0)
#define DBYTE((unsigned char volatile idata*)0)
#define PBYTE((unsigned char volatile pdata*)0)
#define XBYTE((unsigned char volatile xdata*)0)
////////////////////////////////////////////////////////////////////////////
#define CWORD((unsigned int volatile code*)0)
#define DWORD((unsigned int volatile idata*)0)
#define PWORD((unsigned int volatile pdata*)0)
#define XWORD((unsigned int volatile xdata*)0)
以上是宏定义的原型函数,定义在 #include
头文件中
#defme xxx XBYTE[0x8000] //变量类型为unsigned char 类型的数据xxx,位置xdata 0x8000
yyy=XBYTE[0x8000]; //变量类型为unsigned char 类型的数据yyy,位置xdata 0x8000
(在这里,有网友提到,当编译器优化时,用绝对地址定位的变量,可能导致变量在连续读取时出
错,采用解决方法:
a,将编译器优化调整为0,即不优化,程序不用修改,做以下操作
>>选择project窗口的Target,然后打开"OptionsforTarget” 设置对话框,选择“C5l”选项卡,
将“Code Optimiztaion”中的“Level”选择为“0:Costant folding”。再次编译<<
b,修改变量定义,增加“volatile”关键字说明其特征:就是说明该变量具有‘挥发’性,每次的读取都一
有意义的,这样编译器即使在优化时,编译后的代码也不会省略掉重复读取的过程。如:
unsigned char volatile xdata xxx_at_0x8000;
由上文XBYTE等的宏定义函数原型可以看出,该宏定义已经说明了变量具有volatile特性,因此,
也可以直接用XBYTE定义所需要的变量
c,硬件解决办法
以上解决方法为参考网络文章)
*************扩展ROM时的函数定位**************函数一部分在内部ROM,一部分在外部ROM中****************
函数定位,个人理解:当一个完整功能的程序存储在外部内部ROM中时,即利用了内部ROM,可能由于内部ROM空间不够,部分函数在外部中,这时,如果要执行整个功能,就需要告诉编译器,其他功能函数的地址(函数在外部ROM中的地址),此时就要用到函数定位功能。解决方法如下:
....待续.....
51内部ROM地址范围0x0000~0x0FFF,所以外部ROM的地址为0x1000~~最大0xFFFF。
c51bbs有详细介绍
编写完整的程序(如果建立两个工程,堆栈等可能分配位置不同,导致地址重复或多个地址出错),
编译后查看.M51文件,找到需要定位的函数名称信息(如?PR?_BCD2HEX?TOOLS),在KEIL51工程选项---BL51 lacate中code项中加入:?PR?_BCD2HEX?TOOLS(0x1000)再次编译工程,打开.M51文件会发现?PR?_BCD2HEX?TOOLS已经定位在了0x1000位置了。
如果