UCOSIII_消息队列-消息传递实验分析

版权声明:转载注明出处 https://blog.csdn.net/weixin_42108004/article/details/82871055

实验内容:

创建4个任务:

static  void  AppTaskStart(void *p_arg);
static  void  main_task(void *p_arg);
static  void  Keyprocess_task    (void *p_arg);
static  void  msgdis_task    (void *p_arg);
两个消息队列:

static  OS_Q     Key_Msg;
static  OS_Q     Data_Msg;

一个软件定时器:

static  OS_TMR      tmr1; 

AppTaskStart用于创建其他三个任务。

main_task 负责按键检测,并将测得按键值传入消息队列Key_Msg,同时LED绿灯闪烁和检测消息队列Data_Msg的总容量和剩余容量。

Keyprocess_task  根据不同的按键值做出相应的处理内容,其中KEY1按键BLUE灯翻转,KEY2按键RED灯翻转。

msgdis_task    用于在LCD上显示回调函数执行的次数。回调函数执行的次数会发送到消息队列Data_Msg。

关键代码:

任务优先级:

#define  APP_TASK_START_PRIO                        3
#define  APP_MAIN_TASK_PRIO                                                    4
#define  APP_KEYPROCESS_TASK_PRIO                                        5
#define  APP_MSGDIS_TASK_PRIO                                                6

static  void  AppTaskStart (void *p_arg)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;
    OS_ERR      err;
        CPU_SR_ALLOC();  

   (void)p_arg;

    BSP_Init();                                                 /* Initialize BSP functions                             */
    CPU_Init();


    cpu_clk_freq = BSP_CPU_ClkFreq();                           /* Determine SysTick reference freq.  72000000Hz                  */
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;        /* Determine nbr SysTick increments     72000                */
    OS_CPU_SysTickInit(cnts);      //默认时间节拍100ms                             /* Init uC/OS periodic time src (SysTick).              */
  
//            OSSchedRoundRobinCfg(DEF_ENABLED,10,&err);//设置一个时间片10ms
    
        Mem_Init();                                                 /* Initialize Memory Management Module                  */

#if OS_CFG_STAT_TASK_EN > 0u
    OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

    CPU_IntDisMeasMaxCurReset();

#if (APP_CFG_SERIAL_EN == DEF_ENABLED)
    BSP_Ser_Init(115200);                                       /* Enable Serial Interface                              */
#endif
        OS_CRITICAL_ENTER();    //进入临界区
        //创建 Key_Msg 消息队列
        OSQCreate (&Key_Msg, "Key Msg", KEY_MSG_MAX_SIZE, &err);
        
        //创建 Key_Msg 消息队列
        OSQCreate (&Data_Msg, "Data Msg", DATA_MSG_MAX_SIZE, &err);
        
        //创建定时器任务1,周期模式
        OSTmrCreate ( (OS_TMR      *)&tmr1 ,
                  (CPU_CHAR    *)"tmr1",
                   (OS_TICK       )0,
                   (OS_TICK         )5,                 /*定时器定时周期50ms*/
                   (OS_OPT         )OS_OPT_TMR_PERIODIC,
                   (OS_TMR_CALLBACK_PTR    )tmr1_callback,
                   (void      *)0,
                   (OS_ERR    *)&err);

        //创建main_task
    OSTaskCreate((OS_TCB     *)&MainTaskTCB,                /* Create the start task                                */
                 (CPU_CHAR   *)"main task",
                 (OS_TASK_PTR ) main_task,
                 (void       *) 0,
                 (OS_PRIO     ) APP_MAIN_TASK_PRIO,
                 (CPU_STK    *)&MainTaskStk[0],
                 (CPU_STK_SIZE) APP_MAIN_TASK_STK_SIZE / 10,
                 (CPU_STK_SIZE) APP_MAIN_TASK_STK_SIZE,
                 (OS_MSG_QTY  ) 0u,
                 (OS_TICK     ) 0u,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_SAVE_FP),
                 (OS_ERR     *)&err);
                        
        //创建Keyprocess_task
    OSTaskCreate((OS_TCB     *)&KeyProsessTCB,                /* Create the start task                                */
                 (CPU_CHAR   *)"Keyprocess task",
                 (OS_TASK_PTR ) Keyprocess_task,
                 (void       *) 0,
                 (OS_PRIO     ) APP_KEYPROCESS_TASK_PRIO,
                 (CPU_STK    *)&KeyProsessStk[0],
                 (CPU_STK_SIZE) APP_KEYPROCESS_TASK_STK_SIZE / 10,
                 (CPU_STK_SIZE) APP_KEYPROCESS_TASK_STK_SIZE,
                 (OS_MSG_QTY  ) 0u,
                 (OS_TICK     ) 0u,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_SAVE_FP),
                 (OS_ERR     *)&err);
                                 
        //创建msgdis_task
    OSTaskCreate((OS_TCB     *)&MsgDisTCB,                /* Create the start task                                */
                 (CPU_CHAR   *)"msgdis task",
                 (OS_TASK_PTR ) msgdis_task,
                 (void       *) 0,
                 (OS_PRIO     ) APP_MSGDIS_TASK_PRIO,
                 (CPU_STK    *)&MsgDisStk[0],
                 (CPU_STK_SIZE) APP_MSGDIS_TASK_STK_SIZE / 10,
                 (CPU_STK_SIZE) APP_MSGDIS_TASK_STK_SIZE,
                 (OS_MSG_QTY  ) 0u,
                 (OS_TICK     ) 0u,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_SAVE_FP),
                 (OS_ERR     *)&err);
                                                                                          
        OS_CRITICAL_EXIT();    //退出临界区            
        OSTmrStart (&tmr1, &err);                                                                                    /*开启定时器,开始调试时忘记开启,找了好久*/                                 
      OSTaskDel(&AppTaskStartTCB, &err);  //删除起始任务自身                          
}

static  void  main_task (void *p_arg)
{
        uint8_t  time0 =0, key_num ;
    OS_ERR err;
   (void)p_arg;
        
        while(1)
        {
            key_num = 0;        /***此处必须将按键值清零,因为发送到消息队列的值是用指针,不清零总会用上次循环的按键的值***/
            if(Key_Scan(KEY1_GPIO_PORT ,KEY1_GPIO_PIN) == KEY_ON)           /*检测按键值*/
            {
                key_num = 1;
                printf("\nKEY%d按下\n",key_num);    
            }
            else if(Key_Scan(KEY2_GPIO_PORT ,KEY2_GPIO_PIN) == KEY_ON)
            {
                key_num = 2;
                printf("\nKEY%d按下\n",key_num);    
            }            
            if(key_num)
            {
                OSQPost ( &Key_Msg,(void *) &key_num,(OS_MSG_SIZE)1, OS_OPT_POST_FIFO, &err);        /*发送按键值给消息队列*/
                
            }
            time0 ++;
            if(time0 % 10 == 0)
            Check_msg_q();                
            
            if(time0 == 100)    
            {
                LED_GRE_TOGGLE;
                time0 = 0;
            }

            OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_STRICT,&err);           //延时10ms,用来低优先级的任务调度
                        
        }
}

/*

*brief按键处理函数

*/

static  void  Keyprocess_task    (void *p_arg)
{      
    OS_ERR err;
        uint8_t *key_val;
      OS_MSG_SIZE  msg_size;
    printf("进入按键处理任务\n");
        while(1)
        {
            key_val = OSQPend (&Key_Msg, 0, OS_OPT_PEND_BLOCKING, &msg_size, 0,&err);
            switch (*key_val)
            {
                case 1: 
                {
                    LED_BLU_TOGGLE;
                    break ;
                }
                case 2:
                {
                    LED_RED_TOGGLE;
                    break ;
                }
                default :  
                {                    
                    printf("进入默认情况%d\n",*key_val);
                    break;
                }
            }
            OSTimeDlyHMSM(0,0,0,100,OS_OPT_TIME_HMSM_STRICT,&err); //延时10ms
        }
}

void  tmr1_callback(void *p_tmr, void *p_arg)
{        
        static uint16_t exu_time;    /******************次数必须用静态变量,静态变量申明时自动初始化为0,每再次执行回调函数时仍然可以保存上次的值*******************/
      OS_ERR err;
        exu_time ++;
        printf("进入回调函数\n");
        OSQPost (&Data_Msg, (uint16_t *)&exu_time , 2, OS_OPT_POST_FIFO, &err);/*当消息队列慢时则将定时器停止,由于向消息队列发送次数数据与请求消息队列的数据同时在进行,所以应该发送速度大于请求速度,定时器才会停止*/
        if(err != OS_ERR_NONE)
        {
            OSTmrStop ((OS_TMR  *)&tmr1,
                                         (OS_OPT   ) OS_OPT_TMR_NONE,
                                         (void    *)0,
                                         (OS_ERR  *)&err);
            printf("定时器1停止\n");
      }
}

static  void  msgdis_task    (void *p_arg)
{
    OS_ERR err;
        uint8_t *receive_data;
      OS_MSG_SIZE  msg_size;
    
        while(1)
        {
            receive_data = OSQPend (&Data_Msg, 0, OS_OPT_PEND_BLOCKING, &msg_size, 0,&err);
        
            LCD_SetColors(RED,BLACK);        
            sprintf(dispBuff,"定时器1运行次数%d ",*receive_data);
            LCD_ClearLine(LINE(1));                                                                                    /* 清除单行文字 */                
            ILI9341_DispStringLine_EN_CH(LINE(1),dispBuff);            
        
            OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); /*延时1s,由于定时器周期50ms这里延时1s才能保证可以消息队列慢来停止定时器*/
        }
}

oid Check_msg_q(void)                                       /*检测消息队列剩余容量*/
{
    uint8_t max_msg, remain_msg;
    CPU_SR_ALLOC();     

    OS_CRITICAL_ENTER();                                                                                //进入临界区

    max_msg = Data_Msg.MsgQ.NbrEntriesSize ;
    sprintf(dispBuff,"max_msg = %d",max_msg);    
    LCD_SetColors(RED,BLACK);    
    LCD_ClearLine(LINE(2));                                                                            /* 清除单行文字 */    
    ILI9341_DispStringLine_EN_CH(LINE(2),dispBuff);    
    
    remain_msg = Data_Msg.MsgQ.NbrEntriesSize - Data_Msg.MsgQ.NbrEntries;    /* 用总容量减去已经使用的容量 */
    sprintf(dispBuff,"remain_msg = %d",remain_msg);    
    LCD_SetColors(RED,BLACK);    
    LCD_ClearLine(LINE(3));                                                                            /* 清除单行文字 */    
    ILI9341_DispStringLine_EN_CH(LINE(3),dispBuff);    
    
    OS_CRITICAL_EXIT();    //退出临界区        
}

猜你喜欢

转载自blog.csdn.net/weixin_42108004/article/details/82871055