嵌入式工程狮的升级打怪之路

[手搓RT-Thread]5、移植RTT并动态创建线程

Github链接:HawkJ02/RT-Thread_Handmade: 手搓Rt-Thread (github.com)

本章Chapter5还是跟着野火的例程将RTT移植至正点原子的精英V2开发板(牛头人),并且使用线程(动态分配)点灯!

安装RT_Thread nano Pack

pack包安装链接:https://www.rt-thread.org/download/mdk/RealThread.RT-Thread.3.0.3.pack
安装完毕后可以进入已安装软件包看到RTT 3.0.3:

进入此图标:

可以看到RTOS目录下已有RTT,添加kernel:

可以看到左侧的project中已添加RTT的组件:

内核移植,接口文件(RTT官方写的支持MCU的文件):
context_rvds.s
cpuport.c

内核文件:
clock.c
components.c
device.c
idle.c
ipc.c
irq.c
kservice.c
mem.c
object.c
scheduler.c
thread.c
timer.c

应用代码:
board.c

配置文件:
rtconfig.h

这些代码在之前的文章里基本都有所介绍,在接下来移植的过程中,你可以直接在keil自动添加的这些代码中进行修改,也可以打包一份RTT工程,随着我们的项目一起发布。

移植

首先我们将RTT文件夹内这两个程序移动至项目的user文件夹下,意味着这两个文件是使用者进行修改的:

然后在项目管理目录下添加rtt/source和rtt/ports,其中source是rtt的src文件夹下的源代码,ports是mcu的接口文件:

接着我们在魔术棒里添加RTT需要链接的头文件:

TIPS:如果你的文件上带了小钥匙,说明是只读模式,可以在文件的属性中修改:

对rt_config.h进行以下三处修改,其中per_second代表着系统滴答时钟的scale是1ms,THREAD_STACK_SIZE设置为512,并且注释掉RTE头文件:

修改board.c程序,详情请查看github仓库:主要是将时钟部分的初始化使用固件库的程序,添加board.h以供外部程序调用。

并且在stm32的中断服务函数程序中,将PendSV、Systick以及HardFault_Handler(void)这三个函数注释掉,因为在RTT的程序中也有声明,我们既然使用了操作系统,就不用自带的了。

在此部分的最后,我们先测试LED是否能够点亮,再进入创建线程部分。

将LED的GPIO初始化移至board.c的硬件初始化程序中,并在main函数中调用这个函数(记得包含头文件噢),其中:

include “board.h”中是我们自定义的一些函数的头文件

include “rtthread.h”中是RTT官方的头文件

可以看到LED正常点亮(注意:我使用的是正点原子的板子和野火的例程,这两家的原理图不是一样的!相信你这么厉害一定能自己修改下GPIO叭)。

到目前为止,我们的RTT已经移植完毕!

创建单线程

我们目前已经确定LED的硬件没有问题,接下来,我们开始创建线程。创建线程的方式分为静态内存和动态内存:
静态内存是指在程序编译的时候就创建,比如我们之前手搓RTT的时候创建的flag线程都是在main.c的开头定义了线程栈
static rt_uint8_t rt_led1_thread_stack[1024]
当程序开始运行的时候,无论当前有没有创建此线程,它的栈都已经开辟了。

所以在项目中我们更常用的是动态内存。动态内存指的是在我们创建线程的时候分配栈空间,这样的利用效率更高。

首先我们在rt_config.h中将使用HEAP(堆)解除封印:

这样我们在board.c中定义的函数也得以封印解除:

为什么是4KB呢,因为在堆内部,可以理解为一个超级长的数组,每一个元素都是占32bit即4Byte即1Word的空间,那么1024个数组元素就是4096Byte啦。

跟之前手搓的RTT时候使用的静态内存分配不同,使用动态内存分配的时候,我们在thread_init上又包含了一层调用,rt_thread_create:

查看其内部构造:

这个函数就是实现了动态地分配内存,通过RT_KERNEL_MALLOC函数分配到了内存,挖个坑(深究下具体内存是如何分配的!)

就这样,我们的开发板训练师,首先定义线程控制块指针,接着定义线程的入口函数(线程的主要运行代码),然后在主函数中初始化线程,最后线程!启动!


已发布

分类

来自

标签:

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注