PIC单片机基础知识之二

您所在的位置:网站首页 单片机pcl是什么意思 PIC单片机基础知识之二

PIC单片机基础知识之二

2024-07-17 01:38| 来源: 网络整理| 查看: 265

STAUTS 寄存器 14位的指令字

|IRP|RP1|RP0|TO|PD|Z|DC|C| |操作码|d|f|f|f|f|f|f|f|

----------- ---------------

| |

| _________________________________|

| |

V V

|高2位地址| 低7位地址 | 这是CPU访问RAM时用的实际地址

要明白的是,STATUS里面的两位,你不去设置它,它是不会自动改变的,所以,如果你要访问某个不在BANK0,比如某个寄存器在90H地址,你就需要先设置STATUS里面的RP0位到1,然后再用指令操作该寄存器,才能正确操作。如果

不先设置,则很有可能操作错误地址的RAM。通常表现为:仿真时发现,我用指令操作这个寄存器,怎么仿真结果上寄存器没有任何改变?这时,你首先需要查的,就是BANK对不对。

你可能会说,天啊,为什么搞这么麻烦!

我们可以理解,如果把指令字里的f地址位放到更长,就可以访问更长的地址范围。但是,这样指令字长了也就增加

了单片机的硬件成本。缩短指令字长度,增加了一点麻烦,但这也是一种折中的选择。

当然,编译器也充分考虑了因为设置BANK带来的麻烦,提供了BANKSEL宏指令,BANKSEL是BANK Select的缩写,就是

选择BANK的意思,用法如下:

如果你要访问某个寄存器ABC

BANKSEL ABC

MOVWF ABC

编译器在扫描到BANKSEL宏指令时,会自动查询ABC所在的BANK,然后把该宏指令编译成相应的设置STATUS里面RP1和

RP0位的指令。这就省了你自己去查的步骤。要说明的是,当你对BANK理解深入或者程序写完了之后,也要适当看看

这些BANKSEL指令,因为很有可能很多BANKSEL指令都是多余的(比如连续操作的寄存器都在同一个BANK),这时可适当地删掉一些以缩减代码。

总结一下,BANK的概念,被很多初学者诟病,上面说明了它的原理以及为什么要这样,其实等你熟悉了PIC的汇编编

程之后,不会觉得BANK有什么大的麻烦的,适应了就好。

【间接寻址】

和前面的指令里直接描述对象地址的寻址模式完全不一样,它是间接的。

间接寻址使用一个地址指针寄存器FSR,FSR是一个8位的寄存器,当FSR指向某地址时,你对INDF寄存器进行操作,

就是对FSR所指向的地址操作。举个例子:

如果FSR的值为0x80,你执行 MOVWF INDF这条指令,就是把W的值传送到0x80地址的RAM。这里要强调一点,INDF这个名字的寄存器,在物理上是不存在的,INDF的意思就是,FSR所指向的RAM单元。

再来看下面的一段代码:

movlw 0x20

movwf FSR ;FSR里的值为0x20

LOOP clrf INDF ;清掉FSR所指向的RAM单元

incf FSR,F;FSR里的值加一,也就是指针加一

btfss FSR,7;测试FSR里的值有没有超过7F,如果超过,跳过一条指令,这个不用解释了吧。

goto LOOP ;如果没有超过7F地址,跳回循环清RAM单元

上面是一段经典的使用间接寻址的,把RAM初始化为0的小程序。在这里插入一个小常识,单片机在上电时,内部的

通用RAM(非特殊功能寄存器)里的值,并不是软件模拟或者仿真时那样都是00,而是随机值。所以,单片机程序的起始部分,用到的变量一定要记得初始化,或者干脆就先象上面这段程序一样,用几行指令就可以把一段RAM清零。

前面说到了FSR是8位的,问题又来了,PIC中档单片机最多有512个字节的RAM,而8位的地址最多只能访问256个字节,怎么办?还是和上面一样,要另外借助一位作为9位地址的最高位,这个位就是STATUS寄存器里的IRP位。

同样地,看个图示:

STAUTS 寄存器 FSR寄存器

|IRP|RP1|RP0|TO|PD|Z|DC|C| |f|f|f|f|f|f|f|f|

------------ ---------------

| |

| ____________________________|

| |

V V

|最高位| 低8位地址 | 这是CPU访问RAM时用的实际地址

所以,和前面说到的BANK概念一样,当你要用间接寻址访问超过256个字节地址范围的RAM时,要先设置STATUS寄存器里的IRP位。同样地,编译器也提供了BANKISEL宏指令,编译器会把BANKISEL宏指令翻译成相应的设置IRP位的指令,用法和BANKSEL相同,不再赘述,相信大家都能触类旁通的。

2)立即数寻址

这个就简单很多,就是当你使用立即数操作指令时,(如MOVLW xxH,ADDLW xxH,RETLW xxH等指令)14位的指令长字的后面8位就是你所要操作的立即数,这里不多说了,不过介绍一点特殊用法。

你可能会看到这样的指令:

MOVLW PORTA; 这不是把PORTA里的内容给W,而是把PORTA寄存器的地址0x05给W。

MOVLW high Sub_1; 这个指令是把Sub_1子程序标号的PC值的高位送到W里

3)程序寻址/程序跳转

前面介绍的都是RAM的寻址,接下来介绍程序空间的寻址。

【PC绝对寻址】

PC的绝对寻址就是使用CALL或者GOTO指令来改变PC(程序指针)。

这里先介绍一下PC,PIC中档单片机的程序空间最大为8K指令字,那么它的PC长度为13位(自己去算啊)。由于是8位单片机,所以这13位分成两个字节,PCH和PCL,PCH里是高5位,PCL里是PC的低8位。当程序顺序执行的时候,PC会自动加一,当然PCL发生进位的时候PCH也会加一,当PCH和PCL都溢出时回零,整个PC就回到程序起始地址0x00。

好了,回到PC绝对寻址,我们来看一下CALL指令的机器码

指令:CALL Sub_1 机器码:100 kkkkkkkkkkk

这里的100就是CALL指令的操作码,后面11位的k,就是Sub_1标号处的PC值。问题又来了,只有11位,2的11次方只有2K,那么CALL只能调用2K地址范围内的子程序吗?PIC中档不是最大有8K程序空间吗。怎么办?还是一样,不够就找地方来凑。这次不能找STATUS寄存器了,老是找它也不好意思的,呵呵,玩笑。针对PC的问题,有一个专门的寄存器,叫做PCLATH。PCLATH是 PC Latch High的缩写,顾名思义,这个寄存器,是PC的高位(也就是PCH)的锁存器。当你使用CALL或者GOTO指令时,因为指令长度有限,指令里描述的地址只有11位,那么高2位,就借助于PCLATH的D4和D3位,这就是PAGE。一样的,你必须先设好这两位才能使用CALL或者GOTO指令。两位可以有四种组合,所以8K的程序空间分成了4个2K的页,和上面介绍BANK时的原理相同,不再画图表了。

我们来看一个具体的过程。假设你现在要CALL一个在PAGE1的子程序,那么高2位应为 0 1,你必须在执行CALL指令之前设置好,来看下面的示意图。

PCLATH 5bits

-------------

|0|1|x|x|x|

-------------

|PCLATH的d4 d3两位会在执行CALL指令的瞬间装入PCH的高两位

V 这里的11位的k来自于CALL指令

----------- --------------------

|0|1|k|k|k| |k|k|k|k|k|k|k|k| (实际PC)

----------- --------------------

PCH 5bits PCL 8bits

所以,当你的程序超过一页(2K)的时候,执行CALL或GOTO指令之前你必须清楚,你要调用或者跳转的地方是在那个页,相应地要设置PCLATH的d4d3位,也就是设置PAGE。同样地,编译器也提供了一个宏指令给你方便,当你不想去查或者不确定要CALL或者GOTO的地方是哪个页时,可以使用宏指令PAGESEL。

用法,假如你要调用子程序Sub_1,而你又不确定它是在那个PAGE时

PAGESEL Sub_1 ;编译器会自动查找Sub_1在那个页,然后把该指令翻译成相应设置PCLATH d4d3位的指令

CALL Sub_1

PC的高位字节PCH是不可由程序直接写入的,它必须是在PC改变时通过它的锁存器PCLATH装入。

PCLATH始终是作为装载PCH用的一个锁存器,它自己的值不会随着PCH的改变而改变。一个很简单的例子,程序假如顺序执行从00一直到8K末尾,这样PCH的最高两位也就从00一直变成11,但PCLATH的高两位,如果你没有人为改变,原来是什么它还是什么。(很多人犯的一个误解:当前PC在PAGE1,调用PAGE1里的子程序就不用设置PAGE了)

当CALL子程序时,CALL指令当前PC+1的13位PC地址压入堆栈(因为硬件堆栈是和PC等宽的)。所以RETURN时能从堆栈弹出整个13位PC的返回地址,就不再需要设定PCLATH了。但是,要记住,不设定并不代表它自己会改变。假设你CALL之前设定到Page1了,Return之后回到Page0了,但此时,PCLATH里的4:3位还是0:1。

PAGE的概念,一样也是很多初学者不适应的地方,通常没有注意PAGE会出现“我明明是要跳转到这个地方,怎么跑到别的地方去了?”这样的情况,此时赶紧观察一下PCLATH的值,看看有没有忘记设置。总之,等你熟悉了,换页也就没有什么不习惯的。

【PC相对寻址】

简而言之就是,通过计算让程序基于当前的PC值做相对的跳转,例如把PC加上某个值而跳转到另一个地方。如:

addwf PCL,F

执行该指令直接修改PC时,PCLATH里面的5位会在瞬间装入PCH。(请一定要理解PCH为什么要锁存器PCLATH,如果没有锁存器,你如果能用1条指令同时修改两个寄存器PCH和PCL呢?)如下图示:

PCLATH 5bits

----------------

| 4| 3| 2| 1| 0|

---------------- 程序修改PC低位字节

| |

V V

---------------- -----------------

| x| x| x| x| x| | | (实际PC)

---------------- -----------------

PCH 5bits PCL 8bits

所以,在做PC相对寻址前,一定要先确认PCLATH里的值正确。还记得前面的MOVLW指令吗,可以在这时用哦。

MOVLW high Sub_1 ; 把Sub_1处PC的高5位给W

MOVWF PCLATH ; 把高5位的值给PCLATH

MOVF Value,W ; 把查表的索引值给W

ADDWF PCL,F ; PC的低位PCL加上索引值

Sub_1

RETLW 0x00 ; 如果W的值为0,从这里返回一个值,为什么?自己体会,还记得流水线概念吗?

RETLW 0x01 ; 如果W的值为1,从这里返回一个值

....

这是一个典型的使用PC相对寻址来做查表程序的例子。实际使用时,如果PCLATH没注意设置,表现就是PC跑飞。另外要注意的是,W和PCL相加不能溢出,如果表太大必然溢出的话,可以先试运算,然后按进位与否来改变PCLATH。

还有,如果开了中断,现场保护里要注意保护PCLATH,如果不保护,假如恰好在ADDWF PCL,F执行之前进中断了,中断里又改变了PCLATH(极有可能,如切换页),等中断返回之后就会造成PCLATH错误从而PC跑飞。曾经,因为某个

应用笔记的错误,导致了一个说法,说“PIC在查表时必须关中断”,就是因为没有注意保护PCLATH这个错误而产生的,后来一些中文书里面也引用了这个说法,我在这里再次说明,“查表时必须关中断”是一个错误的说法,希望不要

再以讹传讹了。

再次强调:PCLATH是个很重要的寄存器,你对它稍不注意,它就会让你跑飞! 返回搜狐,查看更多



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3