硬件介绍% G9 j; P. v7 L' P' B
我手上开发板使用STM32F030F4P单片机,无外部晶振,所以直接使用内部晶振。开发板上有3个LED灯。
+ h* r( C7 S9 H3 B2 ]: @: a! j# v4 D* }2 c. u5 |# l4 \
: r3 J7 B( b) X6 K
! o T0 X% V/ D1 D; r) J: B4 h安装rtthread_namo包& c1 K6 w7 p6 @* @' \- k0 ^; N6 A/ A
在操作前,需要安装MDK5软件,以及STM32CubeMX,并安装好STM32F0的Pack
5 K4 J! I5 I! c8 V$ B; ~: x, D/ w$ \* T3 q7 c/ s+ G
1.打开MDK软件的Pack Install工具,选择RealThread:RT_Thread进行安装
: I3 H! _4 F5 {
; c- O5 ] d, G V- P. P8 K9 U, N1 X$ D7 N/ N @
* u9 r! y6 U& A9 e" ~' x3 b: a; P p2 S( p4 Q, t% K
# u1 \4 k5 f: f7 G1 @6 b2.在弹出的节目中选择Next,等待安装: k! }& X2 L, W% U5 r) D! ^% U
9 l' n( b/ Z/ \' v
6 n0 j* `/ Q9 [ z) ?- D) ^! ~+ c+ S3 U9 S# ~8 l
3.安装成功后,Reload Packs即可。
( p. h) h4 n7 G% w- f; s6 `4 p! V' c* L
, H+ ]2 V9 \0 z; W- R2 J8 Y
0 \! P" }, P& x" x/ [5 b9 e
创建工程
# m1 N" z! ~) w9 N1 A8 H1.选择芯片STM32F030F4P6
) j8 q" Y( J+ X2 \# E9 h
; t4 y( }4 V1 e
7 K. i8 a7 S/ i J9 Y
) D7 @+ n: F) I4 y' r6 I* Z2.Manage Run-Time Environment6 j+ ?0 ]/ v2 d, g4 y/ y. L% r
( g9 s8 ~( W# z8 a
' d; l9 R" I' Q. |$ I: X$ \2 {+ S/ s$ l9 ~
按照图中进行勾选,由于我们芯片资源有限,而且这次的电路并没有接触串口,所以在RTOS部分,我们没有勾选shell。5 {7 {- ~& s7 f3 Q* q$ x( ?( A
3 W. H$ \$ U; n8 P6 Z, I6 f
3.Start STM32CubeMX9 t1 s6 c3 v) b9 Y- o
& Q ~4 S' N$ b
( ? x! [: R$ \$ P( F: e; h, X, f
/ a, ^+ q( S$ p( @5 s8 G$ F; `3 m 勾选完Run-Time Environment后,会自动弹出启动STM32CubeMX的窗口,我们打开STM32CubeMX进行配置。- j3 N- O+ x" m( K3 h1 M
" s% k7 ~; a1 l9 @5 q, w3 W) w$ g6 b* G
4.STM32CubeMX配置Pinout&Configuration
/ n' j5 j% u; z& `# M: \
! W2 ~7 ]! J6 F2 m
8 T, g- m; y+ j3 o$ ]" z# r0 p& F, I$ A) w# Z; I: ?
* E2 L6 m; `3 I8 a6 ?0 {
' F, e# O, y: J7 M# q: M8 _
5.配置时钟
2 j( |8 |4 a4 M+ L% w9 k1 z% V2 g# `8 E5 y5 V+ m' ]
t( f( B7 T& }# B
* x8 A4 R9 K2 A# I
6.单击生成代码
3 h; a& a/ K3 y4 h& ~- J5 F
]# y8 \4 |) G# J* w) g
6 B9 n+ E5 O3 ~) E% H: D0 r* l
' {% g i2 D# M4 ?5 N7.生成代码如下0 y* v! K+ s9 l+ d* P9 z
$ n4 Z. B& G& J
0 @( F, l8 e4 Q: l8 G2 G1 @- s! l8 ]! _4 t: b5 J4 e, I
配置工程6 _! |9 @2 Y/ K z" c- C+ K% @
1.选中RTOS下的rtconfig.h文件,使用Configuration Wizard进行配置
, Y5 p( l; A) q5 m2 s
* F6 l$ e7 r2 d0 t, k) Y6 c' z2 i' {5 h" _1 ]
; V! y" X7 z. T4 s; y. M. ~; h" g
2.内存管理设置
3 f0 p2 g2 k9 o7 g$ U: R! b, E1 B" K
+ C+ L" o& |) a2 ?/ J0 N4 x4 O& Y- e9 ^/ }
由于芯片内存很少,我们取消Dynamic Heap Management。勾选上using small memory。
) u" R% J4 X. J8 S/ |9 O4 K6 b: w- f5 ]1 k# r6 V- J! D; M
3.关闭console和Finsh8 I5 B! K3 X/ T
8 N4 u, P: k4 J( _4 D* G7 K( K$ C3 c8 Q5 ?1 j. R6 ]# C: J t R- p# D
- l# t: l8 B% O; h! B9 [
由于我们并没有接出串口,所以关闭串口相关的内容。
8 i% p+ H4 d$ H |
, ^0 j8 R1 e+ \修改代码,测试
* S! B; a1 t: S修改stm32f0xx_it.c文件
- j9 |* J) T' P9 c! y8 @$ w: V 由于rtthread重写了部分中断服务函数,所以我们需要将stm32f0xx_it.c中部分函数设置为weak。
1 R* V. v0 T) h4 v- /**
( O. G$ X( i* \* V: ^, ?3 z - * @brief This function handles Hard fault interrupt.+ u: s$ E; p+ b7 W+ H# b& \
- */+ C. w5 T3 c9 n8 `. R' B t5 m& T
- __weak void HardFault_Handler(void)& R' ~$ t. ]- w5 T
- {6 @/ [* ~6 O% t
- /* USER CODE BEGIN HardFault_IRQn 0 */
7 ~, Q$ o# e" T& o - 3 |1 n9 v% y- g. V% q
- /* USER CODE END HardFault_IRQn 0 */
' M: K6 x( }5 o8 w - while (1)% m3 m- q% j' Q3 u. E
- {1 L$ @6 k0 E# ]: O6 [
- /* USER CODE BEGIN W1_HardFault_IRQn 0 */
0 E% B; F: Y0 C5 j - /* USER CODE END W1_HardFault_IRQn 0 */
f5 b' ]* J. _" W5 G: Y - }( ?/ n8 W5 l+ B& B {/ B' h
- }
) N7 ^/ k+ g0 n) x. O! a+ f4 O
+ o; m; H2 X9 }5 V: C* y- E- __weak void PendSV_Handler(void)
+ z2 q& Q( H$ R4 G. G - {; r/ q+ `% ~4 A. q
- /* USER CODE BEGIN PendSV_IRQn 0 */
6 G2 E9 f5 q+ \( G/ n
, D4 M! @8 z& s2 C9 i% Q; D) o- /* USER CODE END PendSV_IRQn 0 */
- m0 q* }. F5 d' y/ c8 L0 n - /* USER CODE BEGIN PendSV_IRQn 1 */
8 r& L4 I C% M9 `% n2 a - ' q( ^! V' p8 p( {
- /* USER CODE END PendSV_IRQn 1 */, g/ U: c' u% n) Z. O+ C
- }
* R( w3 D/ c- }3 {4 o
- ~/ \; @4 b h& n& c- __weak void SysTick_Handler(void)
& q9 J8 i0 \; k5 K - {- X; H; M3 i- X) K, K
- /* USER CODE BEGIN SysTick_IRQn 0 */1 b' Z, g/ J' ?8 ?, ^) f( G. p* B4 H
- 5 _2 c# o5 e2 x l+ k! k5 I m
- /* USER CODE END SysTick_IRQn 0 */
6 m1 ?9 U1 o" M, i3 V3 q/ h( z - HAL_IncTick();7 Z8 ~* v! j( E0 B. w
- /* USER CODE BEGIN SysTick_IRQn 1 */
: W1 v" ^# F3 ^9 Q
/ R7 j4 G. O# I. M/ z: C; ?- /* USER CODE END SysTick_IRQn 1 */6 \+ ~7 y7 f) B( A( {
- }
复制代码
' m& u% @# P+ ?& A修改时钟部分& z# b/ r1 \4 T$ R i1 p
在mian函数中,有HAL_Init()和SystemClock_Config()函数,用来在系统开始的时候初始化HAL和System时钟。但是当我们使用rtthread后,第一个执行的函数不是main()。而是rtthread系统的初始化函数,并在board.c的rt_hw_board_init()中进行硬件初始化。
7 [! [5 T6 I' z% q* @3 Q 我们将HAL_Init()和SystemClock_Config()放到rt_hw_board_init()最前面,保证在用户代码运行时,时钟时我们希望的样子。7 b `5 Y/ @0 x9 Q
- void rt_hw_board_init()7 F# T( h% x G8 A( ]8 e
- { 5 m$ J/ a- o# P, j
- /* System Clock Update */. ^7 B! |9 T+ N: J# B' i9 a( ~) ~/ P
- //SystemCoreClockUpdate();; j, J/ t2 }7 t2 W0 t
- HAL_Init();; ~+ J7 j/ {+ `2 `8 l# p0 G# H" Z
- SystemClock_Config();+ U9 ], H2 m9 h; H9 k7 l+ S
-
% H- G3 z5 j0 @" I - /* System Tick Configuration */
/ g( o2 p3 T* P, C, V/ t% W3 X - _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
$ L: A1 u! `- e7 n - 8 n9 L9 \" s: c7 j, c) [
- /* Call components board initial (use INIT_BOARD_EXPORT()) */
6 K& b: c4 P Y5 q' n - #ifdef RT_USING_COMPONENTS_INIT
+ B) L$ K+ H- i9 s$ D - rt_components_board_init();
! U7 e! F }8 V# T, z( l - #endif
; b8 S( k( C# ^$ K - : q3 h* D5 N3 \* t
- #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)/ v: y4 y) ^1 {4 V/ g/ A( U2 _0 z
- rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
5 T1 Z# B1 v1 K6 H - #endif
: E. C I9 q0 Y& J; B- ~; q6 } N
. ^& N+ W' K' W/ x$ g. _- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)& n; I5 J$ v- Z, f
- rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
: @7 ?* @/ q4 B! S7 `2 c - #endif& `0 \ r# `1 W" q+ w( G2 C; {
- }
复制代码 由于我们屏蔽了stm32f0xx_it.c中的SysTick_Handler(void)函数,SysTick_Handler(void)中的HAL_IncTick()也一同被屏蔽,我们将其移动到board.c的SysTick_Handler(void)中。5 {# x. A9 B: g3 t! h
- void SysTick_Handler(void)
5 N. m% e5 o% v, T8 _ - {
' k8 I3 r1 W1 S9 B1 b7 j - /* enter interrupt */
, W3 p. m9 b2 ]2 O# c7 {9 l - rt_interrupt_enter();
- B& ^* e/ i; }) q) l
/ f! Y, |7 I7 B, F/ u- rt_tick_increase();
- K5 A! ?2 q$ ? N0 X: h - HAL_IncTick();
1 q/ |6 ^/ c9 _ - / x6 A: D4 I0 B2 C
- /* leave interrupt */% G. Q; U" h# |9 c4 T( W# v
- rt_interrupt_leave();
' w E6 j/ d1 d1 U+ a0 l - }
复制代码
3 ]) z# q* W I增加用户代码
3 {3 ?% O Y$ z2 \ - while (1)
) t+ ~" @' l/ ?- `4 S# b) W - {
+ Q+ P. `: C. r6 C - /* USER CODE END WHILE */4 n8 Q; F9 U Q& m# B
- HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_RESET);
_" v4 ?2 ]% D1 k" r- x5 ] - rt_thread_delay(500);
! |6 `/ P1 O3 v1 m' q - HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_SET);
5 v8 H! U3 `1 K( A - rt_thread_delay(500); ) ~. q+ n& S# y8 q
- /* USER CODE BEGIN 3 */$ X% ^/ _! n$ ^' K" p4 v g
- }
复制代码
4 e2 f( o: l% j, W; U- D& ]: R6 A编译测试
8 _* t( [5 y: `' X1 t+ Q7 z& D) [1.使用ARM Compiler version5 进行编译,结果如下:
& l1 }& \5 a( [+ g2 s
! _' A: s& h& I4 I! k k6 ~; R, `% N6 }- W7 F) _
9 w# c' L5 |% ], x; `2. 使用ARM Compiler version6编译,结果如下:) P* J, b4 ~# ?. P6 y+ _( E+ t' d+ U
3 ^) L( {$ E$ B4 W7 D
1 f8 C/ |0 y3 l
9 V8 s* g0 X0 `! `6 K9 } 相对于我第一次写关于ARMCLANG的博客,已经过去很久了,目前很多中间件,以及STM32的HAL库都已经能很好的支持ARMCLAGN,推荐大家使用ARMCLANG编译器进行编译。
: Z' ?* c: E# ~. H& r7 V7 s/ G
# ^. m, k1 B& I& i% d" x1 Z6 T# c1 I' O* q; ` E9 b4 @; D$ [
|