[size=14.3999996185303px]RT_Thread OS 基本例程说明 [size=14.3999996185303px] 本文档主要针对RT-OS基本例程的说明,不对RT-OS的原理进行讲解,也不做移植的说明,因为RT-OS的论坛以及网站,已经对RT-OS的说明很详细,且有移植好的工程文件,移植教程里面也有详细的说明。所以这里我们只是根据下面链接的帖子里面的例程做一个总结,依据STM32F1进行编写的,这里我们把部分例程移植到我们的金龙107上面, [size=14.3999996185303px]这些例程所用到的硬件只有串口,以及我们金龙107开发板的一个LED灯和一个按键,只需要用串口线把我们金龙107和PC机连接起来,只需要一根串口线就可以完成RT-OS所有试验。其中LED灯是作为指示程序的运行,并没有其他作用,按键在其中一个例程中有用到。 [size=14.3999996185303px]例程已将Lwip移植到金龙107开发板上了,如果需要使用到网络可以在rtconfig.h文件里面将#define RT_USING_LWIP宏打开,同时在application.c文件中注释去掉修改如下: [size=14.3999996185303px] [size=14.3999996185303px] [size=14.3999996185303px]跳线帽JP9接23,连接网线设置电脑IP为192.168.1.203,开发板IP为192.168.1.199。进入电脑命令提示符界面输入ping 192.168.1.199,显示如下信息,说明网络连接正常。 [size=14.3999996185303px]
[size=14.3999996185303px]1、动态线程的创建与删除[size=14.3999996185303px]该例程主要说明动态线程的创建与删除,首先我们要在rtconfig.h中开启两个宏定义: [size=14.3999996185303px]#define RT_USING_HEAP;开启此项可以创建动态线程和动态信号量,如果使用静态线程和静态信号量,则此项不是必要的。请注意这里的动态和静态,后面的例程大多用到动态线程或者信号量等,所以此项也是一直开启的,后面将不再赘述。 [size=14.3999996185303px]#define RT_USING_CONSOLE;本实验使用rt_kpriintf向串口打印按键信息,因此需要开启此项。后面的实验,都需要向串口输出数据,所以此项是必须的,我们就不再赘述。 [size=14.3999996185303px]另外还有一个宏定义,我们需要注意,就是:#define RT_TICK_PER_SECOND 100,这个宏定义的意思是,操作系统的100个Tick是1S,则一个OS Tick=10ms。后面的程序中我们使用的都是100,所以后面我们也将不再赘述此选项。 [size=14.3999996185303px]下面开始讲解我们的程序,首先我们要定义两个指向动态线程的指针并建立线程入口函数,如图1-1所示。 [size=14.3999996185303px] [size=14.3999996185303px]图1-1 [size=14.3999996185303px] 如图1-1所示,线程1首先打印信息,然后循环进行计数,并打印,延时1S继续循环。线程2首先也是打印信息,然后延时4S,然后删除线程1,并打印信息。 [size=14.3999996185303px] 下面看线程的创建,如图1-2所示。第一个线程是静态线程,上面提到的LED灯的闪烁,指示程序运行的作用。主要看下面的两个线程的创建下面的两个线程采用的是创建,而不是初始化,是不一样的。这是动态的线程,采用的是rt_thread_create()函数,返回的是线程控制块的地址。也就是我们上面定义的线程指针。 [size=14.3999996185303px]第一个参数是线程的名字,可以随意, [size=14.3999996185303px]第二个参数是线程入口函数, [size=14.3999996185303px]第三个参数是线程入口函数的参数, [size=14.3999996185303px]第四个参数是线程的堆栈空间, [size=14.3999996185303px]第五个参数是线程的优先级, [size=14.3999996185303px]最后一个参数是时间片。 [size=14.3999996185303px]因为RT-OS支持时间片轮法,当两个线程优先级相同时,则采用时间片轮法进行线程的切换。最后判断线程是否创建成功,创建成功则给线程指针分配地址,则其不为空指针,然后启动线程即可。第二个线程一样。 [size=14.3999996185303px] [size=14.3999996185303px]图1-2 [size=14.3999996185303px]结果分析: [size=14.3999996185303px] 程序的执行结果如图1-3所示。 [size=14.3999996185303px] [size=14.3999996185303px]图1-3 [size=14.3999996185303px] 上面是打印的RT-OS的信息,因为线程1的优先级比较高,所以先执行,打印一个数据,在线程1的循环中有一个延时,所以打印一次信息之后,要进行延时,则线程1挂起,执行线程2,打印成功创建线程2之后,线程2也进行了4S的延时,所以线程2挂起,等待线程1再运行三次,因为每次都是延时1S,当到了线程1打印出thread1 count: 1之后,再延时1S的时候,线程2的延时时间到,则执行线程2中的删除线程1代码,则线程1不再运行,线程2打印出信息之后,运行结束,并自行删除。 [size=14.3999996185303px]
[size=14.3999996185303px][size=14.3999996185303px] 2、静态线程初始化与脱离
[size=14.3999996185303px]
[size=14.3999996185303px]该例程主要说明静态线程的初始化和脱离。上一节我们讲的是动态线程,这一节讲的是静态线程,这两种线程的建立有什么不同呢,请看图2-1所示。 [size=14.3999996185303px] [size=14.3999996185303px]图2-1 [size=14.3999996185303px] 从图2-1中看出,静态线程的创建首先要定义线程的堆栈空间,以及定义一个线程控制块。而在动态线程建立的时候,只需要定义一个指向线程控制块的指针即可。这个实验和第一个实验动态线程的使用的实验现象基本上是一样的,一个是动态的,一个是静态的。第一个实验当删除线程1的时候,采用的是rt_thread_delete()函数,删除线程1,而这里采用的是rt_thread_detach()函数,使线程1脱离。这是两者不一样的地方,其次是在线程的创建的不一样。 [size=14.3999996185303px]如图2-2所示。我们看到,线程的创建采用的是rt_thread_init()函数,对线程进行初始化,返回的是线程是否创建成功,而动态线程则采用的是rt_thread_create()函数,进行创建线程,返回的是线程控制块的指针。且其中的参数也是不一样的。Rt_thread_init()函数的 [size=14.3999996185303px]第一个参数是线程控制块的地址,也就是上面我们定义的线程控制块的地址。 [size=14.3999996185303px]第二个参数是线程的名字, [size=14.3999996185303px]第三个参数是线程的入口函数, [size=14.3999996185303px]第四个参数是线程入口函数的参数, [size=14.3999996185303px]第五个参数是线程堆栈空间的首地址, [size=14.3999996185303px]第六个参数是线程堆栈空间的大小, [size=14.3999996185303px]第七个参数是线程的优先级, [size=14.3999996185303px]第八个参数是线程的时间片大小。 [size=14.3999996185303px]创建成功,则启动线程。 [size=14.3999996185303px] [size=14.3999996185303px]图2-2 [size=14.3999996185303px]结果分析: [size=14.3999996185303px] 如图2-3所示,是该程序的运行结果:该程序的运行结果和上一个实验的是类似的,也是在线程1运行一定时间之后,用线程2将线程1脱离或者删除。 [size=14.3999996185303px] [size=14.3999996185303px]
[size=14.3999996185303px] 3、线程让出
本节主要说明的是线程的让出,而不是线程的删除或者脱离。线程的删除或者脱离之后,线程将不再运行,除非重新启动线程,而线程的让出,则只是暂时的把当前线程停止,让给其它就绪的线程,多用于有优先级相同的线程,否则,如果高优先级的线程就绪则直接抢占了,低优先级就绪,就算高优先级的线程让出,很快也会再次被高优先级的线程抢占。线程让出之后并不是线程被挂起了,线程依旧是就绪状态。所以说只对有优先级相同的线程有效。 上面两节我们说了静态线程的初始化和脱离,动态线程的创建以及删除。这节我们将不再说线程的创建或初始化等,只对程序和运行结果进行分析。如图3-1所示,是两个线程的入口函数。 图3-1 从图3-1中我们可以看到,线程1和线程2都是循环进行计数以及让出线程,不过线程1是先计数,然后让出线程,而线程2是先让出线程,在计数并打印。 该例程需要注意的是,上面我们有提到线程的让出,只在相同优先级的任务之间的切换,所以这两个线程的优先级必须是一样的。 结果分析: 如图3-2所示,是该程序的运行结果。从结果中我们可以看出,线程1首先计数并打印了两次,线程2才打印1次,后面的就是线程1和线程2的交替打印。线程1怎么会出现打印两次呢,是因为线程1先建立并启动,所以线程1先执行,首先打印1次,然后让出,线程2执行,线程2则先执行线程让出,这时候又变成线程1执行,然后线程1就又一次进行计数打印,而线程2一次也没有打印。待线程1打印结束之后,再次让出线程,这时候线程2才有机会计数并打印数据。所以后面就是交替的进行数据的打印。 其实这个程序,打印到后面我们会发现又错了,不是交替打印,因为这个时候线程的时间片到了,所以线程被挂起了。 图3-2
|
|