🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习 🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发 ❄️作者主页:一个平凡而乐于分享的小比特的个人主页 ✨收录专栏:UCOS-III,本专栏为UCOS-III学习记录 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖
任务信号量start_task函数:
void start_task(void *p_arg)
{
OS_ERR err;
CPU_INT32U cnts = 0;
CPU_Init();
CPU_SR_ALLOC();
cnts = HAL_RCC_GetSysClockFreq() / OS_CFG_TICK_RATE_HZ;
OS_CPU_SysTickInit(cnts);
CPU_CRITICAL_ENTER(); /* 进入临界区 */
/* 创建task1 */
task1_stack = mymalloc(SRAMIN,TASK1_STACK_SIZE * sizeof(CPU_STK));
OSTaskCreate ( (OS_TCB* ) &task1_tcb,
(CPU_CHAR* ) "task1",
(OS_TASK_PTR ) task1,
(void* ) 0,
(OS_PRIO ) TASK1_PRIO,
(CPU_STK* ) task1_stack,
(CPU_STK_SIZE) TASK1_STACK_SIZE / 10,
(CPU_STK_SIZE) TASK1_STACK_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);
/* 创建task2 */
task2_stack = mymalloc(SRAMIN,TASK2_STACK_SIZE * sizeof(CPU_STK));
OSTaskCreate ( (OS_TCB* ) &task2_tcb,
(CPU_CHAR* ) "task2",
(OS_TASK_PTR ) task2,
(void* ) 0,
(OS_PRIO ) TASK2_PRIO,
(CPU_STK* ) task2_stack,
(CPU_STK_SIZE) TASK2_STACK_SIZE / 10,
(CPU_STK_SIZE) TASK2_STACK_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);
OSTaskSemSet (&task2_tcb , 1 , &err); //<---这里
CPU_CRITICAL_EXIT(); /* 退出临界区 */
OSTaskDel((OS_TCB *)0, &err);
}
/* 往task2释放任务信号量 */
void task1(void *p_arg)
{
OS_ERR err;
uint8_t key = 0;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES)
{
printf("释放任务信号量!!\r\n");
OSTaskSemPost (&task2_tcb , OS_OPT_POST_NONE , &err);
}
OSTimeDly (10 , OS_OPT_TIME_DLY , &err);
}
}
/* 获取任务信号量 */
void task2(void *p_arg)
{
OS_ERR err;
OS_SEM_CTR cnt = 0;
while(1)
{
cnt = OSTaskSemPend (0 , OS_OPT_PEND_BLOCKING , 0 , &err);
printf("获取任务信号量成功!,cnt的值为:%d\r\n",cnt);
OSTimeDly (1000 , OS_OPT_TIME_DLY , &err);
}
} 任务队列start_task函数:
void start_task(void *p_arg)
{
OS_ERR err;
CPU_INT32U cnts = 0;
CPU_Init();
CPU_SR_ALLOC();
cnts = HAL_RCC_GetSysClockFreq() / OS_CFG_TICK_RATE_HZ;
OS_CPU_SysTickInit(cnts);
CPU_CRITICAL_ENTER(); /* 进入临界区 */
/* 创建task1 */
task1_stack = mymalloc(SRAMIN,TASK1_STACK_SIZE * sizeof(CPU_STK));
OSTaskCreate ( (OS_TCB* ) &task1_tcb,
(CPU_CHAR* ) "task1",
(OS_TASK_PTR ) task1,
(void* ) 0,
(OS_PRIO ) TASK1_PRIO,
(CPU_STK* ) task1_stack,
(CPU_STK_SIZE) TASK1_STACK_SIZE / 10,
(CPU_STK_SIZE) TASK1_STACK_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);
/* 创建task2 */
task2_stack = mymalloc(SRAMIN,TASK2_STACK_SIZE * sizeof(CPU_STK));
OSTaskCreate ( (OS_TCB* ) &task2_tcb,
(CPU_CHAR* ) "task2",
(OS_TASK_PTR ) task2,
(void* ) 0,
(OS_PRIO ) TASK2_PRIO,
(CPU_STK* ) task2_stack,
(CPU_STK_SIZE) TASK2_STACK_SIZE / 10,
(CPU_STK_SIZE) TASK2_STACK_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);
CPU_CRITICAL_EXIT(); /* 退出临界区 */
OSTaskDel((OS_TCB *)0, &err);
}
/* 写任务内嵌队列 */
void task1(void *p_arg)
{
OS_ERR err;
uint8_t key = 0;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES || key == KEY1_PRES || key == KEY2_PRES || key == WKUP_PRES)
{
printf("发送键值!\r\n");
OSTaskQPost (&task2_tcb , &key , sizeof(key) , OS_OPT_POST_FIFO , &err);
}
OSTimeDly(10,OS_OPT_TIME_DLY,&err);
}
}
/* 读任务内嵌队列 */
void task2(void *p_arg)
{
OS_ERR err;
uint8_t * key;
OS_MSG_SIZE size = 0;
while(1)
{
key = OSTaskQPend (0 , OS_OPT_PEND_BLOCKING , &size , 0 , &err);
printf("接收到的键值为:%d\r\n", *key);
printf("接收到数据长度为:%d字节\r\n", size);
}
} 疑问1:为什么任务信号量start_task函数,需要用到OSTaskSemSet (&task2_tcb , 1 , &err)代码指定task2_tcb接收信号量,在task1中不是用OSTaskSemPost (&task2_tcb , OS_OPT_POST_NONE , &err)也指定了吗?
疑问2:为什么任务队列start_task函数,不需要用到OSTaskSemSet (&task2_tcb , 1 , &err)类似的函数指定task2_tcb接收队列数据呢
针对疑问,我去deepseek了一下,感觉讲的挺深入的,分享给大家
// 任务信号量需要明确初始值,因为:
// - 可能是二值信号量:初始值=0或1
// - 可能是计数信号量:初始值=N
// - 操作系统不知道你的用途
OSTaskSemSet(&task2_tcb, 1, &err); // 必须明确设置初始状态// 任务消息队列的初始状态永远是:
// - 空队列
// - 没有消息
// - 等待接收状态
// 不需要额外设置,因为初始状态只有这一种可能!// 用例1:二值信号量(互斥)
OSTaskSemSet(&task_tcb, 1, &err); // 初始可用
// 用例2:事件计数
OSTaskSemSet(&task_tcb, 0, &err); // 初始无事件
// 用例3:资源池
OSTaskSemSet(&task_tcb, 5, &err); // 初始5个资源
// ↑ 必须根据用途设置不同的初始值// 所有用例都一样:
// - 初始队列为空
// - 等待消息到达
// ↑ 不需要设置,因为初始状态都一样OSTaskCreate() 函数内部void OSTaskCreate (OS_TCB *p_tcb,
CPU_CHAR *p_name,
OS_TASK_PTR p_task,
void *p_arg,
OS_PRIO prio,
CPU_STK *p_stk_base,
CPU_STK_SIZE stk_limit,
CPU_STK_SIZE stk_size,
OS_MSG_QTY q_size,
OS_TICK time_quanta,
void *p_ext,
OS_OPT opt,
OS_ERR *p_err)
{
// ... 参数检查
/* 初始化TCB - 这是关键步骤! */
OS_TaskInitTCB(p_tcb); // ← 在这里初始化TCB的所有成员
// ... 其他初始化代码
}OS_TaskInitTCB() 函数的详细实现void OS_TaskInitTCB (OS_TCB *p_tcb)
{
/* 清零整个TCB结构体 */
memset((void*)p_tcb, 0, sizeof(OS_TCB)); // ← 关键:全部置零!
/* 然后设置一些特定的初始值 */
p_tcb->TaskState = OS_TASK_STATE_RDY;
p_tcb->Prio = OS_CFG_PRIO_MAX - 1;
p_tcb->StkPtr = DEF_NULL;
p_tcb->StkSize = 0;
/* 初始化任务内嵌消息队列 */
OS_MsgQInit(&p_tcb->MsgQ, // ← 专门初始化消息队列
(OS_MSG_QTY)0);
/* 初始化其他内核对象 */
OS_PendListInit(&p_tcb->PendList);
// ... 设置其他成员
}void OS_MsgQInit (OS_MSG_Q *p_msg_q,
OS_MSG_QTY size)
{
p_msg_q->InPtr = (OS_MSG *)0; // 输入指针置NULL
p_msg_q->OutPtr = (OS_MSG *)0; // 输出指针置NULL
p_msg_q->NbrEntries = (OS_MSG_QTY)0; // 条目数置0
p_msg_q->NbrEntriesMax = (OS_MSG_QTY)0; // 最大条目数置0
}// 你的代码:
task2_stack = mymalloc(SRAMIN, TASK2_STACK_SIZE * sizeof(CPU_STK));
// 栈内存分配好了,但内容是随机的OSTaskCreate(&task2_tcb, "task2", task2, ...);// 在OSTaskCreate()内部:
1. memset(&task2_tcb, 0, sizeof(OS_TCB)); // TCB全部清零
2. OS_MsgQInit(&task2_tcb->MsgQ, 0); // 消息队列专门初始化
3. // 设置任务名、优先级、栈指针等
4. // 把任务加入到就绪表task2_tcb.MsgQ.InPtr = NULL ← 已初始化
task2_tcb.MsgQ.OutPtr = NULL ← 已初始化
task2_tcb.MsgQ.NbrEntries = 0 ← 已初始化
task2_tcb.SemCtr = 0 ← 已清零,但这是随机清零的!// 操作系统知道MsgQ是一个复杂结构体,需要专门初始化
OS_MsgQInit(&p_tcb->MsgQ, 0);
// 明确设置每个成员为合理的初始值// 操作系统只是简单地把整个TCB清零
memset(p_tcb, 0, sizeof(OS_TCB));
// SemCtr被清零为0,但这不一定是应用想要的初始值!
// 你可能希望:
// - 二值信号量:初始值=1(可用)
// - 事件计数:初始值=0(无事件)
// - 资源管理:初始值=N(N个资源)
// 操作系统不知道你的用途,所以需要你明确设置