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

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 组件:


  D# D" M& Y' l% b0 A

1b3dbfb6fe85d38e112bd58feb27f391.png

7 _/ Y8 N9 u1 |5 n/ \

支持架构:ARM:Cortex M0/ M3/ M4/ M7 等、RISC-V 及其他。

功能:线程管理、线程间同步与通信、时钟管理、中断管理、内存管理。

3 k0 R0 Z* ~! @; i1 I% L- {
1 从官网下载RT-Thread源码,里面包含stm32f1xx的例程。

建议使用最新的源码。很多功能老版本的代码里面都没有,比如之前使用3.1.2的源码,想使用ADC功能,发现源码里没有这部分,更新到4.0.0就有了,并且4.0版本也是现在官方推荐使用的,配合ENV工具开发很方便,现在RTT的社区有很多软件包了,通过ENV就可以很轻松的使用这些功能。

BSP  文件夹内


7 N6 v5 ^- k$ g3 {/ G( A

/ ]/ [) j. Q' ~4 u* T" ~9 N* e
2020122409590473.png
* [9 P6 i6 {5 u* Z( K7 B


* V; y, Q, j& e6 h  ~, M

此版本是基于 HAL 的例程   大家如果熟悉使用HAL库 可直接在此使用

* ~5 ^: h% A& d# r) m
5 J/ M+ T2 G, m, I/ b% i+ {1 i
20201224095942708.png
4 Y% A- ~  `4 k  L' W1 L7 ?$ l: f( D6 ^/ Y) a

下面开始正式的介绍移植过程

. I3 o. y. P; `5 t6 W8 _+ W/ O! q
Nano Pack 安装

Nano Pack 可以通过在 Keil MDK IDE 内进行安装,也可以手动安装。下面开始介绍两种安装方式。

方法一:在 IDE 内安装

打开 MDK 软件,点击工具栏的 Pack Installer 图标:


+ }+ r3 V" v5 L$ A5 D: q

41342f0db73e7befc8b0076af4d625c1.png

8 K1 I4 q2 K. m2 C

点击右侧的 Pack,展开 Generic,可以找到 RealThread::RT-Thread,点击 Action 栏对应的 Install ,就可以在线安装 Nano Pack 了。另外,如果需要安装其他版本,则需要展开 RealThread::RT-Thread,进行选择。

- m% G* G  M/ f$ ?% s) B

708412061fe08312095ad4b350db527b.png

( n3 l) n/ T7 V

方法二:手动安装

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

+ P6 N: H' v# `5 t+ S

99a840701f0837d6ac4c2d2b7f39e590.png


6 ?" H/ e; W; U6 D( U

添加 RT-Thread Nano 到工程

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


) S5 [" Y2 s8 m

6d0962b9bed03fec9b637e345539b44d.png


' ]: Q+ Q+ D) u2 V( s7 M

在 Manage Rum-Time Environment 里 "Software Component" 栏找到 RTOS,Variant 栏选择 RT-Thread,然后勾选 kernel,点击 "OK" 就添加 RT-Thread 内核到工程了。

& v3 ^8 G9 |0 u* `! s* S

40c4e7a7d03954dea4dfde0a0d951bd6.png


; b9 t: ]' c/ E9 g: _8 C

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

- d4 j7 X* ?0 m  A

742204638963aeaf0aab8ee4257510a7.png

; U/ C2 d7 w9 b- M: Q# ?

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


0 ]4 W" L5 d2 w

20201224100720186.png

2 c! f9 n# X2 @: U8 u, t% D9 A

适配 RT-Thread Nano中断与异常处理

RT-Thread 会接管异常处理函数 HardFault_Handler() 和悬挂处理函数 PendSV_Handler(),这两个函数已由 RT-Thread 实现,所以需要删除工程里中断服务例程文件中的这两个函数,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。


! [# r( Q8 V3 p2 r- G

系统时钟配置

需要在 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 */
    ' R5 R/ Z5 i! M' e/ Y4 w
  2.        void
    - L0 r6 C$ @  G5 Y
  3.        rt_hw_board_init()
    1 L4 h$ f/ e& d
  4.        {4 r/ I/ l# r3 Q7 k8 c
  5.        HAL_Init();, W  h* N6 O5 j& x  P" s
  6.        SystemClock_Config();% o( ]1 X3 e) Y' E1 c8 n1 J: P" J
  7.        /* System Clock Update */  T1 ~: w9 o, u# _; v  Y2 z& i
  8.        SystemCoreClockUpdate();
    6 @/ B% c# _- f; }5 i3 f6 h
  9.        /* System Tick Configuration */" e5 ^/ {9 n' s/ M$ [* p' a
  10.        _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
    % Q' }- P% W6 q9 }' v
  11.        /* Call components board initial (use INIT_BOARD_EXPORT()) */! b: A% |1 U5 m: o2 E* S6 D
  12.        #ifdef      RT_USING_COMPONENTS_INIT
      T  a: r  j2 u5 X$ Z' @1 U; M
  13.        rt_components_board_init()5 U5 B( O% Y. [. \; `; x6 _( Y, t
  14.        #endif; ]/ {3 _* U% M( H7 S
  15.        #if defined(RT_USING_USER_MAIN) : X3 i; B. _- A3 C
  16.        &
    / I" e4 o; k, ?* R
  17.        &
    9 J- m6 W" z. @/ K* o
  18.        defined(RT_USING_HEAP)       rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get())
    4 o0 Q/ v% m1 j; y. X+ C( @% ]
  19.        #endif
    3 D! \5 x) N2 m' M
  20.        }
复制代码


, Q9 S$ y$ d6 A$ \& q& t/ t8 r1 h

01828e115c452708d24b825adec73a79.png


4 V5 i' t8 p0 ^6 p3 U. @( d* w' ^

由于 SysTick_Handler() 中断服务例程由用户在 board.c 中重新实现,做了系统 OS Tick,所以还需要删除工程里中原本已经实现的 SysTick_Handler() ,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。

' c% W' B, h/ {$ k1 x

内存堆初始化

系统内存堆的初始化在 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() 将被调用,如下所示:


, p# o, e. J7 w' Q/ e: l; ]0 m

ba3278f41f36daf68a3e24a3ba33b4f2.png


2 o8 T& U+ l4 ?$ H7 p8 Y; W6 S2 ~

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


( V/ H8 K* Y2 F7 H

d505d2049539b632a2951a5001656866.png


% X1 G% e- P! w

注意:开启 heap 动态内存功能后,heap 默认值较小,在使用的时候需要改大,否则可能会有申请内存失败或者创建线程失败的情况,修改方法有以下两种:

  • 可以直接修改数组中定义的 RT_HEAP_SIZE 的大小,至少大于各个动态申请内存大小之和,但要小于芯片 RAM 总大小。
  • 也可以参考进行修改,使用 RAM ZI 段结尾处作为 HEAP 的起始地址,使用 RAM 的结尾地址作为 HEAP 的结尾地址,这是 heap 能设置的最大值的方法。
    0 k" ^' f, f: d: H
    0 ^: P* x. K* \0 {
编写第一个应用

移植好 RT-Thread Nano 之后,则可以开始编写第一个应用代码验证移植结果。此时 main() 函数就转变成 RT-Thread 操作系统的一个线程,现在可以在 main() 函数中实现第一个应用:板载 LED 指示灯闪烁,这里直接基于裸机 LED 指示灯进行修改。

  • 首先在文件首部增加 RT-Thread 的相关头文件 <rtthread.h> 。
  • 在 main() 函数中(也就是在 main 线程中)实现 LED 闪烁代码:初始化 LED 引脚、在循环中点亮 / 熄灭 LED。
  • 将延时函数替换为 RT-Thread 提供的延时函数 rt_thread_mdelay()。该函数会引起系统调度,切换到其他线程运行,体现了线程实时性的特点。) D% |6 G2 o5 t. t' M7 d

% y& {5 R8 }7 O  s! P

ad4be7cd4c79e9844056b46d53c5b8c6.png


- T" D9 R( T9 Q

编译程序之后下载到芯片就可以看到基于 RT-Thread 的程序运行起来了,LED 正常闪烁。

注意事项:当添加 RT-Thread 之后,裸机中的 main() 函数会自动变成 RT-Thread 系统中 main 线程 的入口函数。由于线程不能一直独占 CPU,所以此时在 main() 中使用 while(1) 时,需要有让出 CPU 的动作,比如使用 rt_thread_mdelay() 系列的函数让出 CPU。

2 z) ?: \' C1 t/ e

与裸机 LED 闪烁应用代码的不同:

1). 延时函数不同: RT-Thread 提供的 rt_thread_mdelay() 函数可以引起操作系统进行调度,当调用该函数进行延时时,本线程将不占用 CPU,调度器切换到系统的其他线程开始运行。而裸机的 delay 函数是一直占用 CPU 运行的。

2). 初始化系统时钟的位置不同:移植好 RT-Thread Nano 之后,不需要再在 main() 中做相应的系统配置(如 hal 初始化、时钟初始化等),这是因为 RT-Thread 在系统启动时,已经做好了系统时钟初始化等的配置,这在上一小节 “系统时钟配置” 中有讲解。


8 B  H# f2 Z9 P: H+ K2 M! P

配置 RT-Thread Nano

用户可以根据自己的需要通过修改 rtconfig.h 文件里面的宏定义配置相应功能。

RT-Thread Nano 默认未开启宏 RT_USING_HEAP,故只支持静态方式创建任务及信号量。若要通过动态方式创建对象则需要在 rtconfig.h 文件里开启 RT_USING_HEAP 宏定义。

MDK 的配置向导 configuration Wizard 可以很方便的对工程进行配置,Value 一栏可以选中对应功能及修改相关值,等同于直接修改配置文件 rtconfig.h。


& g/ E+ l3 x+ I+ \实现动态内存堆

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
    ) g+ @# {# @5 n
  2.        static
    $ O  j% @- e, D; Z0 `
  3.        uint32_t rt_heap[RT_HEAP_SIZE];8 w/ g9 I2 |- T) K- a! T  ?" ~
  4.        RT_WEAK void *rt_heap_begin_get(void)6 }& m+ ]+ d& @, Z3 o  E3 ~
  5.        {
    ) D: k7 \4 O' S$ a0 T
  6.        return rt_heap;
    8 `, W1 N* _- f# z/ R! T% f7 f! m
  7.        }
    ' r: \$ A: D  |
  8.        RT_WEAK void *rt_heap_end_get(void)
      B* w$ m( |# n# _2 H6 P
  9.        {4 n2 }+ b" i) o6 L5 ]7 V( `
  10.        return rt_heap + RT_HEAP_SIZE;
    ) b5 K! N6 Z1 T" l
  11.        }( F( }* U+ [, |
  12.        void rt_hw_board_init(void)
    & e) h& K7 k$ w+ w# g
  13.        {8 Y9 W( Z0 V3 J) P" ]
  14.            ....
    ( ?6 X6 v( g* H
  15.        #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)# ]9 c1 N) T3 k
  16.            rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());   
    . h& \8 D1 I3 P6 w2 H
  17.        //传入 heap 的起始地址与结束地址
    " Z; p8 o; I+ K2 ~( ~# @3 k
  18.        #endif0 m4 [0 h) O) y8 r" E. o+ ]/ ~' A/ m4 `' ~
  19.            ...., M: Y8 M/ _3 [: ?* o
  20.        }
复制代码
+ T1 j1 u* T( T

) ]' N. b9 I' D  E" B# ^

如果不想使用数组作为动态内存堆,则可以重新指定系统 HEAP 的大小,例如使用 RAM ZI 段结尾处作为 HEAP 的起始地址(这里需检查与链接脚本是否对应),使用 RAM 的结尾地址作为 HEAP 的结尾地址,这样可以将空余RAM 全部作为动态内存 heap 使用。如下示例重新定义了 HEAP 的起始地址与结尾地址,并作为初始化参数进行系统 HEAP 初始化。

  1. #define STM32_SRAM1_START              (0x20000000)# d/ e9 \! O* r0 z/ }
  2.        #define STM32_SRAM1_END                (STM32_SRAM1_START + 20 * 1024)   // 结束地址 = 0x20000000(基址) + 20K(RAM大小)
    ' s5 w7 W7 w% o+ v2 G" f
  3.        #if defined(__CC_ARM) || defined(__CLANG_ARM)/ ?7 V/ G6 p5 p% B
  4.        extern # [- B0 W& `; m# c9 I
  5.        int Image$RW_IRAM1$ZI$Limit;                  
    ' a* @. M3 |: T2 r4 X  ~
  6.        // RW_IRAM1,需与链接脚本中运行时域名相对应: a+ G* Y* `4 F) g2 j
  7.        #define HEAP_BEGIN      ((void *)&Image$RW_IRAM1$ZI$Limit)6 i: z* H7 D0 V7 Z5 B0 R
  8.        #endif8 B$ R- W* o3 e2 Y$ I: J
  9.        #define HEAP_END                       STM32_SRAM1_END
复制代码
  1. void rt_hw_board_init(void); T. w3 O" g8 b+ [0 u
  2.        {
    . ~- _: G+ v; f+ n5 Y& K( a
  3.            ....9 b6 s0 t. N, h: B/ O9 g6 D
  4.        #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    0 A$ h4 [- E* c1 Z
  5. rt_system_heap_init((
    " [2 C0 V3 R7 H/ @: P
  6.        void *)HEAP_BEGIN, (, Z; l) \2 A' O# s4 {* \
  7.        void *)HEAP_END);5 a& w9 s5 N/ V
  8.        #endif$ m0 v3 Z' g2 m2 ~6 I7 j. }
  9.            ....
    5 V/ ]* `0 y- `# W5 x3 q
  10.        }
复制代码
- c, f8 O  s# L* [( j( u: z$ |& S

) ?; T; W3 R1 G1 M

链接脚本

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

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

  1.        LR_IROM1 ) N& _- _: G4 ]
  2.        0x08000000
    1 ?( l/ D5 \  s$ R3 D8 _- l0 }
  3.        0x00020000  {   
    : w$ q( J" @9 J$ t
  4.        ; , P, P/ \: v- O' y/ Q
  5.        load * I" N& |$ x, w. w1 C5 x1 ^0 O
  6.        region - F/ n" U0 `# @5 W- w0 B- H
  7.        size_region
    + \! v  {2 h( V7 Q% q
  8.        ER_IROM1 ; w7 S) ^% S+ D" Z) o! {& U
  9.        0x08000000 ! J9 z" q! `# p1 y" m' O2 _2 b
  10.        0x00020000  {  " E  ?' ~" B; Y5 V5 j
  11.        ;
    9 o: J5 C3 c( _3 [
  12.        load 6 F" C6 l: R- `
  13.        address
    & z; |% t7 D; M+ D% p
  14.        = - e' \: G& K% d- i2 ?  C% U
  15.        execution
    & c# L6 K0 K& ?. J$ k3 u+ U& @
  16.        address: _) b; O3 g0 K8 B4 W& B  Y' I
  17.        *.o ) C# L9 C/ E% \2 _  I3 z& ^9 K
  18.        (RESET,
    + p; u( n  c9 V: D8 A" i2 I. C
  19.        +First)
    2 U$ Z& H7 W1 `; L6 y" u% h) ^
  20.        *(InRoot$Sections)" A/ w% `" G  z( \- _8 @
  21.        .ANY
    : _$ k: p/ }% `4 T% ~, w2 M3 W  K
  22.        (+RO)
    . f% X* B6 h+ W1 ]% z& K
  23.          }% l) X8 K& M2 n
  24.        RW_IRAM1
    : N& ^& ^" @  X( \' y
  25.        0x20000000
    / A1 ~' B, {5 A$ B( q8 r1 H
  26.        0x00005000  {  : U& J* F& ?, O3 E- z* k' s4 U
  27.        ;
    $ w3 a2 y$ y1 y9 p; R0 C
  28.        RW . ~, M8 f( [. H: N
  29.        data
    1 T" B1 e5 u% g# J! Z: h
  30.        .ANY ( y0 l1 y2 k$ O1 ]* \4 k
  31.        (+RW 1 c+ N8 @, a  P. s
  32.        +ZI)
    , `8 W8 J. x( b! B7 a6 z
  33.          }
    * x" e7 y9 L! y2 g9 b. _
  34.        }
复制代码

+ Y6 W- P# u" d6 n* \

其中 RW_IRAM1 0x20000000 0x00005000 表示定义一个运行时域 RW_IRAM1(默认域名),域基址为 0x20000000,域大小为 0x00005000(即 20K ),对应实际 RAM 大小。.ANY (+RW +ZI) 表示加载所有匹配目标文件的可读写数据 RW-Data、清零数据 ZI-Data。所以运行时所占内存的结尾处就是 ZI 段结尾处,可以将 ZI 结尾处之后的内存空间作为系统动态内存堆使用。


7 a4 g- K: n; x

20210320113521357.png

* }+ i. q1 ?) t

02c0c30e07d086dec972a520ff3a733d.png

" D3 e# S* x3 W! ~" f7 L8 x( H

获取示例代码

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

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

4 J& F. T" L1 m1 t

a2f3187d72324887f4e7e80633e7299a.png

3 ]- g3 Q# V) i( [6 X

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


0 P1 x9 h* V0 m/ Z) {% f

20201224101212395.png


9 T5 D  W" c/ ~$ `5 W& k

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

/ G3 j; u* O9 r3 Z: Y( o

: A' k2 K/ N2 T3 z7 e- C 2020122410322937.png ; r( ]1 h! T* e0 y8 y

% J( q9 }/ h2 v6 q- E 20201224103321378.png 5 Z7 i6 K5 G  o3 b' q" Q8 f
8 p9 e0 o6 b* [- E3 U" ~
20201224103347482.png ) _* i! t5 q% P  h; Q9 b  N

; e* p# K0 V4 G! w( @! e

1、拷贝 rtconfig.h 文件到 user 文件夹+ d) ]! H# W" M  N+ Y
将 RT-Thread/3.0.3/bsp 文件夹下面的 rtconfig.h 文件拷贝到工程根目录下面的 user文件夹, 可以通过修改这个 RT-Thread 内核的配置头文件来裁剪 RT-Thread 的功能

2、拷贝 board.c 文件到 user 文件夹下(新建RTE )
4 s) A+ S% n* ]/ ?; c8 a% Z0 p将 RT-Thread/3.0.3/bsp 文件夹下面的 board.c 文件拷贝到工程根目录下面的 user 文件夹, 等下我们需要对这个 board.c 进行修改。

% p" y, `" O) [1 M3 y: ]0 _! y# Y8 e

20201224103553656.png " g7 G; b& c+ Z# J; R) D* E5 ?
" N' S8 W3 w8 i% G6 @0 w! n5 I, g
20201224103930352.png
5 c( a1 F' R: z& p; e1 ]& I2 _* Y* ?2 E# R; C" K6 `

3、添加 RT-Thread 源码到工程组文件夹
, F- u: X4 Q) V. ?8 y0 [- n2 N新建 rtt/source 和 rtt/cpu 两个组文件夹,其中 rtt/source 用于存放 src 文件夹的内容, rtt/cpu用于存放 libcpu/arm/cortex-m? 文件夹的内容,“?”表示0  3、 4 或者 7。内核文件   我们移植的为stm32f103  内核选择  Cortex-M3

7 g# \. k/ ]4 g* W

20201224105043688.png

4 L! ^0 o) o; [' O% _( t" x

指定 RT-Thread 头文件的路径
8 s: w( V' u& l0 {; K8 RRT-Thread 的 源 码 里 面 只 有

RT-Thread\3.1.3\include\libcpu
7 {7 t# N/ y0 N- E5 ^RTThread\3.1.3\include/ p! @- F" z  f6 \: _6 n" U; D
RTThread\3.1.3\src6 e' g2 {% s4 a# Z9 `
RTThread\3.1.3\components\finsh

和 user 文件夹下(RTE) rtconfig.h 有头文件,只需要将这头文件的路径在开发环境里面指定即可。

: w2 M/ D  U  K4 F. w  y

20201224110224895.png
8 n+ @4 b& |7 Y; F5 ~

$ W8 P9 [3 |: h

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

因为还没有配置 RT-Thread Nano

参考上面讲述的配置 步骤

: i1 {; u2 V* {, E, D8 o! I7 C7 K; S8 A
20201224110649146.png - M8 M# N( [4 C8 p7 O

! d4 N9 A+ ?1 ~: w9 a 20201224111035816.png
9 u  T" N$ j- D, Z2 U3 K: B


7 e+ J6 ?6 Z! }! R% C

rtconfig.H  i; o* Y' h7 J3 N
  1. /* RT-Thread config file */0 ^7 A2 b2 i$ J8 Z! M
  2.        #ifndef __RTTHREAD_CFG_H__
    7 `1 o1 F+ k! \8 w- ^
  3.        #define __RTTHREAD_CFG_H__' n2 C% [8 Z+ G- b" m
  4.        #include "RTE_Components.h"
    * }0 z9 j) l3 z1 @  N8 F5 Q
  5.        // <<< Use Configuration Wizard in Context Menu >>>3 I; a) s, C2 W
  6.        // <h>Basic Configuration8 T; v8 R$ F6 {4 N& L
  7.        // <o>Maximal level of thread priority <8-256>
    % k; q3 ~( g2 K
  8.        //        <i>Default: 32: r3 i$ s% c7 u7 m5 O, Q7 C- `
  9. #define RT_THREAD_PRIORITY_MAX  327 o) j6 C4 J9 n$ Y2 P0 }6 L8 w
  10.        // <o>OS tick per second4 c2 O  S4 p0 X) m9 m2 o) c" R, F
  11. //  <i>Default: 1000   (1ms)
    " r4 {/ e- ^. n; }# d7 `# v
  12. #define RT_TICK_PER_SECOND        1000& h( ]2 C4 z7 E( `
  13. // <o>Alignment size for CPU architecture data access, o* s( ^: T- a& m
  14. //        <i>Default: 4
    7 ~( W/ ]# R4 w9 M9 x
  15.        #define RT_ALIGN_SIZE   4
    ' R% W5 L  C" Y# a$ ^( O8 G
  16.        // <o>the max length of object name<2-16>: a1 F5 _6 b! ^  K1 S
  17.        //        <i>Default: 8
    . u$ c  }7 \$ Q- J  D0 U$ e
  18.        #define RT_NAME_MAX           8' W( ?! I. A" V* ^' }
  19.        // <c1>Using RT-Thread components initialization
    ! h! Y8 y" {$ `& A
  20.        //  <i>Using RT-Thread components initialization7 N: V. Y/ N6 o. S1 a# F9 s0 O/ |
  21.        #define RT_USING_COMPONENTS_INIT1 o- H4 n( a, ^& j; Z3 z
  22.        // </c>) }1 p9 z) o, `  b0 s- Z5 A
  23.        // <c1>Using user main$ k2 ?1 H1 h. z
  24.        //  <i>Using user main& S0 k# A4 i# p" d7 a0 y
  25. #define RT_USING_USER_MAIN
    $ @% f( X  x! \, Y/ M% ?; k
  26.        // </c>
    5 g0 L3 h: L' D" s9 ?2 W
  27.        // <o>the size of main thread<1-4086>
    / G" ]7 }' V; ~% k5 v5 @& D
  28.        //        <i>Default: 512: o: w; w. l2 q( z
  29.        #define RT_MAIN_THREAD_STACK_SIZE     256
    4 Q9 z: `9 n4 X9 s" d! g
  30.        // </h>
    / {( H& [+ F- P( v  Q
  31.        // <h>Debug Configuration- E% m  S0 [) s/ p. q, Z
  32.        // <c1>enable kernel debug configuration  Q% K" h/ A/ N6 a% {
  33.        //  <i>Default: enable kernel debug configuration6 ]! A8 _& e* B8 B4 f
  34.        //#define RT_DEBUG. t5 O+ M* x' T1 U
  35.        // </c>$ ~6 s' c0 N3 Q/ O
  36.        // <o>enable components initialization debug configuration<0-1>$ P; b- R7 N  l* e" F7 A: \" |
  37.        //  <i>Default: 0
    1 V8 w' H/ ~# E: `
  38. #define RT_DEBUG_INIT 0
    * B3 G: h5 m1 w6 O( N1 Q1 ?
  39.        // <c1>thread stack over flow detect
    # j5 |  t/ M/ l4 ?( {& J5 V
  40.        //  <i> Diable Thread stack over flow detect. ~9 v8 j3 `4 B; X+ V* ~
  41.        //#define RT_USING_OVERFLOW_CHECK. J: u7 N8 l% D! [3 p4 `/ d
  42.        // </c>* N6 p# J4 A5 }8 {' x' S, V7 g
  43.        // </h>
    . u2 R2 k' Y# w4 e( ~$ \, E$ X
  44.        // <h>Hook Configuration7 K* `% u. l6 w' x; ?- f6 m
  45.        // <c1>using hook
    1 ~: r. P0 t2 M* S9 ^% U4 Y
  46.        //  <i>using hook
    6 K, ]5 Z; S5 o) n+ N
  47.        //#define RT_USING_HOOK
    3 \) Q; @5 p8 Y- T/ Z0 a
  48.        // </c>
    . e8 i6 b- l& I4 n- ?' {. k
  49.        // <c1>using idle hook
    9 E, a: ^8 U0 X
  50.        //  <i>using idle hook
    ; n* b( c( H- e9 R4 _1 c- A$ t
  51.        //#define RT_USING_IDLE_HOOK3 u' {' t5 j# u
  52. //</c>
复制代码
" C6 K7 B* Q8 w$ E
board.c
  1. /*0 T- r& k$ }8 |( `3 e+ s1 h+ e
  2.         * File      : application.c
    # g' x" S8 u5 H6 ~; w
  3.         * This file is part of RT-Thread RTOS0 |: @. `8 l' W) P/ B
  4.         * COPYRIGHT (C) 2006, RT-Thread Development Team
    + p4 ~) Z0 K4 y6 a8 s# N9 O& o
  5.         *, C/ ~- G; u9 g, g5 ]9 ?. j: C
  6.         * The license and distribution terms for this file may be
    ; c) O& D7 B$ b' L5 w
  7.         * found in the file LICENSE in this distribution or at
    , K1 n$ a4 m& W! N
  8.         * http://www.rt-thread.org/license/LICENSE
    * B7 |2 w3 u" A4 N9 D  k
  9.         *  d$ G4 `! e1 [4 I  a2 G
  10.         * Change Logs:- O; c! `9 G3 N6 @# C
  11.         * Date           Author       Notes
    3 m- }4 W- U6 e5 [  A& c: l) j. g1 c
  12.         * 2017-07-24     Tanek        the first version
    1 A2 B- M  v- w. L2 J
  13.         */
    - y7 u4 _6 r$ C) g& R. p, }" Q
  14.        #include <rthw.h>
    1 o, F6 i: X6 A$ o: G& J  ]: Q
  15.        #include <rtthread.h>( U5 I& }* O  P
  16.        #include "usart.h"
    0 L  y* r+ L: F1 E' A# j" I2 Y9 |
  17.        #include "delay.h"
    ) t. d, e1 B; \
  18.        #include "led.h"
    7 U7 p& Z- F0 e* ~0 Z* \( C
  19.        // rtthread tick configuration( E' X& h) ~, W
  20.        // 1. include header files) d) u$ t1 |: a
  21.        // 2. configure rtos tick and interrupt
    8 v+ ]; Z* }) r$ z3 e: Y
  22.        // 3. add tick interrupt handler0 b1 j. p1 e. d0 S9 V
  23.        // rtthread tick configuration
    * D% R! S/ B4 `
  24.        // 1. include some header file as need9 c( [4 b( q$ M  G
  25.        #include <stm32f10x.h>- W' J- W" ^7 W. C9 Q7 d
  26.        #ifdef __CC_ARM1 a, H' _& Z( H0 g
  27.        extern
    2 d" F4 ]0 g+ J* L$ c7 ]" d" }
  28.        int Image$RW_IRAM1$ZI$Limit;
    ( l6 {1 Q+ T) L3 d7 J
  29.        #define HEAP_BEGIN    (&Image$RW_IRAM1$ZI$Limit)0 t# p; _% f9 A3 w$ o
  30.        #elif __ICCARM__. O# w6 \! H, ?9 u& {) _
  31.        #pragma section="HEAP"# S- Q) p; g/ z' R$ f5 Q
  32.        #define HEAP_BEGIN    (__segment_end("HEAP"))
    9 x+ j) [! ^; @" I0 P
  33.        #else
    ( L0 t7 _( |9 @& N: G5 P
  34.        extern 3 q( N* f. v9 D/ {* V% ?# _1 z# K& B
  35.        int __bss_end;
    2 t  S, A/ b& x2 S; ?
  36.        #define HEAP_BEGIN    (&__bss_end)
    ; D$ q! [9 T  u: J1 P, y( n
  37.        #endif9 X1 x: g, j# U; D( I$ o
  38.        #define SRAM_SIZE         8
    1 ~& U8 s- o5 a/ g! F
  39.        #define SRAM_END          (0x20000000 + SRAM_SIZE * 1024)9 N5 z" o5 w  ?  p) \' l1 R& A
  40.        extern uint8_t OSRunning;
    3 X1 P2 r( r- {+ G( V8 I
  41.        /**
    4 }& ~/ y. D1 o; K3 [: u
  42.         * This function will initial STM32 board.
    5 M/ Z+ Q( d" Y( j
  43.         */0 f8 A& T5 b* |. J* j" e3 y4 x/ h
  44.        void rt_hw_board_init()
    2 X- I) W3 n7 `  j2 w3 s
  45.        {
    ! A9 j: k0 N6 H: K
  46.        // rtthread tick configuration, u) l& c# Y# r( Y! Q7 H* k
  47.        // 2. Configure rtos tick and interrupt" O5 ^! [1 S- X  t
  48.                SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
    % p6 H( H" j- J- R5 c
  49.        //串口初始化
    ! r. T% z% x3 Y7 ^
  50.                uart_init(: N2 ]3 k' @4 [+ m" z
  51.        115200);
    7 E. K& w. m2 U3 t
  52.                delay_init(7 T1 Q, A/ s+ E7 J
  53.        72);
    / e& J; w3 w8 P4 U9 L- |
  54.        //初始化LED" D( ^& E, J4 a/ ]$ d7 c% w6 h/ Z
  55.                LED_Init();! Y5 w6 \1 P) k# l) U
  56.        //tips:把硬件初始化放上面) ~) S5 w+ }( B6 L& O
  57.                OSRunning=
    7 M( o. W9 _$ @6 r
  58.        1;
    % w, v5 ]% b$ M; ?- h0 B
  59.        /* Call components board initial (use INIT_BOARD_EXPORT()) */
    ' u- z% V3 a+ S! h% X8 O2 f
  60.        #ifdef RT_USING_COMPONENTS_INIT
    0 l) M( [( P8 z* b% d$ z
  61.            rt_components_board_init();2 c' W5 [' a7 Q# c) P! Y$ v
  62.        #endif
    . Z4 I5 {! I9 V# M
  63.        #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)# |# w& J, ^$ s, N' K4 k- v
  64.                rt_console_set_device(RT_CONSOLE_DEVICE_NAME);& t" B  ~, G1 Q0 n; O% z
  65.        #endif" U2 S# J3 K+ X+ F+ t
  66.        #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP), z, G% l" I( |% N& C" Z7 y. p  r
  67.            rt_system_heap_init((
    : o( [8 Q( |1 z4 @; O
  68.        void*)HEAP_BEGIN, (
    ! v1 N, @( _% T7 D' [4 P# v
  69.        void*)SRAM_END);
    $ A0 X, L: U, \0 [$ ?
  70.        #endif
      l/ a: d/ W& I$ P7 z* `9 |$ S- E
  71.        }8 G- X) j2 P" A& l
  72.        // rtthread tick configuration  V7 `, j7 j  H. t4 B. B
  73.        // 3. add tick interrupt handler
    " a/ I8 x9 t: Y
  74.        void SysTick_Handler(
    % b( m8 U5 R# T/ f. i$ {
  75.        void)6 r" n; _7 s( o/ j- b
  76.         {
    " ^$ g  B5 e  |* T" A; x; `: a3 Z% P
  77.        /* enter interrupt */' i' B" m* x( ?# V
  78.                 rt_interrupt_enter();3 `! p1 I8 M( G# O* b, L0 F- h  ?
  79.                 rt_tick_increase();
    ' n  S& ?7 \5 `
  80.        /* leave interrupt */! M0 j; \5 Z( A
  81.                 rt_interrupt_leave();
    : y% H0 O# r* ^5 f- G2 h5 Y, Z
  82.         }
复制代码

# c1 x4 Y, K* p: }' t) R1 l7 {! y修改完rtconfig.h 和board.c  编译通过


, U1 z" k2 ?+ c* B2 W

20201224133909599.png - b3 v: A6 S! v1 b3 Z( u. _. o
0 Q! N3 e- Y. [: H+ y9 a: g! u
20201224154224945.png
( d8 M: n2 T; r" P- F$ O
# E, a: ?9 y) R" M
( p* Y  M* @) U/ G" g$ x9 ?) o/ E* M转载:熬鱼不放汤" y, w( B5 {: U" e: B* _

! I$ C; f; H; g  B" C8 I0 k) c9 g如有侵权请联系删除
: m9 @0 b# u, R/ i7 f
& |, K9 {. r2 n2 J9 Y( D$ K7 w4 J* b4 x  ]1 ~" d
赞 收藏 评论0 发布时间:2023-3-10 12:11

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版