Chinaunix首页 | 论坛 | 博客
  • 博客访问: 173913
  • 博文数量: 63
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 181
  • 用 户 组: 普通用户
  • 注册时间: 2016-02-25 15:50
文章分类
文章存档

2020年(1)

2016年(62)

我的朋友

分类: 嵌入式

2016-03-02 11:38:12

先看一个临界区代码保护的例子:
      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) |
给主人留下些什么吧!~~