STM32 - FreeRTOS xQueue 接收不完整的数组

Posted

技术标签:

【中文标题】STM32 - FreeRTOS xQueue 接收不完整的数组【英文标题】:STM32 - FreeRTOS xQueue receiving incomplete array 【发布时间】:2018-06-05 06:14:52 【问题描述】:

我无法在 FreeRTOS v8 中实现 xQueue。

该板基于STM32F4,我正在尝试将数据从ISR(串行)发送到主线程。

唯一的问题是不是所有的数据都在主线程上接收到。我在发送之前检查了缓冲区,它已经完成了。在主线程上,无论我发送多少字符,我总是收到缓冲区的前 5 个值。

缓冲区的结构体(我试过用[10]的缓冲区,结果是一样的):

typedef struct SerialBuffer

    uint8_t Buffer[100];
 SerialBuffer;

队列的创建:

xQueueSerialDataReceived= xQueueCreate( 10, sizeof( SerialBuffer * ) );

在 SerialPort 接收处理程序上:

SerialBuffer SerialBufferRec;

static int8_t CDC_Receive_FS (uint8_t *Buf, uint32_t *Len)

    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    uint32_t length = *Len -1;
    //Copy the buffer
    for(int i =0;i<100;i++)
    
        if(i<=length)SerialBufferRec.Buffer[i]=Buf[i];
        else SerialBufferRec.Buffer[i]=0;
    

xQueueSendFromISR(xQueueSerialDataReceived,(void *)&SerialBufferRec,&xHigherPriorityTaskWoken);

    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );

    return (USBD_OK);

关于主要任务:

SerialBuffer SerialBufferReceived;


void ReceiveAndSendSerialData()


if(uxQueueMessagesWaitingFromISR(xQueueSerialDataReceived)>0)
            xQueueReceive(xQueueSerialDataReceived,&SerialBufferReceived,1);
        if(SerialBufferReceived.Buffer[0] != 0)
        
           ...
        


我试过从一个Task发送到另一个Task,没有使用ISR,结果是一样的!

编辑:

解释CDC_Receive_FS (uint8_t *Buf, uint32_t *Len)

如果我从 PC 发送字符串“abcdefg”,*Buf 将是:

Buf[0]='a' ... until Buf[6]='g' 

*Len 将是一个 uint8_t,其值为 7

所以,for(int i =0;i&lt;100;i++) 只是为了确保 SerialBufferRec.Buffer 的所有 100 个位置都将被覆盖。如果它小于接收到的缓冲区的长度,则复制接收到的缓冲区,否则用零填充。它还有助于清空数组中的最后一条消息。

在调用xQueueSendFromISR 之前的SerialBufferRec 将是:

SerialBufferRec.Buffer[0]='a'
...
SerialBufferRec.Buffer[6]='g'
SerialBufferRec.Buffer[7]=0
...
SerialBufferRec.Buffer[99]=0

接收任务上的SerialBufferRecived 像这样到达(缺少“f”和“g”):

SerialBufferRec.Buffer[0]='a'
...
SerialBufferRec.Buffer[4]='e'
SerialBufferRec.Buffer[5]=0
...
SerialBufferRec.Buffer[99]=0

【问题讨论】:

从您提供的内容中不知道如何调用CDC_Receive_FS(...),特别是在作为参数传递之前如何创建和填充uint8_t *Buf 嗨 ryyker,CDC_Receive_FS() 是串行的事件处理程序,当我从 PC 向开发板发送数据时,会触发此方法。我创建了一个全局变量,只使用*Buf 来提供SerialBufferRec,它将通过队列发送。在xQueueSendFromISR 之前添加一个断点,我可以检查SerialBufferRec 是否完整。 您已经创建了一个SerialBuffer 指针队列。尝试将xQueueCreate( 10, sizeof( SerialBuffer * ) ); 更改为xQueueCreate( 10, sizeof( SerialBuffer) ); 我仍然看不到作为参数传递的变量是如何创建的。我可以看到您将它作为指针传递,这是适当的,但我不知道它是被创建为 char buffer[100]; 还是 char *buffer;。如果是第二个,它是用内存初始化的吗?在您的代码示例中显示这些对于其他人提供任何有用反馈的能力至关重要。 除了@tgregory 注释,xQueueSerialDataReceived= xQueueCreate( 10, sizeof( SerialBuffer * ) ); 中的第一个参数应该是100,不是吗?例如。 xQueueSerialDataReceived= xQueueCreate( 100, sizeof( SerialBuffer ) ); 【参考方案1】:

好吧,重构代码,现在它可以工作了。

我不知道是什么错误,还是缺少某些东西。

我在这里发布我的代码是如何结束的,以帮助将来的人。

感谢@tgregory 和@ryyker 的努力!

创建了一个共享结构(customEnum.h):

typedef struct

    char Buffer[100];
 SerialBuffer;

在主任务中:

xQueueSerialDataReceived= xQueueCreate( 2, sizeof( SerialBuffer) );

if(uxQueueMessagesWaitingFromISR(xQueueSerialDataReceived)>0)

    xQueueReceive(xQueueSerialDataReceived,&(SerialBufferReceived),1);
    ...

在 ISR 中:

static int8_t CDC_Receive_FS (uint8_t *Buf, uint32_t *Len)

    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    uint32_t length = *Len -1;
    //Copy the buffer
    for(int i =0;i<100;i++)
    
        if(i<=length)SerialBufferRec.Buffer[i]=Buf[i];
        else SerialBufferRec.Buffer[i]=0;
    
    xQueueSendFromISR(xQueueSerialDataReceived,(void *)&SerialBufferRec,&xHigherPriorityTaskWoken);
if(xHigherPriorityTaskWoken)portYIELD_FROM_ISR( xHigherPriorityTaskWoken );

    return (USBD_OK);

我从 PC 发送了一个 99 个字符的字符,并在主线程上完美地接收到了所有字符。

【讨论】:

【参考方案2】:

...根据原始帖子中的新信息,以前的内容因不相关而被删除。

编辑:基于 OP 的新内容,并取决于以下功能的工作方式:

xQueueSendFromISR(xQueueSerialDataReceived,(void *)&SerialBufferRec,&xHigherPriorityTaskWoken);

基于示例at FreeRTOS regarding usage of xQueueSendFromISR

看来,不是将 100 个元素打包到您在循环之外传递的参数中,而是应该在循环内每次迭代只传递 1 个元素:

void vBufferISR( void )

char cIn;
BaseType_t xHigherPriorityTaskWoken;

    /* We have not woken a task at the start of the ISR. */
    xHigherPriorityTaskWoken = pdFALSE;

    /* Loop until the buffer is empty. */
    do
    
        /* Obtain a byte from the buffer. */
        cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );

        /* Post the byte. */
        xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );

     while( portINPUT_BYTE( BUFFER_COUNT ) );

    /* Now the buffer is empty we can switch context if necessary. */
    if( xHigherPriorityTaskWoken )
    
        /* Actual macro used here is port specific. */
        taskYIELD_FROM_ISR ();
    

然后,在您的代码(缩写描述)中,这将转换为一次发送一个字节: (注意,为简洁起见,我将Buf[i] 的赋值简称为SerialBufferRec.Buffer[i]

...
char cIn;
for(int i =0;i<100;i++)

      xQueueSendFromISR(xQueueSerialDataReceived,&Buf[i],&xHigherPriorityTaskWoken);


【讨论】:

我更新了问题,添加了 *Buf 的含义!如果您需要更多信息,请告诉我。别忘了我不认为CDC_Received_FS() 有问题,因为我尝试在一个任务到另一个任务中使用xQueueSend,但问题仍然存在! @MatheusStumpf - 查看我的编辑。我认为您应该查看我放入 FreeRTOS 的链接中的示例,(大部分相关部分都包含在我的编辑中) 我明天会测试这个,但我担心如果在 i

以上是关于STM32 - FreeRTOS xQueue 接收不完整的数组的主要内容,如果未能解决你的问题,请参考以下文章

stm32 freertos 中回调函数需要做个任务么

STM32 FreeRTOS 与 LibOpenCM3

FREERTOS移植STM32F407

FREERTOS移植STM32F407

免费教程STM32MP157之FreeRTOS系统篇2:FreeRTOS 互斥信号量

stm32中跑freertos,请问在该板子上能运用fopen()之类的C库函数吗?