嵌入式代码中的事件处理

时间:2008-10-22 05:22:16

标签: embedded event-handling

我想知道嵌入式系统代码中如何使用事件。

主要目的是了解在代码中如何设置/重置事件标志。以及如何识别哪个任务正在使用哪个事件标志以及每个任务设置/重置标志的哪些位。

请提出您的建议或意见。

提前致谢。


(编辑1:从以下答案中的澄清复制而来)

很抱歉没有说明所需的详细信息。实际上我对使用vxworks / Itron / OSEK OS用C语言编写的任何应用程序的分析感兴趣。例如,vxworks中有eventLib库来支持事件处理。我想知道如何利用这样的系统例程来处理任务中的事件。什么是事件标志(是全局/本地......还是什么?),如何设置任何事件标志的位,哪些可以是任务和事件标志之间的可能关系?

任务如何在AND和OR模式下等待多个事件? 我遇到了一个例子,其中下面给出的场景看起来很危险,但为什么?

            Scenarios is ==> *[Task1 : Set(e1), Task2 : Wait(e1) and Set(e2), Task3 : Wait(e2) ]*                                             

我知道一个任务等待的多个事件标志或多个任务之间的循环依赖关系(死锁)是任务事件关系中的危险情况,但是上面的情况如何危险,我没有得到它......请解释一下。

                (Are there any more such scenarios possible in task-event handling which should be reviewed in code ?? ) 

我希望以上信息足够......

7 个答案:

答案 0 :(得分:2)

许多嵌入式系统使用中断服务例程(ISR)来处理事件。您将为给定的“标志”定义ISR,并在处理事件后重置该标志。

例如,假设您有一台执行模拟到数字转换(ADC)的设备。在设备上,您可以使用每次ADC完成转换时触发的ISR,然后在ISR中处理它或通知其他任务数据可用(如果您想通过某些通信协议发送它)。完成后,您将重置ADC标志,以便在下次转换时再次触发。

通常在设备手册中定义了一组ISR。有时它们会提供您可以根据需要处理的通用标志。每次重置导致例程触发的标志。

答案 1 :(得分:1)

这个问题需要提供更多背景信息。嵌入式系统可以使用多种语言,操作系统(包括无操作系统),框架等进行创建。在嵌入式系统中如何创建和处理事件没有任何普遍性,就像事件是如何通用的一样。在计算中创建和处理。

答案 2 :(得分:1)

VxWorks中的eventLib类似于unix中的signal() - 它可以向不同的线程指示发生了什么。如果您需要使用事件传递数据,则可能需要使用消息队列。

事件在发送方和接收方之间是“全局的”。由于每个发送者都指出了事件的目标,因此系统中可以有多个事件掩码,每个发送者/接收者对都有自己的解释。

一个基本的例子:

 #define EVENT1       0x00000001
 #define EVENT2       0x00000002
 #define EVENT3       0x00000004
 ...
 #define EVENT_EXIT   0x80000000

 /* Spawn the event handler task (event receiver) */
 rcvTaskId = taskSpawn("tRcv",priority,0,stackSize,handleEvents,0,0,0,0,0,0,0,0,0,0);
 ...

 /* Receive thread: Loop to receive events */
 STATUS handleEvents(void)
 {
     UINT32 rcvEventMask = 0xFFFFFFFF;

     while(1)
     {
         UINT32 events = 0;

         if (eventReceive(rcvEventMask. EVENTS_WAIT_ANY, WAIT_FOREVER, &events) == OK)
         {
             /* Process events */
             if (events & EVENT1)
                 handleEvent1();
             if (events & EVENT2)
                 handleEvent2();
             ...
             if (events & EVENT_EXIT)
                 break;
         }
     }

     return OK;
 }

事件发件人通常是硬件驱动程序(BSP)或其他线程。当发生期望的动作时,驱动程序构建所有相关事件的掩码并将它们发送到接收器任务。

发件人需要获取接收者的taskID。 taskID可以是全局的,

int RcvTaskID = ERROR;
...
eventSend(RcvTaskID, eventMask);

接收方可以向驱动程序/发送方任务注册,

static int RcvTaskID = ERROR;

void DRIVER_setRcvTaskID(int rcvTaskID)
{
    RcvTaskID = rcvTaskID;
}
...
eventSend(RcvTaskID, eventMask);

或驱动程序/发件人任务可以调用接收器API方法来发送事件(包装器)。

static int RcvTaskID;
void RECV_sendEvents(UINT32 eventMask)
{
    eventSend(RcvTaskID, eventMask);
}

答案 3 :(得分:0)

很抱歉没有说明所需的详细信息。实际上我对使用vxworks / Itron / OSEK OS用C语言编写的任何应用程序的分析感兴趣。 例如,vxworks中有eventLib库来支持事件处理。 我想知道如何利用这样的系统例程来处理任务中的事件。什么是事件标志(是全局/本地......还是什么?),如何设置任何事件标志的位,哪些可以是任务和事件标志之间的可能关系?

我希望以上信息足够......

答案 4 :(得分:0)

如果您询问如何设置,清除和检查代表事件的各个位,此示例可能有所帮助。基本策略是声明一个(通常是全局的)变量,并使用一位来表示每个条件。

unsigned char bit_flags = 0;

现在我们可以将事件分配给位:

#define TIMER_EXPIRED   0x01   // 0000 0001
#define DATA_READY      0x02   // 0000 0010
#define BUFFER_OVERFLOW 0x04   // 0000 0100

我们可以使用按位运算符设置,清除和检查位:

// Bitwise OR: bit_flags | 00000001 sets the first bit.
bit_flags |=  TIMER_EXPIRED;  // Set TIMER_EXPIRED bit.

// Bitwise AND w/complement clears bits: flags & 11111101 clears the 2nd bit.
bit_flags &= ~DATA_READY;     // Clear DATA_READY bit.

// Bitwise AND tests a bit.  The result is BUFFER_OVERFLOW
// if the bit is set, 0 if the bit is clear.
had_ovflow = bit_flags & BUFFER_OVERFLOW;

我们还可以设置或清除位组合:

// Set DATA_READY and BUFFER_OVERFLOW bits.
bit_flags |=  (DATA_READY | BUFFER_OVERFLOW);

您经常会将这些操作视为以宏形式实现:

#define SET_BITS(bits, data)    data |=  (bits)
#define CLEAR_BITS(bits, data)  data &= ~(bits)
#define CHECK_BITS(bits, data)  (data & (bits))

另外,关于中断和中断服务程序的注意事项:它们需要运行 fast ,因此典型的ISR只需设置一个标志,递增计数器或复制一些数据并立即退出。然后你可以检查国旗,并在闲暇时参加活动。您可能想要在ISR中进行冗长或容易出错的活动。

希望这有用!

答案 5 :(得分:0)

在我设计的一系列嵌入式系统中(对于带有~128KB闪存和3.5KB RAM的PIC18Fxx micro),我编写了一个库来处理多达16个定时器,分辨率为1/16秒(由16Hz脉冲输入测量)到CPU)。设置代码以确定是否有任何定时器处于过期状态或任何专用唤醒引脚正在发出信号,如果没有,则休眠直到下一个定时器到期或唤醒输入改变状态。相当简单的代码,虽然我应该回想起来可能已经设计它可以使用多组8个定时器而不是一组16个。

我发现有用的时序例程的一个关键方面是它们大多数不是由中断驱动的;相反,我有一个'方便的轮询'例程,它更新16Hz计数器的定时器。虽然定时器不是通过中断运行有时会感觉很奇怪,但这样做可以避免担心奇数时间发生的中断。如果定时器控制的动作不能在中断内发生(由于堆栈嵌套和其他限制),则无需担心中断中的定时器 - 只需跟踪已经过了多长时间。

答案 6 :(得分:0)

如果您对在嵌入级别使用事件驱动编程感兴趣,那么您应该真正研究QP。它是一个优秀的轻量级框架,如果您获得Miro Samek的“C / C ++中的实用UML状态图”一书,您可以找到从如何处理嵌入式Linux内核(ISR等)中的系统事件到在构建中处理和创建它们的所有内容。 QP作为您的环境。 (Here是示例事件的链接。)