当前位置:   article > 正文

UCOS-II 队列的建立过程_uscosii同一接收任务能创建2个队列吗?

uscosii同一接收任务能创建2个队列吗?

本文主要是对UCOS-II中队列的建立过程进行分析及总结。

第一步:OS操作系统会在初始化函数OSInit中对事件进行初始化。

第二步:OS操作系统会在初始化函数OSInit中对队列进行初始化。

第一步和第二步初始化的结果如下图所示,图中只是两个结构体的架构图,其中有些细节需要指出:

1)在初始化完成后,事件结构体中OSEventType为未使用类型。

2)在初始化完成后,事件结构体中OSEventPtr指向下一个事件结构体(该指针代表事件的类型,这里指向下一个指针只是为了临时放置,以便于得到下一个空闲的事件结构体,注意该指针的类型为空指针)

第三步:系统在需要的地方创建消息队列,函数如下所示,通过OSQCreate函数来创建队列。

队列如何工作?

在创建完成队列之后,我们下面来看下,消息队列是如何工作的。由下面的代码可以看出,在OS系统中,建立的是一个环形队列。

  1. //数据存入队列
  2. if (pq->OSQEntries >= pq->OSQSize)
  3. {
  4. OS_EXIT_CRITICAL();
  5. return (OS_ERR_Q_FULL);
  6. }
  7. *pq->OSQIn++ = pmsg; /* Insert message into queue */
  8. pq->OSQEntries++; /* Update the nbr of entries in the queue */
  9. if (pq->OSQIn == pq->OSQEnd)
  10. {
  11. pq->OSQIn = pq->OSQStart;
  12. }
  13. //数据读出队列
  14. if (pq->OSQEntries > 0u)
  15. {
  16. pmsg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */
  17. pq->OSQEntries--; /* Update the number of entries in the queue */
  18. if (pq->OSQOut == pq->OSQEnd) /* Wrap OUT pointer if we are at the end of the queue*/
  19. {
  20. pq->OSQOut = pq->OSQStart;
  21. }
  22. }

为什么在中断中能使用OSQPost函数,但是不能使用OSQPend函数?

首先我们知道,当执行任务调度时,实际上是触发了PendSV中断,如果在任务中执行任务调度,那么ARM将直接跳转到PendSV中断去执行。但是如果在中断中触发了PendSV中断,由于PendSV中断的中断优先级设置的较低,所以系统会等所有的中断执行完了后,再去执行PendSV中断。

那么为什么不能再中断中调用Pend函数呢?我们先看下Pend函数的源码,源码如下所示,注意观察到如果在执行任务调度前,函数没有被返回的话,那么系统将执行任务调度。

如果是在中断中执行任务调度,那么系统不会立即跳转到最高优先级的任务,而是等待函数执行完了再去跳转,那么在该函数中,执行了任务调度后所执行的函数就具有具体意义了。

  1. void *OSQPend (OS_EVENT *pevent,
  2. INT32U timeout,
  3. INT8U *perr)
  4. {
  5. void *pmsg;
  6. OS_Q *pq;
  7. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  8. OS_CPU_SR cpu_sr = 0u;
  9. #endif
  10. #ifdef OS_SAFETY_CRITICAL
  11. if (perr == (INT8U *)0)
  12. {
  13. OS_SAFETY_CRITICAL_EXCEPTION();
  14. }
  15. #endif
  16. #if OS_ARG_CHK_EN > 0u
  17. if (pevent == (OS_EVENT *)0)
  18. { /* Validate 'pevent' */
  19. *perr = OS_ERR_PEVENT_NULL;
  20. return ((void *)0);
  21. }
  22. #endif
  23. if (pevent->OSEventType != OS_EVENT_TYPE_Q)
  24. { /* Validate event block type */
  25. *perr = OS_ERR_EVENT_TYPE;
  26. return ((void *)0);
  27. }
  28. if (OSIntNesting > 0u)
  29. { /* See if called from ISR ... */
  30. *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
  31. return ((void *)0);
  32. }
  33. if (OSLockNesting > 0u)
  34. { /* See if called with scheduler locked ... */
  35. *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
  36. return ((void *)0);
  37. }
  38. OS_ENTER_CRITICAL();
  39. pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */
  40. if (pq->OSQEntries > 0u)
  41. { */
  42. pmsg = *pq->OSQOut++;
  43. pq->OSQEntries--;
  44. if (pq->OSQOut == pq->OSQEnd)
  45. {
  46. pq->OSQOut = pq->OSQStart;
  47. }
  48. OS_EXIT_CRITICAL();
  49. *perr = OS_ERR_NONE;
  50. return (pmsg);
  51. }
  52. OSTCBCur->OSTCBStat |= OS_STAT_Q;
  53. OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
  54. OSTCBCur->OSTCBDly = timeout;
  55. OS_EventTaskWait(pevent);
  56. OS_EXIT_CRITICAL();
  57. OS_Sched();
  58. OS_ENTER_CRITICAL();
  59. switch (OSTCBCur->OSTCBStatPend)
  60. { /* See if we timed-out or aborted */
  61. case OS_STAT_PEND_OK:
  62. pmsg = OSTCBCur->OSTCBMsg;
  63. *perr = OS_ERR_NONE;
  64. break;
  65. case OS_STAT_PEND_ABORT:
  66. pmsg = (void *)0;
  67. *perr = OS_ERR_PEND_ABORT;
  68. break;
  69. case OS_STAT_PEND_TO:
  70. default:
  71. OS_EventTaskRemove(OSTCBCur, pevent);
  72. pmsg = (void *)0;
  73. *perr = OS_ERR_TIMEOUT;
  74. break;
  75. }
  76. OSTCBCur->OSTCBStat = OS_STAT_RDY;
  77. OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
  78. OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
  79. #if (OS_EVENT_MULTI_EN > 0u)
  80. OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
  81. #endif
  82. OSTCBCur->OSTCBMsg = (void *)0;
  83. OS_EXIT_CRITICAL();
  84. return (pmsg);
  85. }

 

 

附录:重要结构体的定义如下所示。

  1. //函数调用:
  2. can1_recv_unit.q_Can_Msg = OSQCreate(&(can1_recv_unit.MsgGrp[0]), CAN1_MSG_GRP_NUM); 
  3. //其中结构体的定义如下:   
  4. //CAN1_MSG_GRP_NUM == 30
  5. typedef struct
  6. {
  7. OS_EVENT *q_Can_Msg;
  8. void *MsgGrp[CAN1_MSG_GRP_NUM];
  9. can_message_t storage[CAN1_MSG_GRP_NUM];
  10. u8 mbox_windex;
  11. can_message_t *prmsg;
  12. }can1_recv_unit_t;
  13. typedef struct os_event
  14. {
  15. INT8U OSEventType; /* Type of event control block (see OS_EVENT_TYPE_xxxx) */
  16. void *OSEventPtr; /* Pointer to message or queue structure */
  17. INT16U OSEventCnt; /* Semaphore Count (not used if other EVENT type) */
  18. OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
  19. OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE];/* List of tasks waiting for event to occur */
  20. } OS_EVENT;
  21. typedef struct os_q
  22. {
  23. struct os_q *OSQPtr; // Link to next queue control block in listof free blocks
  24. void **OSQStart; // Pointer to start of queue data
  25. void **OSQEnd; // Pointer to end of queue data
  26. void **OSQIn; // Pointer to where next message will be inserted in the Q
  27. void **OSQOut; // Pointer to where next message will be extracted from the Q
  28. INT16U OSQSize; //Size of queue (maximum number of entries)
  29. INT16U OSQEntries; /* Current number of entries in the queue */
  30. } OS_Q;

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/50539?site
推荐阅读
相关标签
  

闽ICP备14008679号