这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » OS,ENTER,CRITICAL OS_ENTER_CRITICAL();的问

共2条 1/1 1 跳转至

OS,ENTER,CRITICAL OS_ENTER_CRITICAL();的问题?

院士
2006-09-17 18:14:16     打赏
OS,ENTER,CRITICAL OS_ENTER_CRITICAL();的问题?



关键词: ENTER     CRITICAL     问题    

院士
2006-12-22 22:43:00     打赏
2楼
问 LPC2131中有这表例程:

uint8 UART0Getch(void)
{
    uint8 err;

    OS_ENTER_CRITICAL();//1处
    while ((U0LSR & 0x00000001) == 0)
    {                                           /* 没有收到数据 */
        U0IER = U0IER | 0x01;                   /* 允许接收中断 */
        OSSemPend(Uart0Sem, 0, &err);           /* 等待接收数据 */2处
    }
    err = U0RBR;                                /* 读取收到的数据 */
    OS_EXIT_CRITICAL();
    return err;
}

void UART0_Exception(void)
{
    uint8 IIR, temp, i;
    
    OS_ENTER_CRITICAL();
    while(((IIR = U0IIR) & 0x01) == 0)
    {                                                   /* 有中断未处理完 */
        switch (IIR & 0x0e)
        {
            case 0x02:                                  /* THRE中断    */
                for (i = 0; i < UART0_FIFO_LENGTH; i++) /* 向发送FIFO填充数据 */
                {
                    if (QueueRead(&temp, UART0SendBuf) == QUEUE_OK)
                    {
                        U0THR = temp;
                    }
                    else
                    {
                        U0IER = U0IER & (~0x02);        /* 队列空,则禁止发送中断 */
                    }
                }
                break;
            case 0x04:                                  /* 接收数据可用 */
                OSSemPost(Uart0Sem);  /* 通知接收任务 */3处
                U0IER = U0IER & (~0x01);                /* 禁止接收及字符超时中断 */
                break;
            case 0x06:                                  /* 接收线状态   */
                temp = U0LSR;
                break;
            case 0x0c:                                  /* 字符超时指示 */
                OSSemPost(Uart0Sem);                    /* 通知接收任务 */
                U0IER = U0IER & (~0x01);                /* 禁止接收及字符超时中断 */
                break;
            default :
                break;
        }
    }
    VICVectAddr = 0;            // 通知中断控制器中断结束
    OS_EXIT_CRITICAL();
}



在1处有关中断
OS_ENTER_CRITICAL();
在2处又挂起等待中断发信息,中断都 关了还能等中断3处发信息???
不知所以???


OS_ENTER_CRITICAL();是这样定义的:
case 0x02:                      /* 关中断函数OS_ENTER_CRITICAL(),参考os_cpu.h文件 */
            __asm
            {
                MRS     R0, SPSR
                ORR     R0, R0, #NoInt
                MSR     SPSR_c, R0
            }
            OsEnterSum++;
            break;


1: 2处,上面一条不是允许接收中断么? 2: 用仿真器调试能下来吗? 3: re这个问题以前大家讨论过,周工也给了详细解答。请你找来看看。 4: 看了以前的贴子,还是有问题john1225cn兄:
看了以前你发的贴子,有关于此的讨论,但是最后我还没有看懂,最后一位高手如此回答:

调用函数OSSemPend()后,进行任务调度,进入别的任务中,总有一个任务的中断是开着的。所以就可以进入中断服务程序了。”

什么是总有一个任务是开着的,开中断不是可以用OS_EXIT_CRITICAL()完成吗?
OS_ENTER_CRITICAL()


OS_EXIT_CRITICAL()
实现的目的就是不让中间的任务进入其他的中断,如果又进入其他的中断任务实现OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()的目的又是什么????

请john1225cn兄帮忙回答一下! 5: re每个任务有自己的状态寄存器。

在任务中调用关中断,就是关闭本任务的中断,在本任务执行的时候不准中断。

但是当其他任务执行时,还是可以发生中断。 6: john1225cn兄:状态寄存器应该只有一个吧?john1225cn兄:
    状态寄存器数量是1个,但是所有工作模式共享CPSR,其他的SPSR只是在工作模式切换时保存CPSR;所以我的理解是如果所有的任务在用户模式则状态寄存器只有一个CPSR;
    因在ZLG的开发板中实现OS_ENTER_CRITICAL() 是通过SWI软中断完成 的,所以在OS_ENTER_CRITICAL() 中只修改了SPSR,软中断返回后还给SPSR,如以下:

OS_ENTER_CRITICAL();是这样定义的:
case 0x02:                      /* 关中断函数OS_ENTER_CRITICAL(),参考os_cpu.h文件 */
            __asm
            {
                MRS     R0, SPSR
                ORR     R0, R0, #NoInt
                MSR     SPSR_c, R0
            }
            OsEnterSum++;
            break;

另外如下的代码:

uint8 UART0Getch(void)
{
    uint8 err;

    OS_ENTER_CRITICAL();//1处
    while ((U0LSR & 0x00000001) == 0)
    {                                           /* 没有收到数据 */
        U0IER = U0IER | 0x01;                   /* 允许接收中断 */2处
        OSSemPend(Uart0Sem, 0, &err);           /* 等待接收数据 */
    }
    err = U0RBR;                                /* 读取收到的数据 */
    OS_EXIT_CRITICAL();
    return err;
}

在1处是关IRQ中断,在2外只是开了串口中断,那么此时IRQ中断是关闭的,开中断还有什么意义?
如果按照john1225cn兄所说的在任务中有单独状态寄存器,那么以上应为同一任务,关了中断,在此任务中应该也不会响应中断,那就有可能OSSemPend(Uart0Sem, 0, &err)永远挂着???
不知理解那里出错了???
郁闷中!

7: 请zlg315,john1225cn兄 麻烦回答一下!!!以上问题是否是普遍的问题,麻烦回答一下
8: cloudlily可以这样理解:

串口任务挂了。中断也关了,串口中断开了。串口任务挂了,
然后,另外一个任务task1运行了。task1开始运行的时候,操作系统会全部更新寄存器为task1里原来的状态,包括状态寄存器。在task1运行的时候,状态寄存器则是允许中断的。

因此,就发生了串口中断。 9: 谢谢 john1225cn 兄非常谢谢 john1225cn 兄不厌其烦的解答!
对于中断在其他任务中可以得到响应我已理解了,但是对于以下的代码,

OS_ENTER_CRITICAL()和 OS_EXIT_CRITICAL()是否可以去掉,本来关中断和开中断是为了保护临界代码,现在中间 OSSemPend(Uart0Sem, 0, &err)已挂到其他的任务中,好像开中断和关中断没有什么意义了!



uint8 UART0Getch(void)
{
    uint8 err;

    OS_ENTER_CRITICAL();//1处
    while ((U0LSR & 0x00000001) == 0)
    {                                           /* 没有收到数据 */
        U0IER = U0IER | 0x01;                   /* 允许接收中断 */
        OSSemPend(Uart0Sem, 0, &err);           /* 等待接收数据 */2处
    }
    err = U0RBR;                                /* 读取收到的数据 */
    OS_EXIT_CRITICAL();
    return err;
}
10: 这个问题我查了以前的讨这个问题我查了以前的讨论,好像没有一个真正的结果,不知是否ZLG的模块代码有问题?
请高手指点! 11: 1存在对模块寄存器的读写,而且读写内容会对结果发生改变,所以禁止中断,意图是保证接受数据的流程只能是:1.读取线状态,如果没有数据进来,则任务挂起,等待信号量 2.如果已经有数据进来在getch之前,则直接读数据。

中断的意图只是保证函数只能按照这两种意图发生,因为实时系统,确定程序以已知的行为发生动作是很重要的,不能存在不确定性。

但是不可否认,接口函数写的比较蹩脚,要知道,它挂起的不是函数,而是调用这个函数的任务;清晰的设计任务不会产生问题,可是很多初学者都在一个任务里面顺序做很多事情,然后心血来潮写个别的任务,操作系统多任务还是强调任务之间耦合关系的。

这个函数最简单的改法就是把信号量取改为限时:OSSemPend(Uart0Sem, 0, &err);  0改为确定时间。
这样可以防止多种中断通知事件的时候,不良的任务分配带来错误运行。

当然,大家也可以自己写串口接收函数,简单而且高效,毕竟不同的项目是不同的用法,通用函数当然不可能最优。 

共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]