## 介绍 在嵌入式开发中,现在很多设备都会都会跑专门的操作系统,比如linux、rt_thread、freertos、ucos等,但还是会有不少设备用不上的操作系统,就会采取裸跑的形式(又叫前后台系统)。像在这种不带操作系统的软件开发中,很常见的形式就是把所有要执行的函数全部放在循环当中,按顺序循环的执行每一个函数,然后加入对函数执行的周期有要求还可以采用定时器来确定多久来执行某个函数。但是这对于我们要来管理多个这样的函数时候,在编程上就显得很冗余繁琐了,也不方便我们管理。 这里写了一个方便我们管理定时任务管理内核。需要用到的硬件资源也就一个定时器(用于得到时间片),当然也可以在电脑上运行,只要能获取到时间片就可以。这个内核最主要的功能就是实现函数的周期调用,说白了,这个内核就是实现软件定时器的功能。 ## 接口 ### 内核初始化 ```c int kern_init(kern_tick_t tick_func, unsigned short time_slice); ``` 在进行任务调度之前,必须先进行内核的初始化。初始化很简单,传入能够获取时间片的时钟函数`tick_func`,以及时钟函数具体的时钟周期`time_slice`(一般是毫秒)。初始化成功就返回`KE_OK`,其他值失败。 ### 创建任务和删除任务 ```c task_t task_create(unsigned short period, task_handler_t handler); int task_delete(task_t task); ``` 创建任务很简单,一个是传入任务的周期`period`(单位是内核初始化时传入的时间片),另一个是任务的执行函数`handler`,创建成功返回任务的id(唯一),失败返回0。删除的话,就把任务id传进去即可,返回`KE_OK`,其他值失败。 ### 任务调度 ```c void kern_schedule(void); ``` 在初始化完内核后,就可以调用内核调度函数了,不过还没有任务。一般是先创建了任务,再调度。 这个调度函数,没有函数出口,会一值运行,直至程序结束,所以调度函数后面的代码都执行不了,不要把代码写在调度函数后面。 ### 运行中的任务 ```c task_t task_running(void); ``` 不同的任务是可以相同的执行函数的,这个函数就是区分是哪个任务调用的执行函数。 ## 例子 ```c static unsigned int get_msec(void) { struct timeval mstime; unsigned int ms = 0; gettimeofday(&mstime, NULL); ms = mstime.tv_sec * 1000 + mstime.tv_usec / 1000; return ms; } void task1(void) { static int count = 0; printf("task1 running! %d\r\n", ++count); } void task2(void) { static int count = 0; printf("task2 running! %d\r\n", ++count); } int main(int argc, char *argv[]) { if (kern_init(get_msec, 1) == KE_OK) { printf("kern init success!\r\n"); } else { printf("*** kern init fail!\r\n"); return; } printf("create task %d\r\n", task_create(1000, task1)); printf("create task %d\r\n", task_create(500, task2)); kern_schedule(); return 0; } ``` 运行结果: ``` kern init success! create task 1 create task 2 task1 running! 1 task2 running! 1 task2 running! 2 task1 running! 2 task2 running! 3 task2 running! 4 task1 running! 3 task2 running! 5 task2 running! 6 task1 running! 4 task2 running! 7 task2 running! 8 ``` 任务2运行了2次,相应任务1运行1次。