精华内容
下载资源
问答
  • 最简单的stm32 RTOS

    2018-09-14 18:00:58
    RTOS命名为HesOS,实现多任务切换,移植超简单,1ms调度一次, 实时性非常高
  • 所谓 RTOS (Real time operation system)指就是实时操作系统。如何理解这一句话呢?那么就要首先知道什么是系统,在日常生活中我们常常会听到系统这个词,比如有windows操作系统,Android操作系统,苹果...

    1、什么是RTOS?

      所谓的 RTOS (Real time operation system)指的就是实时的操作系统。如何理解这一句话呢?那么就要首先知道什么是系统,在日常的生活中我们常常会听到系统这个词,比如有windows操作系统,Android操作系统,苹果系统等,也有形容一个领域的,比如生态系统等。通过对这些系统的特性做归纳,那么我们会发现,系统描述的是一套复杂的事件或者行为,将这些行为或事件组合起来,就是一个系统。
      人其实也是一个系统,因为人的行为是复杂的,可变的。比如周末不上班,那么我可以选择在家,也可以出门。在家我可以选择睡觉,看电视,烹饪等等。出门我可以选择去公园,也可以选择去购物。这样我周末的行为就会有很多分支,多分支造成了系统的复杂性。除了分支以外,系统还具有多输入 的特性,比如我周末很不幸要加班,那么我周末的计划就泡汤了,意味着我的输出随着输入的变化而变化。多输入和多分支输出,造成了系统的不确定性,也是系统复杂的关键原因。
      虽然系统有着不确定性,但是也有确定性,

    展开全文
  • stm32 Ctext-M3内核最简单的多任务RTOS

    千次阅读 2018-09-14 18:01:51
    RTOS 实时操作系统,我做是一个多任务操作系统,可以同时运行多个任务,我这里设置最大任务数是32个, 估计跑30多个任务嵌入式设备很少吧,32个任务够用了。 OS我把它叫做HesOS,主要功能如下,比较简单。...

       RTOS 实时操作系统,我做的是一个多任务的操作系统,可以同时运行多个任务,我这里设置的最大任务数是32个,

    估计跑30多个任务的嵌入式设备很少吧,32个任务够用了。

    OS我把它叫做HesOS,主要功能如下,比较简单。

    1--实现多任务调度

    2--实现任务调度锁

    3--实现临界区保护

    4--实现读取cpu使用率(这个功能比较重要的)

    5--实现us延时(用于模拟如IIC总线模拟)

    对于一般的嵌入式应用有这些功能,差不多够用了。

    移植HesOS也非常简单,不会像其它的OS一样比较庞大,修改的地方也比较多,使用起来也复杂。

    HesOS不管是移植和使用都是非常简单的,类似于PC的线程使用。

    主函数初始化:系统一共跑了10个任务。

    部分任务定义:

    打印cpu使用量任务:

    不能在所有任务里串口打印,因为串口打印非常的占用cpu,除非使用dma传输。

    说一下移植,只需要实现以下代码

    _uint32 fac_us;
    //SysTick定时器
    void set_systick(_uint32 ms)
    {
    	fac_us=SystemCoreClock/1000000;				//不论是否使用OS,fac_us都需要使用
    	SysTick->LOAD	=	ms	*	SystemCoreClock/1000-1;
    	NVIC_SetPriority(SysTick_IRQn,(1<<__NVIC_PRIO_BITS)-1);
    	SysTick->VAL	=	0;
    	SysTick->CTRL	=	SysTick_CTRL_CLKSOURCE_Msk|
    									SysTick_CTRL_TICKINT_Msk|
    									SysTick_CTRL_ENABLE_Msk;
    	
    	
    }
    
    /*延时us
    
    这里裁剪的原子哥的
    
    
    */
    void delay_us(_uint32 nus)
    {		
    	_uint32 ticks;
    	_uint32 told,tnow,tcnt=0;
    	_uint32 reload=SysTick->LOAD;				//LOAD的值	    	 
    	ticks=nus*fac_us; 								//需要的节拍数 
    	told=SysTick->VAL;        				//刚进入时的计数器值
    	while(1)
    	{
    		tnow=SysTick->VAL;	
    		if(tnow!=told)
    		{	    
    			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
    			else tcnt+=reload-tnow+told;	    
    			told=tnow;
    			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
    		}  
    	};										    
    } 
    
    //滴答中断必须调用以下代码,是关于任务调度的
    void SysTick_Handler()
    {
    	
    		if(now_task!=0)			//如果当前任务不为空则执行任务调度
    		{	
    	
    			//任务调度
    			tran_delay();
    		}
    }

    把工程下的HesOS.lib加入工程,HesOS系统文件只有这3个

    具体可以参考实例工程:https://download.csdn.net/download/hes_c/10667667

    说明:本RTOS是借鉴freeRTOS和原子哥部分代码,演示工程是原子哥的库函数点灯工程。

    展开全文
  • 文章目录调度器调度器策略调度算法代码分析总结调度器流程 实验平台:stm32f10x(cortex-m3)开发板,RTT3.0 ...调度作用就是从一堆当前需要运行线程中找到那个需要马上运行程序。然后通过上下文切换,将...

    实验平台:stm32f10x(cortex-m3)开发板,RTT3.0
    资料来源:RTT官网文档及cortex-M3权威指南
    关键字:分析RT-Thread源码、stm32编写一个简单的RTOS、调度器。

    调度器

    额,这里还是介绍一下调度的功能吧(瞬间打脸)。
    调度的作用就是从一堆当前需要运行的线程中找到那个最需要马上运行的程序。然后通过上下文切换,将cpu的控制权移交给该线程。上一节我们已经了解并完成了上下文切换功能,所以这一节主要就是介绍如何找到那个最需要马上运行的线程,但也要保证各个线程尽可能的公平共享cpu时间。而且应该保证调度花费的时间尽量的小,不然实时性就会降低。所以对调度器就有如下要求:

    1):响应快。不能因线程的增多就导致调度时间变长,所以要求调度算法的时间复杂度要为O(1)。
    2):实时性。当系统发生突发事件时,如某个线程需要立刻运行,调度器能让其马上得到cpu控制权。所以调度器还得支持可抢占的。

    调度器的策略

    RT-Thread中提供的线程调度器是基于优先级的全抢占式调度:在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自身。系统总共支持256个优先级。在系统中,当有比当前线程优先级更高的线程就绪时,当前线程将立刻被换出,高优先级线程抢占处理器运行。RT-Thread内核中也允许创建相同优先级的线程。相同优先级的线程采用时间片轮转方式进行调度(也就是通常说的分时调度器),时间片轮转调度仅在当前系统中无更高优先级就绪线程存在的情况下才有效。

    调度算法

    RT-Thread内核中采用了基于位图(bitmap)的优先级算法(时间复杂度O(1),即与就绪线程的多少无关),通过位图的定位快速的获得优先级最高的线程。
    如果你看过编程珠玑,你应该对位图算法有一定的了解,记得这是第一章的内容吧,用位图算法来排序号码。下面介绍一下这个算法。

    看名称我们就可以知道这个算法和位(bit)有关系,位图排序算法和这里的查找算法其实都是一个原理,都是通过置位来标记,通过一定的规则算出最高优先级号。下面就直接举例子了。
    我们知道一个字节有8bit,范围从0-255。假设现在有两个不同的优先级5(低)和3(高优先级)。
    我们将按照不同的优先级将1进行左移,即优先级5:1 << 5,优先级3:1 << 3。将优先级都保存到一个变量rt_thread_ready_priority_group上。即:

    rt_thread_ready_priority_group |= 1 << 5; //0010 0000
    rt_thread_ready_priority_group |= 1 << 3; //0010 1000

    假设数字越小优先级越大,可以看到,我们只需要查找rt_thread_ready_priority_group最低位为1的位置就是我们要找的最高优先级了。8个bit有256种不同的结果。如果我们提前将其算好,如上的值为0x28,array[28] = 3,我们马上就可以知道最高的优先级是哪一个了,而且时间复杂度为O(1),这个就是典型的空间换时间了。

    rt_thread_ready_priority_group有32bit,所以可以保存32个不同的优先级了。但是当优先级数超过32时,怎么办?我们的单片机也就32bit?原理其实还是一样的,RTT采用了二级位图来解决这个问题。即一个不够记那么我们就用多个来记。因为数组的地址刚好是连续的,所以我们可以用数组来记录。如果我们规定的最大优先级是256的话,那么32*8=256,所以我们只需要32个字节就够了。但是如果只有一个数组的话,我们每次都要从0下标的数组元素开始扫描,如果我们只有一个优先级255,那么我们可能得扫描到数组array[31]才能得到最高优先级,这样花费的时间就有点多了。前面我们已经说了,RTT是采用二级位图来解决这个问题的,其实方法还是一样,我们用一个变量来标记哪些数组下标是有存储优先级的,这样我们就能直接找到那个最高优先级的数组元素而不用去轮询了。
    举个例子:
    rt_uint32_t ready_priority_group; //标记哪些数组下标有存储优先级
    rt_uint8_t ready_table[32]; //实际记录了优先级的情况

    假如现在有个优先级为9的线程。一个数组元素可以存储8个优先级。所以将优先级除以8就知道该存储在那个数组元素了。
    ready_priority_group = 9 / 8 = 9 >> 3 = 1; //左右移更快。
    ready_table[1] = 9 % 8 = 9 & 0x07 = 1; //先不用或,方便理解

    我们就可以通过这两个变量找到具体的优先级了。__rt_ffs假设这个函数可以找到一个变量的最低被置1的位置。那么:
    index = __rt_ffs(ready_priority_group)就可以找到哪个数组下标了,
    然后__rt_ffs(ready_table[index])就得到了具体的优先级。但是我们还得将index * 8,因为一个数组元素代表8个优先级嘛。
    所以highest_ready_priority = index * 8 + __rt_ffs(ready_table[index]);

    代码分析

    好了算法就介绍到这,下面跟着代码分析一下:

    /* Maximum priority level, 256 */
    rt_uint32_t rt_thread_ready_priority_group;
    rt_uint8_t rt_thread_ready_table[32];
    

    从线程初始化函数开始,这里设置的线程优先级被保存到了thread->init_priority,current_priority 中。假设我们优先级为123.

    static rt_err_t _rt_thread_init (...)
    {
    	...
    	thread->init_priority    = priority;	//123
    	thread->current_priority = priority;	//123
    	...
    }
    

    而在rt_thread_startup中进行了如下操作。

    rt_err_t rt_thread_startup(rt_thread_t thread)
    {
    	....
        thread->number  = thread->current_priority >> 3;    /* 5bit */ //除以8,number = 15 => table[15]
        thread->number_mask = 1L << thread->number;	//位15被置1了
        thread->high_mask   = 1L << (thread->current_priority & 0x07);  /* 3bit */	//1L << 3
    	...
    }
    

    在加入调度队列时的处理:

    void rt_schedule_insert_thread(struct rt_thread *thread)
    {
    	...
    	rt_thread_ready_table[thread->number] |= thread->high_mask;	//table[15]位3置1
    	rt_thread_ready_priority_group |= thread->number_mask;	//位15被置1了
    	...
    }
    

    接下来我们看在调度的时候是如何得到这个值的。

    void rt_schedule(void)
    {
    	...
    	 register rt_ubase_t number;
    	
    	 number = __rt_ffs(rt_thread_ready_priority_group) - 1;	//算出最高优先级的数组下标16 - 1
    	 highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;		//(15*8) + 4 - 1 = 123
    	......
    }
    

    RTT2.0版本,3.0之后的改为汇编了,为了方便理解,这里贴2.0的。
    因为__lowest_bit_bitmap是256个字节的,即8bit,所以需要将32bit分为4段,所以需要n(1~4)*8。

    int __rt_ffs(int value)
    {
        if (value == 0) return 0;
    
        if (value & 0xff)
            return __lowest_bit_bitmap[value & 0xff] + 1;
    
        if (value & 0xff00)	// bit15 : 0x8000 >>8 =  0x80 = 128
            return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;	//7 +9 = 16
    
        if (value & 0xff0000)
            return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;
    
        return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
    }
    

    所以就这样算出最高优先级了。其实并不难理解,不过我写的好像有点乱七八糟,反而有点懵逼。。
    今天就先摸鱼到这里。。

    现在我们找到了最高优先级,要怎么用最高优先级找到具体的线程呢?这个时候我们需要用到双链表的知识,所以这块还不熟悉的可能理解起来会有困难。这里我就不讲链表相关的知识了,篇幅有限。
    我们先来看一下RTT是怎么通过优先级找到线程的句柄。如下:

    void rt_schedule(void)
    {
    	...
    	register rt_ubase_t number;
    	
    	number = __rt_ffs(rt_thread_ready_priority_group) - 1;
    	highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
    	
    	 /* get switch to thread */
    	 to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
    	                                 	 struct rt_thread,
    	                                 	 tlist);
    	...
    }
    

    这里说一下rt_list_entry的作用:就是通过结构体的成员地址去算结构体的起始地址。是的,就是linux中的container_of宏。关于container_of网上已经介绍的十分详细,这里也不再讲解,自行百度。我们这里只关心一下数组rt_thread_priority_table,这是一个链表数组,即数组的元素是由链表组成的。其定义如下:
    struct rt_list_node
    {
    struct rt_list_node *next; /< point to next node. */
    struct rt_list_node *prev; /
    < point to prev node. */
    };
    typedef struct rt_list_node rt_list_t; /**< Type for lists. */

    rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

    我们看一下它和线程又有什么关系。
    首先在rt_system_scheduler_init中初始化了该数组,目前还没有和线程有什么关联。

     void rt_system_scheduler_init(void)
    {
    	...
    	for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
    	{
    	    rt_list_init(&rt_thread_priority_table[offset]);
    	}
    	...
    }
    

    它是在什么时候和线程关联上的呢?我们看一下 rt_thread_startup。

    rt_err_t rt_thread_startup(rt_thread_t thread)
    {
    	...
     /* change thread stat */
        thread->stat = RT_THREAD_SUSPEND;	//修改线程状态为挂起状态
        /* then resume it */
        rt_thread_resume(thread);	//恢复线程
        if (rt_thread_self() != RT_NULL)
        {
            /* do a scheduling */
            rt_schedule();	//调度
        }
    
        return RT_EOK;
    }
    
    rt_err_t rt_thread_resume(rt_thread_t thread)
    {
    	...
    	/* insert to schedule ready list */
    	rt_schedule_insert_thread(thread);
    	...
    }
    
    void rt_schedule_insert_thread(struct rt_thread *thread)
    {
    	...
    	 /* change stat */
    	thread->stat = RT_THREAD_READY;	//修改为就绪状态,只有就绪才能转入运行状态。
    	
    	/* insert thread to ready list */	//插入链表中,这是线程就和rt_thread_priority_table关联了。
    	rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
    	                          &(thread->tlist));
    	...
    }
    

    在rt_thread_resume中调用了rt_schedule_insert_thread,此时线程就和rt_thread_priority_table联系上了。
    rt_thread_priority_table[priority]就是存储已经就绪的线程链表。
    在这里插入图片描述
    所以我们通过thread的成员tlist就可以用rt_list_entry/container_of找到线程的句柄了。
    /* get switch to thread */
    to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
    struct rt_thread,
    tlist);
    找到句柄我们就可以用上下文切换函数进行任务的切换了。
    rt_hw_context_switch((rt_uint32_t)&from_thread->sp,
    (rt_uint32_t)&to_thread->sp);

    总结调度器流程

    1:调度器初始化
    2:将就绪状态的线程插入就绪优先级表中
    3:找到最高优先级号(利用位图来记录就绪优先级存储和预先算好8bit的所有可能值的最低位)
    4:用优先级号找到线程句柄
    5:进行上下文切换

    关于调度就介绍到这结束了。

    展开全文
  • Free RTOS简单排除争夺资源时死锁

    千次阅读 2009-08-06 09:07:00
    A8 (pp:6215714)2009-8-5 22:28:06 FreeRTOS一般用信号量Semaphore作为任务独占资源凭证。如果有多个并发任务共享一个硬件资源,如SPI接口,那么就得为该硬件设置一个信号量。当一个任务获得该信号量,那么这个...

    A8 (pp:6215714)2009-8-5 22:28:06
    FreeRTOS一般用信号量Semaphore作为任务独占资源的凭证。如果有多个并发的任务共享一个硬件资源,如SPI接口,那么就得为该硬件设置一个信号量。当一个任务获得该信号量,那么这个任务就可以独占该信号量代表的资源(不一定是硬件资源)。
         如果这个任务顺利地执行完涉及到该资源的代码,并最后释放信号量,那么一切OK。此处没什么好说的。
        如果这个任务在执行的过程中(相关信号量还没有释放),比它优先级相同(时间片轮转的结果)或者更高(可剥夺型配置的结果)的其它任务获得CPU执行权(比当前任务优先级低的任务没有可能获得CPU执行权),在这种情况下,情况分为几种:
        1、如果另一个的任务没有用到该信号量,那么情况比较简单。
        2、如果另一个任务(称为第二个任务)用到该信号量,由于前一个任务(称为第一个任务)还没有释放该信号量,那么第二个任务必然得不到该信号量,为这个信号它必须等待(可设定有限时间的等待或者无限等待),也就是此任务被系统挂起。当第二个任务被系统挂 起后,第一个任务将重新获得CPU的执行权。这种情况叫优先级反转,也就是低优先级的任务反而优先运行。一旦第一个任务释放掉该信号量,系统将立即恢复第二个任务的执行。
       3、这种情况比较复杂。当第二个任务中断第一个任务运行时,第一个任务还没有释放该信号量,那么第二个任务必将被挂起,于是第一个任务被恢复运行,然而第一个任务继续运行的时候需要另外一个信号量,而这个信号量恰被第二个任务占有。于是我方有你需要的信号量,你方有我需要的信号量,两个任务就相互卡壳了,谁也执行不了了。这种情况在编程时,必须要避免,它就像是定时炸弹一样。

     

    对于第三种情况,如果2个资源是用的一个互斥量,那么就不会出现两个任务各占一个资源的情况,从而排除。(当然这不是最好的办法)。

    展开全文
  • 了解RTOS

    2008-12-26 15:39:19
    嵌入式软件由RTOS跟其上跑应用部分软件组成,应用部分软件可简单看成一个个任务,每个任务可以对相关外界产生事件或是异常响应。而RTOS的核心功能就是管理各个任务,并建立起任务和外界事件联系。 一个...
  • CMSIS-RTOS 信号量使用Using Semaphores

    千次阅读 2016-11-20 21:50:30
    信号量的使用Using Semaphores前面说过信号量包含较多的OS调用,所以它拥有广泛的同步应用,这也就导致了它可能是RTOS里面最难理解...发送信号Signaling两个线程之间的同步是信号量最简单的使用方式:osSemaphoreId sem
  • 使用这种新模型,我们可以更快地推出错误修复并实现更简单的维护。 路线图 ESP8266_RTOS_SDK的框架是相当过时,并从当前不同的 ,我们计划V2.0.0后ESP8266_RTOS_SDK迁移到ESP-IDF最后。 但是,我们首先提供一个新...
  • RTOS 相关术语,简单地分为内核类与线程类相关术语,理解这些基本概念,是学习 RTOS 关键一环。 一、内核类概念 在 RTOS 基础上编程,芯片启动过程先运行一段程序代码,开辟好用户线程运行环境,准备好对...
  • (1)主从结构:修改一个OS内核使其支持多处理器系统的最简单的方法,是将整个OS视为一个不可分割的整体,并限定所有内核模式的操作均运行于同一个处理器(即主处理器)上,而另一个处理器(即从处理器)只用来执行...
  • 目录环境设置如何构建支持电路板/仿真器环境设置TizenRT提供了使用Docker进行构建的最简单方法。 不需要安装所需库和工具链,因为提供Docker容器已经包含TizenRT开发所需一切。 但是,如果你发展
  • 使用这种新模型,我们可以更快地推出错误修复并实现更简单的维护。 路线图 ESP8266_RTOS_SDK的框架是相当过时,并从当前不同的 ,我们计划V2.0.0后ESP8266_RTOS_SDK迁移到ESP-IDF最后。 但是,我们首先提供一个新...
  • 虽然说small rtos51可能是最简单的操作系统,是学习操作系统最容易入门的,但是,还是有一定难度。 对于一个只学会了51单片机简单开发的工程师来说,也许会熟练应用keil调试程序,但可能没有写过操作系统这么复杂的...
  • TizenRT提供了使用进行构建的最简单方法。 不需要安装所需库和工具链,因为提供Docker容器已经包含TizenRT开发所需一切。 但是,如果您开发系统不适合运行Docker容器,则应手动安装所有库和工具链。 请参阅...
  • KLite是一个为ARM Cortex-M微控制器设计微内核,设计思想是"简洁易用". 它最大特性在于简洁易用,可能是目前为止最简单易用嵌入式操作系统内核.
  • 在所有时间服务功能中,基本一个就是延时函数。它可以在你应用中提供非常简单易用延时功能。也许你会觉得CMSIS-RTOS已经占用了5k字节代码量,但是在非RTOS的应用中,我们也常会用到...
  • 非常久没有关注RTOS了,所以也一直没有更新。近期闲了,把GPIO I2C调通了。简单移植了Touch。在S5PV210上使用。 调试I2C时。废了非常多周折,最后借助示波器才发现一个小小错误。折腾了非常久非常久。 简要说下...
  • 主流国产RTOS ...TencentOS tiny提供精简的RTOS内核,内核组件可裁剪可配置,可灵活移植到多种终端MCU上。而且,基于RTOS内核,提供了COAP/MQTT/TLS/DTLS等常用物联网协议栈及组件,方便用户快速接入腾讯
  • 开发环境搭建好后,接下来写第一个程序,当然,要写最简单的程序,把板子上的LED灯点亮。 打开CCS,选择菜单【Project】-->【New CSS Project】,弹出New CSS Project对话框:【Connection】组合框选择...
  • 如何将RTOS添加到ZYNQ SoC设计中

    千次阅读 2015-08-12 17:14:17
    在寻求获得来自处理系统内的赛灵思Zynq®-7000全可编程SoC的最大利益,操作系统将让你更不是一个简单的裸机解决方案。任何开发ZYNQ SoC设计有大量的操作系统可供选择,并根据最终应用程序,你可以选择一个实时版本。...
  • 之前做示例由于不了解task,我把代码简化,现在可以深入一些去学习了。所以先学前面示例,再来学这个,会简单些。 两个示例,两种不同使用方法,下面一一道来。示例可从菜单【View】→【Resource Exploer ...
  • 而且我们在使用emWin时往往是搭配RTOS一块使用,于是这天我想搞一个emWin+LiteOS(华为物联网操作系统)工程。 我先是在LiteOS工程上移植emWin,然后各种玄学,最后放弃。 然后我再在emWin裸机工程上移植LiteOS...
  • RTOS实时操作系统uCOS-III向STM32F103移植过程

    千次阅读 多人点赞 2018-02-02 16:08:18
    本人是一名大三学生,在前一段时间曾陷入了对未来...操作系统大体上分为两大类:一个是实时操作系统,另一个则是非实时操作系统(具体的区别简单的说就是前者是对实时性有硬性要求的,但性能却远低于后者,后者能处理的
  • 一个最简单的操作系统只要能完成任务管理就可以,这也可以说是操作系统的核心内容(是我个人的看法),在写单片机的这些年里,我一直在运用和探索UCOS,UCLINUX,WINCE,QNX,RTOS和ECOS等操作系统,这其中UCOS和RTOS是最为...
  • 工作了两年了,现在对于C有了比较深入的了解,现在才发现,基础真的很重要,以前学习的都是些华丽而没多少用处的东西,这段时间看最简单的RTOS的代码,才了解到,以前老师总是强调的数据结构加上算法的概念,内核...
  • FreeRTOS系列第8篇---FreeRTOS内存管理

    万次阅读 多人点赞 2015-12-10 13:41:24
    其中最简单的管理策略也能满足很多应用的要求,比如对安全要求高的应用,这些应用根本不允许动态内存分配的。 FreeRTOS也允许你自己实现内存堆管理,甚至允许你同时使用两种内存堆管理方案。同时实现两种内存堆允许...
  • 现世面上流传着很多嵌入式操作系统,都已经非常优秀,但本人还是自己编写了一个RTOS,不敢说优秀,但绝对是使用起来最简单的.

空空如也

空空如也

1 2 3 4 5
收藏数 85
精华内容 34
关键字:

最简单的rtos