写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。
标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。
点击此处进入学习日记的总目录
2024.04.07:UCOSIII第三十五节:互斥量实验
- 四十九、UCOSIII:互斥量实验
- 1、模拟优先级翻转实验
- 2、模拟优先级翻转实验现象
- 3、互斥量实验
- 4、互斥量实验现象
四十九、UCOSIII:互斥量实验
1、模拟优先级翻转实验
模拟优先级翻转实验是在μC/OS中创建了三个任务与一个二值信号量,任务分别是高优先级任务AppTaskLed3,中优先级任务AppTaskLed2,低优先级任务AppTaskLed1, 用于模拟产生优先级翻转。
低优先级任务在获取信号量的时候,被中优先级打断,中优先级的任务开始执行,因为低优先级还未释放信号量, 那么高优先级任务就无法取得信号量继续运行,此时就发生了优先级翻转,任务在运行中,使用串口打印出相关信息,源码具体如下:
#include <includes.h>
/*
****************************************************************
* LOCAL DEFINES
****************************************************************
*/
OS_SEM TestSem; //信号量
/*
*********************************************************************
* TCB
*********************************************************************
*/
static OS_TCB AppTaskStartTCB;
static OS_TCB AppTaskLed1TCB;
static OS_TCB AppTaskLed2TCB;
static OS_TCB AppTaskLed3TCB;
/*
*************************************************************
* STACKS
*************************************************************
*/
static CPU_STK AppTaskStartStk[APP_TASK_START_STK_SIZE];
static CPU_STK AppTaskLed1Stk [ APP_TASK_LED1_STK_SIZE ];
static CPU_STK AppTaskLed2Stk [ APP_TASK_LED2_STK_SIZE ];
static CPU_STK AppTaskLed3Stk [ APP_TASK_LED3_STK_SIZE ];
/*
*********************************************************
* FUNCTION PROTOTYPES
*********************************************************
*/
static void AppTaskStart (void *p_arg);
static void AppTaskLed1 ( void * p_arg );
static void AppTaskLed2 ( void * p_arg );
static void AppTaskLed3 ( void * p_arg );
int main (void)
{
OS_ERR err;
OSInit(&err); /* Init μC/OS-III. */
OSTaskCreate((OS_TCB *)&AppTaskStartTCB,/* Create the start task*/
(CPU_CHAR *)"App Task Start",
(OS_TASK_PTR ) AppTaskStart,
(void *) 0,
(OS_PRIO ) APP_TASK_START_PRIO,
(CPU_STK *)&AppTaskStartStk[0],
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSStart(&err);
}
static void AppTaskStart (void *p_arg)
{
CPU_INT32U cpu_clk_freq;
CPU_INT32U cnts;
OS_ERR err;
(void)p_arg;
BSP_Init(); /* Initialize BSP functions */
CPU_Init();
cpu_clk_freq = BSP_CPU_ClkFreq();
cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;
OS_CPU_SysTickInit(cnts);
Mem_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err);
#endif
CPU_IntDisMeasMaxCurReset();
/* 创建信号量 TestSem */
OSSemCreate((OS_SEM *)&TestSem, //指向信号量变量的指针
(CPU_CHAR *)"TestSem ", //信号量的名字
(OS_SEM_CTR )1,
//信号量这里是指示事件发生,所以赋值为0,表示事件还没有发生
(OS_ERR *)&err); //错误类型
/* Create the Led1 task */
OSTaskCreate((OS_TCB *)&AppTaskLed1TCB,
(CPU_CHAR *)"App Task Led1",
(OS_TASK_PTR ) AppTaskLed1,
(void *) 0,
(OS_PRIO ) APP_TASK_LED1_PRIO,
(CPU_STK *)&AppTaskLed1Stk[0],
(CPU_STK_SIZE) APP_TASK_LED1_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED1_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
/* Create the Led2 task */
OSTaskCreate((OS_TCB *)&AppTaskLed2TCB,
(CPU_CHAR *)"App Task Led2",
(OS_TASK_PTR ) AppTaskLed2,
(void *) 0,
(OS_PRIO ) APP_TASK_LED2_PRIO,
(CPU_STK *)&AppTaskLed2Stk[0],
(CPU_STK_SIZE) APP_TASK_LED2_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED2_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
/* Create the Led3 task */
OSTaskCreate((OS_TCB *)&AppTaskLed3TCB,
(CPU_CHAR *)"App Task Led3",
(OS_TASK_PTR ) AppTaskLed3,
(void *) 0,
(OS_PRIO ) APP_TASK_LED3_PRIO,
(CPU_STK *)&AppTaskLed3Stk[0],
(CPU_STK_SIZE) APP_TASK_LED3_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED3_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSTaskDel ( & AppTaskStartTCB, & err );
}
/*
***************************************************************
* LED1 TASK
**************************************************************
*/
static void AppTaskLed1 ( void * p_arg )
{
OS_ERR err;
static uint32_t i;
CPU_TS ts_sem_post;
(void)p_arg;
while (DEF_TRUE)
{
printf("AppTaskLed1 获取信号量\n");
//获取二值信号量TestSem,没获取到则一直等待
OSSemPend ((OS_SEM *)&TestSem, //等待该信号量被发布
(OS_TICK )0, //无期限等待
(OS_OPT )OS_OPT_PEND_BLOCKING,
//如果没有信号量可用就等待
(CPU_TS *)&ts_sem_post,
//获取信号量最后一次被发布的时间戳
(OS_ERR *)&err); //返回错误类型
for (i=0; i<600000; i++) //模拟低优先级任务占用信号量
{
OSSched();//发起任务调度
}
printf("AppTaskLed1 释放信号量!\n");
OSSemPost((OS_SEM *)&TestSem,
//发布SemOfKey
(OS_OPT )OS_OPT_POST_1,
//发布给所有等待任务
(OS_ERR *)&err);
macLED1_TOGGLE ();
OSTimeDlyHMSM (0,0,1,0,OS_OPT_TIME_PERIODIC,&err);
}
}
/*
*********************************************************
* LED2 TASK
*********************************************************
*/
static void AppTaskLed2 ( void * p_arg )
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE)
{
printf("AppTaskLed2 Running\n");
macLED2_TOGGLE ();
OSTimeDlyHMSM (0,0,0,200,OS_OPT_TIME_PERIODIC,&err);
}
}
/*
*************************************************************
* LED3 TASK
*************************************************************
*/
static void AppTaskLed3 ( void * p_arg )
{
OS_ERR err;
CPU_TS ts_sem_post;
(void)p_arg;
while (DEF_TRUE)
{
printf("AppTaskLed3 获取信号量\n");
//获取二值信号量TestSem,没获取到则一直等待
OSSemPend ((OS_SEM *)&TestSem, //等待该信号量被发布
(OS_TICK )0, //无期限等待
(OS_OPT )OS_OPT_PEND_BLOCKING,
//如果没有信号量可用就等待
(CPU_TS *)&ts_sem_post,
//获取信号量最后一次被发布的时间戳
(OS_ERR *)&err); //返回错误类型
macLED3_TOGGLE ();
printf("AppTaskLed3 释放信号量\n");
//给出二值信号量
OSSemPost((OS_SEM *)&TestSem,
//发布SemOfKey
(OS_OPT )OS_OPT_POST_1,
(OS_ERR *)&err);
OSTimeDlyHMSM (0,0,1,0,OS_OPT_TIME_PERIODIC,&err);
}
}
2、模拟优先级翻转实验现象
在计算机上打开串口调试助手,然后复位开发板就可以在调试助手中看到串口的打印信息,它里面输出了信息表明任务正在运行中, 并且很明确可以看到高优先级任务在等待低优先级任务运行完毕才能得到信号量继续运行,具体见图
3、互斥量实验
互斥量实验是基于优先级翻转实验进行修改的,将信号量改为互斥量,目的是为了测试互斥量的优先级继承机制是否有效,具体如下
#include <includes.h>
/*
*****************************************************************
* LOCAL DEFINES
*****************************************************************
*/
OS_SEM TestMutex; //互斥量
/*
*******************************************************************
* TCB
*******************************************************************
*/
static OS_TCB AppTaskStartTCB;
static OS_TCB AppTaskLed1TCB;
static OS_TCB AppTaskLed2TCB;
static OS_TCB AppTaskLed3TCB;
/*
********************************************************************
* STACKS
*******************************************************************
*/
static CPU_STK AppTaskStartStk[APP_TASK_START_STK_SIZE];
static CPU_STK AppTaskLed1Stk [ APP_TASK_LED1_STK_SIZE ];
static CPU_STK AppTaskLed2Stk [ APP_TASK_LED2_STK_SIZE ];
static CPU_STK AppTaskLed3Stk [ APP_TASK_LED3_STK_SIZE ];
/*
********************************************************************
* FUNCTION PROTOTYPES
*******************************************************************
*/
static void AppTaskStart (void *p_arg);
static void AppTaskLed1 ( void * p_arg );
static void AppTaskLed2 ( void * p_arg );
static void AppTaskLed3 ( void * p_arg );
int main (void)
{
OS_ERR err;
OSInit(&err);
OSTaskCreate((OS_TCB *)&AppTaskStartTCB,
(CPU_CHAR *)"App Task Start",
(OS_TASK_PTR ) AppTaskStart,
(void *) 0,
(OS_PRIO ) APP_TASK_START_PRIO,
(CPU_STK *)&AppTaskStartStk[0],
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSStart(&err);
}
static void AppTaskStart (void *p_arg)
{
CPU_INT32U cpu_clk_freq;
CPU_INT32U cnts;
OS_ERR err;
(void)p_arg;
BSP_Init();
CPU_Init();
cpu_clk_freq = BSP_CPU_ClkFreq();
cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;
OS_CPU_SysTickInit(cnts);
Mem_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err);
#endif
CPU_IntDisMeasMaxCurReset();
/* 创建互斥信号量 mutex */
OSMutexCreate ((OS_MUTEX *)&TestMutex, //指向信号量变量的指针
(CPU_CHAR *)"Mutex For Test", //信号量的名字
(OS_ERR *)&err); //错误类型
/* Create the Led1 task */
OSTaskCreate((OS_TCB *)&AppTaskLed1TCB,
(CPU_CHAR *)"App Task Led1",
(OS_TASK_PTR ) AppTaskLed1,
(void *) 0,
(OS_PRIO ) APP_TASK_LED1_PRIO,
(CPU_STK *)&AppTaskLed1Stk[0],
(CPU_STK_SIZE) APP_TASK_LED1_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED1_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
/* Create the Led2 task */
OSTaskCreate((OS_TCB *)&AppTaskLed2TCB,
(CPU_CHAR *)"App Task Led2",
(OS_TASK_PTR ) AppTaskLed2,
(void *) 0,
(OS_PRIO ) APP_TASK_LED2_PRIO,
(CPU_STK *)&AppTaskLed2Stk[0],
(CPU_STK_SIZE) APP_TASK_LED2_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED2_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
/* Create the Led3 task */
OSTaskCreate((OS_TCB *)&AppTaskLed3TCB,
(CPU_CHAR *)"App Task Led3",
(OS_TASK_PTR ) AppTaskLed3,
(void *) 0,
(OS_PRIO ) APP_TASK_LED3_PRIO,
(CPU_STK *)&AppTaskLed3Stk[0],
(CPU_STK_SIZE) APP_TASK_LED3_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED3_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSTaskDel ( & AppTaskStartTCB, & err );
}
/*
************************************************************************
* LED1 TASK
************************************************************************
*/
static void AppTaskLed1 ( void * p_arg )
{
OS_ERR err;
static uint32_t i;
(void)p_arg;
while (DEF_TRUE)
{
printf("AppTaskLed1 获取互斥量\n");
//获取互斥量 ,没获取到则一直等待
OSMutexPend ((OS_MUTEX *)&TestMutex, //申请互斥量
(OS_TICK )0, //无期限等待
(OS_OPT )OS_OPT_PEND_BLOCKING,
//如果不能申请到信号量就阻塞任务
(CPU_TS *)0, //不想获得时间戳
(OS_ERR *)&err); //返回错误类型
for (i=0; i<600000; i++) //模拟低优先级任务占用互斥量
{
OSSched();//发起任务调度
}
printf("AppTaskLed1 释放互斥量\n");
OSMutexPost ((OS_MUTEX *)&TestMutex, //释放互斥量
(OS_OPT )OS_OPT_POST_NONE, //进行任务调度
(OS_ERR *)&err); //返回错误类型
macLED1_TOGGLE ();
OSTimeDlyHMSM (0,0,1,0,OS_OPT_TIME_PERIODIC,&err);
}
}
/*
**********************************************************************
* LED2 TASK
**********************************************************************
*/
static void AppTaskLed2 ( void * p_arg )
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE)
{
printf("AppTaskLed2 Running\n");
macLED2_TOGGLE ();
OSTimeDlyHMSM (0,0,0,200,OS_OPT_TIME_PERIODIC,&err);
}
}
/*
*********************************************************************
* LED3 TASK
********************************************************************
*/
static void AppTaskLed3 ( void * p_arg )
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE)
{
printf("AppTaskLed3 获取互斥量\n");
//获取互斥量 ,没获取到则一直等待
OSMutexPend ((OS_MUTEX *)&TestMutex, //申请互斥量
(OS_TICK )0, //无期限等待
(OS_OPT )OS_OPT_PEND_BLOCKING,
//如果不能申请到信号量就阻塞任务
(CPU_TS *)0, //不想获得时间戳
(OS_ERR *)&err); //返回错误类型
macLED3_TOGGLE ();
printf("AppTaskLed3 释放互斥量\n");
OSMutexPost ((OS_MUTEX *)&TestMutex, //释放互斥量
(OS_OPT )OS_OPT_POST_NONE, //进行任务调度
(OS_ERR *)&err); //返回错误类型
OSTimeDlyHMSM (0,0,1,0,OS_OPT_TIME_PERIODIC,&err);
}
}
4、互斥量实验现象
在计算机上打开串口调试助手,然后复位开发板就可以在调试助手中看到串口的打印信息,它里面输出了信息表明任务正在运行中, 并且很明确可以看到在低优先级任务运行的时候,中优先级任务无法抢占低优先级的任务,这是因为互斥量的优先级继承机制, 从而最大程度降低了优先级翻转产生的危害,具体见图