# tiny_rtos **Repository Path**: luckkeyhub/tiny_rtos ## Basic Information - **Project Name**: tiny_rtos - **Description**: 极小rtos, 具备互斥锁,信号量,邮箱, 定时器, 内存管理,初始化器,错误异常捕获定位,cpu占用率和栈水位统计,设备模型等功能. - **Primary Language**: C - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 0 - **Created**: 2025-03-14 - **Last Updated**: 2025-12-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # TINY RTOS ## 简介 RTOS是专门为实时任务设计,它的任务调度算法和中断处理机制都是为了确保实时性。RTOS的特点是响应速度快、可靠性高、稳定性好、实时性强等。目前市面上有很多RTOS,但大部分rtos十分臃肿, 且很多场景其实只需要简单使用一些功能,而tiny_rtos是完全重写,保留主要功能的极小rtos, 其具备互斥锁,信号量,邮箱, 定时器, 内存管理,初始化器,错误异常捕获定位,cpu占用率和栈水位统计,设备模型等常用的功能,可以简单的在这些场景下运行,且能帮助其定位一些问题,优化线程资源配置。 > *一些说明 :* > > 1. tiny_rtos最开始是为了好玩而作,随着不断完善,可能开始重视,后续会继续完善文档,规范代码,之后打算引入未来完善好的shell,在shell中像keil中单步调试一样远程调试rtos,以及搭建文件系统,脚本解释器,OTA升级等组件生态,保证极小简约按需所用的风格 。 > > 2. tiny_rtos_keil_emulation.zip解压后 可以在keil中仿真运行.里面有一些例程, 可以参考使用。 > > 3. 目前只支持CortexM3。 > > 4. **当前此rtos适合研究学习RTOS原理和某些学校比赛使用,其它条件下暂时不能保证安全,以后会在安全相关下功夫。** ## 怎么配置 ### tiny_rtos心脏配置 在使用之前需要在滴答定时器中调用tiny_kernel_system_tick() 如tiny_startup.c 一样 ![](img/config_rtos1.png) 对于hal库或其他库也可仿照类似配置: ``` HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / TINY_TICK_PER_SECOND); ``` 在SysTick_Handler中调用tiny_kernel_system_tick(),如: ```C void SysTick_Handler(void) { tiny_kernel_system_tick(); } ``` 同时还需将系统自带的PendSV_Hander和SysTick_Handler注释掉 ### **打印Fault信息配置** 需要将HardFault_Handler从相关C库中注释掉,用tiny_rtos自带的,之后如果触发fault会打印以下信息,前提支持printf到相关平台。 **效果:** ![](img/fault_1.png) 在...\tiny_rtos\Objects中按照提示调用(需要有arm-none-eabi-gcc工具链, 其中命令中的test.axf需要换成你的项目目录中的xxx.axf): ![](img/fault_2.png) 缺少工具链可在下面下载: [ARM+GCC工具链: 使用VSCode代替Keil进行STM32开发。 arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi; mingw64; OpenOCD-20240916-0.12.0;](https://gitee.com/luckkeyhub/GCC) ## keil仿真平台使用 解压tiny_rtos_keil_emulation.zip后用keil打开 编译后点击keil右上角带d的放大器符号 ![](img/keil_1.png) 在View下的Serial Windows中点击UART #1 即可出现串口窗口. ![](img/keil_2.png) 点击运行 ![](img/keil_3.png) **仿真运行后内置信号量, 互斥锁, 队列, 邮箱相关案例命令, 输入命令可以进行演示,具体代码可以在app下参考使用.** ![](img/keil_4.png) ## 通用功能 ### 创建线程和启动线程 #### 说明 与常规流程不同, tiny_rtos需要调用tiny_thread_create() 创建线程和tiny_thread_startup() 启动线程, 将创建和启动分离 #### 相关函数 ##### tiny_thread_create() 创建线程 ```C tiny_thread_hander tiny_thread_create( const char *name, tiny_uint32_t stack_size, tiny_uint32_t priority, thread_callback_t entry_callback, void *param ); ``` **参数说明** ​ `const char *name` ​ 线程名字 ​ `tiny_uint32_t stack_size` ​ 栈大小 ​ `tiny_uint32_t priority` ​ 优先级 最大优先级为TINY_THREAD_MAX_PRIORITY-1大于这个值会设置为这个值 ​ `thread_callback_t entry_callback` ​ 函数回调, 类型为void (*thread_callback_t)(void *) ​ `void *param` ​ 函数回调参数 **返回值** ​ 线程句柄, 如果失败反回tiny_null ##### tiny_thread_startup() 启动线程 ```C void tiny_thread_startup( tiny_thread_hander thread ); ``` **参数说明** ​ `tiny_thread_hander thread` ​ 线程句柄 #### 示例 ```C /* 创建线程 */ tiny_thread_hander thread1 = tiny_thread_create("task1", 512, 2, task_queue_1, tiny_null); if (thread1) { /* 可以设置每个线程即将消亡前执行的钩子函数 */ tiny_thread_set_exit_hook(thread1, thread_exit_callback, "task1"); /* 启动线程 */ tiny_thread_startup(thread1); } ``` ### 线程休眠、杀死、挂起/恢复、总调度开启/关闭 #### 说明 对线程相关管理, 尤其是延时的时候, 在线程中请调用tiny_thread_delay_ms, 而不是其他延时函数。 tiny_suspend_thread() 挂起线程相当于无线延时需调用tiny_resume_thread()恢复。 tiny_open_schedule()和tiny_close_schedule() 可控制os调度开关, 关闭后将不会发生调用, 同时软件定时器也失效。 #### 相关函数 ##### tiny_thread_delay_ms() 线程休眠 ```C void tiny_thread_delay_ms( tiny_int32_t ms ); ``` **参数说明** ​ `tiny_int32_t ms` ​ 延时的毫秒数 小于0无限延时,即被挂起, 需调用tiny_resume_thread()恢复。 ##### tiny_kill_thread() 杀死线程 ```c void tiny_kill_thread( tiny_thread_hander hander ); ``` **参数说明** ​ `tiny_thread_hander hander` ​ 线程句柄 ##### tiny_suspend_thread() 挂起线程 ```c void tiny_suspend_thread( tiny_thread_hander hander ); ``` **参数说明** ​ `tiny_thread_hander hander` ​ 线程句柄 ##### tiny_resume_thread() 恢复线程 ```c void tiny_resume_thread( tiny_thread_hander hander ); ``` **参数说明** ​ `tiny_thread_hander hander` ​ 线程句柄 ##### tiny_open_schedule() 开总调度 ```c void tiny_open_schedule(void); ``` ##### tiny_close_schedule() 关总调度 ```c void tiny_close_schedule(void); ``` #### 示例 ```C static void task3(void *arg) { UNUSED_PARAMETER(arg); int a = 0; while (1) { printf("task3() %d\r\n", a); a++; if (a == 10) { tiny_kill_thread(thread1); /* 杀死线程1 */ tiny_kill_thread(thread2); /* 杀死线程2 */ break; /* 退出后自杀会被os回收资源 */ } tiny_thread_delay_ms(1000); /* 延时1000ms, 在这段时间内cpu执行其他任务 */ } } ``` ### 信号量 #### 说明 信号量(Semaphore)是一种实现任务间通信的机制,其作为资源计数器, 可以实现任务之间同步或临界资源的互斥访问,其实信号量主要的功能就是实现任务之间的同步与互斥,根据特殊性衍生出二值信号量其取值为取值仅为0或1。 需要注意tiny_semaphore_take不能在中断中调用。 #### 相关函数 ##### tiny_semaphore_create() 创建信号量 ```c tiny_semaphore_t tiny_semaphore_create( tiny_int32_t init_val, tiny_int32_t max_val ); ``` **参数说明** ​ `tiny_int32_t init_val` ​ 初始信号值 ​ `tiny_int32_t max_val` ​ 最大信号值 **返回值** ​ 信号量实例, 如果失败返回tiny_null ##### tiny_binary_semaphore_create() 创建二进制信号量 ```c tiny_semaphore_t tiny_binary_semaphore_create(void) ``` **返回值** ​ 信号量实例, 如果失败返回tiny_null ##### tiny_semaphore_release() 释放信号量实例 ```c void tiny_semaphore_release( tiny_semaphore_t semaphore ); ``` **参数说明** ​ `tiny_semaphore_t semaphore` ​ 待释放的信号量实例 ##### tiny_semaphore_take() 获得信号量 ```c tiny_ret_status_t tiny_semaphore_take( tiny_semaphore_t semaphore, tiny_int32_t timeout ); ``` **参数说明** ​ `tiny_semaphore_t semaphore` ​ 待获取的信号量实例 ​ `tiny_int32_t timeout` ​ 超时时间 小于于0表示无限等待 **返回值** ​ tiny_true表示成功 tiny_false表示失败 ##### tiny_semaphore_give() 释放一个信号量 ```c tiny_ret_status_t tiny_semaphore_give( tiny_semaphore_t semaphore ); ``` **参数说明** ​ `tiny_semaphore_t semaphore` ​ 待释放的信号量实例 **返回值** ​ tiny_true表示成功 tiny_false表示失败 #### 示例 ```c static tiny_semaphore_t semaphore; static tiny_semaphore_t binary_semaphore; static void val_init(void) { /* 信号量初始化 */ semaphore = tiny_semaphore_create(5, 5); /* 二值信号量初始化 */ binary_semaphore = tiny_binary_semaphore_create(); } //////////////////////////////////////////////////////////////////// /* 信号量 */ //////////////////////////////////////////////////////////////////// static NORETUTN void task_semaphore1(void *arg) { UNUSED_PARAMETER(arg); int a = 0; while (1) { if (tiny_true == tiny_semaphore_take(semaphore, 100)) { printf("task1() take semaphore %d\r\n", a++); } else { printf("task1() take semaphore error...\r\n"); } } } static NORETUTN void task_semaphore2(void *arg) { UNUSED_PARAMETER(arg); int a = 0; while (1) { tiny_thread_delay_ms(500); printf("task2() %d\r\n", a++); if (tiny_false == tiny_semaphore_give(semaphore)) { printf("task2() give semaphore error...\r\n"); } } } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// /* 二值信号量 */ //////////////////////////////////////////////////////////////////// static NORETUTN void task_binary_semaphore_1(void *arg) { UNUSED_PARAMETER(arg); int a = 0; while (1) { tiny_semaphore_take(binary_semaphore, -1); printf("task1() %d\r\n", a++); tiny_semaphore_give(binary_semaphore); tiny_thread_delay_ms(50); } } static NORETUTN void task_binary_semaphore_2(void *arg) { UNUSED_PARAMETER(arg); int a = 0; while (1) { tiny_semaphore_take(binary_semaphore, -1); int t = 10000000; while (t--) { } printf("task2() %d\r\n", a++); tiny_semaphore_give(binary_semaphore); tiny_thread_delay_ms(70); } } ``` ### 互斥锁 #### 说明 在多任务系统中,多个任务可能同时访问共享的资源,如全局变量,而这样的并发访问可能导致竞争冒险(Race Condition),从而影响程序的正确性和可靠性。为了解决这一问题,tiny_rtos提供了互斥锁(Mutex)机制,用于确保多个任务安全地访问共享资源。 互斥锁是一种同步机制,用于保护共享资源,确保在任何时刻只有一个任务能够访问这些资源。通过使用互斥锁,我们可以在多任务系统中避免竞争冒险,保证对共享资源的安全访问。 相对于二值信号量他有以下特点: - 所有权机制(仅获取者能释放) - 优先级继承防止优先级反转 需要注意tiny_mutex_lock()不能在中断中使用。 #### 相关函数 ##### tiny_mutex_create() 创建互斥锁 ```c tiny_mutex_t tiny_mutex_create(void); ``` **返回值** ​ 互斥锁实例, 如果失败返回tiny_null ##### tiny_mutex_release() 释放互斥锁 ```c void tiny_mutex_release( tiny_mutex_t mutex ); ``` **参数说明** ​ `tiny_mutex_t mutex` ​ 待释放的互斥锁 ##### tiny_mutex_lock() 上锁 ```c void tiny_mutex_lock( tiny_mutex_t mutex ); ``` **参数说明** ​ `tiny_mutex_t mutex` ​ 待被上锁的互斥锁实例 **注意** ​ 如果互斥锁已经被某线程持有, 则阻塞当前线程, 但不会阻塞持有该锁的线程。 ##### tiny_mutex_unlock() 解锁 ```c void tiny_mutex_unlock( tiny_mutex_t mutex ); ``` **参数说明** ​ `tiny_mutex_t mutex` ​ 待被解锁的互斥锁实例 **注意** ​ 只有锁的拥有者才能解锁。 #### 示例 ```c static tiny_mutex_t mutex; static void val_init(void) { /* 互斥锁初始化 */ mutex = tiny_mutex_create(); } static NORETUTN void task_mutex_1(void *arg) { UNUSED_PARAMETER(arg); int a = 0; while (1) { tiny_mutex_lock(mutex); printf("task1() %d\r\n", a++); tiny_mutex_unlock(mutex); tiny_thread_delay_ms(50); } } ``` ### 队列 #### 说明 消息队列,是一种用于任务与任务间、中断和任务间传递一条或多条信息的数据结构,实现了任务接收来自其他任务或中断的不固定或固定长度的消息。 任务从队列里面读取消息时,如果队列中消息为空,读取消息的任务将被阻塞;否则任务就读取消息并且处理。用户还可以指定阻塞任务时间 ,在指定阻塞时间内,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。 有多个消息发送到消息队列时,通常将先进入队列的消息先传给任务,也就是说,任务一般读取到的消息是最先进入消息队列的消息,即先进先出原则(FIFO)。 需要注意在中断中不能调用tiny_queue_send()和tiny_queue_receive(), 而是tiny_queue_send_irq()和tiny_queue_receive_irq()。 #### 相关函数 ##### tiny_queue_create() 创建队列实例 ```c tiny_queue_t tiny_queue_create( tiny_uint32_t block_count, tiny_uint32_t block_size ); ``` **参数说明** ​ `tiny_uint32_t block_count` ​ 块数量 ​ `tiny_uint32_t block_size` ​ 块大小 **返回值** ​ 队列实例, 如果失败返回tiny_null ##### tiny_queue_release() 释放队列实例 ```c void tiny_queue_release( tiny_queue_t queue ); ``` **参数说明** ​ `tiny_queue_t queue` ​ 待释放的队列 ##### tiny_queue_send() 发送数据到队列 ```c QUEUE_RET_STATUS tiny_queue_send( tiny_queue_t queue, tiny_uint8_t *data, tiny_uint32_t size, tiny_int32_t timeout ); ``` **参数说明** ​ `tiny_queue_t queue` ​ 待发送的队列 ​ `tiny_uint8_t *data` ​ 待发送的数据 ​ `tiny_uint32_t size` ​ 发送数据大小, 如果大于块大小, 则直接返回 ​ `tiny_int32_t timeout` ​ timeout 超时时间 小于于0表示无限等待 **返回值** ​ 执行状态, 详细查看QUEUE_RET_STATUS ##### tiny_queue_receive() 接收队列数据 ```c QUEUE_RET_STATUS tiny_queue_receive( tiny_queue_t queue, tiny_uint8_t *data, tiny_uint32_t size, tiny_int32_t timeout ); ``` **参数说明** ​ `tiny_queue_t queue` ​ 待接收的队列 ​ `tiny_uint8_t *data` ​ 待接收的数据缓存内存 ​ `tiny_uint32_t size` ​ 待接收的数据缓存内存大小 ​ `tiny_int32_t timeout` ​ timeout 超时时间 小于于0表示无限等待 **返回值** ​ 执行状态, 详细查看QUEUE_RET_STATUS ##### tiny_queue_send_irq() 中断中发送数据到队列 ```c QUEUE_RET_STATUS tiny_queue_send_irq( tiny_queue_t queue, tiny_uint8_t *data, tiny_uint32_t size, tiny_ret_status_t *is_shcduled ); ``` **参数说明** ​ `tiny_queue_t queue` ​ 待发送的队列 ​ `tiny_uint8_t *data` ​ 待发送的数据 ​ `tiny_uint32_t size` ​ 发送数据大小, 如果大于块大小, 则直接返回 ​ `tiny_ret_status_t *is_shcduled` ​ 是否调度 **返回值** ​ 执行状态, 详细查看QUEUE_RET_STATUS ##### tiny_queue_receive_irq() 中断中接收队列数据 ```c QUEUE_RET_STATUS tiny_queue_receive_irq( tiny_queue_t queue, tiny_uint8_t *data, tiny_uint32_t size, tiny_ret_status_t *is_shcduled ); ``` **参数说明** ​ `tiny_queue_t queue` ​ 待接收的队列 ​ `tiny_uint8_t *data` ​ 待接收的数据缓存内存 ​ `tiny_uint32_t size` ​ 待接收的数据缓存内存大小 ​ `tiny_ret_status_t *is_shcduled` ​ 是否调度 **返回值** ​ 执行状态, 详细查看QUEUE_RET_STATUS #### 示例 在线程中 ```c static tiny_queue_t queue; struct queue_data { int port; int val; }; static void val_init(void) { /* 队列初始化 */ queue = tiny_queue_create(5, sizeof(struct queue_data)); } static NORETUTN void task_queue_1(void *arg) { UNUSED_PARAMETER(arg); int a = 0; struct queue_data data; while (1) { if (a % 5 == 0) { if (QUEUE_OK == tiny_queue_receive(queue, (tiny_uint8_t*)&data, sizeof(data), -1)) printf("task1() a=%d recv: port: %d val %d\r\n", a, data.port, data.val); else printf("task1() recv error...\r\n"); } a++; tiny_thread_delay_ms(100); } } static NORETUTN void task_queue_2(void *arg) { UNUSED_PARAMETER(arg); int a = 0; struct queue_data data; data.port = 0; while (1) { data.port++; data.port %= 4; data.val = a * 19; if (QUEUE_OK == tiny_queue_send(queue, (tiny_uint8_t*)&data, sizeof(data), -1)) printf("task2() send:%d 0k\r\n", a); else printf("task2() send:%d error...\r\n", a); a++; tiny_thread_delay_ms(100); } } ``` 在中断中 ```c void xxx_handler(void) { tiny_ret_status_t is_shcduled = tiny_false; if (QUEUE_OK == tiny_queue_send_irg(queue, (tiny_uint8_t*)&data, sizeof(data), &is_shcduled)) printf("task2() send:%d 0k\r\n", a); // ... // 在中断最后看is_shcduled是否为tiny_true 是说明需要调度 if (is_shcduled) { tiny_yield(); } } ``` ### 邮箱 #### 说明 相对于队列邮箱存储固定大小的消息, 提供更轻量级的通信机制,速度更快。 需要注意在中断中不能调用tiny_mailbox_send()和tiny_mailbox_receive(), 而是tiny_mailbox_send_irq()和tiny_mailbox_receive_irq()。 #### 相关函数 ##### tiny_mailbox_create() 创建邮箱 ```c tiny_mailbox_t tiny_mailbox_create( tiny_uint32_t size ); ``` **参数说明** ​ `tiny_uint32_t size` ​ 邮箱数量 **返回值** ​ 邮箱实例, 如果失败返回tiny_null ##### tiny_mailbox_release() 释放邮箱 ```c void tiny_mailbox_release( tiny_mailbox_t mailbox ); ``` **参数说明** ​ `tiny_mailbox_t mailbox` ​ 待释放的邮箱 ##### tiny_mailbox_send() 发送邮箱数据 ```c QUEUE_RET_STATUS tiny_mailbox_send( tiny_mailbox_t mailbox, tiny_uint64_t data, tiny_int32_t timeout ); ``` **参数说明** ​ `tiny_mailbox_t mailbox` ​ 待发送的邮箱 ​ `tiny_uint64_t data` ​ 待发送的数据 ​ `tiny_int32_t timeout` ​ timeout 超时时间 小于于0表示无限等待 **返回值** ​ 执行状态, 详细查看QUEUE_RET_STATUS ##### tiny_mailbox_receive() 接收邮箱数据 ```c QUEUE_RET_STATUS tiny_mailbox_receive( tiny_mailbox_t mailbox, tiny_uint64_t *data, tiny_int32_t timeout ); ``` **参数说明** ​ ` tiny_mailbox_t mailbox` ​ 待接收的邮箱 ​ `tiny_uint64_t* data` ​ 待接收的数据缓存地址 ​ `tiny_int32_t timeout` ​ timeout 超时时间 小于于0表示无限等待 **返回值** ​ 执行状态, 详细查看QUEUE_RET_STATUS ##### tiny_mailbox_send_irq() 在中断中发送邮箱数据 ```c QUEUE_RET_STATUS tiny_mailbox_send_irq( tiny_mailbox_t mailbox, tiny_uint64_t data, tiny_ret_status_t *is_shcduled ); ``` **参数说明** ​ `tiny_mailbox_t mailbox` ​ 待发送的邮箱 ​ `tiny_uint64_t data` ​ 待发送的数据 ​ `tiny_ret_status_t *is_shcduled` ​ 是否调度 **返回值** ​ 执行状态, 详细查看QUEUE_RET_STATUS ##### tiny_mailbox_receive_irq() 在中断中接收邮箱数据 ```c QUEUE_RET_STATUS tiny_mailbox_receive_irq( tiny_mailbox_t mailbox, tiny_uint64_t *data, tiny_ret_status_t *is_shcduled ); ``` **参数说明** ​ `tiny_mailbox_t mailbox` ​ 待接收的邮箱 ​ `tiny_uint64_t*data` ​ 待接收的数据缓存地址 ​ `tiny_ret_status_t *is_shcduled` ​ 是否调度 **返回值** ​ 执行状态, 详细查看QUEUE_RET_STATUS #### 示例 在线程中 ```c static tiny_mailbox_t mailbox; static void val_init(void) { /* 邮箱初始化 */ mailbox = tiny_mailbox_create(3); } static NORETUTN void task_mailbox_1(void *arg) { UNUSED_PARAMETER(arg); int a = 0; tiny_uint64_t data; while (1) { if (QUEUE_OK == tiny_mailbox_receive(mailbox, &data, 100)) printf("task1() a=%d recv:%d\r\n", a, (int)data); else printf("task1() recv error...\r\n"); a++; tiny_thread_delay_ms(50); } } static NORETUTN void task_mailbox_2(void *arg) { UNUSED_PARAMETER(arg); int a = 0; while (1) { if (a % 5 == 0) { if (QUEUE_OK == tiny_mailbox_send(mailbox, a, -1)) printf("task2() send:%d 0k\r\n", a); else printf("task2() send:%d error...\r\n", a); } a++; tiny_thread_delay_ms(100); } } ``` 在中断中 ```c void xxx_handler(void) { tiny_ret_status_t is_shcduled = tiny_false; if (QUEUE_OK == tiny_mailbox_send_irg(queue, (tiny_uint8_t*)&data, &is_shcduled)) printf("task2() send:%d 0k\r\n", a); // ... // 在中断最后看is_shcduled是否为tiny_true 是说明需要调度 if (is_shcduled) { tiny_yield(); } } ``` ### 定时器 #### 说明 不同于硬件定时器,他是由软件触发,到点调用相应函数。 在使用前需调用tiny_timer_init()初始化定时器 需要注意: 任何不能在中断中使用的API也不能在定时器中使用 #### 相关函数 ##### **tiny_timer_create() 创建定时器资源** ```C tiny_timer_t *tiny_timer_create( TIMER_TYPE type, tiny_uint32_t interval, tiny_timer_callback_t callback, void *arg ); ``` **参数说明** ​ `TIMER_TYPE type` ​ 定时器触发类型 TIMER_ONCE: 触发一次 TIMER_PERIODIC: 周期触发 ​ `tiny_uint32_t interval` ​ 触发间隔, 单位os滴答, 如果要转化成ms请用CONVERT_MS_TO_TICK()转化 ​ `tiny_timer_callback_t callback` ​ 定时回调, 类型void (*tiny_timer_callback_t)(void *) ​ `void *arg` ​ 回调参数 **返回值** ​ 返回定时器实例 ##### **tiny_timer_start() 启动定时器** ```C void tiny_timer_start( tiny_timer_t *timer ); ``` **参数说明** ​ `tiny_timer_t *timer` ​ timer 定时器实例 ##### **tiny_timer_stop() 暂停定时器** ```C void tiny_timer_stop( tiny_timer_t *timer ); ``` **参数说明** ​ `tiny_timer_t *timer` ​ timer 定时器实例 ##### **tiny_timer_delete() 删除定时器** ```C void tiny_timer_delete( tiny_timer_t *timer ); ``` **参数说明** ​ `tiny_timer_t *timer` ​ timer 定时器实例 ##### **tiny_timer_set_interval() 设置定时器间隔** ```C void tiny_timer_set_interval( tiny_timer_t *timer, tiny_uint32_t interval ); ``` **参数说明** ​ `tiny_timer_t *timer` ​ timer 定时器实例 ​ `tiny_uint32_t intervalr` ​ 时间间隔ms #### 示例 ```c tiny_timer_init(); tiny_timer_t *timer = tiny_timer_create(TIMER_PERIODIC, CONVERT_MS_TO_TICK(200), task_info, tiny_null); if (timer) { tiny_timer_start(timer); } //.... tiny_timer_stop(timer); // ... tiny_timer_delete(timer); ``` ### 内存管理 #### 说明 完全自己写的malloc free,这样申请和释放内存,但优化效率目前并不快。 #### 相关函数 ##### tiny_malloc 申请内存 ```C void *tiny_malloc( unsigned int size ); ``` **参数说明** ​ `unsigned int size` ​ 申请内存size 大小 **返回值** ​ 新申请的内存, 失败返回tiny_null ##### tiny_free 释放内存 ```C void tiny_free( void *ptr ); ``` **参数说明** ​ `void *ptr` ​ ptr 需释放内存指针 ## 其他功能 ### 自动初始化器 #### 配置 ***自动初始化器默认关闭*** 如果要打开需要在tiny_def.h中将IS_OPEN_INITER给PROFILE_OPEN, 并且在keil中使用需要在Linker下的Misc Controls下配置--keep *.o(.fn.*) #### 使用说明 自动初始化器调用顺序: ```c init_driver(); main(); init_moudle(); init_application(); tiny_kernel_startup(); ``` 通过**EXPORT_DRIVER(void(*)())**可加入init_driver()中调用 通过**EXPORT_MOUDLE(void(*)())**可加入init_moudle()中调用 通过**EXPORT_APPLICATION(void(*)())**可加入init_application()中调用 > 需要注意: > > 用了自动初始化器无需调用额外tiny_kernel_startup(), 且main()中不能有堵塞, 尤其是hal库请在相应地方跳出while循环。 **示例:** ```C static void val_init(void) { /* 信号量初始化 */ semaphore = tiny_semaphore_create(5, 5); /* 二值信号量初始化 */ binary_semaphore = tiny_binary_semaphore_create(); /* 互斥锁初始化 */ mutex = tiny_mutex_create(); printf_mutex = tiny_mutex_create(); /* 邮箱初始化 */ mailbox = tiny_mailbox_create(3); /* 队列初始化 */ queue = tiny_queue_create(5, sizeof(struct queue_data)); } /* 将val_init导出后会自动执行 */ EXPORT_MOUDLE(val_init); ``` ### 统计cpu占用率和历史最小剩余栈 #### 配置 ***统计cpu占用率和历史最小剩余栈默认关闭*** 统计cpu占用率功能需要在tiny_def.h中将IS_OPEN_GET_CPU给PROFILE_OPEN 统计历史最小剩余栈大小功能需要在tiny_def.h中将IS_OPEN_STACK_HIGH_WATER给PROFILE_OPEN #### 使用说明 统计cpu占用率和历史最小剩余栈可以有效估计各个线程资源使用情况,只需调用tiny_thread_get_stack_high_water()和tiny_thread_get_cpu_usage() 便可轻松获得相关信息 *需要注意以上两个功能会拖慢时间,消耗内存资源,建议在debug时候用.* **示例:** ```C static void list_thread_callback(tiny_thread_t* thread) { printf("%-15s %-15d %-10s %-15d %0.2f%% \r\n", thread->name, thread->cur_priority, tiny_thread_status2str(thread->statu), // 将线程状态转化为字符串 tiny_thread_get_stack_high_water(thread), // 获取历史最小剩余栈 tiny_thread_get_cpu_usage(thread)) // 获取cpu占用率 } /* 定时器中统计(与下面选一个用) */ static void task_info(void *arg) { UNUSED_PARAMETER(arg); printf("=======================================================================\n\r"); printf("%-15s %-15s %-10s %15s %8s\n", "Name", "Cur_Priority", "Statu", "Min_Remaining_Stack", "CPU"); tiny_list_thread(list_thread_callback); // 遍历所有线程 printf("=======================================================================\n\r"); } /* 线程中统计 */ static void task_info_thread(void *arg) { UNUSED_PARAMETER(arg); while (1) { printf("=======================================================================\n\r"); printf("%-15s %-15s %-10s %15s %8s\n", "Name", "Cur_Priority", "Statu", "Min_Remaining_Stack", "CPU"); tiny_list_thread(list_thread_callback); // 遍历所有线程 printf("=======================================================================\n\r"); tiny_thread_delay_ms(200); } } ``` **效果:** ![](img/task_show.png) ### 设备模型 #### 说明 类似Linux, 可以注册, 卸载设备,支持open, close, read, write接口。 #### 使用 ```c // ... /* 按需要准备设备操作函数,不需要全部都注册一个函数 */ static tiny_operator_t led_op = { .open = led_open, .close = led_close, .read = led_read, .write = led_write}; // ... /* 注册设备 */ tiny_dev_regsiter("led", &led_op, 1); // ... /* 使用设备 */ const tiny_driver_t *pdriver = tiny_dev_get("led"); tiny_driver_open(pdriver); tiny_driver_write(pdriver, &temp, sizeof(led_t)); tiny_driver_read(pdriver, &temp, sizeof(led_t)); tiny_driver_close(pdriver); // ... /* 卸载设备 */ tiny_dev_unregsiter("led"); ``` ## 未来目标 - [ ] 支持更多芯片 - [ ] 支持设备树 - [ ] 引入组件系统,适配文件系统组件,脚本解释器,OTA升级等组件生态 - [ ] 引入自写shell,具备像keil中单步调试一样远程调试rtos - [ ] 引入日志,守护线程等各种对线程监测守护功能,使其更安全 - [ ] 优化内核速度 联系邮箱: luckkeymail@163.com