OSMboxPend()

本文详细解析了RTOS中消息邮箱的请求与处理流程,包括检查请求有效性、获取消息、设置任务状态、调度任务等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

void  *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif   
    void      *msg;


    if (OSIntNesting > 0) {                           /* See if called from ISR ...                    */
        *err = OS_ERR_PEND_ISR;                       /* ... can't PEND from an ISR                    */
        return ((void *)0);
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
        *err = OS_ERR_PEVENT_NULL;
        return ((void *)0);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {  /* Validate event block type                     */
        *err = OS_ERR_EVENT_TYPE;
        return ((void *)0);
    }
    OS_ENTER_CRITICAL();
    msg = pevent->OSEventPtr;             ;首先将消息邮箱的指针成员(数据缓冲区指针)赋值给局部变量msg
    if (msg != (void *)0) {                          ; 检测是否为空指针,如果不是空指针,就将消息邮箱的指针赋给msg,并
        pevent->OSEventPtr = (void *)0;     ;将err指针指向的值赋于常数OS_NO_ERR,然后把msg即消息邮          
        OS_EXIT_CRITICAL();                      ;箱里的指针返回。
        *err = OS_NO_ERR;
        return (msg);                                 
    }
    OSTCBCur->OSTCBStat |= OS_STAT_MBOX;              ;如果消息邮箱的指针不可用,就将当前任务控制块的
    OSTCBCur->OSTCBDly   = timeout;                              ;表征当前任务状态的成员赋值表示任务由于等待消息邮
    OS_EventTaskWait(pevent);                         ;箱而处于挂起状态,任务等待的时限为timeout
    OS_EXIT_CRITICAL();
    OS_Sched();                                    ;该任务已经挂起,使用调度器进行任务调度。如果中断程序都结束、调度器没有锁定、就绪表中优先级别最高的任务不是当前任务,那么进行任务调度,切换程序;否则,从调度其中返回,不做任务diaod
    OS_ENTER_CRITICAL();
    msg = OSTCBCur->OSTCBMsg;                 ;将当前任务控制块指向消息邮箱的指针又给了局部变量msg
    if (msg != (void *)0) {                             ;如果msg指针有效,则改变任务控制块相应的成员变量,给err指针返回
        OSTCBCur->OSTCBMsg      = (void *)0;         ;无错信息,并返回msg指针,即返回消息邮箱的指针。
        OSTCBCur->OSTCBStat     = OS_STAT_RDY;
        OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;      /* No longer waiting for event                   */
        OS_EXIT_CRITICAL();
        *err                    = OS_NO_ERR;
        return (msg);                                 /* Return the message received                   */
    }
    OS_EventTO(pevent);                               ;任务等待该消息邮箱的时限到
    OS_EXIT_CRITICAL();
    *err = OS_TIMEOUT;                                ;返回超时标志到err指针
    return ((void *)0);                               /* Return a NULL message                         */
}
请求消息邮箱的工作主要有:第一, 检查是在中断服务程序中调用请求消息邮箱,如果是则给err指针返回常数OS_ERR_PEND_ISR,程序返回一个空指针;第二,检查所请求的邮箱是否有效,如果无效,则给err指针返回常数OS_ERR_PEVENT_NULL,程序返回一个空指针;第三,检查所请求的消息邮箱的类型是否为邮箱类型,如果不是,则给err指针返回OS_ERR_EVENT_TYPE,程序返回一个空指针;第四,获得所请求的邮箱指针,若果该指针有效,将消息邮箱中的指针清空(表示已经被获得),然后给err指针返回常数OS_NO_ERR,然后程序返回邮箱的指针;第五,如果获得的邮箱指针无效,就将任务控制块的状态设为等待状态,并告诉任务控制块要等待的时限,然后调用OS_EventTaskWait ,删除掉任务在就绪表中的相应位置,置位任务在事件等待列表中的相应位置;第六,调用OS_Sched()进行任务调度,如果调度成功,则进行任务切换,如果调度条件不满足,又返回到该程序;第七,将任务控块成员OSTCBCur->OSTCBMsg指针值(即邮箱的指针)给了msg指针,如果这个指针不空,将OSTCBCur->OSTCBMsg  清零,任务未就绪状态,给err 指针返回常数OS_NO_ERR,程序返回邮箱指针msg;第八,调用OS_EventTO(pevent);等待时限到,给err指针返回常数OS_TIMEOUT,程序返回一个空指针,程序结束。

void  OS_EventTaskWait (OS_EVENT *pevent)
{
    INT8U  y;


    OSTCBCur->OSTCBEventPtr = pevent;            ;把事件控制块的指针保存在任务控制块成员OSTCBEventPtr里
    y                       = OSTCBCur->OSTCBY;             ;把当前任务从任务就绪表中删除
    OSRdyTbl[y]            &= ~OSTCBCur->OSTCBBitX;
    if (OSRdyTbl[y] == 0x00) {                  
        OSRdyGrp &= ~OSTCBCur->OSTCBBitY;        /* Clear event grp bit if this was only task pending  */
    }
    pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;         ;把当前任务在事件控制块的
    pevent->OSEventGrp                   |= OSTCBCur->OSTCBBitY;                           ;列表中的相应位置位。
}该函数主要完成的工作:第一,把事件控制块的指针保存在等待该事件的任务的任务控制块的成员OSTCBEventPtr 里面;第二,把该任务在任务就绪表中的相应位删除,即该任务处于挂起等待状态,等待消息邮箱的状态;第三,把该任务要等待的事件的事件控制块里的等待任务列表的相应位置位,表示这个任务要等到这个事件的发生。

void  OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
    OS_CPU_SR  cpu_sr;
#endif   
    INT8U      y;


    OS_ENTER_CRITICAL();
    if (OSIntNesting == 0) {                          ;所有的中断服务程序结束并且调度器没有锁定,才进行调度
        if (OSLockNesting == 0) {                     
            y             = OSUnMapTbl[OSRdyGrp];     ;找出任务就绪表中优先级别最高的就绪任务
            OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
            if (OSPrioHighRdy != OSPrioCur) {          ;如果就绪表中的优先级别最高的任务不是当前任务就进行调度
                OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
                OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task      */
#endif
                OSCtxSwCtr++;                          /* Increment context switch counter             */
                OS_TASK_SW();                          /* Perform a context switch                     */
            }
        }                                                      ;如果就绪表中优先级最高的任务就是当前的任务,就不再进行任务调度,从
    }                                                          ;调度器返回。
    OS_EXIT_CRITICAL();
}调度器完成的主要工作有:第一,在所有中断服务结束并且调度器没有被锁定时才进行任务调度;第二,找出任务就绪表中优先级别最高的就绪任务;第三,如果优先级别最高的就绪任务不再是当前任务,就进行任务调度,转去执行优先级别最高的任务,如果就绪表中优先级别最高的任务还是当前任务,那么不进行任务调度,调度其返回到调用它的程序里面。

void  OS_EventTO (OS_EVENT *pevent)
{
    INT8U  y;


    y                      = OSTCBCur->OSTCBY;
    pevent->OSEventTbl[y] &= ~OSTCBCur->OSTCBBitX;
    if (pevent->OSEventTbl[y] == 0x00) {
        pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY;
    }
    OSTCBCur->OSTCBStat     = OS_STAT_RDY;       /* Set status to ready                                */
    OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;     /* No longer waiting for event                        */
};任务等待事件的时限到,删除事件控制块等待任务列表中该任务的相应位,是任务的状态处于就绪状态。

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "includes.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* �������ȼ����� */ #define START_TASK_PRIO 10 #define KEY_TASK_PRIO 11 #define LED_TASK_PRIO 12 /* �����ջ��С */ #define START_TASK_STK_SIZE 128 #define KEY_TASK_STK_SIZE 128 #define LED_TASK_STK_SIZE 128 /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* �����ջ */ OS_STK StartTaskStk[START_TASK_STK_SIZE]; OS_STK KeyTaskStk[KEY_TASK_STK_SIZE]; OS_STK LED_TaskStk[LED_TASK_STK_SIZE]; /* ��Ϣ���� */ OS_EVENT *CMbox; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ void StartTask(void *p_arg); void KeyTask(void *p_arg); void LED_Task(void *p_arg); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ /* ��ʼ��UCOSII */ OSInit(); /* ������Ϣ���� */ CMbox = OSMboxCreate((void *)0); /* ������ʼ���� */ OSTaskCreate(StartTask, (void *)0, &StartTaskStk[START_TASK_STK_SIZE - 1], START_TASK_PRIO); /* ����UCOSII */ OSStart(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* ��ʼ���� - ������������ */ void StartTask(void *p_arg) { // ��������ɨ������ OSTaskCreate(KeyTask, (void *)0, &KeyTaskStk[KEY_TASK_STK_SIZE - 1], KEY_TASK_PRIO); // ����LED�������� OSTaskCreate(LED_Task, (void *)0, &LED_TaskStk[LED_TASK_STK_SIZE - 1], LED_TASK_PRIO); // ɾ����ʼ���� OSTaskDel(OS_PRIO_SELF); } /* ����ɨ������ */ void KeyTask(void *p_arg) { while (1) { // ���KEY1�������������ӵ�PA0�� if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) { HAL_Delay(20); // ���� if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) { OSMboxPost(CMbox, (void *)"left"); // ����������Ϣ while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET); // �ȴ��ͷ� } } // ���KEY2�������������ӵ�PB1�� if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET) { HAL_Delay(20); // ���� if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET) { OSMboxPost(CMbox, (void *)"right"); // ����������Ϣ while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET); // �ȴ��ͷ� } } OSTimeDly(50); // ��ʱ50ms } } /* LED�������� */ void LED_Task(void *p_arg) { uint8_t led_state = 0x01; while (1) { // �ȴ���Ϣ char *msg = (char *)OSMboxPend(CMbox, 0, NULL); if (msg != NULL) { if (strcmp(msg, "left") == 0) { // ���� if (led_state >= 0x80) led_state = 0x01; else led_state <<= 1; } else if (strcmp(msg, "right") == 0) { // ���� if (led_state <= 0x01) led_state = 0x80; else led_state >>= 1; } // ����LED��ʾ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3| GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET); // ȫ��Ϩ�� // ������ӦLED if (led_state & 0x01) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); if (led_state & 0x02) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET); if (led_state & 0x04) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET); if (led_state & 0x08) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET); if (led_state & 0x10) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET); if (led_state & 0x20) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_RESET); if (led_state & 0x40) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET); if (led_state & 0x80) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET); } } } /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */
最新发布
05-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值