IAR 430 头文件中#define定义的部分解释
[复制链接]
今天在阅读 RF_Example_Code_v1.0中头文件 cc430x613x.h时发现了几部分的疑问。
首先来看一下 cc430x613x.h 中的 3个 #define的例子:
#define DEFC(name, address) __no_init volatile unsigned char name @ address;
#define DEFW(name, address) __no_init volatile unsigned short name @ address;
#define DEFCW(name, address) __no_init union \
{ \
struct \
{ \
volatile unsigned char name##_L; \
volatile unsigned char name##_H; \
}; \
volatile unsigned short name; \
} @ address;
前面的两个 #define的用法是一样的。首先我可以发现,在宏定义里面都有一个关键字 __no_init。查看了《 MSP430 IAR C/EC++ Compiler Reference Guide》内的 IAR Language Extension Overview 可以发现, __no_init是 IAR扩展语法里面的一个扩展关键字。作用是声明一个 non-volatile类型的内存地址( Support non-valotile memory)。
于是解决了 __no_init的问题。
再者对 @这个字符存在一定的疑问,于是上网查了查资料。虽然对于 @这个字符的用法还是不是很明确,但是可以明确的是:
#define DEFC(name, address) __no_init volatile unsigned char name @ address;
#define DEFC(name, address) sfrb name = address;
这两种定义是等价的,但是后者是基于汇编嵌入式编程的情况下才成立。也就是说“ =”是 MSP430汇编中数据分配伪指令中的一种。我们来看一下 MSP430汇编的数据分配伪指令有哪些:
这类指令有以下一些:
SET (VAR, ASSIGN) 赋予一个临时值;
EQU (=) 在当前模块中赋予一个永久的值;
DEFINE 定义一个整个文件中都有效的值;
sfrb 寄存器类型的字节;
sfrw 寄存器类型的字。
使用语法如下:
label SET expr
label EQU expr
label = expr
label DEFINE expr
[const] sfrb register = value
[const] sfrw register = value
其中,
label 定义一个标志符、
expr 标志符的值、
register 特殊功能寄存器、
value 特殊功能寄存器的值。
在下面的例子中使用了局部变量与全局变量,在模块 add1 中定义了符号 value ,同样在
模块 add2 中也定义了符号 value,但它们表示两个不同的量,都只在各自的模块内部有效,
这是局部变量。而在模块 add1 中定义的 locn 则为全局变量,在两个模块中表示同一个值。
NAME add1
locn DEFINE 100H
value EQU 77
MOV locn,R4
ADD #value,R4
ENDMOD
NAME add2
value EQU 88
MOV locn,R5
ADD #value,R5
END
很明显,“ =”也就是 EQU,作用是:在当前模块中赋予一个永久的值。
至此,
#define DEFCW(name, address) __no_init union \
{ \
struct \
{ \
volatile unsigned char name##_L; \
volatile unsigned char name##_H; \
}; \
volatile unsigned short name; \
} @ address;
这种定义也变得相对好理解。以上的这种定义只是多了一个 union的定义,将一个 16位的地址存储空间分成 2个 8bits或者 1个 16位。可以实现字访问,也可以实现字节访问。以上定义是将一个无名的 union与 address联系起来,使得访问 address对应的内存时,就像访问 union一样。
那么对于下面的一些看起来貌似比较复杂的定义就相对比较好理解了:
#define RF1AIFCTL1_ (0x0F02u) /* Radio interface control register 1 */
DEFCW( RF1AIFCTL1 , RF1AIFCTL1_)
#define RF1AIFIFG RF1AIFCTL1_L /* Radio interface interrupt flag register */
#define RF1AIFIE RF1AIFCTL1_H /* Radio interface interrupt enable register */
可以发现,第一个宏定义,“ RF1AIFCTL1_”在字符串的最后带一个下划线,其实代表这只是一个地址。而通过宏扩展 DEFCW( RF1AIFCTL1 , RF1AIFCTL1_),将会被扩展为:
__no_init union \
{ \
struct \
{ \
volatile unsigned char RF1AIFCTL1_L; \
volatile unsigned char RF1AIFCTL1_H; \
}; \
volatile unsigned short RF1AIFCTL1; \
} @ (0x0F02u);
关于 @的用法,今天查阅了《 MSP430 IAR C/EC++ Compiler Reference Guide》,找到了结果:
A variable that has been explicitly placed at an address, for example by using the compiler @ syntax, will be placed in either the DATA16_AC or the DATA16_AN segment.
从中可以看出, @是一种语法。那么它的作用很明显就是将变量放置到对应的地址中。使用 @,一个变量可以明确的制定一个存储地址。
因此之前的宏定义就变得好理解了。
#define DEFC(name, address) __no_init volatile unsigned char name @ address;
就是将 name变量存放在 address地址中,那么如此一来就可以为每个寄存器进行命名了,也就是说可以实现每个寄存器对应一个或者多个变量。
至此头文件中另外一个问题也迎刃而解:
#define RF1AIFCTL1_ (0x0F02u) /* Radio interface control register 1 */
DEFCW( RF1AIFCTL1 , RF1AIFCTL1_)
#define RF1AIFIFG RF1AIFCTL1_L /* Radio interface interrupt flag register */
#define RF1AIFIE RF1AIFCTL1_H /* Radio interface interrupt enable register */
我们将 DEFCW( RF1AIFCTL1 , RF1AIFCTL1_)展开:
__no_init union \
{ \
struct \
{ \
volatile unsigned char RF1AIFCTL1_L; \
volatile unsigned char RF1AIFCTL1_H; \
}; \
volatile unsigned short RF1AIFCTL1; \
} @ (0x0F02u);
那么可以知道, RF1AIFCTL1, RF1AIFCTL1_L, RF1AIFCTL1_H已经声明成为一个变量,存放的地址分别是 0x0F02u, 0x0F02u+1, 0x0F02u。因此接下来后面两条宏定义就自然的解开了。
#define RF1AIFIFG RF1AIFCTL1_L /* Radio interface interrupt flag register */
#define RF1AIFIE RF1AIFCTL1_H /* Radio interface interrupt enable register */
功能只是为变量 RF1AIFCTL1_L, RF1AIFCTL1_H定义了另外的一种名字作为替换。