先看一个临界区代码保护的例子:
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
#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程序中要求变量需先定义所有要使用的变量,然后才使用,是对用一个层次模块来说,在子层次中可以遵循这个规则再次定义变量。一个花括号中的括起来的内容{...}可以看作一个子模块。
阅读(1063) | 评论(0) | 转发(0) |