|
本帖最后由 vuxtvg 于 2024-7-28 01:54 编辑
本文基于叶大鹏老师分享的任务调度方案,然后在工作使用的过程中发现有一些可以优化的,然后又添加了一些内容。
增加的内容
-- 添加获取当前函数执行次数的接口 PS:例如test 100ms执行一次 可以调用接口获取运行次数 然后获取到的次数对2取余可以200ms执行一次,这样可以在单个函数中又多个时基的执行(主要是为了代码看起来比较简洁)
-- 添加任务使能/失能
-- 添加哈希算法节省查找任务的所需时间
以下是代码部分:
/*
* task_scheduler.h
*
* Created on: Jul 26, 2024
* Author: vuxtvg@163.com
*/
#ifndef TASK_SCHEDULER_H_
#define TASK_SCHEDULER_H_
#include <stdint.h>
#include <stdlib.h>
#define EnableTask(taskFunc) SetTaskEnabled((taskFunc), 1)
#define DisableTask(taskFunc) SetTaskEnabled((taskFunc), 0)
// 定义任务结构体
typedef struct
{
void (*pTaskFuncCb)(void); // 函数指针变量,用来保存业务功能模块函数地址
uint16_t timCount; // 时间片计数值
uint16_t timRload; // 时间片重载值
uint32_t run :1; // 调度标志,1:调度,0:挂起
uint32_t enabled :1; // 任务启用标志,1:启用,0:禁用
uint32_t runCount :30; // 任务运行次数计数器
} TaskComps_t;
extern TaskComps_t g_taskComps[];
extern uint8_t TASK_NUM_MAX;
// 函数声明
void TaskInit(void);
void TaskHandler(void);
void TaskScheduleCbReg(void (*pFunc)(void));
void SetTaskEnabled(void (*taskFunc)(void), uint8_t state);
uint32_t GetTaskRunCount(void (*taskFunc)(void));
void ExecuteOnMultiple(void (*taskFunc)(void), uint32_t multiple,
void (*ActionFunc)(void));
void FreeHashTable(void);
#endif /* TASK_SCHEDULER_H_ */
/*
* task_scheduler.c
*
* Created on: Jul 26, 2024
* Author: vuxtvg@163.com
*/
#include "task_scheduler.h"
#define HASH_TABLE_SIZE 17
typedef struct HashNode
{
void (*pTaskFuncCb)(void);
TaskComps_t *taskComp;
struct HashNode *next;
} HashNode_t;
HashNode_t *hashTable[HASH_TABLE_SIZE];
uint32_t HashFunc(void (*taskFunc)(void))
{
return ((uintptr_t) taskFunc) % HASH_TABLE_SIZE;
}
void HashTableInsert(void (*taskFunc)(void), TaskComps_t *taskComp)
{
uint32_t index = HashFunc(taskFunc);
HashNode_t *newNode = (HashNode_t*) malloc(sizeof(HashNode_t));
newNode->pTaskFuncCb = taskFunc;
newNode->taskComp = taskComp;
newNode->next = hashTable[index];
hashTable[index] = newNode;
}
void InitHashTable(void)
{
for (uint8_t i = 0; i < HASH_TABLE_SIZE; i++)
{
hashTable = NULL;
}
for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
{
HashTableInsert(g_taskComps.pTaskFuncCb, &g_taskComps);
}
}
TaskComps_t* HashTableSearch(void (*taskFunc)(void))
{
uint32_t index = HashFunc(taskFunc);
HashNode_t *node = hashTable[index];
while (node)
{
if (node->pTaskFuncCb == taskFunc)
{
return node->taskComp;
}
node = node->next;
}
return NULL;
}
void FreeHashTable(void)
{
for (uint8_t i = 0; i < HASH_TABLE_SIZE; i++)
{
HashNode_t *node = hashTable;
while (node)
{
HashNode_t *temp = node;
node = node->next;
free(temp);
}
hashTable = NULL;
}
}
void TaskHandler(void)
{
for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
{
if (g_taskComps.run && g_taskComps.enabled)
{
g_taskComps.run = 0;
g_taskComps.runCount++;
g_taskComps.pTaskFuncCb();
}
}
}
void TaskScheduleCb(void)
{
for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
{
if (g_taskComps.timCount && g_taskComps.enabled)
{
g_taskComps.timCount--;
if (g_taskComps.timCount == 0)
{
g_taskComps.run = 1;
g_taskComps.timCount = g_taskComps.timRload;
}
}
}
}
void SetTaskEnabled(void (*taskFunc)(void), uint8_t state)
{
TaskComps_t *taskComp = HashTableSearch(taskFunc);
if (taskComp)
{
taskComp->enabled = state;
}
}
uint32_t GetTaskRunCount(void (*taskFunc)(void))
{
TaskComps_t *taskComp = HashTableSearch(taskFunc);
if (taskComp)
{
return taskComp->runCount;
}
return 0; // 如果没有找到匹配的任务函数,返回0
}
void ExecuteOnMultiple(void (*taskFunc)(void), uint32_t multiple,
void (*ActionFunc)(void))
{
uint32_t runCount = GetTaskRunCount(taskFunc);
if (runCount % multiple == 0)
{
ActionFunc();
}
}
void TaskInit(void)
{
TaskScheduleCbReg(TaskScheduleCb);
InitHashTable();
}
/*
* task.c
* Created on: Jul 26, 2024
* Author: vuxtvg@163.com
*/
#include "main.h"
#include "task_scheduler.h"
typedef struct
{
uint16_t p1cnt;
uint16_t p2cnt;
uint16_t p3cnt;
} CNT;
CNT cnt;
void uart_printf(void);
void led_toggle(void);
void PrintData1(void)
{
cnt.p1cnt++;
printf("cnt.p1cnt:%d\r\n", cnt.p1cnt);
}
void PrintData2(void)
{
cnt.p2cnt++;
printf("cnt.p2cnt:%d\r\n", cnt.p2cnt);
}
void PrintData3(void)
{
cnt.p3cnt++;
printf("cnt.p3cnt:%d\r\n", cnt.p3cnt);
}
void led_toggle(void)
{
EnableTask(uart_printf);
DisableTask(led_toggle);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
uint16_t cc;
void uartf(void)
{
cc++;
}
void uartf1(void)
{
cc++;
}
void uartf2(void)
{
cc++;
}
void uartf3(void)
{
cc++;
}
void uartf4(void)
{
cc++;
}
void uartf5(void)
{
cc++;
}
void uart_printf(void)
{
EnableTask(led_toggle);
DisableTask(uart_printf);
printf("uartTaskRunCount:%ld ledTaskRunCount:%ld \r\n",
GetTaskRunCount(uart_printf), GetTaskRunCount(led_toggle));
ExecuteOnMultiple(uart_printf, 1, PrintData1);
ExecuteOnMultiple(uart_printf, 2, PrintData2);
ExecuteOnMultiple(uart_printf, 3, PrintData3);
}
TaskComps_t g_taskComps[] =
{
{ led_toggle, 500, 500, 0, 1 },
{ uartf, 1000, 1000, 0, 1 },
{ uartf1, 1000, 1000, 0, 1 },
{ uartf2, 1000, 1000, 0, 1 },
{ uartf3, 1000, 1000, 0, 1 },
{ uartf4, 1000, 1000, 0, 1 },
{ uartf5, 1000, 1000, 0, 1 },
{ uart_printf, 500, 500, 0, 0 },
// 添加其他任务
};
uint8_t TASK_NUM_MAX = (sizeof(g_taskComps) / sizeof(g_taskComps[0]));
#include "task_scheduler.h"
int main(void)
{
TaskInit();
while (1)
{
TaskHandler();
}
}
static void (*g_pTaskScheduleFunc)(void); // 函数指针变量,保存任务调度的函数地址
void TaskScheduleCbReg(void (*pFunc)(void))
{
g_pTaskScheduleFunc = pFunc;
}
void SysTick_Handler(void)
{
if (g_pTaskScheduleFunc) g_pTaskScheduleFunc();
}
这个是本人优化后的代码,测试使用OK,如果缺点,还望指正
应该是可以支持所有的单片机的,硬件仅需用一个定时器即可,方便移植,task_scheduler.c/.h 不需要修改,task.c是使用示例,main.c是接口调用
Ps:如果您用到项目中,还望可以署名我(本人邮箱:vuxtvg@163.com)是这个模块的一个小小的作者 ,也希望您能在这个帖子下面发表一下评论,让我开心一下(*^▽^*)
如有转载,注明出处(本人邮箱:vuxtvg@163.com)
本文结束啦,谢谢大家,感谢平台
|
|