89c51单片机机P4SW和P4M0分别是指什么

C51单片机被定义的值怎么会变了的呢a=0 P1=a为什么不等于P1=0xfe,这两个完全相反呢?#include //包含51单片机寄存器定义的头文件sbit a=0void main(){while(1){P1=a; //这个值怎么会等于()?P1=0//这个值怎么会等于()?}}
kjfnn002A6
因为P1=a,且a是一个位变量,位变量非0即1P1=0Xfe,就是,没错啊
因为P1=a,且a是一个位变量,位变量非0即1
我还是弄不懂怎么位变量是非0即1呢,是不是成了一个反相器吖?
编译器就是这么规定的
为您推荐:
其他类似问题
sbit只能定义一个位,是用来进行位操作的。所以 sbit a =0 a=0xP1的缺省值是0, 所以 P1=a; P1=0x
1楼正确。a是位变量,初始值为1(只要不为0都是1,所以FE也是1)初始值为1,0xfe二进制不就是
是不是按最后那个0为准,如是最后一位的话那不是只输出一个0?前面7位就不算了,但按
void main()
//这个值应等于()才对吧...
不是呀,在给位变量a赋值时,只要是不等于0的数就认为是1,所以你给它的FEH就当成1了,这个1再给一个字符变量P1时,1就是01H.
哦,也就是说不管你给位赋的值是十六进制也好,不是也好,大于0的它就是当成1了,那其它位呢都是0了,其它位是不是所有单片机都认0了的呢
一个位变量哪有其它位呀,只有1或者0两个值,没有其它位。
原是()P1=a 那值就是(),前面7个0是怎来的呢?
你怎么还没明白呢。一开始是1
然后赋值给P1时也是1,但由于P1这个寄存器(也是I/O口)是8位的,前面当然自动填上0了,也就是说就是1
一楼是对的。C51是这么规定的
扫描下载二维码89C51单片机内部结构深度解析三
10:52:34&&&来源:eefocus &&
深度解析三:单片机RAM地址空间
单片机的工作寄存器:00H~1FH
单片机在工作时需要处理大量的数据,这些数据有些要用来运算,有些要反复调用,有些用来比较检验,这时单片机就需要有这些位置暂时存放这些数据,以方便后面数据的处理,而单片机提供暂存数据的地方就是工作寄存器。工作寄存器有4组,每组都是8个工作寄存器R0~R7,通过PSW中的RS1、RS0两位来选择使用哪一组,如果不选,默认是选择第0组。
RS1RS0组合为00时,选中第0组工作寄存器,R0~R7地址为00H~07H;
RS1RS0组合为01时,选中第1组工作寄存器,R0~R7地址为08H~0FH;
RS1RS0组合为10时,选中第2组工作寄存器,R0~R7地址为10H~17H;
RS1RS0组合为11时,选中第3组工作寄存器,R0~R7地址为18H~1FH。
真正的RAM:20H~7FH
SFR:special function register,特殊功能寄存器的总称,是单片计算机中的一组特殊的临时存储区域,用于动态存放计算机运行过程的一些状态信息、并依此做相应的控制,总共21个。
高位(MSB)&&&&&&&&&&&&&&&&&&&&&位定义&&&&&&&&&&&&&&&&&&&&&&低位(LSB)
B(通用寄存器B,初值:)
ACC(累加器,初值:)
PSW(程序状态寄存器,初值:)
*IAP_CONTR
*IAP_ADDRL
*IAP_ADDRH
*WDT_CONTR
*ADC_CONTR
IP(中断优先级寄存器,初值:)
P3(I/O接口第3组,初值:1x11 1111)
IE(中断控制寄存器,初值:)
*BUS_SPEED
P2(I/O接口第2组,初值:)
SBUF(UART串口数据寄存器,初值:xxxx xxxx)
SCON(UART串口控制寄存器,初值:)
P1(I/O接口第1组,初值:)
*WAKE_CLK0
TH1(T1定时/计数器16位寄存器高8位,初值:)
TH0(T0定时/计数器16位寄存器高8位,初值:)
TL1(T1定时/计数器16位寄存器低8位,初值:)
TL0(T0定时/计数器16位寄存器低8位,初值:)
TMOD(定时/计数器方式控制寄存器,初值:)
TCON(定时/计数器控制寄存器,初值:)
PCON(控制寄存器,初值:)
DPH(通用16位指针高8位,初值:)
DPL(通用16位指针低8位,初值:)
SP(堆栈指针,初值:)
P0(I/O接口第0组,初值:xxxx 1111)
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。
89C51相关资源
单片机相关资源
内部结构相关资源
编辑:什么鱼
本文引用地址:
本周热门资源推荐
EEWORLD独家关于C51单片机单片机的几个问题_百度知道
关于C51单片机单片机的几个问题
#33H 是把33H当成无符号数吧,则TH0、”MCS 51的程序计数器PC不能被用户使用、0CH,只不过程序不会回到断点处罢了,首先、MOV A1、”80C51单片机子程序调用时能自动保护断点和现场“、在方式0定时器T0的初值为1E0CH,因为他没有地址“、0CH啊、向前转移的偏移量为什么等于(目的地址+0100H)-(原地址+3),@DPTR 这个语句错了是因为DPTR只能用于片外寻址么5、徐汉斌版单片机微型计算机原理教材P144上说“中断服务程序最后一条指令必须是中断返回指令RETI“?6,PC也会填充跳转处PC地址2?如果最后一句话是跳转指令不是也可以么,这句话是不是错了,它没有地址那他到底在哪,这句话错了是不是因为只能自动保护断点不能自动保护现场,不能被用户使用指的收拾什么?其次,TL0的初值分别为()这题答案给的居然是F0H,0100H是什么、MOV 20H?那么如果我想移入一个带符号数呢7?4,是不是答案错了3,我觉得分明是1EH
提问者采纳
另外一个参数不能使用直接寻址方式中断程序会自动保护,个性化程序需要巧妙使用。你用其他方式结束当然程序也能继续执行,多次中断执行下来会把堆栈挤满,若是你要把它作为有符号数处理,减法也是用加法器完成的,子程序不会自动保护,溢出,编译器(比如KeilC)会自动处理你的各种数据类型单片机里只有加法器书上说的是正常完善的中断程序最后需要reti结束,往往就是不注意这些细节造成的,你需要在程序中自行转换和识别数值,但是如果他的初值的意思是设定的定时时间的话,会发生不可预料的执行结果,堆栈数据不会释放,若需要必须在子程序中自行安排指令进行51单片机只有无符号数,如果没有reti指令,被减数-减数=被减数+减数的补码。但是我不建议您这样使用。当然如果你使用C语言编写程序,向堆栈中存入一些数据。有的人不知道自己的程序为什么会莫名跑飞。首先中断程序响应前会保护现场,TL0=0CH,TH0=E1H,TL0=F4HPC不能直接读取或改变其数值使用指针时,才能避免灾难性故障TH0=1EH
提问者评价
大神真吊啊。。。几句话解决问题,敢问你是做什么的?感觉就是我们老师都不一定这么厉害的样子
其他类似问题
使用方法如下,位0 为正数这就是有符号数,最高位为1位负数?2。6,只能保护断点地址。3,也就是讲地址压栈,一般而言,一般都是做无符号数处理、应该是TH0=1EH,一般而言是程序执行过程中靠硬件自动改变值大小的,答案有错,你执行完后跳转回去就不会有出栈操作,@A+PC4,没有特别说明和设定1、是的,不能保护现场比如PSW状态等,而且只能传送到累加器A,DPTR只能通过MOVC或MOVX来访问,要不来多少次就会使SP爆满的,@DPTR是没有这个指令的、MOV 20H。何况你知道什么时候进入中断的吗,如果是跳转那么就会出现SP堆栈混乱、我感觉你的0100H应该是当前转移指令的地址,有无符号是靠你自己的决定的,只是不能赋值而已、PC是可以使用的,当然它确实没有物理地址,进入中断时有一个保护现场的操作,TL0=0CH、可以呀。7:MOVC A、这句话是对的。5,也即是SJMP的地址
来自团队:
为您推荐:
其他1条回答
1、徐汉斌版单片机微型计算机原理教材P144上说“中断服务程序最后一条指令必须是中断返回指令RETI”,
这句话是不是错了?
如果最后一句话是跳转指令不是也可以么,只不过程序不会回到断点处罢了,PC也会填充跳转处PC地址
--写跳转指令、或者写其它什么指令,都行,随你便。单片机都会执行。
--只是,单片机没有执行 RETI 指令,中断程序就没有结束。
--如果,你不写 RETI,中断后,单片机就永远处于中断程序之内。
2、在方式0定时器T0的初值为1E0CH,则TH0,TL0的初值分别为()
这题答案给的居然是F0H、0CH,我觉得分明是1EH、0CH啊,是不是答案错了
--写成二进制:1E0CH = 00 1100B
--取其低 13 位,写成高八位、低五位:100
--方式0的初值,就应该是...
果真大神啊。。。先感谢还想问一下,2中低五位少的前三位是直接补0么6中,首先,如果我想表示负的01H,那么最高位运算时是自动改成1么其次,我想表示正数是是应该加+吗?
--取其低 13 位,写成高八位、低五位:、XXX01100--方式0的初值,就应该是:F0、0C。2中低五位少的前三位是直接补0么--这前三位,写什么都不起作用,单片机并不接受这三位。6中,首先,如果我想表示负的01H,那么最高位运算时是自动改成1么,其次,我想表示正数是是应该加+吗?负一,你就直接写-1,即可。在编译时,负数就变成了补码。于是,-1就成了255。正数,符号就可以省略。~~~~~~~~~~~~~~~~~~~~~~~以上是在
22:06 做出的回答。后来发现,提问者采纳了错误的答案,就此又补充了一些。下面,对错误的答案,逐条的加以分析:1. 如果没有reti指令,...多次中断...把堆栈挤满溢出...--如果没有reti指令,本次中断就没有结束,也就不会有多次中断。--即使再发生了高优先级的中断,最多会也只会发生两次中断,谈何溢出?--中断嵌套,最多只有两层。--认为可以出现多次中断,这是基本概念不清。2....TH0=E1H,TL0=F4H--错误。--正确数值可见题目给出的数值,推导过程可见做而论道的回答。3. PC不能直接读取或改变其数值--错误。--去看看JMP指令的功能,就知道能不能改变 PC 了。4.使用指针时,另外一个参数不能使用直接寻址方式--基本概念不清。汇编语言里面,没有指针的说法。--另外一个参数,可以使用直接寻址方式,如下:--MOV B,@R0 这里的B,是不是直接寻址?5.中断程序会自动保护...--错误。--保护断点,这是主程序干的。--中断程序不会自动保护任何东西。6. 51单片机只有无符号数,...--错误。--可以使用补码,即带符号数。--也可以直接写上符号:-、+。7.表达不清。为什么向前转移的偏移量等于...,并没有答出来。============================================提问者采纳了满篇错误的回答,还不忘贬低自己的老师,不仅是水平太低,人品,更差。呵呵
单片机的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁查看: 803|回复: 1
单片机C语言指针意义浅析—Keil-C51
本帖最后由 piaolin 于
14:02 编辑
通常认为,C语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上,甚至认为指针是C语言的灵魂。这里说通常,是广义上的,因为随着编程语言的发展,指针也饱受争议,并不是所有人都承认指针的“强大”和“优点”。在单片机领域,指针同样有着应用,本章节针对Keil C-51环境下的指针意义做简要分析。
1& &&&指针与变量
指针是一个变量,它与其他变量一样,都是RAM中的一个区域,且都可以被赋值,如程序①所示。
#include &REG52.H&& && &&&
unsigned char *p;
void main()
& && && &while(1)
& && && &{
& && && && && && & j=0
& && && && && && & p=0
& && && &}
在Debug Session模式下,将鼠标指针移到到变量“j”“p”位置,可以显示变量的物理地址,如图1-1、1-2所示。
图中箭头所指处即为变量在RAM中的“首地址”,为什么是“首地址”呢?变量根据类型可分为8位(单字节)、16位(双字节),程序中变量“j”是无符号整型,所占物理空间应为2字节,而在8位单片机中,RAM的一个存储单元大小是8位,即1字节,因此需2个存储单元才满足变量“j”长度。所以实际上变量“j”的物理地址为“08H”“09H”。同理,“p(D:0x0A)”即变量“p”的首地址为“0AH”。
下面通过单步执行程序来观察RAM内的数据变化,打开两个Memory Windows窗口,在Keil软件下方显示为Memory1和Memory2,在两个窗口中,分别做如图2-1、2-2所示的设置。
两个Address填写的内容分别是:D:0x08、D:0x0A,即变量“j”和变量“p”的首地址,输入后回车,便可监视RAM中该地址下的数据。设置好后,准备调试。
在Debug Session模式中,箭头所指处即为即将执行的语句,单击“Step”功能按钮(或按F11键),让程序运行,如图3所示。
第一次单击“Step”按钮后,Memory1窗口内数据如图4所示。
由调试结果可知,08H数据由00H变为ABH,09H数据由00H变为CDH,出现这种变化是因为执行了语句j=008H为变量“j”高八位,存储“AB”,09H为变量“j”低八位,存储“CD”。
第二次单击“Step”按钮,执行语句:p=0此时需观察Memory2窗口内数据,如图5所示。
由调试结果可知,0CH处值由00变为“AAH”,程序相吻合。这里需要注意,在Keil C-51编译环境下,指针变量,不管长度是单字节或是双字节,指针变量所占字节数为3字节。故此处“AAH”不是存储在0AH而存储在0CH(0A+2)地址中。
综上所述,指针实际上是变量,都是映射到RAM中的一段存储空间,区别是,指针占用3字节,而其他变量可根据需要设定其所占RAM是1字节(char)、2字节(int)、4字节(long)。
2& && & 指针作用
指针的作用是什么呢?先来看下面的程序:
#include &REG52.H&& && && &
unsigned chartab1[8]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
unsigned char codetab2[8]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};
unsigned char N1,N2;
void main()
& && && && &N1=tab1[0];
& && && && &N2=tab2[0];
显然,程序执行的结果是N1=0x01,N2=0x10。这里都是讲数组内的数据赋值给变量,但存在区别,tab1数组使用的是单片机RAM空间,而tab2数组使用的是单片机程序存储区(ROM)空间。尽管使用C语言为变量赋值时语句相同,但编译结果并不相同,此程序编译后的结果如图6所示。
由编译结果可知,N1=tab1[0]语句实际上是直接寻址,而N2=tab2[0]是寄存器变址寻址。不管是何种寻址方式,都是将一个物理地址内的数据取出来使用:tab1数组中,tab[0]对应的RAM地址是0x0A,tab[1]对应的RAM地址是0x0B……以此类推;tab2数组中,tab[0]对应的ROM地址是0x00A5,tab[1]对应的ROM地址是0x00A6……以此类推。不管这些数组或变量所在的RAM或ROM地址如何,用户最终需要的是数组或变量的数据,而指针,就是通过变量或数组的物理地址访问数据,也就是说,通过指针,同样可以访问数组或变量数据。现将程序②做出调整,得到程序③如下:
#include &REG52.H&& && && &
unsigned chartab1[8]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
unsigned char code tab2[8]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};
unsigned char N1,N2;
unsigned char&&*p;
void main()
& && && &p=tab1;
& && && &for(i=0;i&8;i++,p++)
& && && &N1=*p;
& && && &p=tab2;
& && && &for(i=0;i&8;i++,p++)
& && && &N2=*p;
程序执行结果:tab1数组内的8个数值依次被赋值给N1;tab2数组内的8个数值依次被赋值给N2;
程序③执行Debug Session功能后,打Watch Windows窗口,在Watch1窗口下添加需要监视的变量,此处为“p”和“N1”,如图7所示。
Value为当前变量数值,程序为运行前,p值为0x00,单击Step按键功能后,执行p=tab1;p值变为0x0A,如图8所示。
0x0A是什么值呢?将鼠标移至tab1数组位置,可显示出数组所在的物理地址,0x0A就是数组tab1的首地址,如图9所示。
p=tab1就是将tab1数组的首地址赋值给变量p,执行p++即地址值加1;*p则是此物理地址内的具体数据,因此for循环中,N1=*p是依次将tab1数组中的数据赋值给变量N1。由此可见,指针是作为一个变量,指向某一个地址。
那么指针到底是如何将某个地址内的数据“拿”出来的?下面通过N1=*p语句做演示说明,N1=*p编译后的汇编代码如图10所示。
C:0x00A0至C:0x00A9的汇编代码即是C程序中的N1=*p。程序先将变量p的值赋值给R3、R2、R1三个通用寄存器,程序为:
MOV& &R3,p(0x12)
MOV& &R2,0x13
MOV& &R1,0x14
然后调用了一个子函数:LCALL&&C?CLDPTR(C:00E4),而C程序中,未定义或使用任何子函数,那么这个子函数是哪里来的?作用是什么?根据标号C:00E4可找到该子函数,程序代码如下:
C:0x00E4& &BB0106& &CJNE& &&&R3,#0x01,C:00ED
C:0x00E7& &8982& &&&MOV& && &DPL(0x82),R1
C:0x00E9& &8A83& &&&MOV& && &DPH(0x83),R2
C:0x00EB& &E0& && & MOVX& &&&A,@DPTR
C:0x00EC& &22& && & RET& && &
C:0x00ED& &5002& &&&JNC& && &C:00F1
C:0x00EF& &E7& && & MOV& && &A,@R1
C:0x00F0& &22& && & RET& && &
C:0x00F1& &BBFE02& &CJNE& &&&R3,#0xFE,C:00F6
C:0x00F4& &E3& && & MOVX& &&&A,@R1
C:0x00F5& &22& && & RET& && &
C:0x00F6& & 8982& & MOV& && &DPL(0x82),R1
C:0x00F8& &8A83& &&&MOV& && &DPH(0x83),R2
C:0x00FA& &E4& && & CLR& && &A
C:0x00FB& &93& && & MOVC& &&&A,@A+DPTR
C:0x00FC& &22& && & RET& && &
此程序功能是:先用R3寄存器的值与0x01比较,当R3的值大于0x01时,再和0xFE做比较,比较的结果有如下情况:
(1)R3的值等于0x01时,执行如下程序:
C:0x00E7& &8982& &&&MOV& && &DPL(0x82),R1
C:0x00E9& &8A83& &&&MOV& && &DPH(0x83),R2
C:0x00EB& &E0& && & MOVX& &&&A,@DPTR
C:0x00EC& &22& && & RET& && &
程序功能:读取扩展RAM内的数据并赋值给A,寻址范围0~65535。当数组用xdata定义时,会跳转到此处。
(2)R3的值小于0x01即等于0x00时,执行如下程序:
C:0x00EF& &E7& && & MOV& && &A,@R1
C:0x00F0& &22& && & RET&&
程序功能:读取单片机内部256字节RAM内的数据并赋值给A,寻址范围0~255。当数组用data或idata定义时,会跳转到此处。如执行N1=*p语句时,即跳转到自处,读取内部RAM地址内的数据。& &
(3)R3的值不等于0x00或0x01时,通过JNC指令跳转到C:0x00F1处,开始与0xFE做比较。R3的值等于0xFE时,执行如下程序:
C:0x00F4& &E3& && & MOVX& &&&A,@R1
C:0x00F5& &22& && & RET&&
程序功能:读取单片机片外RAM内的数据并赋值给A,寻址范围0~255。当数组用pdata定义时,会跳转到此处。通常8051单片机不使用pdata定义变量或数组。
(4)R3的值不等于0xFE时,即R3的值等于0xFF时,跳转到C:0x00F6处执行如下程序:
C:0x00F6& &8982& &&&MOV& && &DPL(0x82),R1
C:0x00F8& &8A83& &&&MOV& && &DPH(0x83),R2
C:0x00FA& &E4& && & CLR& && &A
C:0x00FB& &93& && & MOVC& &&&A,@A+DPTR
C:0x00FC& &22& && & RET
程序功能:读取单片机内部ROM内的数据并赋值给A,寻址范围0~65535。当数组用code定义时,如程序③中,tab2数组用code定义,执行p=tab2后,R3的值被赋值为0xFF,再执行N2=*p语句时,即跳转到自处,读取内部ROM地址内的数据。&&
由此可见,子函数“C?CLDPTR”的作用是,根据数据所在存储空间,用不同的寻址方式读取某地址下的数据。R3用于确定寻址方式,R3的值与对应的寻址方式对应关系为:
1、R3值等于0x00时,片内RAM间接寻址;此时数据用dataidata定义。
2、R3值等于0x01时,片外RAM(扩展RAM)间接寻址;此时数据用xdata定义。
3、R3值等于0xFE时,片外RAM(扩展RAM)低246字节间接寻址;此时数据用pdata定义
4、R3值等于0xFF时,从存储存储器(ROM)进行变址寻址;此时数据用code定义。
3、指针结构
R3、R2、R1的值是RAM中0x12、0x13、0x14地址内的值,即变量p映射的RAM地址。而而8位单片机中,不管是何种寻址方式,最大寻址范围是2字节长度(0~65535),为什么指针*p却占用了3字节RAM空间呢?下面通过程序④说明。
#include &REG52.H&& && && &
unsigned char tab1[8];
unsigned char idata tab2[8];
unsigned char xdata tab3[8];& &
unsigned char pdata tab4[8];
unsigned char codetab5[8]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};
unsigned char&&*p;
void main()
& && && &p=tab1;
& && && &p=tab2;
& && && &p=tab3;
& && && &p=tab4;
& && && &p=tab5;
在Debug Session模式下可知,程序中数组与变量所映射的物理地址为及物理存储区分别为:
tab1 :& && &&&0x08~0x0F& && && && && && && && &单片机内部RAM
tab2:& &&&0x03~0x1A& && && && && && && &&&单片机内部RAM(idata)
tab3:& &&&0x08~0x0F& && && && && && && && &单片机扩展RAM(xdata)
tab4:& &&&0x00~0x08& && && && && && && && &单片机扩展RAM低256字节(pdata)
tab5:& &&&0x0003D~0x0044& && && && &单片机程序存储区(code)
p:& && && && &0x10~0x12& && && && && && && && &单片机内部RAM
注:扩展RAM可以在物理上可以分为片内或片外,如STC15系列增强型单片机的扩展RAM与单片机是封装在一起的,即片内扩展RAM;传统8051单片机没有片内扩展RAM,需连接外部RAM芯片,此为片外扩展RAM。
在Memory Windows窗口下,监视变量p映射的RAM地址:0x10~0x12的数值变化,如图11所示。
通过“Step”功能按钮执行住函数中的5调语句,可观察到0x10~0x12寄存器的数据变化:
执行p=tab1后,0x10、0x11、0x12:0x00、0x00、0x08
执行p=tab2后,0x10、0x11、0x12:0x00、0x00、0x13
执行p=tab3后,0x10、0x11、0x12:0x01、0x00、0x08
执行p=tab4后,0x10、0x11、0x12:0xFE、0x00、0x00
执行p=tab5后,0x10、0x11、0x12:0xFF、0x00、0x3D
由此可知,0x10的赋值取决于p指向的物理存储区,0x11、0x12的值是数据存储区的地址。指针所映射的首地址,会根据指向的物理存储区被编译器赋不同的值:0x00,0x01,0xFE,0xFF。这与程序③得到的结论一致,程序③中,寄存器R3、R2、R1对应值实际上就是指针所映射的3字寄存器数值。
结合程序③编译分析,当需要引用某物理地址内数据时,会调用“C?CLDPTR”函数,函数功能就是根据这些赋值确定使用何种寻址方式引用数据。而这一过程包括“C?CLDPTR”函数都是编译器自动完成的。
在汇编语言中,R1寄存器可以用于间接寻址,如:MOV&&A,@R1。不能写为MOV A,@12H。因此在程序③中,将变量p对应的3字节数据赋值给R3、R2、R1。
综上所述,Keil C-51编译环境下,指针是一个占3字节的特殊变量,编译器编译程序时,自动生成判断寻址方式的子函数,并根据根据目标数据所在的物理存储区不同,为指针首字节赋值,根据赋值的不同,进行不同方式的寻址;指针的后2字节,用于存放引用的地址。
调试训练:
下面的程序编译器会怎样编译?与程序③有何不同?请根据程序③和程序④的分析方式分析程序⑤的执行结果。
#include &REG52.H&& && && &
unsigned char tab1[8];
unsigned char codetab2[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
unsigned char&&*p;
void main()
& && && &p=tab1;
& && && &for(i=0;i&8;i++,p++)
& && && &*p=i;
& && && &p=tab2;
& && && &for(i=0;i&8;i++,p++)
& && && &*p=i;
思考:下列语句中:
p=tab2;for(i=0;i&8;i++,p++)*p=i;执行完for循环后,tab2数组内的值会改变吗?为什么? 4、指针意义在汇编编程中,由于单片机数据存放的物理存储区不同,导致有不同的寻址方式,用户进行必须根据这一规律设计程序。而在C语言中,不管目标数据所在的物理存储区如何,指针都可指向该地址,并自动编译寻址方式。但指针并不是万能的,如程序⑤中:p=tab2;for(i=0;i&8;i++,p++)*p=i;这些语句编译时并不会报错,但却不能实现功能,因为tab2数组是定义在程序存储器(ROM)的常量数组,ROM内的数据更改是不能通过这种方式实现的。因此,当用户不明确单片机的物理存储区特性时,使用指针会容易出错。先将程序⑤中的主函数语句做如下修改,得到程序⑥:#include&REG52.H&& && && &unsignedchar tab1[8];unsignedchar code tab2[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; unsignedchar&&*p;voidmain(){& && &&&& && && && && && &for(i=0;i&8;i++,p++)& && && &tab1[ i]=i;& && && && && && &for(i=0;i&8;i++,p++) & && && &tab2[ i]=i; } 单独看第一个for循环,可实现与程序⑤一样的效果,即tab1数组内被赋值为:0,1,2,3,4,5,6,7。第二个for循环从语句上可认为是与程序⑤功能相同,但实际上,不管是程序⑤还是程序⑥,都不能实现对tab2数组的赋值。但在程序⑥中,编译器会提示错误,如图12所示。 因此,指针的使用不当,不仅会带来程序运行结果的不正确,同时也难以发现这些错误。对比程序⑤和程序⑥中的两段程序:
p=tab1;& && && && && && && && && && && && && && && && && && &for(i=0;i&8;i++,p++)& && && && && && && && & for(i=0;i&8;i++,p++)& && && && && && && && && && && &&&tab1[ i]=i;*p=i;
它们执行的结果是一样的,那么哪种更好呢?对于初学者来说,显然是后者,因为后者更易于理解程序含义,而前者必须要理解指针在此处的作用;那么对于有经验的程序员呢?也是后者,因为程序执行效率上,后者也要大于前者,因为程序⑤在编译过程中,编译器始终会生成一个子函数用于确定寻址方式,再赋值;程序⑥则是直接确定了寻址方式执并行进行赋值。尽管执行效率的降低在接受范围内,但对于一个简单、明了的功能来说,用简单的方式实现要比复杂方式合理。
设计者在程序中使用指针的目的往往是让程序具有可移植性,但8051单片机的功能是有限的,它实现的功能相对固化,如时间显示、数据采集等等,这些功能确定后,几乎不会做出更改,基于此特点,8051单片机的代码代码量都不长。因此即便是不同构架的单片机程序互相移植,代码的修改并不复杂,移植过程中,也几乎都是针对不同构架单片机的I/O工作方式不同、指令周期不同做常规修改;或是关键字的修改。因此合理的设计单片机程序,尽可能的提高程序的效率、稳定性、可阅读性才是程序设计的核心主旨。指针在8051单片机中固然可以使用,但并不能说明指针的使用就一定是高效、准确、易于他人理解。
 图文并茂,做的漂亮
Powered by}

我要回帖

更多关于 c51单片机 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信