现象:
从这看见DEFC DEFW
#define __MSP430_HAS_SD16_A1__
#define SD16INCTL0_(0x00B0u)DEFC(SD16INCTL0, SD16INCTL0_) #define SD16AE_(0x00B7u)DEFC(SD16AE, SD16AE_) #define SD16CONF0_(0x00F7u)DEFC(SD16CONF0, SD16CONF0_) #define SD16CONF1_(0x00BFu)DEFC(SD16CONF1, SD16CONF1_)
#define SD16CTL_(0x0100u)DEFW(SD16CTL, SD16CTL_) #define SD16CCTL0_(0x0102u)DEFW(SD16CCTL0, SD16CCTL0_) #define SD16IV_(0x0110u)DEFW(SD16IV, SD16IV_) #define SD16MEM0_(0x0112u)DEFW(SD16MEM0, SD16MEM0_)
接着找到下面的定义
#ifdef __IAR_SYSTEMS_ICC__ #include "in430.h" #pragma language=extended
#define DEFC(name, address) __no_init volatile unsigned char name @ address; #define DEFW(name, address) __no_init volatile unsigned short name @ address; #define DEFXCvolatile unsigned char #define DEFXWvolatile unsigned short
#endif
#ifdef __IAR_SYSTEMS_ASM__ #define DEFC(name, address) sfrb name = address; #define DEFW(name, address) sfrw name = address;
解释:
数值分配伪指令:主要用于对符合的数值定义,以下是常见的定义
EQU在当前模块中赋予一个永久的值
=同上
DEFINE在多个模块环境下,定义一个在整个文件中都有效的值
sfrb和sfrw是老的版本对功能寄存器的定义
DEFC是新的版本对功能寄存器的定义
READ_ONLY DEFC是新的版本定义只读功能模块寄存器
3.3.1扩展关键字 关键字的概念前面已经介绍过。下面是除了 C语言标准关键字之外的扩展部分,这里只 介绍常用的扩展关键字。 1.asm 也可以写成 __asm。功能是在 C 程序中直接嵌入汇编语言。 语法: asm ("string"); 其中 string 必须是有效的汇编语句。 2.__interrupt 放在函数前面,标志中断函数。下面这段程序是异步串行口 UART0 的接收中断函数。 UART0RX_VECTOR 为异步串行口 UART0 的接收中断向量。 举例: #pragma vector=UART0RX_VECTOR __interrupt void UART0_R(void)//UART0接收中断 {TXBUF0=RXBUF0; } 3.__monitor 放在函数前面, 功能是当这一函数执行的时候自动关闭中断。 应该尽量缩短这样的函数, 否则,中断事件无法得到及时的响应。 4.__no_init 放在全局变量前面,功能是使程序启动时不为变量赋初值。 5.__raw 编译中断函数时,编译器会自动生成一段代码,首先保存当时所用到 CPU 内寄存器的内 容,退出中断程序时再进行恢复。将__raw放在中断函数前可以禁止保存 CPU内寄存器的过 程,当然退出时也不会恢复。是否为中断函数使用此关键字要根据需要而定。 6.__regvar 放在变量前面,作用是声明变量为寄存器变量。可以用于整数、指针、32 位浮点数以及 只含有一个元素的结构和联合。寄存器变量的地址只能为 R4 或者R5,也不能用指针指向这 个寄存器变量,而且必须用__no_init 禁止初始化。如: __regvar __no_init unsigned char q0 @ __R4;– 57 – 其他不常用的关键字还有:__data16、__intrinsic、__noreturn、 __root、__task、__word16。
IAR编程环境 _no_init
今天在阅读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)
DEFCW( RF1AIFCTL1 , RF1AIFCTL1_)
#define RF1AIFIFG RF1AIFCTL1_L
#define RF1AIFIE RF1AIFCTL1_H
可以发现,第一个宏定义,“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)
DEFCW( RF1AIFCTL1 , RF1AIFCTL1_)
#define RF1AIFIFG RF1AIFCTL1_L
#define RF1AIFIE RF1AIFCTL1_H
我们将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
#define RF1AIFIE RF1AIFCTL1_H
功能只是为变量RF1AIFCTL1_L,RF1AIFCTL1_H定义了另外的一种名字作为替换。