先看一个临界区代码保护的例子: HAL_ENTER_CRITICAL_SECTION(intState); events = activeTask->events; activeTask->events = 0; //清楚任务的事件 HAL_EXIT_CRITICAL_SECTION(intState); 其中:中断宏定义如下 #define HAL_ENABLE_INTERRUPTS() st( EA = 1; ) #define HAL_DISABLE_INTERRUPTS() st( EA = 0; ) #define HAL_INTERRUPTS_ARE_ENABLED() (EA) typedef unsigned char halIntState_t; #define HAL_ENTER_CRITICAL_SECTION(x) st( x = EA; HAL_DISABLE_INTERRUPTS(); ) #define HAL_EXIT_CRITICAL_SECTION(x) st( EA = x; ) #define HAL_CRITICAL_STATEMENT(x) st( halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); x; HAL_EXIT_CRITICAL_SECTION(s); ) 以及相关的st宏: #define st(x) do { x } while (__LINE__ == -1) (1)cc2430芯片中的中断使能的特殊功能寄存器(SFRs):IEN0,IEN1和IEN2,(见cc2430 datasheet: P49)。这三个寄存器的不同的位控制了不同的硬件的中断使能,比如IEN2中的第五位WDTIE控制着看门狗时钟的中断使能。这其中有一个比较特殊的位是IEN0的第7位,名称为EA,控制着所有中断的使能,为0时将没有中断相应,为1时每一个中断源的使能受相应的位的控制。上面的宏即是用芯片的EA=0来关中断实现临界资源的保护。 (2)set宏定义如下,表示执行x指令,注意x是一个完整的语句,需要加分号。 #define st(x) do { x } while (__LINE__ == -1) 而整个宏的定义结束时没有分号,而是在最后的应用时加的分号,如:HAL_ENTER_CRITICAL_SECTION(intState); (3) HAL_ENABLE_INTERRUPTS()和 HAL_DISABLE_INTERRUPTS()这两个宏分别实现了cc2430的所有中断的开和关。 HAL_ENTER_CRITICAL_SECTION(x)宏首先将EA的值保存在变量x中,然后关闭所有中断,进行后面的临街资源处理。 HAL_EXIT_CRITICAL_SECTION(x)宏则是回复刚才保存在x中的EA的值。 HAL_CRITICAL_STATEMENT(x)宏的功能是将x作为临界代码执行,首先声明了用于保存EA值的变量,然后调用进入临界区宏,执行临界代码x,最后执行退出临界区的宏。 (4)注意 HAL_CRITICAL_STATEMENT(x)这个宏,因为st宏的实现中x是一些可以执行的完整c语句,更主要的是写在do{}while()中,它值一个子的程序片段,因此x可以做很多事,比如声明变量等。否则你会奇怪,这样定义宏在宏展开的时候如果使用多个这个宏,会不会出现重复定义(HAL_CRITICAL_STATEMENT(x) 实现代码中的halIntState_t s;),会不会出现在程序的中间来定义变量(c语言要求要使用的变量需在最前面定义)等问题。其实这些问题是不会出现的,真是因为HAL_CRITICAL_STATEMENT(x)的x的执行在do-while中的do子句中。 下面是一个类似的验证例子程序: #include <stdio.h> #define st(x) do{x}while(__LINE__==-1) #define enable() st(EA = 1;) //使能所有中断 #define disable() st(EA = 0;) //关闭所有中断 #define enter(x) st(x = EA; disable();) //进入临界区 #define exit(x) st(EA = x;) //退出临界区 //简写临界代码的执行 #define critical(s) st(int temp; enter(temp); s; exit(temp);) //模拟控制所有中断的变量 int EA = 5; int main() { int a; enter(a); printf("EA=%d, a=%d\n",EA,a); exit(a); //验证多次执行宏不会出现重复定义变量的问题 critical(printf("hello world-first\n");); critical(printf("hello world-second\n");); //上面的critical(printf("hello world-first\n"););展开后的等价代码 do { int temp; do{ temp = EA; do{ EA = 0; }while(__LINE__==-1); }while(__LINE__==-1); printf("hello world\n"); do{ EA =temp; }while(__LINE__==-1); }while(__LINE__==-1); //验证在子模块中可以再次声明变量 { int a = 12; printf("%d\n",a); { int a = 89; printf("%d\n",a); } } return 0; } 执行结果为: EA=0, a=5 hello world-first hello world-second hello world 12 89 PS: (1)c程序中的各个宏定义的顺序任意。 (1)c程序中要求变量需先定义所有要使用的变量,然后才使用,是对用一个层次模块来说,在子层次中可以遵循这个规则再次定义变量。一个花括号中的括起来的内容{...}可以看作一个子模块。