【问题标题】:Reading from queue delivers always wrong value从队列中读取总是提供错误的值
【发布时间】:2012-03-28 09:07:40
【问题描述】:

这是我的问题:

我正在使用带有 Cortex-M3 MCU 的 FreeRTOS。我有一个名为 EXTI15_10 的 ISR,它 在引脚 EXTI_Line10、EXTI_Line11..etc 的上升沿期间触发。 在 ISR 中,我在离开 ISR 之前将变量“状态”设置为某个指定值 我将变量状态放入队列并将其发送到我的线程。效果很好。

线程周期性调用,调用函数 xQueuePeek() 从队列中获取项目。注意xQueuePeek() 从队列中获取项目而不将其从队列中删除。 这也很好,但我只收到一次正确的值。 这意味着,中断产生,状态被设置为一个值并放入 队列,线程读取正确的值。但是接下来的所有中断 正确设置状态(我在将项目放入队列之前检查了它),但我的 线程总是读取旧值。我这里的编译器有问题吗 优化和易变? xQueueSendFromISR(),期望作为第二个参数 一个 const void * 而不是 volatile void *。我在这里做错了什么?

ISR:

void EXTI15_10_IRQHandler()
{   
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    int status;

    if (EXTI_GetITStatus(EXTI_Line10))
        status = 100;
    else if (EXTI_GetITStatus(EXTI_Line11))
        status = 200
    else if (EXTI_GetITStatus(EXTI_Line12))
        status = 300;
    else if (EXTI_GetITStatus(EXTI_Line13))
        status = 400;
    else if (EXTI_GetITStatus(EXTI_Line14))
        status = 500;
    else if (EXTI_GetITStatus(EXTI_Line15))
        status = 600;

    // Clear the pending interrupt bits
    EXTI_ClearITPendingBit(EXTI_Lines15_10);

    xQueueSendFromISR(queue, &status, &xHigherPriorityTaskWoken);
    portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}

线程:

static void thread_xy()
{
    portTickType xLastExecutionTime;

    xLastExecutionTime = xTaskGetTickCount();
    int status_from_queue = 0;

    for (;;) {
        xLastExecutionTime = xTaskGetTickCount();
        vTaskDelayUntil(&xLastExecutionTime, CHECK_AND_ENABLE_LEDS_DELAY);

        if (queue != 0) {
            if (xQueuePeek(queue, &status_from_queue, portMAX_DELAY))
                // Received item from queue...
                print("Status from queue = %d\n", status_from_queue);
        }
    }
}

【问题讨论】:

  • 如果你只偷看而不删除,那么你只会得到一次正确的值。你也有一场激烈的比赛,你不能在不禁用中断的情况下偷看队列。
  • 除非我理解错了,它应该每次都读取相同的状态,因为它每次都读取第一项?由于您实际上从未从队列中删除任何内容,因此 xQueuePeek 始终会读取第一项,因此您将始终获得第一个状态?

标签: c


【解决方案1】:

如果你只是偷看队列,那么,是的,你总是会得到相同的值,只是因为你把它留在那里。队列是一种先进先出的数据结构,但为了获得队列中的第二个值,您通常必须删除第一个值。

考虑以下顺序:

initial state            queue = { }
interrupt adds 7         queue = { 7 }
application peeks (7)    queue = { 7 }
interrupt adds 42        queue = { 7, 42 }
application peeks (7)    queue = { 7, 42 }
interrupt adds 314159    queue = { 7, 42, 314159 }
application peeks (7)    queue = { 7, 42, 314159 }

如果你想从队列中提取一个值并使用它,你需要获取它而不是偷看它。否则,队列最终也会被填满。

我还应该提到,这里可能存在竞争条件,很可能会给您带来问题。如果您的应用程序在中断到达时正在修改队列(通过从中获取值),那么您最终会遇到各种麻烦,因为队列将不会处于一致状态。

当队列可能处于不一致状态时,您需要一种方法来停止(或者,更好的是延迟)中断。这可能就像在您的应用程序修改它时禁用中断一样简单(或者,如果您在多处理器系统上,它可能需要更复杂的代码)。

当然,xQueuePeek()(和其他相关的)代码可能已经这样做了,因为您有一个xQueueSendFromISR(),这似乎表明这种保护已经成为队列实现的一部分。我只是把它作为需要注意的事情提出来。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多