RT-Thread Nano 简介 RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。适用于家电、消费电子、医疗设备、工控等领域大量使用的 32 位 ARM 入门级 MCU 的场合。 下图是 RT-Thread Nano 的软件框图,包含支持的 CPU 架构与内核源码,还有可拆卸的 FinSH 组件:
' V$ G/ g+ l& J1 F$ H# W
W1 S2 _) f6 q4 R& S) ?

支持架构:ARM:Cortex M0/ M3/ M4/ M7 等、RISC-V 及其他。 功能:线程管理、线程间同步与通信、时钟管理、中断管理、内存管理。 * [- T2 P5 X* x: w+ @) |
1 从官网下载RT-Thread源码,里面包含stm32f1xx的例程。建议使用最新的源码。很多功能老版本的代码里面都没有,比如之前使用3.1.2的源码,想使用ADC功能,发现源码里没有这部分,更新到4.0.0就有了,并且4.0版本也是现在官方推荐使用的,配合ENV工具开发很方便,现在RTT的社区有很多软件包了,通过ENV就可以很轻松的使用这些功能。 BSP 文件夹内
3 I5 C. u+ X$ `9 i5 M5 I
4 w. t8 {$ F! q# M8 W( s0 E
. y- A5 ?* L* Z, F9 A" `
( G+ y4 ~+ @8 p c/ Y1 q' x3 b此版本是基于 HAL 的例程 大家如果熟悉使用HAL库 可直接在此使用
+ R/ `, ~2 h. N* H# p- U$ j) Z
, R% l) g$ _; v9 t2 d/ R
+ Z/ y6 Z: `/ S; H# \# O5 u& `/ u# r4 v3 K( ]

下面开始正式的介绍移植过程 - @$ A; p( B X# H1 A* u# X
Nano Pack 安装Nano Pack 可以通过在 Keil MDK IDE 内进行安装,也可以手动安装。下面开始介绍两种安装方式。 方法一:在 IDE 内安装 打开 MDK 软件,点击工具栏的 Pack Installer 图标: 9 N1 Z. s8 {+ i4 B1 d+ D
( q6 G v( S/ N" W$ n, {

点击右侧的 Pack,展开 Generic,可以找到 RealThread::RT-Thread,点击 Action 栏对应的 Install ,就可以在线安装 Nano Pack 了。另外,如果需要安装其他版本,则需要展开 RealThread::RT-Thread,进行选择。 3 e7 ~+ O; N0 L3 J6 j
! t5 @9 M$ U3 ]

方法二:手动安装 我们也可以从官网下载安装文件,RT-Thread Nano 离线安装包下载,下载结束后双击文件进行安装:
& n4 {" L# t1 k, Q& a& z' }
1 N" a" X8 a5 T8 _4 J
 添加 RT-Thread Nano 到工程打开已经准备好的可以运行的裸机程序,将 RT-Thread 添加到工程。如下图,点击 Manage Run-Time Environment。
9 w+ [/ y% W0 m7 ~2 a% ~
8 s' N) U2 u3 M7 w N2 y

在 Manage Rum-Time Environment 里 "Software Component" 栏找到 RTOS,Variant 栏选择 RT-Thread,然后勾选 kernel,点击 "OK" 就添加 RT-Thread 内核到工程了。
* \9 v. Z! C1 A& I( Z
% n0 i6 _( Z" y/ Q \4 `' f: s

现在可以在 Project 看到 RT-Thread RTOS 已经添加进来了,展开 RTOS,可以看到添加到工程的文件:
3 Y. C) e" y# v( G
8 _ @. ^* k' g' ~; k* t

移植完 打开过程文件是错误的 2 N7 X3 ~/ S8 `7 a
/ j8 y) d3 c: ~+ O
 适配 RT-Thread Nano中断与异常处理RT-Thread 会接管异常处理函数 HardFault_Handler() 和悬挂处理函数 PendSV_Handler(),这两个函数已由 RT-Thread 实现,所以需要删除工程里中断服务例程文件中的这两个函数,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。 , s, H8 `! v3 ~ N1 {9 o
系统时钟配置需要在 board.c 中实现 系统时钟配置(为 MCU、外设提供工作时钟)与 os tick 的配置(为操作系统提供心跳 / 节拍)。 如下代码所示, HAL_Init() 初始化 HAL 库, SystemClock_Config()配置了系统时钟, SystemCoreClockUpdate() 对系统时钟进行更新,_SysTick_Config() 配置了 OS Tick。此处 OS Tick 使用滴答定时器 systick 实现,需要用户在 board.c 中实现 SysTick_Handler() 中断服务例程,调用 RT-Thread 提供的 rt_tick_increase() ,如下图所示。 - /* board.c */
9 N$ ~8 ^; D6 Q" k! O - void % w* m3 k A7 S! u- j9 I) J. D9 L
- rt_hw_board_init()- J( O. @' ~- f' e
- {* u& b1 r7 n4 D/ C0 d8 ^+ d
- HAL_Init();% l* u- J/ O9 Y3 J
- SystemClock_Config();- M% L: }2 \! Q
- /* System Clock Update */# W, n) ~! |/ J+ F
- SystemCoreClockUpdate();7 a6 W2 J- f$ l3 S) b
- /* System Tick Configuration */* ?- C% z9 B- B+ K; W: M4 O v
- _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
1 e% o3 ^$ _! @& t3 G2 u { - /* Call components board initial (use INIT_BOARD_EXPORT()) */
: a! k& ^1 g7 w, h& j% u - #ifdef RT_USING_COMPONENTS_INIT
$ ~2 e+ |3 @: v+ B# Y) |4 Q9 F - rt_components_board_init()
1 h' V' t% ?' X - #endif
* e! B$ T' c0 p! ~ - #if defined(RT_USING_USER_MAIN)
$ G: a7 }) e. d# K% T - &
7 p% W" q9 z1 Y/ x+ B; j - & 0 f; U6 e/ M4 x& \" v& \8 H
- defined(RT_USING_HEAP) rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get())
9 z+ [9 h- X7 C' r; H: t0 z - #endif6 C: Z1 p1 ~ D. \
- }
复制代码
1 Y* Y% ], K& x, E$ c, H
! W, `& w5 p; g9 g: B; r9 Q
由于 SysTick_Handler() 中断服务例程由用户在 board.c 中重新实现,做了系统 OS Tick,所以还需要删除工程里中原本已经实现的 SysTick_Handler() ,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。 Z8 ?% T: X# B1 Q/ z+ C1 K: j
内存堆初始化系统内存堆的初始化在 board.c 中的 rt_hw_board_init() 函数中完成,内存堆功能是否使用取决于宏 RT_USING_HEAP 是否开启,RT-Thread Nano 默认不开启内存堆功能,这样可以保持一个较小的体积,不用为内存堆开辟空间。 开启系统 heap 将可以使用动态内存功能,如使用 rt_malloc、rt_free 以及各种系统动态创建对象的 API。若需要使用系统内存堆功能,则打开 RT_USING_HEAP 宏定义即可,此时内存堆初始化函数 rt_system_heap_init() 将被调用,如下所示:
; X) P+ A4 |4 \9 e; }1 K
! K1 R! D- X2 M+ `1 z4 A8 \! Q

初始化内存堆需要堆的起始地址与结束地址这两个参数,系统中默认使用数组作为 heap,并获取了 heap 的起始地址与结束地址,该数组大小可手动更改,如下所示: - Y6 x* w8 ?( V8 |) I
0 k* y0 P3 P5 B5 ^

注意:开启 heap 动态内存功能后,heap 默认值较小,在使用的时候需要改大,否则可能会有申请内存失败或者创建线程失败的情况,修改方法有以下两种: - 可以直接修改数组中定义的 RT_HEAP_SIZE 的大小,至少大于各个动态申请内存大小之和,但要小于芯片 RAM 总大小。
- 也可以参考进行修改,使用 RAM ZI 段结尾处作为 HEAP 的起始地址,使用 RAM 的结尾地址作为 HEAP 的结尾地址,这是 heap 能设置的最大值的方法。/ i7 s* `' N- m, Z) }. T/ M1 a9 _* A% W
& z+ d, X* X; j [9 d: a3 H
编写第一个应用移植好 RT-Thread Nano 之后,则可以开始编写第一个应用代码验证移植结果。此时 main() 函数就转变成 RT-Thread 操作系统的一个线程,现在可以在 main() 函数中实现第一个应用:板载 LED 指示灯闪烁,这里直接基于裸机 LED 指示灯进行修改。 - 首先在文件首部增加 RT-Thread 的相关头文件 <rtthread.h> 。
- 在 main() 函数中(也就是在 main 线程中)实现 LED 闪烁代码:初始化 LED 引脚、在循环中点亮 / 熄灭 LED。
- 将延时函数替换为 RT-Thread 提供的延时函数 rt_thread_mdelay()。该函数会引起系统调度,切换到其他线程运行,体现了线程实时性的特点。5 @9 L8 i! |, i8 _8 Q

5 c8 ~3 y: k% I. c N! \3 U
* B% f& ]" a) O) V3 G6 i7 V
编译程序之后下载到芯片就可以看到基于 RT-Thread 的程序运行起来了,LED 正常闪烁。 注意事项:当添加 RT-Thread 之后,裸机中的 main() 函数会自动变成 RT-Thread 系统中 main 线程 的入口函数。由于线程不能一直独占 CPU,所以此时在 main() 中使用 while(1) 时,需要有让出 CPU 的动作,比如使用 rt_thread_mdelay() 系列的函数让出 CPU。
. N; G b- E& M% B0 ]7 `
与裸机 LED 闪烁应用代码的不同: 1). 延时函数不同: RT-Thread 提供的 rt_thread_mdelay() 函数可以引起操作系统进行调度,当调用该函数进行延时时,本线程将不占用 CPU,调度器切换到系统的其他线程开始运行。而裸机的 delay 函数是一直占用 CPU 运行的。 2). 初始化系统时钟的位置不同:移植好 RT-Thread Nano 之后,不需要再在 main() 中做相应的系统配置(如 hal 初始化、时钟初始化等),这是因为 RT-Thread 在系统启动时,已经做好了系统时钟初始化等的配置,这在上一小节 “系统时钟配置” 中有讲解。 0 l m& `! B9 K' f
配置 RT-Thread Nano用户可以根据自己的需要通过修改 rtconfig.h 文件里面的宏定义配置相应功能。 RT-Thread Nano 默认未开启宏 RT_USING_HEAP,故只支持静态方式创建任务及信号量。若要通过动态方式创建对象则需要在 rtconfig.h 文件里开启 RT_USING_HEAP 宏定义。 MDK 的配置向导 configuration Wizard 可以很方便的对工程进行配置,Value 一栏可以选中对应功能及修改相关值,等同于直接修改配置文件 rtconfig.h。
; X( }4 t2 a- j# @/ o9 l实现动态内存堆RT-Thread Nano 默认不开启动态内存堆功能,开启 RT_USING_HEAP 将可以使用动态内存功能,即可以使用 rt_malloc、rt_free 以及各种系统动态创建对象的 API。动态内存堆管理功能的初始化是通过 rt_system_heap_init() 函数完成的,动态内存堆的初始化需要指定堆内存的起始地址和结束地址,函数原型如下: - void rt_system_heap_init(void *begin_addr, void *end_addr)
复制代码开启 RT_USING_HEAP 后,系统默认使用数组作为 heap,heap 的起始地址与结束地址作为参数传入 heap 初始化函数,heap 初始化函数 rt_system_heap_init() 将在 rt_hw_board_init() 中被调用。 开启 heap 后,系统中默认使用数组作为 heap(heap 默认较小,实际使用时请根据芯片 RAM 情况改大),获得的 heap 的起始地址与结束地址,作为参数传入 heap 初始化函数: - #define RT_HEAP_SIZE 1024
( I9 a' R8 [" o% N5 g - static - j% e5 w! T5 y, ^/ R" J* R
- uint32_t rt_heap[RT_HEAP_SIZE];
& Z; A6 Q1 F- D: w - RT_WEAK void *rt_heap_begin_get(void)
, ?. q" U+ r; _) @ - {' r1 x: Z: u8 i! j7 q9 L; _
- return rt_heap;/ ]1 ?/ }+ i$ O7 b7 R
- }, c0 u, E) c" J
- RT_WEAK void *rt_heap_end_get(void)
) T0 u$ I6 _; K8 t8 ~9 S% F. N/ ~ - {
" T: F- @$ C; a4 N3 j# B - return rt_heap + RT_HEAP_SIZE;
3 `3 F, M) d# c) N% w+ l9 W' A - }' g \- E4 N* U" \/ X6 q8 C9 `
- void rt_hw_board_init(void)
4 O i- _: C6 m5 \$ m {5 U+ J! ~ - {
2 S7 P5 S, k9 ^4 n5 @2 F - ....* ~$ C/ n3 C |& Z
- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
0 _* T+ W: E1 v: G, v - rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
& ^ m+ j& y7 ]) E9 l - //传入 heap 的起始地址与结束地址
" M) I, {: u5 p& D d6 s5 N - #endif
& n H. Z7 T2 g" Z - ..../ ]1 q+ l& j: d4 }
- }
复制代码 4 M M6 O+ t. |8 A! D; k' [! Z1 [; n
, M K" J/ I" u4 ` s
如果不想使用数组作为动态内存堆,则可以重新指定系统 HEAP 的大小,例如使用 RAM ZI 段结尾处作为 HEAP 的起始地址(这里需检查与链接脚本是否对应),使用 RAM 的结尾地址作为 HEAP 的结尾地址,这样可以将空余RAM 全部作为动态内存 heap 使用。如下示例重新定义了 HEAP 的起始地址与结尾地址,并作为初始化参数进行系统 HEAP 初始化。 - #define STM32_SRAM1_START (0x20000000)
: z& L* \. Y5 W/ L2 @% ?! { - #define STM32_SRAM1_END (STM32_SRAM1_START + 20 * 1024) // 结束地址 = 0x20000000(基址) + 20K(RAM大小)
/ ^; D2 e# a G p* D: p/ e - #if defined(__CC_ARM) || defined(__CLANG_ARM)
- s) X/ R) ]9 [1 h" P! e; c - extern - q# b/ r4 E" V, `
- int Image$RW_IRAM1$ZI$Limit; " s$ z) b l+ d5 t' F! k( ~
- // RW_IRAM1,需与链接脚本中运行时域名相对应2 `/ |1 ^9 m5 K, M& O: @+ |
- #define HEAP_BEGIN ((void *)&Image$RW_IRAM1$ZI$Limit); M% u* y( u/ R7 R0 e% }6 I z, S) k
- #endif& N3 l% S& [4 \9 f
- #define HEAP_END STM32_SRAM1_END
复制代码- void rt_hw_board_init(void)
7 U) x# V" H: m$ R. s - {
G' V% V$ f4 p+ R8 C) e - ....9 p f L+ P4 @1 s3 [/ j+ u
- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)0 g# C- w7 {/ E
- rt_system_heap_init((
7 J) o- l0 q' i% _+ L - void *)HEAP_BEGIN, (
$ Z9 T6 a* k! Z; [! E3 V3 M% Z - void *)HEAP_END);1 o% U( Z* R$ u5 w$ L9 @" j
- #endif
1 B$ i7 D1 [3 _ s: v7 q: ?0 P - ...., M; E" i& A- p( a
- }
复制代码
2 v* Q. ?7 k5 ?8 l& d" s) h$ ?+ g/ Y: k4 _# k
链接脚本 链接脚本,也称分散加载文件,决定在生成 image 文件时如何来分配相关数据的存放基址,如果不指定特定的链接脚本,连接器就会自动采用默认的链接脚本来生成镜像。 举例 stm32 在 KEIL MDK 开发环境下的链接脚本文件 xxx.sct: - LR_IROM1
% E8 k; _* }0 \5 c- G' |: p - 0x08000000 & e" _7 J' U+ |, o
- 0x00020000 {
; U/ k0 D% m2 o8 r* ` - ; ( y4 l T9 S8 n4 Z: P& W7 e) p
- load 7 @4 e! m' y, h) E a. ^4 f
- region
& p$ y3 X' A% U% T - size_region* w" _+ B( Q* B5 ^4 ~2 l
- ER_IROM1 1 U! `- p0 F1 F8 Y1 L& n* |* U
- 0x08000000
2 e3 A7 o* `; A( y - 0x00020000 { 8 t- z6 i3 i M* [( ]- }
- ;
; i, B+ m7 [: F* q( K8 t6 a - load ! E* M. C9 r6 j1 [
- address
' j6 \& ]. M7 ]" k5 W5 P& @. j - = - j) h/ U7 C1 i" E* v: F6 ?
- execution , r: e* q$ z* ^4 I/ x
- address" z0 Y. ]- T9 B0 K" |7 i1 H
- *.o
9 V$ E3 I5 V' Z$ O0 b; B! | k e - (RESET, . g1 H/ ~' h: h7 e: J8 [* k
- +First)
1 b0 D7 j0 o$ s, g0 ?( ? - *(InRoot$Sections)( U1 }# U, C5 E2 n1 z9 r0 u
- .ANY " `& u% _ l; V1 F! w
- (+RO)
$ k9 C6 v. J3 A4 f0 v6 c2 k - }; d- f" m0 U* \
- RW_IRAM1
5 _' |( e. X! J - 0x20000000
! M! \* n. Y7 d; }: V- a8 w, ] - 0x00005000 { 3 R- B* a% n9 h- s- U
- ;
- d- P$ n) R0 F - RW 5 U9 ~) O% C2 y$ x/ v" y
- data
) c& c8 e: f9 P9 P* K - .ANY 8 m; g% r5 D; e) n9 x
- (+RW
1 x6 N8 ?/ o* m9 @8 y m - +ZI)- V5 g2 T Y2 u5 v5 z
- }
. j/ ?& k" w- Y+ f# G - }
复制代码& E6 N+ i& N. z
其中 RW_IRAM1 0x20000000 0x00005000 表示定义一个运行时域 RW_IRAM1(默认域名),域基址为 0x20000000,域大小为 0x00005000(即 20K ),对应实际 RAM 大小。.ANY (+RW +ZI) 表示加载所有匹配目标文件的可读写数据 RW-Data、清零数据 ZI-Data。所以运行时所占内存的结尾处就是 ZI 段结尾处,可以将 ZI 结尾处之后的内存空间作为系统动态内存堆使用。 9 i! B7 p1 P8 W6 k* ]7 W# p% g
s$ y, W; _, R

1 B7 f/ b% G5 C* w1 L% B, s" D 获取示例代码Keil MDK 中集成的 RT-Thread Nano 软件包附带示例代码,如果需要参照示例代码,则可以在 Keil 中打开相应的示例代码工程。 首先点击 Pack Installer,进入下图所示界面:
( w* o2 M" G* c
/ P- A# e6 I) n& j

右侧界面切换到 Examples,然后在左侧界面搜索 Device 或者 Boards,点击搜索出的芯片或者开发板,会显示与其相关的所有示例代码,同时可以看到 RT-Thread 的示例代码也在其中,点击 Copy,选择一个路径,然后点击 OK 即可打开示例代码工程
; [% m- b, j4 V, g0 s1 S. u

( ?* p% l+ l8 p9 R; w* X( }0 V打开 keil 的安装路径 将 RT-Thread Package 到裸机工程根目录 


1 E$ l9 r n. Z5 V) g8 P8 d# G$ a- u: X; q0 U
6 }1 T' l H4 ]1 w& e- }' o% R: ]% q
7 J7 j# T* S4 d% o4 x$ o+ M$ t' X
6 K. r* c+ F+ G$ O% n
! b& w& u9 x' F9 r. V3 I$ E
! x1 m1 G- p6 R: r) q4 p& x# R$ f
1、拷贝 rtconfig.h 文件到 user 文件夹8 ]- V" R2 r8 w+ L8 v4 C6 o
将 RT-Thread/3.0.3/bsp 文件夹下面的 rtconfig.h 文件拷贝到工程根目录下面的 user文件夹, 可以通过修改这个 RT-Thread 内核的配置头文件来裁剪 RT-Thread 的功能 2、拷贝 board.c 文件到 user 文件夹下(新建RTE )
) {/ L* f' {- y" v! z+ K4 ]将 RT-Thread/3.0.3/bsp 文件夹下面的 board.c 文件拷贝到工程根目录下面的 user 文件夹, 等下我们需要对这个 board.c 进行修改。
5 q0 L# b5 w$ y% a
* L y \2 T: [; c
9 K2 R0 ]. ^5 k3 A) `$ d. o
/ j8 \6 A) x2 W/ ~0 h) x
& R' M: b1 h$ v2 w, C q0 ?

3、添加 RT-Thread 源码到工程组文件夹
, I+ p5 L. C6 Y% ~) O# ~6 i新建 rtt/source 和 rtt/cpu 两个组文件夹,其中 rtt/source 用于存放 src 文件夹的内容, rtt/cpu用于存放 libcpu/arm/cortex-m? 文件夹的内容,“?”表示0 3、 4 或者 7。内核文件 我们移植的为stm32f103 内核选择 Cortex-M3 - z+ R0 ?- d6 r- W
, h% }/ }1 ?$ H+ ^

指定 RT-Thread 头文件的路径) R& I; g" E% _1 m& z+ e
RT-Thread 的 源 码 里 面 只 有 RT-Thread\3.1.3\include\libcpu9 j5 z4 {2 L, S, P
RTThread\3.1.3\include
: O5 M" n; ^+ f8 y9 ~ ARTThread\3.1.3\src
4 }2 w2 w7 f0 e9 @5 a VRTThread\3.1.3\components\finsh和 user 文件夹下(RTE) rtconfig.h 有头文件,只需要将这头文件的路径在开发环境里面指定即可。
9 L4 n$ k. H* D9 x `2 H" b; ~
, z5 F9 r. Y5 T' I) l
7 a! s V( [3 l1 L( p3 F这些都做完之后 编译还是有两个错误 因为还没有配置 RT-Thread Nano 参考上面讲述的配置 步骤 0 Z7 Z4 C. w1 \
; Y0 b% p% }1 @+ A! \$ r+ s- R, ~& s0 P8 h7 D7 U
! l8 M' m6 V2 Z5 c) D4 l& y# e, V5 a: N7 v
0 o1 P; S, S+ U* o2 l, K% a { rtconfig.H
L0 M- C" G0 u s# M- /* RT-Thread config file *// B \5 |5 U9 r* L, n: R
- #ifndef __RTTHREAD_CFG_H__3 n( {: b( b c% w* ^" @
- #define __RTTHREAD_CFG_H__: F7 f. _3 g0 s$ d# M* |7 h+ s5 `
- #include "RTE_Components.h"; s- x# X$ D: q; d3 d" q
- // <<< Use Configuration Wizard in Context Menu >>>' t9 G, i. b2 M+ M. o8 h
- // <h>Basic Configuration
5 b5 y& \: |* {5 ^) c# f8 Q0 s - // <o>Maximal level of thread priority <8-256>
" d7 |- L" O# H2 U% m - // <i>Default: 32
9 _/ B1 Q @" [" b( } - #define RT_THREAD_PRIORITY_MAX 32
4 t; Z8 T- _+ ^1 ~8 V - // <o>OS tick per second- ~( l/ u. }! j( Y
- // <i>Default: 1000 (1ms)
" v6 j J$ N/ R" b8 G - #define RT_TICK_PER_SECOND 10006 i6 H* Q; t5 q+ b7 U- @5 d0 B
- // <o>Alignment size for CPU architecture data access
5 i A: j( L$ k3 L- r - // <i>Default: 4
$ x, J) Q" w/ K, ?% ]# l - #define RT_ALIGN_SIZE 4
, K! _' m6 A# k$ g' r. [$ I/ | - // <o>the max length of object name<2-16>/ |3 N8 G3 ^9 X9 z
- // <i>Default: 8
1 @7 ]) M K: u- X* x0 l) E - #define RT_NAME_MAX 8
& _( y* I! L; g6 n% L: w9 t6 T - // <c1>Using RT-Thread components initialization* A6 e8 y) N: {0 r0 S
- // <i>Using RT-Thread components initialization
4 Z" z$ \) n. g6 b$ D R - #define RT_USING_COMPONENTS_INIT) e, b+ G; d( L; B& T, M
- // </c>+ E" b1 ?% m. ^: v, U* J6 K
- // <c1>Using user main( w3 Y* u7 b6 E
- // <i>Using user main
0 O( L1 P. l0 ?1 z1 n. W - #define RT_USING_USER_MAIN
$ o: }2 H; c% ^* Q7 w, C6 M - // </c>
5 ^* p6 S5 F4 H- Q! W& } - // <o>the size of main thread<1-4086>7 e# f6 h- B: C% x
- // <i>Default: 5129 R) W* K, p7 j0 s9 ^; U& Z
- #define RT_MAIN_THREAD_STACK_SIZE 256! ^/ M. C9 G& u3 L" H
- // </h>0 E1 q% G: c; [1 M) L
- // <h>Debug Configuration3 m/ M3 U% u/ A) C7 u
- // <c1>enable kernel debug configuration
/ ~9 w3 ~7 i1 D, Y$ b+ R$ @ - // <i>Default: enable kernel debug configuration& {' _. A3 j6 g8 [
- //#define RT_DEBUG0 r& W; R" u7 p) V3 b$ O
- // </c>: y* e1 m! l" }! M3 U: z" S
- // <o>enable components initialization debug configuration<0-1># N; q8 }5 [ P1 i, N5 D
- // <i>Default: 0
3 c5 N _- f. R5 A1 E- B - #define RT_DEBUG_INIT 03 I: }) p6 w" U+ Q4 w
- // <c1>thread stack over flow detect$ |2 u% E% ^4 B7 x4 Q3 u
- // <i> Diable Thread stack over flow detect3 }( p y# r' ]+ v- w2 v5 }) V
- //#define RT_USING_OVERFLOW_CHECK3 u5 x4 W5 o% D) ^
- // </c>$ C' M9 c: {9 A+ Q: @
- // </h>
9 H" w3 Q- Z! b - // <h>Hook Configuration
( c; O* ^+ W- Q/ j! |; b# {) S - // <c1>using hook8 y: i% Z) J/ q0 ?6 `' T' `
- // <i>using hook
" B8 n1 F2 J: r/ V" } - //#define RT_USING_HOOK& D" i/ h0 l) B( t' f
- // </c>
" k( [! r4 G& u) @5 g- B - // <c1>using idle hook4 W) J q( O0 _$ O$ V
- // <i>using idle hook
4 s; ^5 J4 Q: }. B% A8 K) i - //#define RT_USING_IDLE_HOOK
: X* C! u x+ I4 l" R# c5 a* s - //</c>
复制代码
8 ~# P* c: E0 f( N8 lboard.c - /*
: b) Q+ r) t, L$ B1 U$ @* b8 e5 W( L - * File : application.c
8 i/ M' d _) l3 \7 N- n& ? - * This file is part of RT-Thread RTOS/ L9 x" Y5 j1 a6 c& S
- * COPYRIGHT (C) 2006, RT-Thread Development Team! ]' f- s! R# C' J; p+ \0 s
- *
8 h% f5 ~5 m: X& ~! A9 R - * The license and distribution terms for this file may be
z5 S0 b# f3 ^8 S4 O5 ` - * found in the file LICENSE in this distribution or at! {: ?8 T3 ?( ~9 f2 \9 }& s
- * http://www.rt-thread.org/license/LICENSE6 N% y# n- E* l: y- ^
- *: [$ v' I- ~, x
- * Change Logs:
~- H! c3 J' B - * Date Author Notes
6 ?: V. s; R$ d - * 2017-07-24 Tanek the first version) u6 B/ i4 s/ n* E% g9 N
- */
* A9 ]7 o1 G' @% j; o3 ^' e) @/ p! a - #include <rthw.h>4 I( c- d+ }2 g7 h% |
- #include <rtthread.h>2 ?# {4 P- N- B
- #include "usart.h"
- e% S8 Z- R) q M# _- W$ u, L - #include "delay.h"' A8 S5 n+ ]9 b A4 ?
- #include "led.h"* }8 P/ K0 [2 f2 G1 ?
- // rtthread tick configuration8 h8 W* [9 ~' V4 O# C8 j$ Z0 M
- // 1. include header files) E; ~, E4 j4 _1 X
- // 2. configure rtos tick and interrupt" F- `- k$ X r6 f1 _! n
- // 3. add tick interrupt handler
- h; Y' p" a8 ^7 S$ E - // rtthread tick configuration
0 D7 O2 q. n1 A0 D5 Q0 { - // 1. include some header file as need
8 U; _( z) D- o3 ~ e& R - #include <stm32f10x.h>0 X8 z, X! W) u9 D' X9 [' X* ?
- #ifdef __CC_ARM
' b5 B. r! Z5 o, ~8 C: I - extern \3 [( z9 U" N* B( x" k
- int Image$RW_IRAM1$ZI$Limit;
, _3 t4 v: A7 ~1 U$ r9 ` - #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)! v' d/ ^3 q# I: }0 v: Z# Z3 i
- #elif __ICCARM__
4 g) Q& @6 k1 e8 p - #pragma section="HEAP"7 b; W; @4 C- u# o; @* ]& b5 D
- #define HEAP_BEGIN (__segment_end("HEAP"))( q. s9 U' S3 U% ^2 ^* e3 ]
- #else& p3 u" h* e$ z- F5 b+ k
- extern
9 M& y: s& z$ J. ~ - int __bss_end;+ P( _8 N6 C% |! {1 q
- #define HEAP_BEGIN (&__bss_end)
) K( x7 \- d' c. \+ V$ G- A( C: u. x - #endif
6 S t7 _5 {; o* @8 | - #define SRAM_SIZE 85 L9 m2 a$ [: ~6 `! f5 ?/ L) D# E
- #define SRAM_END (0x20000000 + SRAM_SIZE * 1024)
) u) k# }$ Y3 z/ I+ ]4 b, `* @( s - extern uint8_t OSRunning;8 g$ Y4 I0 i$ _+ e6 r1 \0 t
- /**
+ N: C R2 D8 v X% f7 Z7 q' U3 T - * This function will initial STM32 board.
+ E: [) c! i! E2 Y5 U - */! }3 l( l8 r0 C7 F1 J0 o4 i
- void rt_hw_board_init()6 k4 ]3 ^5 j! S2 B
- {
5 v! c9 W8 Z, Y5 j' x( [2 b: Z9 Q - // rtthread tick configuration
U+ p) V: s$ a4 q2 D - // 2. Configure rtos tick and interrupt
7 q F+ @9 s" v& }( U7 l+ m - SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); z# J" w. Q; n k- ~5 z
- //串口初始化
- @ B: L2 P5 s3 Y' i - uart_init(& L0 b' o( t9 Z! j- t' x/ r
- 115200);
$ ^1 c6 w" y* {8 H9 V# E" }) { - delay_init(
, H2 |" S: T9 |1 o0 L( \) l0 A - 72);
M, P; Z) }" B5 {+ B$ M, f. A3 f - //初始化LED
/ d, ]' p y; ^$ ^. P, N - LED_Init();
) \7 e9 G3 `6 g g* C - //tips:把硬件初始化放上面1 h4 A# I1 [& V( `. |% w
- OSRunning=+ q% g' v, j& k6 H, e% P
- 1;
2 g- n3 q+ d8 b5 z - /* Call components board initial (use INIT_BOARD_EXPORT()) */
2 E$ f4 V& q& `! ^ Y- A" ~' ~ - #ifdef RT_USING_COMPONENTS_INIT
d+ [6 B1 r& N7 N6 O - rt_components_board_init();
) O) p8 ^3 ^1 f2 r - #endif5 H) x) `6 n# @; r! X+ g: d
- #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
( q; _6 Z1 |3 |- ]8 y+ a0 \ - rt_console_set_device(RT_CONSOLE_DEVICE_NAME);4 S" z( w! U f% ~
- #endif
, {5 \) F! V3 b - #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
- V( k# f4 l4 q2 ~ - rt_system_heap_init((
' U& y/ K- J+ ~6 ^& h; R3 F% K - void*)HEAP_BEGIN, (
5 P# D n! c p4 F - void*)SRAM_END);5 |3 {2 W0 k% ~. b. V
- #endif
, x1 g6 p6 y! R% N8 q# M; ~ - }
9 W# z$ W9 e+ A Y& r4 [ - // rtthread tick configuration
$ \7 q$ C4 ~# t) W# Y0 _ - // 3. add tick interrupt handler9 ?5 n7 c$ J' r+ r5 v7 p, E; M S# Z
- void SysTick_Handler(: s' k# [( x$ S9 J; T! p* `
- void)7 I; P5 \) s- o9 x T5 X
- {. s) B0 Y: F0 Y1 D4 ^) f! Q
- /* enter interrupt */
8 j" Y% ?0 B, p9 b* m - rt_interrupt_enter();& ~9 j/ U, T3 g6 r# q
- rt_tick_increase();
1 C+ J2 b3 s" O8 I. z X$ P - /* leave interrupt */
7 n/ q2 t! z1 g& i9 z9 o7 N5 `. B - rt_interrupt_leave();
- k. ^+ w# b! F4 }4 ^* ^ - }
复制代码
" u8 q- Y/ r( x修改完rtconfig.h 和board.c 编译通过
& R6 I) [$ {+ X/ c
$ O' x+ a% a: _* s" t
- r- Z9 b! l% s u1 H, F8 a
7 D5 o3 Q# P% q; u/ T) f- e0 N0 g4 r+ o* C1 }* k. |
# f% P' R$ s: x# P
转载:熬鱼不放汤
Y- z9 J \- R; u! r( {# I: {/ b" e- t1 j+ O
如有侵权请联系删除
/ B' w# R2 U3 j5 v6 |$ y& `: R
- u [+ C; I7 c. v3 j! n+ c' E$ Q+ m4 S
|