你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32移植RT_thread经验分享

[复制链接]
STMCU小助手 发布时间:2023-3-10 12:11
RT-Thread Nano 简介

RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。适用于家电、消费电子、医疗设备、工控等领域大量使用的 32 位 ARM 入门级 MCU 的场合。

下图是 RT-Thread Nano 的软件框图,包含支持的 CPU 架构与内核源码,还有可拆卸的 FinSH 组件:


' V$ G/ g+ l& J1 F$ H# W

1b3dbfb6fe85d38e112bd58feb27f391.png

  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
2020122409590473.png
. 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 20201224095942708.png
+ 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

41342f0db73e7befc8b0076af4d625c1.png


( 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

708412061fe08312095ad4b350db527b.png

! t5 @9 M$ U3 ]

方法二:手动安装

我们也可以从官网下载安装文件,RT-Thread Nano 离线安装包下载,下载结束后双击文件进行安装:


& n4 {" L# t1 k, Q& a& z' }

99a840701f0837d6ac4c2d2b7f39e590.png


1 N" a" X8 a5 T8 _4 J

添加 RT-Thread Nano 到工程

打开已经准备好的可以运行的裸机程序,将 RT-Thread 添加到工程。如下图,点击 Manage Run-Time Environment。


9 w+ [/ y% W0 m7 ~2 a% ~

6d0962b9bed03fec9b637e345539b44d.png


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

40c4e7a7d03954dea4dfde0a0d951bd6.png


% n0 i6 _( Z" y/ Q  \4 `' f: s

现在可以在 Project 看到 RT-Thread RTOS 已经添加进来了,展开 RTOS,可以看到添加到工程的文件:


3 Y. C) e" y# v( G

742204638963aeaf0aab8ee4257510a7.png


8 _  @. ^* k' g' ~; k* t

移植完  打开过程文件是错误的

2 N7 X3 ~/ S8 `7 a

20201224100720186.png

/ 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() ,如下图所示。

  1.        /* board.c */
    9 N$ ~8 ^; D6 Q" k! O
  2.        void % w* m3 k  A7 S! u- j9 I) J. D9 L
  3.        rt_hw_board_init()- J( O. @' ~- f' e
  4.        {* u& b1 r7 n4 D/ C0 d8 ^+ d
  5.        HAL_Init();% l* u- J/ O9 Y3 J
  6.        SystemClock_Config();- M% L: }2 \! Q
  7.        /* System Clock Update */# W, n) ~! |/ J+ F
  8.        SystemCoreClockUpdate();7 a6 W2 J- f$ l3 S) b
  9.        /* System Tick Configuration */* ?- C% z9 B- B+ K; W: M4 O  v
  10.        _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
    1 e% o3 ^$ _! @& t3 G2 u  {
  11.        /* Call components board initial (use INIT_BOARD_EXPORT()) */
    : a! k& ^1 g7 w, h& j% u
  12.        #ifdef      RT_USING_COMPONENTS_INIT
    $ ~2 e+ |3 @: v+ B# Y) |4 Q9 F
  13.        rt_components_board_init()
    1 h' V' t% ?' X
  14.        #endif
    * e! B$ T' c0 p! ~
  15.        #if defined(RT_USING_USER_MAIN)
    $ G: a7 }) e. d# K% T
  16.        &
    7 p% W" q9 z1 Y/ x+ B; j
  17.        & 0 f; U6 e/ M4 x& \" v& \8 H
  18.        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
  19.        #endif6 C: Z1 p1 ~  D. \
  20.        }
复制代码


1 Y* Y% ], K& x, E$ c, H

01828e115c452708d24b825adec73a79.png

! 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

ba3278f41f36daf68a3e24a3ba33b4f2.png

! K1 R! D- X2 M+ `1 z4 A8 \! Q

初始化内存堆需要堆的起始地址与结束地址这两个参数,系统中默认使用数组作为 heap,并获取了 heap 的起始地址与结束地址,该数组大小可手动更改,如下所示:

- Y6 x* w8 ?( V8 |) I

d505d2049539b632a2951a5001656866.png

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

ad4be7cd4c79e9844056b46d53c5b8c6.png


* 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() 函数完成的,动态内存堆的初始化需要指定堆内存的起始地址和结束地址,函数原型如下:

  1. 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 初始化函数:

  1. #define RT_HEAP_SIZE 1024
    ( I9 a' R8 [" o% N5 g
  2.        static - j% e5 w! T5 y, ^/ R" J* R
  3.        uint32_t rt_heap[RT_HEAP_SIZE];
    & Z; A6 Q1 F- D: w
  4.        RT_WEAK void *rt_heap_begin_get(void)
    , ?. q" U+ r; _) @
  5.        {' r1 x: Z: u8 i! j7 q9 L; _
  6.        return rt_heap;/ ]1 ?/ }+ i$ O7 b7 R
  7.        }, c0 u, E) c" J
  8.        RT_WEAK void *rt_heap_end_get(void)
    ) T0 u$ I6 _; K8 t8 ~9 S% F. N/ ~
  9.        {
    " T: F- @$ C; a4 N3 j# B
  10.        return rt_heap + RT_HEAP_SIZE;
    3 `3 F, M) d# c) N% w+ l9 W' A
  11.        }' g  \- E4 N* U" \/ X6 q8 C9 `
  12.        void rt_hw_board_init(void)
    4 O  i- _: C6 m5 \$ m  {5 U+ J! ~
  13.        {
    2 S7 P5 S, k9 ^4 n5 @2 F
  14.            ....* ~$ C/ n3 C  |& Z
  15.        #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    0 _* T+ W: E1 v: G, v
  16.            rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());   
    & ^  m+ j& y7 ]) E9 l
  17.        //传入 heap 的起始地址与结束地址
    " M) I, {: u5 p& D  d6 s5 N
  18.        #endif
    & n  H. Z7 T2 g" Z
  19.            ..../ ]1 q+ l& j: d4 }
  20.        }
复制代码
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 初始化。

  1. #define STM32_SRAM1_START              (0x20000000)
    : z& L* \. Y5 W/ L2 @% ?! {
  2.        #define STM32_SRAM1_END                (STM32_SRAM1_START + 20 * 1024)   // 结束地址 = 0x20000000(基址) + 20K(RAM大小)
    / ^; D2 e# a  G  p* D: p/ e
  3.        #if defined(__CC_ARM) || defined(__CLANG_ARM)
    - s) X/ R) ]9 [1 h" P! e; c
  4.        extern - q# b/ r4 E" V, `
  5.        int Image$RW_IRAM1$ZI$Limit;                   " s$ z) b  l+ d5 t' F! k( ~
  6.        // RW_IRAM1,需与链接脚本中运行时域名相对应2 `/ |1 ^9 m5 K, M& O: @+ |
  7.        #define HEAP_BEGIN      ((void *)&Image$RW_IRAM1$ZI$Limit); M% u* y( u/ R7 R0 e% }6 I  z, S) k
  8.        #endif& N3 l% S& [4 \9 f
  9.        #define HEAP_END                       STM32_SRAM1_END
复制代码
  1. void rt_hw_board_init(void)
    7 U) x# V" H: m$ R. s
  2.        {
      G' V% V$ f4 p+ R8 C) e
  3.            ....9 p  f  L+ P4 @1 s3 [/ j+ u
  4.        #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)0 g# C- w7 {/ E
  5. rt_system_heap_init((
    7 J) o- l0 q' i% _+ L
  6.        void *)HEAP_BEGIN, (
    $ Z9 T6 a* k! Z; [! E3 V3 M% Z
  7.        void *)HEAP_END);1 o% U( Z* R$ u5 w$ L9 @" j
  8.        #endif
    1 B$ i7 D1 [3 _  s: v7 q: ?0 P
  9.            ...., M; E" i& A- p( a
  10.        }
复制代码

2 v* Q. ?7 k5 ?8 l& d" s) h$ ?+ g/ Y: k4 _# k

链接脚本

链接脚本,也称分散加载文件,决定在生成 image 文件时如何来分配相关数据的存放基址,如果不指定特定的链接脚本,连接器就会自动采用默认的链接脚本来生成镜像。

举例 stm32 在 KEIL MDK 开发环境下的链接脚本文件 xxx.sct:

  1.        LR_IROM1
    % E8 k; _* }0 \5 c- G' |: p
  2.        0x08000000 & e" _7 J' U+ |, o
  3.        0x00020000  {   
    ; U/ k0 D% m2 o8 r* `
  4.        ; ( y4 l  T9 S8 n4 Z: P& W7 e) p
  5.        load 7 @4 e! m' y, h) E  a. ^4 f
  6.        region
    & p$ y3 X' A% U% T
  7.        size_region* w" _+ B( Q* B5 ^4 ~2 l
  8.        ER_IROM1 1 U! `- p0 F1 F8 Y1 L& n* |* U
  9.        0x08000000
    2 e3 A7 o* `; A( y
  10.        0x00020000  {  8 t- z6 i3 i  M* [( ]- }
  11.        ;
    ; i, B+ m7 [: F* q( K8 t6 a
  12.        load ! E* M. C9 r6 j1 [
  13.        address
    ' j6 \& ]. M7 ]" k5 W5 P& @. j
  14.        = - j) h/ U7 C1 i" E* v: F6 ?
  15.        execution , r: e* q$ z* ^4 I/ x
  16.        address" z0 Y. ]- T9 B0 K" |7 i1 H
  17.        *.o
    9 V$ E3 I5 V' Z$ O0 b; B! |  k  e
  18.        (RESET, . g1 H/ ~' h: h7 e: J8 [* k
  19.        +First)
    1 b0 D7 j0 o$ s, g0 ?( ?
  20.        *(InRoot$Sections)( U1 }# U, C5 E2 n1 z9 r0 u
  21.        .ANY " `& u% _  l; V1 F! w
  22.        (+RO)
    $ k9 C6 v. J3 A4 f0 v6 c2 k
  23.          }; d- f" m0 U* \
  24.        RW_IRAM1
    5 _' |( e. X! J
  25.        0x20000000
    ! M! \* n. Y7 d; }: V- a8 w, ]
  26.        0x00005000  {  3 R- B* a% n9 h- s- U
  27.        ;
    - d- P$ n) R0 F
  28.        RW 5 U9 ~) O% C2 y$ x/ v" y
  29.        data
    ) c& c8 e: f9 P9 P* K
  30.        .ANY 8 m; g% r5 D; e) n9 x
  31.        (+RW
    1 x6 N8 ?/ o* m9 @8 y  m
  32.        +ZI)- V5 g2 T  Y2 u5 v5 z
  33.          }
    . j/ ?& k" w- Y+ f# G
  34.        }
复制代码

& 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

20210320113521357.png


  s$ y, W; _, R

02c0c30e07d086dec972a520ff3a733d.png


1 B7 f/ b% G5 C* w1 L% B, s" D

获取示例代码

Keil MDK 中集成的 RT-Thread Nano 软件包附带示例代码,如果需要参照示例代码,则可以在 Keil 中打开相应的示例代码工程。

首先点击 Pack Installer,进入下图所示界面:


( w* o2 M" G* c

a2f3187d72324887f4e7e80633e7299a.png


/ P- A# e6 I) n& j

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


; [% m- b, j4 V, g0 s1 S. u

20201224101212395.png


( ?* p% l+ l8 p9 R; w* X( }0 V

打开 keil  的安装路径 将  RT-Thread Package 到裸机工程根目录


1 E$ l9 r  n. Z
5 V) g8 P8 d# G$ a- u: X; q0 U
2020122410322937.png
6 }1 T' l  H4 ]1 w& e- }' o% R: ]% q
20201224103321378.png 7 J7 j# T* S4 d% o4 x$ o+ M$ t' X

6 K. r* c+ F+ G$ O% n 20201224103347482.png ! 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

20201224103553656.png
* L  y  \2 T: [; c
9 K2 R0 ]. ^5 k3 A) `$ d. o 20201224103930352.png / 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

20201224105043688.png

, 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; ~

20201224110224895.png
, z5 F9 r. Y5 T' I) l


7 a! s  V( [3 l1 L( p3 F

这些都做完之后   编译还是有两个错误

因为还没有配置 RT-Thread Nano

参考上面讲述的配置 步骤

0 Z7 Z4 C. w1 \
20201224110649146.png
; Y0 b% p% }1 @+ A! \$ r+ s- R, ~& s0 P8 h7 D7 U
20201224111035816.png
! 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
  1. /* RT-Thread config file *// B  \5 |5 U9 r* L, n: R
  2.        #ifndef __RTTHREAD_CFG_H__3 n( {: b( b  c% w* ^" @
  3.        #define __RTTHREAD_CFG_H__: F7 f. _3 g0 s$ d# M* |7 h+ s5 `
  4.        #include "RTE_Components.h"; s- x# X$ D: q; d3 d" q
  5.        // <<< Use Configuration Wizard in Context Menu >>>' t9 G, i. b2 M+ M. o8 h
  6.        // <h>Basic Configuration
    5 b5 y& \: |* {5 ^) c# f8 Q0 s
  7.        // <o>Maximal level of thread priority <8-256>
    " d7 |- L" O# H2 U% m
  8.        //        <i>Default: 32
    9 _/ B1 Q  @" [" b( }
  9. #define RT_THREAD_PRIORITY_MAX  32
    4 t; Z8 T- _+ ^1 ~8 V
  10.        // <o>OS tick per second- ~( l/ u. }! j( Y
  11. //  <i>Default: 1000   (1ms)
    " v6 j  J$ N/ R" b8 G
  12. #define RT_TICK_PER_SECOND        10006 i6 H* Q; t5 q+ b7 U- @5 d0 B
  13. // <o>Alignment size for CPU architecture data access
    5 i  A: j( L$ k3 L- r
  14. //        <i>Default: 4
    $ x, J) Q" w/ K, ?% ]# l
  15.        #define RT_ALIGN_SIZE   4
    , K! _' m6 A# k$ g' r. [$ I/ |
  16.        // <o>the max length of object name<2-16>/ |3 N8 G3 ^9 X9 z
  17.        //        <i>Default: 8
    1 @7 ]) M  K: u- X* x0 l) E
  18.        #define RT_NAME_MAX           8
    & _( y* I! L; g6 n% L: w9 t6 T
  19.        // <c1>Using RT-Thread components initialization* A6 e8 y) N: {0 r0 S
  20.        //  <i>Using RT-Thread components initialization
    4 Z" z$ \) n. g6 b$ D  R
  21.        #define RT_USING_COMPONENTS_INIT) e, b+ G; d( L; B& T, M
  22.        // </c>+ E" b1 ?% m. ^: v, U* J6 K
  23.        // <c1>Using user main( w3 Y* u7 b6 E
  24.        //  <i>Using user main
    0 O( L1 P. l0 ?1 z1 n. W
  25. #define RT_USING_USER_MAIN
    $ o: }2 H; c% ^* Q7 w, C6 M
  26.        // </c>
    5 ^* p6 S5 F4 H- Q! W& }
  27.        // <o>the size of main thread<1-4086>7 e# f6 h- B: C% x
  28.        //        <i>Default: 5129 R) W* K, p7 j0 s9 ^; U& Z
  29.        #define RT_MAIN_THREAD_STACK_SIZE     256! ^/ M. C9 G& u3 L" H
  30.        // </h>0 E1 q% G: c; [1 M) L
  31.        // <h>Debug Configuration3 m/ M3 U% u/ A) C7 u
  32.        // <c1>enable kernel debug configuration
    / ~9 w3 ~7 i1 D, Y$ b+ R$ @
  33.        //  <i>Default: enable kernel debug configuration& {' _. A3 j6 g8 [
  34.        //#define RT_DEBUG0 r& W; R" u7 p) V3 b$ O
  35.        // </c>: y* e1 m! l" }! M3 U: z" S
  36.        // <o>enable components initialization debug configuration<0-1># N; q8 }5 [  P1 i, N5 D
  37.        //  <i>Default: 0
    3 c5 N  _- f. R5 A1 E- B
  38. #define RT_DEBUG_INIT 03 I: }) p6 w" U+ Q4 w
  39.        // <c1>thread stack over flow detect$ |2 u% E% ^4 B7 x4 Q3 u
  40.        //  <i> Diable Thread stack over flow detect3 }( p  y# r' ]+ v- w2 v5 }) V
  41.        //#define RT_USING_OVERFLOW_CHECK3 u5 x4 W5 o% D) ^
  42.        // </c>$ C' M9 c: {9 A+ Q: @
  43.        // </h>
    9 H" w3 Q- Z! b
  44.        // <h>Hook Configuration
    ( c; O* ^+ W- Q/ j! |; b# {) S
  45.        // <c1>using hook8 y: i% Z) J/ q0 ?6 `' T' `
  46.        //  <i>using hook
    " B8 n1 F2 J: r/ V" }
  47.        //#define RT_USING_HOOK& D" i/ h0 l) B( t' f
  48.        // </c>
    " k( [! r4 G& u) @5 g- B
  49.        // <c1>using idle hook4 W) J  q( O0 _$ O$ V
  50.        //  <i>using idle hook
    4 s; ^5 J4 Q: }. B% A8 K) i
  51.        //#define RT_USING_IDLE_HOOK
    : X* C! u  x+ I4 l" R# c5 a* s
  52. //</c>
复制代码

8 ~# P* c: E0 f( N8 lboard.c
  1. /*
    : b) Q+ r) t, L$ B1 U$ @* b8 e5 W( L
  2.         * File      : application.c
    8 i/ M' d  _) l3 \7 N- n& ?
  3.         * This file is part of RT-Thread RTOS/ L9 x" Y5 j1 a6 c& S
  4.         * COPYRIGHT (C) 2006, RT-Thread Development Team! ]' f- s! R# C' J; p+ \0 s
  5.         *
    8 h% f5 ~5 m: X& ~! A9 R
  6.         * The license and distribution terms for this file may be
      z5 S0 b# f3 ^8 S4 O5 `
  7.         * found in the file LICENSE in this distribution or at! {: ?8 T3 ?( ~9 f2 \9 }& s
  8.         * http://www.rt-thread.org/license/LICENSE6 N% y# n- E* l: y- ^
  9.         *: [$ v' I- ~, x
  10.         * Change Logs:
      ~- H! c3 J' B
  11.         * Date           Author       Notes
    6 ?: V. s; R$ d
  12.         * 2017-07-24     Tanek        the first version) u6 B/ i4 s/ n* E% g9 N
  13.         */
    * A9 ]7 o1 G' @% j; o3 ^' e) @/ p! a
  14.        #include <rthw.h>4 I( c- d+ }2 g7 h% |
  15.        #include <rtthread.h>2 ?# {4 P- N- B
  16.        #include "usart.h"
    - e% S8 Z- R) q  M# _- W$ u, L
  17.        #include "delay.h"' A8 S5 n+ ]9 b  A4 ?
  18.        #include "led.h"* }8 P/ K0 [2 f2 G1 ?
  19.        // rtthread tick configuration8 h8 W* [9 ~' V4 O# C8 j$ Z0 M
  20.        // 1. include header files) E; ~, E4 j4 _1 X
  21.        // 2. configure rtos tick and interrupt" F- `- k$ X  r6 f1 _! n
  22.        // 3. add tick interrupt handler
    - h; Y' p" a8 ^7 S$ E
  23.        // rtthread tick configuration
    0 D7 O2 q. n1 A0 D5 Q0 {
  24.        // 1. include some header file as need
    8 U; _( z) D- o3 ~  e& R
  25.        #include <stm32f10x.h>0 X8 z, X! W) u9 D' X9 [' X* ?
  26.        #ifdef __CC_ARM
    ' b5 B. r! Z5 o, ~8 C: I
  27.        extern   \3 [( z9 U" N* B( x" k
  28.        int Image$RW_IRAM1$ZI$Limit;
    , _3 t4 v: A7 ~1 U$ r9 `
  29.        #define HEAP_BEGIN    (&Image$RW_IRAM1$ZI$Limit)! v' d/ ^3 q# I: }0 v: Z# Z3 i
  30.        #elif __ICCARM__
    4 g) Q& @6 k1 e8 p
  31.        #pragma section="HEAP"7 b; W; @4 C- u# o; @* ]& b5 D
  32.        #define HEAP_BEGIN    (__segment_end("HEAP"))( q. s9 U' S3 U% ^2 ^* e3 ]
  33.        #else& p3 u" h* e$ z- F5 b+ k
  34.        extern
    9 M& y: s& z$ J. ~
  35.        int __bss_end;+ P( _8 N6 C% |! {1 q
  36.        #define HEAP_BEGIN    (&__bss_end)
    ) K( x7 \- d' c. \+ V$ G- A( C: u. x
  37.        #endif
    6 S  t7 _5 {; o* @8 |
  38.        #define SRAM_SIZE         85 L9 m2 a$ [: ~6 `! f5 ?/ L) D# E
  39.        #define SRAM_END          (0x20000000 + SRAM_SIZE * 1024)
    ) u) k# }$ Y3 z/ I+ ]4 b, `* @( s
  40.        extern uint8_t OSRunning;8 g$ Y4 I0 i$ _+ e6 r1 \0 t
  41.        /**
    + N: C  R2 D8 v  X% f7 Z7 q' U3 T
  42.         * This function will initial STM32 board.
    + E: [) c! i! E2 Y5 U
  43.         */! }3 l( l8 r0 C7 F1 J0 o4 i
  44.        void rt_hw_board_init()6 k4 ]3 ^5 j! S2 B
  45.        {
    5 v! c9 W8 Z, Y5 j' x( [2 b: Z9 Q
  46.        // rtthread tick configuration
      U+ p) V: s$ a4 q2 D
  47.        // 2. Configure rtos tick and interrupt
    7 q  F+ @9 s" v& }( U7 l+ m
  48.                SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);  z# J" w. Q; n  k- ~5 z
  49.        //串口初始化
    - @  B: L2 P5 s3 Y' i
  50.                uart_init(& L0 b' o( t9 Z! j- t' x/ r
  51.        115200);
    $ ^1 c6 w" y* {8 H9 V# E" }) {
  52.                delay_init(
    , H2 |" S: T9 |1 o0 L( \) l0 A
  53.        72);
      M, P; Z) }" B5 {+ B$ M, f. A3 f
  54.        //初始化LED
    / d, ]' p  y; ^$ ^. P, N
  55.                LED_Init();
    ) \7 e9 G3 `6 g  g* C
  56.        //tips:把硬件初始化放上面1 h4 A# I1 [& V( `. |% w
  57.                OSRunning=+ q% g' v, j& k6 H, e% P
  58.        1;
    2 g- n3 q+ d8 b5 z
  59.        /* Call components board initial (use INIT_BOARD_EXPORT()) */
    2 E$ f4 V& q& `! ^  Y- A" ~' ~
  60.        #ifdef RT_USING_COMPONENTS_INIT
      d+ [6 B1 r& N7 N6 O
  61.            rt_components_board_init();
    ) O) p8 ^3 ^1 f2 r
  62.        #endif5 H) x) `6 n# @; r! X+ g: d
  63.        #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
    ( q; _6 Z1 |3 |- ]8 y+ a0 \
  64.                rt_console_set_device(RT_CONSOLE_DEVICE_NAME);4 S" z( w! U  f% ~
  65.        #endif
    , {5 \) F! V3 b
  66.        #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    - V( k# f4 l4 q2 ~
  67.            rt_system_heap_init((
    ' U& y/ K- J+ ~6 ^& h; R3 F% K
  68.        void*)HEAP_BEGIN, (
    5 P# D  n! c  p4 F
  69.        void*)SRAM_END);5 |3 {2 W0 k% ~. b. V
  70.        #endif
    , x1 g6 p6 y! R% N8 q# M; ~
  71.        }
    9 W# z$ W9 e+ A  Y& r4 [
  72.        // rtthread tick configuration
    $ \7 q$ C4 ~# t) W# Y0 _
  73.        // 3. add tick interrupt handler9 ?5 n7 c$ J' r+ r5 v7 p, E; M  S# Z
  74.        void SysTick_Handler(: s' k# [( x$ S9 J; T! p* `
  75.        void)7 I; P5 \) s- o9 x  T5 X
  76.         {. s) B0 Y: F0 Y1 D4 ^) f! Q
  77.        /* enter interrupt */
    8 j" Y% ?0 B, p9 b* m
  78.                 rt_interrupt_enter();& ~9 j/ U, T3 g6 r# q
  79.                 rt_tick_increase();
    1 C+ J2 b3 s" O8 I. z  X$ P
  80.        /* leave interrupt */
    7 n/ q2 t! z1 g& i9 z9 o7 N5 `. B
  81.                 rt_interrupt_leave();
    - k. ^+ w# b! F4 }4 ^* ^
  82.         }
复制代码

" u8 q- Y/ r( x修改完rtconfig.h 和board.c  编译通过


& R6 I) [$ {+ X/ c

20201224133909599.png
$ O' x+ a% a: _* s" t
- r- Z9 b! l% s  u1 H, F8 a 20201224154224945.png
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
收藏 评论0 发布时间:2023-3-10 12:11

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版