硬件介绍
: F( I2 S5 |! @: v/ ~: u2 f 我手上开发板使用STM32F030F4P单片机,无外部晶振,所以直接使用内部晶振。开发板上有3个LED灯。9 q$ @/ _3 J& p0 {" R1 h( x
' y0 C+ `* F- E# K/ [( V# ~
% n2 g; U/ p0 {' B6 W0 r4 f3 _1 n& ?) m2 i; Z( z
安装rtthread_namo包
. w9 R1 ]# h$ A/ ~$ P+ M/ {在操作前,需要安装MDK5软件,以及STM32CubeMX,并安装好STM32F0的Pack
( J7 {5 N- `' W7 k W, e% J
9 x7 U2 I- |' w& J. q1.打开MDK软件的Pack Install工具,选择RealThread:RT_Thread进行安装; N& i1 j* B3 j' X/ G7 T- D# @
9 s' U' Q( j6 s5 i6 ?
3 D+ @ K J# S
5 q x8 W0 G0 I# L
- l. }# a& {: N) m
! [1 u$ J* ]7 R% M, Y7 n
2.在弹出的节目中选择Next,等待安装
9 L6 z& F1 D: I# }0 {7 [ y3 [$ v% s: B$ n5 G
3 ~7 [# m% t% B" k! z, C7 r2 c
. D6 X& F4 k! N. o9 a7 C
3.安装成功后,Reload Packs即可。+ ]; \! B3 Z0 | O' U1 ^, a5 b* @
( k' N- t. j3 _; H9 j4 G) _# }
5 _2 b# \& L' Z2 D; g
- D1 u% ~1 c- S' Y# z$ q创建工程
6 s. U: u4 s* {4 ?1.选择芯片STM32F030F4P62 g8 N2 T6 c+ P4 ^
0 J+ J F2 l3 l
* d' B2 r: ]+ E% s
7 o; A) e5 s5 ~" x& l. Y7 z2.Manage Run-Time Environment
+ g6 ^0 \) G. f' \6 ~
& c5 v, ^& C- S8 C0 ?7 h, R- C# o1 `* H% f3 h5 p' Z
+ |. L' y' Y% j" p0 d' O4 g 按照图中进行勾选,由于我们芯片资源有限,而且这次的电路并没有接触串口,所以在RTOS部分,我们没有勾选shell。
& G2 n z8 f( k( Y& x* d* [) ]0 {* {& \
3.Start STM32CubeMX- j1 d7 D$ D4 m
$ n m/ W: K7 O" g* P8 g! c/ L4 v# v: q
. i6 C0 h3 `7 S( S3 ^6 U h3 L
勾选完Run-Time Environment后,会自动弹出启动STM32CubeMX的窗口,我们打开STM32CubeMX进行配置。
& @- [' q( I# L! Q, a
) W6 }& w L; B3 p& G% H: _0 d4.STM32CubeMX配置Pinout&Configuration
3 |: s7 i- z3 V' B
" I) ?2 @6 c/ d8 [7 ~9 P6 Q* G& b R; i: \/ k
6 M' m! `& a) y0 j0 Y( y# A0 |
, k# W; z& I" I3 I% \" h9 S1 r, Y( h' P) x* `( J) A) B8 m7 [
5.配置时钟
. j4 `; q5 a$ Y9 y! K
- ^4 W% m/ X& R' L! q
; @$ r# _( K. B( e6 ]) |* h! T5 i: s" B5 h# f
6.单击生成代码
! i# Z( e/ N/ A3 B' }: J
+ F. q1 J2 x$ e/ b) }) b: y" k7 c1 H4 |
8 _! {) V9 i; [2 B8 e |. U3 C
: E1 j) t; v/ o$ E" N7.生成代码如下! ?3 @% y8 x; X/ U+ c; n
, [! [6 q! `# D9 T2 i* ^0 y' q, W0 {. f( @2 ^# e' W
+ c" O$ g; `4 A
配置工程
9 K+ f+ t/ W t6 b: C" M8 J1.选中RTOS下的rtconfig.h文件,使用Configuration Wizard进行配置; Y2 [- `# I$ `' n, |
u4 y) e2 Z, A5 f7 }! X7 E
2 w! w4 } G% i+ o* t. K3 e' H% e4 [, X2 p. |
2.内存管理设置, f" w& N. C8 Z& u" A
% Z0 S: [; V+ @; `& y1 Y4 d* V( Q" Y4 J2 S" y- Y3 m2 I, ~8 D" Z
! h- z+ L+ @6 N# I 由于芯片内存很少,我们取消Dynamic Heap Management。勾选上using small memory。# R% K. l- i4 J+ |3 W
0 m. g& e) U+ j" G# K4 `. e7 v
3.关闭console和Finsh
- p/ ?) p; O+ g5 _8 Q! r* f: @
( [7 v$ i S2 }# m9 a5 Z% E* `
5 B1 M4 E' a. c% _7 j4 ?6 Y: g; G1 P$ g/ g4 f3 ? y
由于我们并没有接出串口,所以关闭串口相关的内容。# I5 ^# ~4 P5 k* E- ?& O
1 n l0 k! r9 M5 X6 i修改代码,测试8 @3 \/ h' {0 k4 x7 V
修改stm32f0xx_it.c文件4 ]4 P- p% A+ `7 z# B$ y! f; a2 v
由于rtthread重写了部分中断服务函数,所以我们需要将stm32f0xx_it.c中部分函数设置为weak。
) t6 } r1 w% e6 \/ P- s- /**& |! H; B, @, z2 r3 s+ L- h
- * @brief This function handles Hard fault interrupt.
- o3 Q: ^7 ?4 F7 X+ q2 E% C$ @) I - */
2 g$ o, ?# S& \( J) v( O - __weak void HardFault_Handler(void)/ e, [+ k# y' r6 I4 f$ {
- {
/ c8 S T4 e+ @, |: @" L% [! u - /* USER CODE BEGIN HardFault_IRQn 0 */& l* `6 z9 q. l% N
- 1 e& K3 H8 C! p
- /* USER CODE END HardFault_IRQn 0 */
2 Z. L, P( v0 g, H - while (1)7 E$ `! Y/ \; O) O$ L( R
- {
% ]' v! a- O. x* h$ \4 R - /* USER CODE BEGIN W1_HardFault_IRQn 0 */$ A5 G; D, T! N
- /* USER CODE END W1_HardFault_IRQn 0 */
, C( ]% G2 b: c+ |8 k - }+ m8 L* E% d" ?* c- Q2 N( a
- }
. `3 }- P+ W- @8 _
* E! [) H( d1 r9 J- b( S5 |- __weak void PendSV_Handler(void)
* D: {: c( @8 x% T2 W( L1 U - {/ d* z$ G2 @ j5 e8 O
- /* USER CODE BEGIN PendSV_IRQn 0 */
% {5 l1 }" k' M, A0 x. n
7 U \2 l3 V, `2 H1 j' [- /* USER CODE END PendSV_IRQn 0 */
$ v1 x3 o5 b) G4 V `0 S - /* USER CODE BEGIN PendSV_IRQn 1 */
0 |6 p- b! z2 R% a2 n. w$ `. C' m6 s
" t$ p- b6 r" B! X3 ~- /* USER CODE END PendSV_IRQn 1 */4 S4 [; b" G+ F5 A# r Z
- } X( E: O/ _/ u: N6 s$ P; k, y, k
- & C2 F: G3 l, d( e3 r, ~2 W
- __weak void SysTick_Handler(void)' F0 @9 h9 Y1 w
- {3 j: q* e. O, Y+ c
- /* USER CODE BEGIN SysTick_IRQn 0 */0 h# p" w+ }( m2 }
" b' s0 ?( |! {6 P8 i- /* USER CODE END SysTick_IRQn 0 */
0 w2 Y) w; V8 E - HAL_IncTick();
$ S3 I1 |8 D: b; m - /* USER CODE BEGIN SysTick_IRQn 1 */
) X2 a6 P, A1 j% ^' y0 O6 a; r
( U( Z+ `3 T" s4 a7 R6 `( }+ z- /* USER CODE END SysTick_IRQn 1 */8 Q+ h) u& Q& [: U/ [ d
- }
复制代码
J/ G [" D7 w/ M* @$ w修改时钟部分
, L+ u3 u2 ]9 w( d 在mian函数中,有HAL_Init()和SystemClock_Config()函数,用来在系统开始的时候初始化HAL和System时钟。但是当我们使用rtthread后,第一个执行的函数不是main()。而是rtthread系统的初始化函数,并在board.c的rt_hw_board_init()中进行硬件初始化。
* f0 w- I: g$ h8 L 我们将HAL_Init()和SystemClock_Config()放到rt_hw_board_init()最前面,保证在用户代码运行时,时钟时我们希望的样子。
0 e" n% x0 F2 y; \6 w- F1 e+ \4 |- void rt_hw_board_init()
8 `. |2 z6 N8 K" |1 t - {
5 f T/ O3 M# N1 W: | - /* System Clock Update */9 U" n M; A: G% y k! w8 L' L
- //SystemCoreClockUpdate();* h* Y0 u, m; j* |% c1 Q: y
- HAL_Init();
. ]4 _5 A* Y: @6 r9 T. n. m: n - SystemClock_Config();# q6 Y" t4 L9 l
- , R$ e' h5 |, V
- /* System Tick Configuration */: A! n. j: n% M5 C2 W& R
- _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
. a. n! W, F- ^
: h4 Z5 r) M) Z% X6 m! R: K- /* Call components board initial (use INIT_BOARD_EXPORT()) */" e5 a+ O1 }5 m7 ?$ g( m7 n' ^
- #ifdef RT_USING_COMPONENTS_INIT% P, D$ b7 c' C' A c3 r8 K5 X
- rt_components_board_init();% z7 P$ D! m2 a" z6 x9 }1 b( z
- #endif5 Z& [ L$ T4 H3 z1 e
- & a' R& C4 X; n, S2 z. z1 N7 G8 @
- #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
# K8 _0 s7 n0 K! C/ i - rt_console_set_device(RT_CONSOLE_DEVICE_NAME);* h* ?: W; }( h3 ]2 K2 P B
- #endif# z+ g, l+ f! \
$ B# }% J, k/ G( ]' }' C1 f3 I- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
6 p' p3 i% s* P( G# l- z+ W - rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());0 B$ E( o3 t- ?7 p& Z
- #endif
, S, Q1 V5 g* {1 t2 L1 r - }
复制代码 由于我们屏蔽了stm32f0xx_it.c中的SysTick_Handler(void)函数,SysTick_Handler(void)中的HAL_IncTick()也一同被屏蔽,我们将其移动到board.c的SysTick_Handler(void)中。
; h0 Q# ?6 b" ?% Z5 |- void SysTick_Handler(void)0 M* c; V0 R9 N2 W. D0 M9 L8 v9 \
- {; ~% p3 ]; V/ A6 j' K( N+ s/ S a
- /* enter interrupt */( }7 d* e# }, l
- rt_interrupt_enter();
( ^$ ?2 k# [/ N/ ]2 ^
$ d, ~6 f% W% l! V! R3 B' E, A9 o- rt_tick_increase();! R' c; o1 i( B
- HAL_IncTick();
$ U4 O. Q# t2 F5 P3 \# I3 B -
% Z3 Y* Y) g( L8 V2 ^ - /* leave interrupt *// @, p4 V6 x$ ~
- rt_interrupt_leave();
0 a* b5 s% N% `# ~( W/ F - }
复制代码
+ e- @: ]$ v; {5 P+ p2 \增加用户代码
- @: S y9 ~9 }9 ~8 s - while (1)
' l7 m. t* ^( H6 e' ] - {
8 v3 Y; u/ j+ A( _( w1 L) s2 p0 E - /* USER CODE END WHILE */! y. G& Y! Y& \- I) b$ v q
- HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_RESET);
2 i3 e+ \7 A4 d O& s. X" G, O - rt_thread_delay(500); l9 k; ]/ @0 x% f% G' T Y
- HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_SET);
- Y: X& ~3 l6 b - rt_thread_delay(500); ' Q" ~$ Z% n( Q6 O/ {4 C* ~, `. y
- /* USER CODE BEGIN 3 */
. i7 c* E3 Y5 {+ ~) Y - }
复制代码 ~5 l) @, i, f3 [5 b6 M8 c
编译测试( z" ]; k7 x3 P5 I# e# y, k/ }
1.使用ARM Compiler version5 进行编译,结果如下:2 g, d( R$ T* x( M5 g& C
0 o# N+ k) q' u2 t8 Q2 s9 x4 ?' N# @# u, Y1 G l3 ?
) G# O/ H0 h8 v) B' ~* d* B
2. 使用ARM Compiler version6编译,结果如下:
1 @: B8 q; \4 `8 ?& i' Q" F) ]9 _, s4 y
2 p c8 n1 u* K5 r- M/ G7 I9 P0 p+ A/ b) Q: [/ X
相对于我第一次写关于ARMCLANG的博客,已经过去很久了,目前很多中间件,以及STM32的HAL库都已经能很好的支持ARMCLAGN,推荐大家使用ARMCLANG编译器进行编译。
9 G6 c- B, |; Q. a- g+ O9 i
; p1 W# E$ s8 f: ?! t7 B- j( R
7 g4 m8 F' L; e( \" p9 i* R |