目录0裸机编程引发的思考...........................................................................................................21Rt-hread简介........................................................................................................................61.1RT-Thread内核...................................................................................................61.2RT-Thread与µC/OS-II对比................................................................................71.3支持平台.............................................................................................................71.4获取RT-Thread最新动态,寻求帮助..............................................................82RT-Thread应用开发..............................................................................................................92.1第一个应用流水灯.........................................................................................9仿真运行.........................................................................................................15开发板上实际运行.........................................................................................16RT-Thread学习笔记0裸机编程引发的思考现在摆在面前你有一个任务:两个LED灯,LED1每隔1S闪烁一次,而LED2每隔2S闪烁一次。仔细想一下,裸机代码中如何实现呢?我们可以使用一个定时器实现一个时基中断,比如50ms中断一次,那么需要20次中断即可以统计1S,并使用两个全局变量来表示两个LED的状态,伪代码如下。编程模型1:intmain(void){系统初始化操作for(;;){//空循环}}Time_INTR_Hander()//定时器中断函数,这个名字为仅为示意{staticintled1_tinc=0;//统计第一个定时的定时时间staticintled2_tinc=0;//统计第二个定时的定时时间staticintled1_status=0;//标示第一个led的状态staticintled2_status=0;//标示第二个led的状态//检测是否是定时器中断溢出if(led1_tinc++20)//表示到了S的时间了{led1_status=!led1_status;if(led1_status)点亮led1else熄灭led1}if(led2_status++40)//表示到达S的时间了{led2_status=!led2_status;if(led2_status)点亮led2else熄灭led2//清除定时器中断标志位}使用裸机编程,我们可以轻易的达到目的。但是这种方式会带来两个问题1)需要我们来自己管理所有的硬件设备,包括使用系统的定时器。2)led1和led2看起来没有任何的关系,但是我们却要在同一个定时器的中断处理子程序中操作他们。点亮LED这个动作很简单,耗费的CPU时间也很短,以至于我们可以把点亮LED的代码放在中断中,而main函数中只需要一个for(;;)死循环即可,main函数中甚至都不知道有两个LED灯在交替闪烁。点亮两个LED灯只是对多任务运行的一种最简单的抽象。我们来考虑另外一种情况。比如说需要控制两个复杂的外设,比如说GPRS模块,和电机模块,其中电机每1S中启动一次,控制电机需要花费0.3S钟,而GPRS每2S就要向外部发送一些信息,耗费的时间大约为0.5S钟。此时系统中可能还要执行其他的一些控制,比如控制串口(USRT)或者同时做GUI显示。系统中也可能会有其他的一些中断,而不是单纯是一个定时器中断这么简单。无疑这种情况是复杂的,至少相对于流水灯而言,我们不能简单的把控制电机的代码和控制GPRS的代码简单的放在定时器中中断中执行,为什么呢??因为当系统中断很多时,中断时间执行过长,将导致比它优先级低的中断被抢占而无法执行。对于不支持中断嵌套的MCU,采用这种方式,将会导致一个更重要的事件被阻塞。当然,在支持中断嵌套的MCU上,这么设计也是可以的,但这不是一个好的设计方案,因为一般来说,同级别的中断是不可以被另外一个同级别的中断抢占的。从一般意义上来说,中断程序应该尽可能快的执行完毕。这种编程方式很容易使我们在使系统的各个部分协调工作上耗费大量的时间,而不是专注各个部分的功能。让我们来考虑第二种写法。把点亮led的代码从中断处理子程序中取出放在main中,为了实现这种效果,我们需要增加两个变量,用来做事件标志。编程模型2staticintflag_led1=0;//led1事件标志,表示led1的s间隔到staticintflag_led2=0;//led2事件标志,表示led2的s间隔到staticintled1_status=0;staticintled2_status=0;intmain(void){//..完成系统初始化操作for(;;){if(flag_led1){flag_led1=0;led1_status=!led1_status;if(led1_status)点亮led1else熄灭led1}if(flag_led2){flag_led2=0;led2_status=!led2_status;if(led2_status)点亮led2else熄灭led2}}}Time_INTR_Hander()//定时器中断函数,这个名字为仅为示意{staticintled1_tinc=0;//用来统计第一个定时的定时时间staticintled2_tinc=0;//用来统计第二个定时的定时时间//检测是否是定时器中断溢出if(led1_tinc++20)//表示到了S的时间了{flag_led1=1;}if(led2_tinc++40)//表示到达S的时间了{flag_led2=1;}//清楚定时器中断标志位}看起来这种代码满足上上面所说的原则:“从一般意义上来说,中断程序应该尽可能快的执行完毕。”main函数采用的是轮询方式来处理事件。并且中断中来触发事件标志,这是一种经典的前后台的编程思想。一般来说,这种代码可以工作的很好,并且可以解决我们可以遇到的大部分问题。不过让我们仔细的分析一下这种方法的问题。闪烁led1和led2变成了相同优先级事件了。为什么呢?因为我们采用的轮询方式,没有抢占,这意味着所有的事件都是相同优先级的,main中依次扫描各个事件标志,当发现某个事件标志为1,则表示该事件满足,进入事件处理的代码,别忘了,处理之前,先把这个标志清楚为0,就像flag_led1=0;一般来说变成相同优先级没什么问题,并且实践表明,这样处理可以解决很多问题。但是在某些实时要求严格的情况下,这种编程模型不能满足系统的性能。这就是轮询最大的弊端。它将所有的事件混为一潭,不能区分不同事件的次重级别。因而在某些紧急情况出现时,不能很好的工作。系统的响应时间受限于for循环中事件的多寡,以及每个事件函数执行的时间。此外还有其他的一些编程模型,比如定义一个函数指针数组,然后将各个模块代码各自写成函数,向函数指针数组中填充模块的函数指针,这种编程的方式实际是轮询式编程的一种变形。因为不支持抢占,所以还是轮询的方式,并没有从根本上解决轮询的弊端。当系统中各个部分复杂起来,各种控制逻辑相互交织的时候,编写一个清晰的裸机程序会耗费一些脑细胞,尤其是当代码量增长到数千行至上万行时,如果没有一个合理并且清晰的程序结构,问题会更糟糕。让我们来考虑一下桌面系统,比如大名鼎鼎的windows-XP,这是一个多任务的操作系统,每个应用程序各自工作,它们并不知道其它应用程序处于什么状态,是运行还是关闭,每个应用程序仿佛占用了整个CPU一样,由操作系统管理多个应用程序的运行,套用伟大的政治课本上的一句伟大的名言,这极大的解放了我们的生产力。采用RTOS,多个人可以为多个模块各自编写代码。每个任务占用一个线程,任务在线程中活动,最简单的情况下,它可以不知道其它线程的状态。这种方式,无疑可以大大加快程序的编写,并且减轻程序拼装的难度。RTOS接管了最令人头痛的环节。在嵌入式系统中,显然不能运行桌面操作系统,在这种情况下,嵌入式操作系统横空出世。在嵌入式领域,主要使用的嵌入式系统都是实时嵌入式系统,故了描述方便,下面称之为RTOS。下一节我将隆重介绍国产实时嵌入式系统RT-Thread。1Rt-hread简介实时线程操作系统(RT-Thread)是国内RT-Thread工作室精心打造的稳定的开源实时操作系统(RealTimeOperationSystem简称为RTOS),历时4年,呕心沥血研发,力图突破国内没有小型稳定的开源实时操作系统的局面。它不仅仅是一款开源意义的实时操作系统,也是一款产品级别的实时操作系统,目前已经被国内十多所企业采用,被证明是一款能够稳定持续运行的操作系统。实时线程操作系统(RT-Thread)不仅是一个单一的实时操作系统内核,它也是一个完整的嵌入式系统,包含了实时嵌入式系统相关的各个组件:FinshShell文件系统图形界面RTGUITCP/IP协议栈1.1RT-Thread内核RT-Thread实时操作系统核心是一个高效的硬实时核心,它具备非常优异的实时性、稳定性、可剪裁性。当进行最小配置时,内核体积可以到3kROM占用、1kRAM占用。内核对象系统实时线程操作系统内部采用面向对象的方式设计,内建内核对象管理系统,能够访问或管理所有内核对象。内核对象包含了内核中绝大部分设施,而这些内核对象可以是静态分配的静态对象,也可以是从系统内存堆中分配的动态对象。通过内核对象系统,RT-Thread可以做到不依赖于具体的内存分配方式,伸缩性得到极大的加强。任务/线程调度支持以线程为基本调度单位的多任务系统。调度算法是基于优先级的全抢占式线程调度,支持256个线程优先级(亦可配置成32个线程优先级),0优先级代表最高优先级,255优先级留给空闲线程使用;相同优先级上支持多个线程,这些相同优先级的线程采用可设置时间片长度的时间片轮转调度;调度器寻找下一个最高优先级就绪线程的时间是恒定的(O(1))。系统不限制线程数量的多少,只与物理平台的具体内存相关。同步机制系统支持semaphore(信号量),mutex(互斥锁)等线程间同步机制。mutex采用优先级继承方式以防止优先级翻转。semaphore释放动作可安全用于中断服务例程中。同步机制支持线程按优先级等待或按先进先出方式获取信号量或互斥锁。通信机制系统支持event,mailbox,messagequeue通信机制等。event支持多