RT-Thread Nano 简介 RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。适用于家电、消费电子、医疗设备、工控等领域大量使用的 32 位 ARM 入门级 MCU 的场合。 下图是 RT-Thread Nano 的软件框图,包含支持的 CPU 架构与内核源码,还有可拆卸的 FinSH 组件:
- @! I, E" G0 i3 A; S
+ }; }3 M8 \* v! `6 N0 H* K* n

支持架构:ARM:Cortex M0/ M3/ M4/ M7 等、RISC-V 及其他。 功能:线程管理、线程间同步与通信、时钟管理、中断管理、内存管理。 ) g w( l( P3 l. b
1 从官网下载RT-Thread源码,里面包含stm32f1xx的例程。建议使用最新的源码。很多功能老版本的代码里面都没有,比如之前使用3.1.2的源码,想使用ADC功能,发现源码里没有这部分,更新到4.0.0就有了,并且4.0版本也是现在官方推荐使用的,配合ENV工具开发很方便,现在RTT的社区有很多软件包了,通过ENV就可以很轻松的使用这些功能。 BSP 文件夹内 # k. y( U2 ^' l S' a0 U- R' C
( p9 H2 H- ]% f% ]4 N8 x, |. N) F
& H/ V& z8 G& i9 N, u

; h' I1 \$ L8 D, {9 D) {; k此版本是基于 HAL 的例程 大家如果熟悉使用HAL库 可直接在此使用
# j) M% G' {. E
: e: a \, F5 f
3 W# _, [9 E1 m# y' D) W1 Z
& C k7 e3 c# [3 J
下面开始正式的介绍移植过程
8 p. {& _* I8 B, L) U1 u lNano Pack 安装Nano Pack 可以通过在 Keil MDK IDE 内进行安装,也可以手动安装。下面开始介绍两种安装方式。 方法一:在 IDE 内安装 打开 MDK 软件,点击工具栏的 Pack Installer 图标:
; s6 P5 l }9 P, {7 @5 | J
& S. H1 H9 `% n6 a Y1 c

点击右侧的 Pack,展开 Generic,可以找到 RealThread::RT-Thread,点击 Action 栏对应的 Install ,就可以在线安装 Nano Pack 了。另外,如果需要安装其他版本,则需要展开 RealThread::RT-Thread,进行选择。 7 Z, d& T8 O$ [" U8 w: q6 s0 J0 C
4 e- \: K7 _7 X- [

方法二:手动安装 我们也可以从官网下载安装文件,RT-Thread Nano 离线安装包下载,下载结束后双击文件进行安装:
( @' a* }9 S7 ]5 }3 _
- B7 l! |: i% o$ }* \7 s, F
 添加 RT-Thread Nano 到工程打开已经准备好的可以运行的裸机程序,将 RT-Thread 添加到工程。如下图,点击 Manage Run-Time Environment。
, e3 P* G! J2 l) _- w$ \8 _
* b4 r$ L9 ^2 G9 o: s

在 Manage Rum-Time Environment 里 "Software Component" 栏找到 RTOS,Variant 栏选择 RT-Thread,然后勾选 kernel,点击 "OK" 就添加 RT-Thread 内核到工程了。
}* T( @; K7 _4 y# g
# C4 u/ y+ E9 ?3 i$ P

现在可以在 Project 看到 RT-Thread RTOS 已经添加进来了,展开 RTOS,可以看到添加到工程的文件:
5 Q- Y0 ?- ~- Z1 @
( C4 s1 I, @) |& O" G

移植完 打开过程文件是错误的 7 T" K* t! ?. n; N
+ a5 I" K, \( C) [
 适配 RT-Thread Nano中断与异常处理RT-Thread 会接管异常处理函数 HardFault_Handler() 和悬挂处理函数 PendSV_Handler(),这两个函数已由 RT-Thread 实现,所以需要删除工程里中断服务例程文件中的这两个函数,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。
" h |( X7 o" l& A) W 系统时钟配置需要在 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 */
, r) Y5 X* K( w, E1 o - void 7 D% [( f8 g4 m/ H
- rt_hw_board_init()
2 b( L& U' \- T/ f - {
d4 X. u5 V; k+ S/ Q& f( s - HAL_Init(); m4 Y, J% h/ n
- SystemClock_Config();
& y) O% _( ?' u5 L - /* System Clock Update */
+ z% ^/ `; [. J% \+ x - SystemCoreClockUpdate();
* Q; g- c# N! q - /* System Tick Configuration */" Q" K4 U6 t( g5 N7 U
- _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
' Y& _ V% B9 x5 c& n - /* Call components board initial (use INIT_BOARD_EXPORT()) */
% [2 T9 H: O# G - #ifdef RT_USING_COMPONENTS_INIT
1 ?, {! ^/ J) L - rt_components_board_init()6 C: ]) l8 y3 y. o f5 C
- #endif
5 }6 ?( z V; J - #if defined(RT_USING_USER_MAIN)
% z: U! ~% {5 c' r, Y2 Z5 F - &) t+ h4 M4 T7 v1 {/ ~
- & - K1 \4 k$ L( x# n1 D' U
- defined(RT_USING_HEAP) rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get())
! l! Y, ?* w+ z' O+ n - #endif
) \* w3 B- T. Q# G# v: a% E0 x - }
复制代码
2 |5 x" i2 r# g% l
- \$ C8 X+ V" X$ p" a" w* @0 _2 a
由于 SysTick_Handler() 中断服务例程由用户在 board.c 中重新实现,做了系统 OS Tick,所以还需要删除工程里中原本已经实现的 SysTick_Handler() ,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。 - n% w* D; ~( J3 U! O- o7 K4 \/ Z
内存堆初始化系统内存堆的初始化在 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() 将被调用,如下所示:
, a6 y5 P% O* n' v. M2 ^% A7 ]0 H
( k8 x% z7 a* l

初始化内存堆需要堆的起始地址与结束地址这两个参数,系统中默认使用数组作为 heap,并获取了 heap 的起始地址与结束地址,该数组大小可手动更改,如下所示:
0 |/ E& F. y* P% X x6 H8 H, Z, @7 ~
8 x5 V7 f& X) O% P* a, J

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

7 t/ ~# Z1 N- A5 Y# ^
9 Z( s( `0 M/ m2 {3 I
编译程序之后下载到芯片就可以看到基于 RT-Thread 的程序运行起来了,LED 正常闪烁。 注意事项:当添加 RT-Thread 之后,裸机中的 main() 函数会自动变成 RT-Thread 系统中 main 线程 的入口函数。由于线程不能一直独占 CPU,所以此时在 main() 中使用 while(1) 时,需要有让出 CPU 的动作,比如使用 rt_thread_mdelay() 系列的函数让出 CPU。 E! d) u0 @! l# ?) b
与裸机 LED 闪烁应用代码的不同: 1). 延时函数不同: RT-Thread 提供的 rt_thread_mdelay() 函数可以引起操作系统进行调度,当调用该函数进行延时时,本线程将不占用 CPU,调度器切换到系统的其他线程开始运行。而裸机的 delay 函数是一直占用 CPU 运行的。 2). 初始化系统时钟的位置不同:移植好 RT-Thread Nano 之后,不需要再在 main() 中做相应的系统配置(如 hal 初始化、时钟初始化等),这是因为 RT-Thread 在系统启动时,已经做好了系统时钟初始化等的配置,这在上一小节 “系统时钟配置” 中有讲解。
! }0 F0 D0 n' {. D# d) S 配置 RT-Thread Nano用户可以根据自己的需要通过修改 rtconfig.h 文件里面的宏定义配置相应功能。 RT-Thread Nano 默认未开启宏 RT_USING_HEAP,故只支持静态方式创建任务及信号量。若要通过动态方式创建对象则需要在 rtconfig.h 文件里开启 RT_USING_HEAP 宏定义。 MDK 的配置向导 configuration Wizard 可以很方便的对工程进行配置,Value 一栏可以选中对应功能及修改相关值,等同于直接修改配置文件 rtconfig.h。
" ~& q# p- }) b6 D, A7 [实现动态内存堆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
) b7 i Z' c0 j( F - static
3 H+ G4 G; I P1 t+ Q; N" ] - uint32_t rt_heap[RT_HEAP_SIZE];8 y6 i% t3 }8 L* k1 i- D, B
- RT_WEAK void *rt_heap_begin_get(void)$ K1 A' q+ c+ s- M4 l0 v6 m
- {& g! ]( ?( V; V& t+ a
- return rt_heap;
. q5 \$ }* w9 S! n% i d$ N - }6 z* J! G. R+ {' f" J) G1 y6 [2 f$ p
- RT_WEAK void *rt_heap_end_get(void)
$ k8 }; [, h; ^" i" a. u - {
8 b/ v+ r4 ?$ y2 J - return rt_heap + RT_HEAP_SIZE;# p' h& ?2 j% m5 K' x
- }
! Q% k1 l. b! ]8 p5 ~( Y( d - void rt_hw_board_init(void)
- I& D+ J9 J' @* F - {+ z! ^( B0 ~; z
- ..../ l% C3 Z- w' q6 I5 v
- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
' F4 b( ?( U3 ]' z; Z - rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get()); 2 e' w: P9 R! g6 y1 V3 J% x4 |2 i
- //传入 heap 的起始地址与结束地址
( [# u5 l ?! x7 k! K8 [6 i - #endif
6 P' d4 t' x6 j- B$ Z5 v2 K* N - ....+ {. h/ p" Y- \. L5 M( [$ }% R/ P# [
- }
复制代码 : C' i9 y/ H! {5 e
) d d% D$ c8 H4 J1 k" Q# x2 v" m
如果不想使用数组作为动态内存堆,则可以重新指定系统 HEAP 的大小,例如使用 RAM ZI 段结尾处作为 HEAP 的起始地址(这里需检查与链接脚本是否对应),使用 RAM 的结尾地址作为 HEAP 的结尾地址,这样可以将空余RAM 全部作为动态内存 heap 使用。如下示例重新定义了 HEAP 的起始地址与结尾地址,并作为初始化参数进行系统 HEAP 初始化。 - #define STM32_SRAM1_START (0x20000000)
% e D- c( M# e l, o, _ - #define STM32_SRAM1_END (STM32_SRAM1_START + 20 * 1024) // 结束地址 = 0x20000000(基址) + 20K(RAM大小). j9 W! B* N9 p
- #if defined(__CC_ARM) || defined(__CLANG_ARM)
( B' F9 y% X6 |! ~% q9 [ - extern : a- o* `) v W4 e9 |+ c; a
- int Image$RW_IRAM1$ZI$Limit;
" Y5 m& ^. R3 m& b; M - // RW_IRAM1,需与链接脚本中运行时域名相对应; q& F# p$ a2 O
- #define HEAP_BEGIN ((void *)&Image$RW_IRAM1$ZI$Limit)
* ^4 _7 k2 r$ G: H - #endif3 |( }0 B: q4 A, |, I+ |7 g: s: ^
- #define HEAP_END STM32_SRAM1_END
复制代码- void rt_hw_board_init(void)6 o3 _& M, `' T/ a
- {1 ]$ x, q- T: Z( I1 P/ {! G+ k
- ....
) T" E Z; O, O, i1 J - #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
) x3 Y' i' }9 k; h4 \0 z/ a - rt_system_heap_init((
+ v/ K4 @9 b- n - void *)HEAP_BEGIN, (
# T1 d; i& h1 t# P W) u; F - void *)HEAP_END);. K$ F+ H, g& S8 A9 x
- #endif) F! }; ?, x% P3 [
- ....
" J" G/ g+ p' R% I+ }7 R s4 j! \ - }
复制代码
/ ^' T, k e K5 i7 G- o
5 e3 w- f& }. B' h! G2 _8 T链接脚本 链接脚本,也称分散加载文件,决定在生成 image 文件时如何来分配相关数据的存放基址,如果不指定特定的链接脚本,连接器就会自动采用默认的链接脚本来生成镜像。 举例 stm32 在 KEIL MDK 开发环境下的链接脚本文件 xxx.sct: - LR_IROM1
; ]; r5 l7 B% Q; X6 I4 A - 0x08000000 ' _8 H' t/ G- z3 L
- 0x00020000 {
% l- l% Z! @' ~/ I P* t - ; ' K( ]. k7 B! M5 Q& D/ W7 R
- load
5 ~" y' j$ p: I) r+ b7 e' ? - region $ h0 W8 W* M( ?" ]) s2 c( Q* `
- size_region
% k. c3 F, ^" g- {# O! Z - ER_IROM1 1 F. H) z: a, _ u
- 0x08000000
# w+ g$ L6 \1 H# d - 0x00020000 { / U/ _" m) B5 [, K9 S
- ;
5 L5 i1 I K5 N x* v* g( z - load
: z f* l# T" i - address 1 b4 d7 l4 l6 }+ e. d
- =
* i. d' Q) T) X! R8 |4 f - execution
, x$ Y" ?1 Z2 T% z - address
4 n5 h) X- L2 y) X8 Z' [, w - *.o
; l/ x$ _9 m8 X5 H% h - (RESET,
- P* T% a* a; T6 A" S4 k7 U - +First)- k. Q g) P3 N: }; d
- *(InRoot$Sections)
* Z/ ~2 ?6 c8 V) |) u! s1 v - .ANY
! g( w! _2 J3 c; W) v, _; M7 A1 { - (+RO)7 a1 j- Y! r2 L0 o0 T2 O( m
- }
* K2 s9 {4 Z- K5 e9 p - RW_IRAM1
9 d8 } s8 C1 {2 M" [ - 0x20000000 7 l n. l& z: l- w
- 0x00005000 { / H7 F3 Z+ W; J, I. M( g9 x
- ; & q: b$ F8 T$ Z! T4 i
- RW
0 K3 S4 B t, }+ ]8 _ - data
$ v+ B7 U% C% [# L: t% { - .ANY
/ n7 }6 _! L8 N" a, C B* k6 a I; ] - (+RW 3 F) W' n% o) ] @
- +ZI)- _7 ^% B9 _, [& l
- }9 v# B* T/ z4 q0 _& ?6 M
- }
复制代码4 K8 D: \4 q% _/ H" ^
其中 RW_IRAM1 0x20000000 0x00005000 表示定义一个运行时域 RW_IRAM1(默认域名),域基址为 0x20000000,域大小为 0x00005000(即 20K ),对应实际 RAM 大小。.ANY (+RW +ZI) 表示加载所有匹配目标文件的可读写数据 RW-Data、清零数据 ZI-Data。所以运行时所占内存的结尾处就是 ZI 段结尾处,可以将 ZI 结尾处之后的内存空间作为系统动态内存堆使用。
2 C, J8 X% b# _# f9 I/ f
: d1 ~$ v a( j$ @, y* H; Q- T
 1 P1 k% y% y+ Q* P; b5 P
 获取示例代码Keil MDK 中集成的 RT-Thread Nano 软件包附带示例代码,如果需要参照示例代码,则可以在 Keil 中打开相应的示例代码工程。 首先点击 Pack Installer,进入下图所示界面: ( [: A- U: n6 T: f
! {1 V: g4 Z _' H& f1 Y3 w+ p

右侧界面切换到 Examples,然后在左侧界面搜索 Device 或者 Boards,点击搜索出的芯片或者开发板,会显示与其相关的所有示例代码,同时可以看到 RT-Thread 的示例代码也在其中,点击 Copy,选择一个路径,然后点击 OK 即可打开示例代码工程
' d9 a5 v) ^) A
 ^- a+ H; `, m9 V7 u3 o8 w+ O5 }
打开 keil 的安装路径 将 RT-Thread Package 到裸机工程根目录 

 / u9 L" Y# e, g) H9 \
. y6 }- c( a9 a9 a% w
, J% u, j, N& M/ i8 |# A) y
$ d7 Z2 V" D3 H
$ w* D4 c! F" y9 G: {
# T' j5 ~* s, `, i
0 }, d: a) }" F0 |9 S9 V, P4 n& F. ^/ E% p* @9 w! M
1、拷贝 rtconfig.h 文件到 user 文件夹1 w# C2 ~( y/ N! B5 T$ _
将 RT-Thread/3.0.3/bsp 文件夹下面的 rtconfig.h 文件拷贝到工程根目录下面的 user文件夹, 可以通过修改这个 RT-Thread 内核的配置头文件来裁剪 RT-Thread 的功能 2、拷贝 board.c 文件到 user 文件夹下(新建RTE )' a/ z8 q1 L! ]9 F
将 RT-Thread/3.0.3/bsp 文件夹下面的 board.c 文件拷贝到工程根目录下面的 user 文件夹, 等下我们需要对这个 board.c 进行修改。
, e1 f3 J8 a1 I; @6 H \5 _
. {5 I8 I9 ?% Z; F( p' p& @- B. _4 L
2 w& N5 `) }. G& M4 k. ?. m, A3 m
' Y4 M* i( T; Y( R( m
3、添加 RT-Thread 源码到工程组文件夹
( t/ E! ]) m# z8 ~- B- l3 E2 R新建 rtt/source 和 rtt/cpu 两个组文件夹,其中 rtt/source 用于存放 src 文件夹的内容, rtt/cpu用于存放 libcpu/arm/cortex-m? 文件夹的内容,“?”表示0 3、 4 或者 7。内核文件 我们移植的为stm32f103 内核选择 Cortex-M3 6 i: W: N- [( [% l% c: S$ O
( \9 z* F2 w" I

指定 RT-Thread 头文件的路径
4 A8 t- l) x: _4 d* L- JRT-Thread 的 源 码 里 面 只 有 RT-Thread\3.1.3\include\libcpu
7 z* J! v5 {8 F% s# kRTThread\3.1.3\include
% A6 ^7 {1 O1 E! O! @& z* HRTThread\3.1.3\src- U* V3 G' _+ x, @3 E6 j& q
RTThread\3.1.3\components\finsh和 user 文件夹下(RTE) rtconfig.h 有头文件,只需要将这头文件的路径在开发环境里面指定即可。
( o' Z+ i& }- p+ ^! @6 B" v4 b0 g. n
) ^$ M8 S& o# G! k; E$ W

2 ]1 Y, Y% g6 l0 r* t这些都做完之后 编译还是有两个错误 因为还没有配置 RT-Thread Nano 参考上面讲述的配置 步骤 ) Z( ~4 r8 ^& z% B8 Z
5 r% ^5 |3 n; Z" k( h1 D* o3 k$ t4 l; z$ }, d
% T9 p& S, i( `$ s) i
 : k- c, E* ]; I8 W# y
 rtconfig.H0 ?: h; b) L5 P2 a% E- O
- /* RT-Thread config file */! ?. M4 j( ^, N, k
- #ifndef __RTTHREAD_CFG_H__
, O( d, {; `4 J t - #define __RTTHREAD_CFG_H__& ?7 k7 [. F% m! p" p; H3 `
- #include "RTE_Components.h"( u* s9 U3 i; {$ q9 i; f
- // <<< Use Configuration Wizard in Context Menu >>>: g' X# ~/ B; v
- // <h>Basic Configuration
$ K$ d' l5 Z" x8 B - // <o>Maximal level of thread priority <8-256>
, T! v! v2 l2 N9 e9 d2 ~ - // <i>Default: 328 Q! Z5 i/ ~! w4 q
- #define RT_THREAD_PRIORITY_MAX 322 ~7 U" B \& ~) d/ W S
- // <o>OS tick per second
, _" @% t/ L6 X' m. s4 m- i- [ - // <i>Default: 1000 (1ms)
- W8 g$ Q$ ?: K& y% N Y9 b! P - #define RT_TICK_PER_SECOND 1000* [# s/ Q+ T* o1 e$ k4 T1 Q4 t
- // <o>Alignment size for CPU architecture data access
/ U, P9 _2 ?; J/ C% p6 C - // <i>Default: 4$ q7 V0 n/ [ w6 v, `
- #define RT_ALIGN_SIZE 4
/ r6 [' D9 @( A8 i - // <o>the max length of object name<2-16>8 P- x. x; E. V$ r4 e5 J' O7 y) V- @& a
- // <i>Default: 82 B( j# g X& j; `9 T
- #define RT_NAME_MAX 8
5 _# ~8 s7 N' m/ I& \7 p; Z+ J9 W - // <c1>Using RT-Thread components initialization% R, P1 f# Q1 B9 S# I6 [
- // <i>Using RT-Thread components initialization
~! _, Z8 w6 b8 n+ S+ @ H2 r - #define RT_USING_COMPONENTS_INIT
: W) S8 L3 B% g. ? - // </c>
2 f0 h8 L) z% |6 N# r - // <c1>Using user main
1 q8 Z+ m! ~. G3 k/ @ - // <i>Using user main
6 x6 A/ S3 T+ F3 F) U! K - #define RT_USING_USER_MAIN
! M8 q2 W% R0 n0 u - // </c>
: F' U' F) _6 d1 }1 t# E l2 e# M# _7 J - // <o>the size of main thread<1-4086>
2 ]$ {/ e% u3 Z! w5 f - // <i>Default: 512$ W6 s3 x. X3 T# X& ?9 a' a
- #define RT_MAIN_THREAD_STACK_SIZE 256
5 r$ R: R# p! P6 O7 R - // </h>/ J3 D D- l; E/ j$ |; Q2 \& g
- // <h>Debug Configuration
: r \! S+ N1 b0 j. c% ~! ` - // <c1>enable kernel debug configuration7 u: n2 J; s) o. t8 y* b, H
- // <i>Default: enable kernel debug configuration
2 f$ t) j1 W {9 H0 t# b - //#define RT_DEBUG/ m: D e1 x v+ f
- // </c>
: \1 ~$ K6 I5 {8 K! ]' }7 m - // <o>enable components initialization debug configuration<0-1>! W* X; Q: K% ?- | H
- // <i>Default: 0
( m6 q+ B; k! B# |5 r* ? - #define RT_DEBUG_INIT 0
2 }) Q' P! S# H6 t0 j+ A# _/ L/ j - // <c1>thread stack over flow detect0 _/ W- ~7 N8 |9 G! ~2 u4 F4 _/ a
- // <i> Diable Thread stack over flow detect8 ^9 q6 M7 h$ Y! }) w' [
- //#define RT_USING_OVERFLOW_CHECK. n0 U, x/ U }; l
- // </c>% P" z- x& @+ Z+ A- `' u' U( q
- // </h>1 T# l! ]4 X% f1 N4 [) F+ ]
- // <h>Hook Configuration
! E& _3 n9 A4 t, l1 t0 u$ i) o4 N - // <c1>using hook3 N. M- R9 d @' f
- // <i>using hook
& \4 N0 a$ a+ n" m9 D+ b) {1 f* g, a# | - //#define RT_USING_HOOK) h0 y ]5 V& r9 x8 W& P0 z
- // </c>, W9 G9 |' P3 w1 t8 V7 V! e2 ?8 H. v
- // <c1>using idle hook
" r1 F- I& d$ N! L+ F: K- d7 f - // <i>using idle hook, V5 p- g7 J2 D4 f' Z+ F$ j4 }
- //#define RT_USING_IDLE_HOOK3 x! E* ^/ p! _9 E7 \9 a! ]
- //</c>
复制代码
% b8 d4 b8 }" g, M, T! Qboard.c - /*( q7 m; l7 R3 { [( n4 \' n" E) B
- * File : application.c8 ~9 p) x/ R' Y4 M2 n" p8 ^
- * This file is part of RT-Thread RTOS
k2 I" E- I) E5 _ - * COPYRIGHT (C) 2006, RT-Thread Development Team4 U8 L z$ R. o/ p8 N
- *
. I' O! f; R( p' E$ J - * The license and distribution terms for this file may be. Z+ K. N& P/ c0 e
- * found in the file LICENSE in this distribution or at
0 J. w: m8 H( o* |9 L - * http://www.rt-thread.org/license/LICENSE5 k! _, b$ D4 n, c9 I8 ?5 ^
- *
6 }9 c. Y" }9 h* g - * Change Logs:# v% h2 n+ e# g m8 i
- * Date Author Notes& F6 y D' G6 Y5 K" h, ^, Q* b
- * 2017-07-24 Tanek the first version
- [! N% d$ H& }8 {: m( b2 F d - */
' H! M5 G; t- {7 w& p, C8 S! @8 e - #include <rthw.h>
( o# c! f& Y' n6 `" s9 ] - #include <rtthread.h>
. ~9 q6 g. J" _0 G" D - #include "usart.h"
7 g$ k/ A- c+ m - #include "delay.h"
- W5 X5 i c. u% T2 k+ y4 G - #include "led.h"3 P J6 }* q W9 }
- // rtthread tick configuration
" u6 {6 b! \( @0 Q( ?9 x7 L - // 1. include header files( \% g( g7 a- B1 Y
- // 2. configure rtos tick and interrupt
$ B7 d- h/ F7 y: r - // 3. add tick interrupt handler
, E2 m! M" K. m U) I9 } - // rtthread tick configuration
' f0 T' S- }0 J# Z - // 1. include some header file as need8 k1 \( V S: [( U
- #include <stm32f10x.h>+ g K7 F0 q2 D" z. G. {/ }
- #ifdef __CC_ARM" _) x4 S8 W* Q' Z( y
- extern " x; U9 _( V* C5 N
- int Image$RW_IRAM1$ZI$Limit;
! t; k+ x1 Z/ d+ i( V - #define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit). N2 Z0 M1 }9 t5 _, ~
- #elif __ICCARM__8 l7 c& T- G4 i9 Z1 p% \; \4 `4 l
- #pragma section="HEAP"/ L# H6 U4 H! M% z
- #define HEAP_BEGIN (__segment_end("HEAP"))
# V, n2 Y+ E# \( H6 v$ m7 e6 ~ - #else
0 b! A: I6 \, S) M" F/ u/ { - extern
( J9 J' ]' k# P( o' H2 d; I - int __bss_end;
2 v% l: v, c' |* B2 s* @ - #define HEAP_BEGIN (&__bss_end)2 P, V+ {& T3 A0 l: n7 ^
- #endif) U8 {9 e: S, t4 A
- #define SRAM_SIZE 8
: L* L3 v0 ]7 C7 P% C9 n - #define SRAM_END (0x20000000 + SRAM_SIZE * 1024)
7 A4 D4 V @, e- b) ?+ I+ j7 r1 G - extern uint8_t OSRunning;
4 {& M; @5 M/ m' V - /**
# x# a$ c$ {% x6 s* A% C/ O p - * This function will initial STM32 board. @/ x- }$ j! R' ~( n: w; D
- */
! b+ `( m8 w' T" a; O' f - void rt_hw_board_init()0 Z$ {. Y- }. Y! H3 P
- {
; ^: Z+ w# c8 d' m: Q% p - // rtthread tick configuration
# t! U, ^0 S. M# J - // 2. Configure rtos tick and interrupt
8 P2 R* Y! o5 @" D! y% |, C( h - SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);0 T7 d2 K; n2 B; ?; ^" {
- //串口初始化
. l- X* G" Z; D, e# B) D% { - uart_init(2 ^3 B7 l# X/ t: f& O8 K
- 115200);0 L9 s8 r; E, L- b" B. W2 ]
- delay_init(4 N5 x9 s5 f |
- 72);
' B0 _! | s6 _8 h4 W1 e+ _ - //初始化LED1 l+ W# ~8 r* F9 T3 E4 P( g' \
- LED_Init();
% y, b* t5 I4 Z1 F3 E8 q% e# L - //tips:把硬件初始化放上面% W: L4 h! C" }8 \( @
- OSRunning=
: g, R9 n5 i3 l( } l - 1;
1 | u' y8 }+ b" \: ? Y3 M+ X - /* Call components board initial (use INIT_BOARD_EXPORT()) */$ P- `0 Q3 V& c
- #ifdef RT_USING_COMPONENTS_INIT
2 A+ _' w" G/ y - rt_components_board_init();
4 F H2 ^) D4 P. T" l- c. ` - #endif
, U) Q1 i! F0 x9 c - #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
& M0 V. f) w! a4 P Q7 N - rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
3 a! s6 s. F5 a% I - #endif
8 n* J( h& s& \ - #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
4 Z5 V* J1 N* }) u" a# w/ w, G8 w - rt_system_heap_init((1 j% y9 e9 I( V0 }# J+ f
- void*)HEAP_BEGIN, ( D0 l. @1 R0 P3 w. B0 C* r! l
- void*)SRAM_END);
* x2 o" ] |( |* Z, o; Q" `6 j - #endif6 J3 x3 Y( y, G+ _5 M; f2 K
- }
" n% Q8 c+ U3 X" T7 a' J8 m+ ~$ D' I' | - // rtthread tick configuration1 J! i2 B0 z$ q* h( t; ?$ F6 U y8 {, {
- // 3. add tick interrupt handler! L7 E3 Z$ k& W- ]8 h n( h
- void SysTick_Handler(8 f& Q8 l e3 J4 b2 y3 B" K! M) r
- void)$ y! i3 B0 t/ p- V% P
- {2 p8 a" s' \4 p$ f& L3 g/ J4 a) h% e% [
- /* enter interrupt */9 k% z1 q: \/ G* l8 A1 J& h
- rt_interrupt_enter();
) c H% \* u0 U8 Q& ` - rt_tick_increase();$ c/ ~& N% A) o' G& X) m
- /* leave interrupt */
& A5 P7 u, n% t' d6 P2 W8 ~* I% D - rt_interrupt_leave();
5 |; m; f( a! a5 n8 T - }
复制代码 + m' R9 @' ~2 @* B
修改完rtconfig.h 和board.c 编译通过
" m- h: q6 P9 q. t6 s
7 F9 l* G; K1 V$ i' J
" m" s" M" r0 |1 D; P, u: d$ \
4 X' ?4 c8 |* l8 ^' k, X" F
* l1 r) C- `) W% Q
( V/ N' m5 }7 d* k a转载:熬鱼不放汤1 A! F; m9 W5 j$ f% G# Z4 i, [
9 i. I! h) Q* @. s4 g) }; k如有侵权请联系删除
8 G0 O }! J. P! [/ c% u# E; _- V7 D
( M( o0 ~1 ?/ a0 Y; V
|