1.DSP指令没有位寻址,也没有位设置。要设置寄存器的某一位,可以写如下语句:
位清0: 位置1:
LACC * LACC *
AND #0FFF7H OR #0008H
SACL * SACL *
我们可以这样定义位:
B0 .set 0001h
B1 .set 0002h
B2 .set 0004h
…
B15 .set 8000h
再如下宏定义
BCLR .macro DMA, MASK ;Clear bit Macro (BCLR是PIC33位清除指令)
LACC DMA
AND #(0FFFFh-MASK)
SACL DMA
.endm
BSET .macro DMA, MASK ;Set bit Macro (BSET是PIC33位设置指令)
LACC DMA
OR #(MASK)
SACL DMA
.endm
因为SACL可以直接和间接寻址,所以宏也可以直接和间接寻址,但在间接寻址时禁止改变当前AR和ARP;否则会出错。
对于一些如外设寄存器,如地址为7018H的系统配置寄存器SCSR1,我们可以如下定义:
SCSR1 .set 7018h
CLKSRC .set 4000h
LPM1 .set 2000h
LPM0 .set 1000h
CLKPS2 .set 0800h
CLKPS1 .set 0400h
CLKPS0 .set 0200h
ADC_CLKEN .set 0080h
SCI_CLKEN .set 0040h
SPI_CLKEN .set 0020h
CAN_CLKEN .set 0010h
EVB_CLKEN .set 0008h
EVA_CLKEN .set 0004h
ILLADR .set 0001h
调用宏:1.直接寻址 2.间接寻址
MAR *, AR0 LDP #0E0H (SCSR1高9位地址)
LAR AR0, # SCSR1 BSET SCSR1,CLKSRC
BSET *, CLKSRC BCLR SCSR1, CLKSRC
BCLR *, CLKSRC
间接寻址看起来更直观,LDP指令没有移位载入功能,所以在写LDP指令时还要计算其高9位地址的值,这有点不方便。
直接寻址如果直接加载地址到当前AR,可以少写MAR *, AR0这条指令,即直观,又方便。
执行完宏后如果有必要,要注意DP和AR的恢复。
下面是关于清看门狗的宏:
KICK_DOG .macro ;Watchdog reset macro
LDP #WDKEY>>7 ;DP-->7000h-707Fh
SPLK #05555h, WDKEY ;WDCNTR is enabled to be reset by next AAh
SPLK #0AAAAh, WDKEY ;WDCNTR is reset
.endm
这里的WDKEY定义的也是16位的地址,用直接寻址,自动舍弃高位。
踢狗宏里面没有恢复DP针指,所以在踢完狗后要注意DP指针的恢复。
2008-3-7
关于页面指针的装载
.bss x, 1
LDP #x
WDKEY .set 7025h
LDP #WDKEY>>7
.bss x, 1是定义一个变量x,#x就是一个16位的地址,而LDP #x指令自动的取其地址的高9位送到DP。相当于C语言中的&x。
WDKEY .set 7025h是定义一个符号名,用法与变量x不同
LDP #WDKEY>>7
如果写成LDP #x>>7或LDP #WDKEY都是错误的。
以下是对x,WDKEY赋值的直接、间接寻址方式的正确写法:
直接寻址 间接寻址
LDP #x MAR *, AR1
SPLK #3000H, x LAR AR1, #x
SPLK #3000H, x+1 SPLK #3000H, *
;赋值下一个存储单元
LDP #WDKEY>>7 MAR *,AR1
SPLK #55H, WDKEY LAR AR1, #WDKEY
SPLK #AAH, WDKEY SPLK #55H, *
;警告,但自动丢掉高9位
.set定义的符号不占数据存储空间,符号代表的是值本身。而用.bss .WORD等定义的变量是要占数据空间的,变量或常量名代表的是地址而不是其值。
2008-3-7
如果把位测试一起做成宏的话,在BIT dma, bit code(测试位号=15-bit code)中定义位的话是如下定义:
B0 .set 15
B1 .set 14
…
B15 .set 0
如果要让位的定义统一的话,即在BSET、BCLR、BTST(位测试)中都可以用的话,要改BSET、BCLR宏。修改如下:
BCLR .macro DMA, MASK ;Clear bit Macro (BCLR是PIC33位清除指令)
LACC DMA
AND #(0FFFFh-(8000h>>MASK))
SACL DMA
.endm
BSET .macro DMA, MASK ;Set bit Macro (BSET是PIC33位设置指令)
LACC DMA
OR #(8000h>>MASK)
SACL DMA
.endm
BTST .macro DMA, MASK ;Text bit Macro (BTST是PIC33的位测设指令)
BIT DMA, MASK
.endm
可以看出关于位测试完全没有必要做成宏,我们要做的只是把两种位定义做成一样的就好了。
关于BSET、BCLR宏参数DMA,其说明是用直接寻址,但用(也只能用)间接寻址中的*操作符也可以。
2008-3-12
宏定义BCLR、BSET是把要设的位清0置1,没设的位原值写入。这对如中断标志位等写1清零的位操作时会出错。
这些位有的是整个寄存器都是写1清零的标志位,有的寄存器又只有一两位。应该如何写通用的BSET、BCLR宏呢?
写1清零的位有:
SCSR2<5>WD_OVERRIDE
WDCR<7>WDFLAG
XINT1CR<15>FLAG XINT2CR<15>FLAG
以上只有一个位的,对其清0置1还可以用原来的BSET、BCLR宏。但对其同字的其他位操作时要注意不要改变标志位。
EVAIFRA EVAIFRB EVAIFRC
EVBIFRA EVBIFRB EVBIFRC
IFR
对整个字都是标志位的,我们可以另外定义清标志位宏:
FCLR .macro DMA, MASK ;Clear bit Macro (FLAG CLR)
LACC #8000h>>MASK
SACL DMA
.endm
不需要置标志位宏。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。