任务信号量直接内嵌在UCOSIII中,使用也十分方便,今日学习使用一下:
本文学习与程序编写基于 正点原子的 STM32F1 UCOS开发手册
文章提供测试代码讲解、完整工程下载、测试效果图
目录
任务内嵌信号量:
- 请求次数的确定:任务内嵌信号量的请求次数并不是直接通过某个设置来确定的,而是通过信号量的发送和接收操作来管理的。每当一个任务发送信号量时,接收任务的信号量值就会增加,从而允许接收任务进行相应次数的请求。
- 示例:假设任务A向任务B发送了3次信号量,那么任务B就可以请求3次任务内嵌信号量。每次请求成功后,任务B的信号量值就会减1,直到信号量值为0时,任务B再次请求信号量将会挂起等待。
实验目标解释:
ComTask 先将CalculateTask删除,随后每隔10秒发送一次系统内建信号量(循环发送五次信号量),
MessageTask等待请求得到系统内建信号量在运行,请求到了就打印自己运行次数
目前各个文件任务:
#include "main.h"
创建开始任务初始化每个基本任务,虽然有信号量与互斥信号量创建,但本文实际用不到!
#include "main.h" void start_task(void *p_arg);//开始任务函数 int main(void) { OS_ERR err; CPU_SR_ALLOC(); Init_ALL(); OSInit(&err); //初始化UCOSIII OS_CRITICAL_ENTER();//进入临界区 //创建开始任务 OSTaskCreate((OS_TCB * )&StartTaskTCB, //任务控制块 (CPU_CHAR * )"start task", //任务名字 (OS_TASK_PTR )start_task, //任务函数 (void * )0, //传递给任务函数的参数 (OS_PRIO )START_TASK_PRIO, //任务优先级 (CPU_STK * )&START_TASK_STK[0], //任务堆栈基地址 (CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位 (CPU_STK_SIZE)START_STK_SIZE, //任务堆栈大小 (OS_MSG_QTY )0, //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息 (OS_TICK )0, //当使能时间片轮转时的时间片长度,为0时为默认长度, (void * )0, //用户补充的存储区 (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项 (OS_ERR * )&err); //存放该函数错误时的返回值 OS_CRITICAL_EXIT(); //退出临界区 OSStart(&err); //开启UCOSIII while(1); } //开始任务函数 void start_task(void *p_arg) { OS_ERR err; CPU_SR_ALLOC(); p_arg = p_arg; CPU_Init(); #if OS_CFG_STAT_TASK_EN > 0u OSStatTaskCPUUsageInit(&err); //统计任务 #endif #ifdef CPU_CFG_INT_DIS_MEAS_EN //如果使能了测量中断关闭时间 CPU_IntDisMeasMaxCurReset(); #endif #if OS_CFG_SCHED_ROUND_ROBIN_EN //当使用时间片轮转的时候 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms OSSchedRoundRobinCfg(DEF_ENABLED,1,&err); #endif //初始化 OS_Timer1_Periodic 软件定时器 OSTmrCreate((OS_TMR *) &OS_Timer1_Periodic , //OS系统 软件定时器 1 周期模式 (CPU_CHAR *) "OS_Timer1_Periodic", //定时器名称 (OS_TICK ) 100, // 启动延时 为100*10 ms (OS_TICK ) 20, // 周期为 20*10 ms (OS_OPT ) OS_OPT_TMR_PERIODIC, //周期定时模式 (OS_TMR_CALLBACK_PTR ) OS_Timer1_Periodic_callback,//回调函数 (void * ) 0,//参数为0 (OS_ERR *) &err ); OS_CRITICAL_ENTER(); //进入临界区 //创建ComTask任务 OSTaskCreate((OS_TCB * )&COMTASKTaskTCB, (CPU_CHAR * )"com task", (OS_TASK_PTR )comTask, (void * )0, (OS_PRIO )COMTASK_TASK_PRIO, (CPU_STK * )&COMTASK_TASK_STK[0], (CPU_STK_SIZE)COMTASK_STK_SIZE/10, (CPU_STK_SIZE)COMTASK_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, //之前为0 //2个时间片 2*5ms (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )&err); //创建MessageTask任务 OSTaskCreate((OS_TCB * )&MessageTaskTaskTCB, (CPU_CHAR * )"Message task", (OS_TASK_PTR )MessageTask, (void * )0, (OS_PRIO )MessageTask_TASK_PRIO, (CPU_STK * )&MessageTask_TASK_STK[0], (CPU_STK_SIZE)MessageTask_STK_SIZE/10, (CPU_STK_SIZE)MessageTask_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, //之前为0 //2个时间片 2*5ms (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )&err); //创建CalculateTask任务 OSTaskCreate((OS_TCB * )&CalculateTaskTaskTCB, (CPU_CHAR * )"Calculate task", (OS_TASK_PTR )CalculateTask, (void * )0, (OS_PRIO )CalculateTask_TASK_PRIO, (CPU_STK * )&CalculateTask_TASK_STK[0], (CPU_STK_SIZE)CalculateTask_STK_SIZE/10, (CPU_STK_SIZE)CalculateTask_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )&err); //创建 Shared_Str共享全局资源 的 信号量 OSSemCreate((OS_SEM *) &SEM_Shared_Str, //指向信号量 (CPU_CHAR *) "SEM_Shared_Str", //信号量名称 ( OS_SEM_CTR ) 1, //信号量值为1 (OS_ERR *) &err ); //创建 Shared_Str共享全局资源 的 互斥信号量 OSMutexCreate((OS_MUTEX *) &MUTEX_Shared_Str, //指向互斥信号量 (CPU_CHAR *) "MUTEX_Shared_Str", //互斥信号量名称 (OS_ERR *) &err ); OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err); //挂起开始任务 OS_CRITICAL_EXIT(); //进入临界区 }
#include "ComTask.h"
#include "ComTask.h" /* ComTask 删除CalculateTask 延时10s 向 MessageTask 发布 系统内建信号量 //循环发送五次信号量 ComTask 计数打印自己运行次数 */ void comTask(void * p_arg) { OS_ERR err; int i=0,OSTime_tickRate,j; //char ComTask_str[]="ComTask_write"; p_arg = p_arg; OSTime_tickRate=OSCfg_TickRate_Hz; //获取系统节拍频率,(该宏定义在 OS_CFG_APP.H) UsartPrintf(USART1, "OSCfg_TickRate_Hz = %d Hz \r\n",OSTime_tickRate); //打印系统节拍频率 OSTaskDel((OS_TCB*)&CalculateTaskTaskTCB,&err); //删除CalculateTask UsartPrintf(USART1, "ComTask delete CalculateTask !\r\n"); //打印删除 CalculateTask 提示 while (DEF_TRUE) { OSTimeDlyHMSM(0,0,10,0,OS_OPT_TIME_HMSM_STRICT,&err); //延时10s i++; //循环发送五次信号量 for(j=0;j<5;j++) { OSTaskSemPost(&MessageTaskTaskTCB,OS_OPT_POST_NONE,&err); } UsartPrintf(USART1, "ComTask Post SEM to MessageTask\r\n"); //ComTask 向 MessageTask 发布了 系统内建信号量 UsartPrintf(USART1, "ComTask Print %d\r\n",i); //打印 ComTask 运行次数 } }
#include "MessageTask.h"
#include "MessageTask.h" /* MessageTask 等待-请求系统内建信号量 有信号量允许次数就 打印自己运行次数 延时500ms */ void MessageTask (void * p_arg) { OS_ERR err; int i=0; //char MessageTask_str[]="MessageTask_write"; p_arg = p_arg; while (DEF_TRUE) { i++; OSTaskSemPend(0,OS_OPT_PEND_BLOCKING,0,&err); //请求任务内建信号量 UsartPrintf(USART1, "Signal Count remining %d times\r\n",MessageTaskTaskTCB.SemCtr); //打印信号量剩余次数 UsartPrintf(USART1, "MessageTask Print %d \r\n",i); //打印自己运行次数 OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_HMSM_STRICT,&err); //延时500ms } }
#include "CalculateTask.h"
在本文一开始就被ComTask 删除了,不做解释
测试效果截图:
解释都在截图里了:
如果没有任务内建信号量次数限制的话:
以 MessageTask 的0.5 秒的速率,在ComTask俩次间隔不会只运行 5次
测试工程下载:
工程包含一份程序设计框架说明,不明白可以看看:
https://download.csdn.net/download/qq_64257614/90149144?spm=1001.2014.3001.5503