PIC汇编程序中的存储区切换

时间:2009-05-05 11:41:47

标签: assembly switch-statement pic bank

我对PIC汇编程序中的银行转换感到困惑......这适用于在usart上放置'Q':

bsf PORTB,1         ;Set Transmit DIR (PORTB (0x6) not mirrored in other banks)
movlw 'Q'           ;'Q' to work reg
movwf TXREG         ;work reg to TXREG (TXREG (0x19) not mirrored in other banks)
clrwdt              ;Clear watchdog
btfss TXSTA,TRMT    ;Wait until 'Q' is shifted (TXSTA is 0x18, not mirrored)
goto $-2
bcf PORTB,1         ;Set Recive DIR

这同样有效:

BCF 0x3, 0x5        ;Switch to bank 0
BCF 0x3, 0x6
bsf PORTB,1         ;Set Transmit DIR
movlw 'Q'           ;'Q' to work reg
movwf TXREG         ;work reg to TXREG 
BSF 0x3, 0x5        ;Switch to bank 1
clrwdt              ;Clear watchdog
btfss TXSTA,TRMT    ;Wait until 'Q' is shifted
goto $-2
BCF 0x3, 0x5        ;Switch to bank 0
bcf PORTB,1         ;Set Recive DIR

我已经检查过编译器在我不看的时候没有进行任何银行切换......什么时候需要切换银行?

3 个答案:

答案 0 :(得分:7)

最好只使用BANKSEL自动进行银行转换。它是一个特殊的汇编程序指令,告诉汇编程序切换到正确的存储区。因此,如果您希望在使用之前访问PORTB,只需使用BANKSEL(PORTB)。

PS:PORTB在PIC16系列的BANK0中,而不是代码中的BANK1。

答案 1 :(得分:5)

我也发现银行选择很难理解。

我正在使用PIC12F1822s开始一个项目,以实现其I2C功能。研究背景就像解开线程的束缚,每个人在明确之前都需要进行大量的挣扎。我设法撤出的其中一个主题是对“BANKSEL”指令的解释。

背景。有几十个SFR - 特殊功能寄存器 - 帮助设备操作,映射到较低的数据存储器。因为有这么多,它们被组织成32个银行,编号为0到31,每个32个SFR。 SFR以形式(位) bbbbbfffffff 顺序编号,其中 bbbbb 是存储区编号, fffffff 是存储区中的偏移。它们的值在PIC的.INC文件中定义,序列中有许多间隙。请注意,对于0到30存储区中的SFR偏移,只需要5位,但对于存储区31,则需要7位。

当访问其中一个SFR时,其Bank编号必须位于BSR寄存器中,该寄存器由“MOVLB”汇编器指令设置。为了简化这一过程,可以在每次访问SFR之前使用指令“BANKSEL”。 (在其他PIC中,STATUS寄存器中的位保存存储区编号)成功测试后,可以删除任何多余的BANKSEL。我的谜题(到目前为止建立这个 - 文档中的信息稀疏和分散)是这个指令的工作原理。当然,在生成任何代码之前,汇编程序会对其进行评估,这是我的测试代码,使用EQU进行计算并解释它(注意locn是“Location”即指令的地址。):

        ;BANKSEL is a directive that does the equivalent of 
        ;       movlb  (<SFRname> & 0XF0) >> 7

        ;For example TRISA is defined in P12F1822.INC as:

        ;-----Bank1------------------
        TRISA            EQU  H'008C' 

   Assembler:
   Locn   Resulting value     Line  Original code line content ";" is a comment
   ~~~~   ~~~~~~~~~~~~~~~     ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                              00047 ; Test of equivalent of BANKSEL directive          
          0000008C            00048 selbank equ TRISA
          00000080            00049 selbnk1 equ selbank & 0XF80 ; Extract bank no. ..
          00000001            00050 selbnk2 equ selbnk1 >> 7 ; .. move it to the right
          0000000C            00051 selbnk3 equ TRISA & 0XF80 >> 7 
        [ Operator precedence: >> (bit shift right) higher than & (bitwise AND) ]
          0000000C            00052 selbnk4 equ TRISA & (0XF80 >> 7) ; default
          00000001            00053 selbnk5 equ (TRISA & 0XF80) >> 7 ; as needed`
                     . . .
   006C   0021                00100 movlb  1           ; Should be same as next line
   006D   0021                00101 banksel TRISA       

答案 2 :(得分:3)

首先关闭哪个pic设备,因为这确实会产生细微差别。 您还在使用哪种编译器。

然而,你的代码工作的原因是因为你需要对tx执行ux的所有操作都在bank 0.你对端口b的写操作什么都没做我猜你想要切换trisb而那是在bank 1中但由于uart控制了写入端口B的引脚,因此它本身没有任何效果。在你的第二个例子中,你正在轮询你认为TXSTA,但是在银行0而不是银行1.我猜你通过轮询错误的位置而得到幸运,并且该位总是处于正确状态,因此循环终止。

当我进行传输时,我更喜欢先看看uart是否为空并等到它是,然后发送char。无需等待它完成传输,除非您想使用中断例如获取下一个字符。

因此,当您执行movRf TXREG时,两个代码都有效,因为您在两个代码中都处于存储区0中。其余部分由硬件处理。

编辑: 现在我知道你正确的部分是TXSTA在银行1.你通过我,因为你有一个地址的评论为0x18,它应该是0x98。在第一个示例中,您轮询RCSTA位1,即OERR而不是TXSTA。因此,如果它正在工作,这意味着OERR = 1这是非常可能的,当我对接收做任何事情时,我通常会清除它。