硬件介绍
4 M v/ C6 N4 a1 t; q! p 我手上开发板使用STM32F030F4P单片机,无外部晶振,所以直接使用内部晶振。开发板上有3个LED灯。
! J, B! I: C3 G5 E9 v& w( h2 h8 B( D1 F" X# f
8 n+ q% y, Y" p) ^( i, n$ k
/ N/ W1 }2 r. G. r6 x2 ?/ _1 @6 ?安装rtthread_namo包
% @9 L2 D# Y0 t8 k h在操作前,需要安装MDK5软件,以及STM32CubeMX,并安装好STM32F0的Pack- D7 y0 p# B, W9 |+ b
% h" i9 M" N, Z, i1.打开MDK软件的Pack Install工具,选择RealThread:RT_Thread进行安装3 @. U; b4 v* E( R2 ]3 A- I2 e
7 ]- e5 u" h5 `. ?
' \# _( ]# U/ C6 Q
: U' B/ p9 s: S
4 ]/ V( F \$ d) p1 M
X$ y+ f: e+ r3 j2.在弹出的节目中选择Next,等待安装
) x9 i3 |+ i: k
s1 c, P* K: P5 a/ `0 n+ m
7 `8 L6 l/ u' F, C; T0 L! v b4 l& a& n* T
3.安装成功后,Reload Packs即可。6 G. W0 b' o8 K0 [
0 b+ D4 _4 P* K3 t( s
& T, ?4 x- B/ D/ Z0 G* [
6 p& }' S7 h: U* a* q$ k创建工程5 q) o3 C9 n, S6 X% o) Z
1.选择芯片STM32F030F4P6* l# N3 T8 i6 g9 L! N& X
/ O3 w* e0 F/ G3 y$ E6 d# `' k3 A# }
# T4 M% r2 z, H4 L* B3 T8 Q
8 t/ x0 S; Z- r9 ^( s7 J2.Manage Run-Time Environment/ [+ M# k' a: N% t- v D
8 f6 ?: {- S5 }0 e8 L J" X- o& T8 `3 e) {/ K8 l* ^6 U" N4 b- l
1 R8 \4 [) e) `3 r/ I5 h" D
按照图中进行勾选,由于我们芯片资源有限,而且这次的电路并没有接触串口,所以在RTOS部分,我们没有勾选shell。
0 x( \6 g% j' O3 M1 X% Q9 O( K" s5 n# z# `
3.Start STM32CubeMX* f# F# g F" y4 Z% a
5 G% W. L4 N% x$ h* \6 v* }5 \# V8 }& |5 |* b4 }) R4 X
6 \9 e7 \$ @" i" `2 |. O+ w; T, ?
勾选完Run-Time Environment后,会自动弹出启动STM32CubeMX的窗口,我们打开STM32CubeMX进行配置。" r6 k" a- ?' }3 i$ R6 h0 e& n( v
" t! c1 }7 ]- d9 F' P) K4 u, r7 H% y4.STM32CubeMX配置Pinout&Configuration
6 `; W2 D* A% d2 @1 B5 W( P
4 g0 l# q& F% H% v& u
1 ^( r- r6 o1 S3 a! Y
2 b6 Q* B' x& N: D1 m) C$ p
. z3 j; p( r8 M; B$ q7 u( M' w$ e$ Q0 o3 ]. J1 l$ G7 l5 U- u0 _% h
5.配置时钟! U: [: C' ?; M+ D
/ G' V% q4 Z! U) V9 h _, }( f8 Q6 Q9 q
" Z/ H# r( S# ~ X6.单击生成代码
2 c! s# o' ?/ d
7 j5 q1 G. a; }7 v' n
4 @ |% B5 q; `
( D- f- q- G J. i- Y$ b0 l% ]8 x7.生成代码如下% J% `4 _* a- S4 W! |- T
0 R8 i) e* L0 O# L: J
5 s( k& D# Y- v3 L) ` S5 f% l
+ m/ L: o5 `; g" o0 W配置工程9 \, r9 F! ~) X
1.选中RTOS下的rtconfig.h文件,使用Configuration Wizard进行配置
8 Y' X& `: c- V" v: p
# [! N: o# W# z8 v+ o3 J
7 `" `! r& f1 g4 o3 X; [; h9 g: Q% R1 f1 r- v0 w+ O
2.内存管理设置
, ?$ q1 k8 [! |" ^: [/ p( y6 V7 t/ k
1 `5 j. `$ ~( e/ l" T$ h$ g# A1 n8 J# [& d0 K& s0 i) L) F
由于芯片内存很少,我们取消Dynamic Heap Management。勾选上using small memory。9 U7 m; v) M" t8 E- _- z$ p
" u/ A6 l" t+ @* s7 t/ B
3.关闭console和Finsh3 c- k% Y. _+ h: X
% V- o8 i9 r7 b2 U! b5 W, K3 M5 l5 _" v1 o
7 U8 y- w X' R 由于我们并没有接出串口,所以关闭串口相关的内容。
4 O S1 ^! k+ O/ }" r$ R) ? F0 C$ V# H0 u5 j2 B" b
修改代码,测试3 w3 I7 z% j' H$ h
修改stm32f0xx_it.c文件
: g4 L% i% A" \7 P 由于rtthread重写了部分中断服务函数,所以我们需要将stm32f0xx_it.c中部分函数设置为weak。- S4 _' Y9 r [. h# {$ ~3 k- l$ R1 p
- /**6 k9 T4 B4 f+ A6 D$ A9 y1 O/ B
- * @brief This function handles Hard fault interrupt./ ?) O; P: B! U
- */
& R3 {$ G1 b1 N: I - __weak void HardFault_Handler(void)
: U. ~. _( t8 J4 l - {$ |, Z' j" K8 ?
- /* USER CODE BEGIN HardFault_IRQn 0 */+ [% s- L1 T$ U8 X1 o3 \
' I9 Y5 H) c- y, `0 f3 w- /* USER CODE END HardFault_IRQn 0 */
! U x! _, p: [4 @8 r3 l' y - while (1)
' B O& ^, h7 b" b - {6 @6 y/ V, D* l$ `8 U6 t# Y( s
- /* USER CODE BEGIN W1_HardFault_IRQn 0 */
( i1 Y, r2 k; @; K+ a5 R" m. k - /* USER CODE END W1_HardFault_IRQn 0 */2 R p: [ J: K3 p
- }
9 ~- X* q. T8 U# k) q, } - }- Q& ?4 h6 ]) I# M. U& g
/ o) F( I0 I! Y- x- __weak void PendSV_Handler(void)3 ]. P4 W3 I, V! C% j+ S* u
- {5 P6 E: f3 R* U& Y% a4 e/ h
- /* USER CODE BEGIN PendSV_IRQn 0 */
/ {4 o9 e$ A5 C/ o; U7 I& B5 @8 d
: o7 s! a0 _* {- /* USER CODE END PendSV_IRQn 0 */
* B% s/ i4 n# G+ K/ U' m - /* USER CODE BEGIN PendSV_IRQn 1 */
, }) t6 E- W- G! v, D* m! U - - ~) f7 T( B1 ?# H( {- z
- /* USER CODE END PendSV_IRQn 1 */- g: g5 z4 K4 Q
- }
- l' O# f4 u$ }$ ~$ _
z% f6 `7 ~. F0 p- __weak void SysTick_Handler(void)- z m; ]6 |# y
- {
5 h* j1 F$ j/ a9 Y# ~6 U) F. A3 o) ^ - /* USER CODE BEGIN SysTick_IRQn 0 */
$ v! R& \, i; v( K' } - 8 c C0 D, y2 }1 H! i
- /* USER CODE END SysTick_IRQn 0 */6 K$ r/ \2 q9 s9 }( N
- HAL_IncTick();
* t* ^: U5 ~1 }# f S7 N) R% S& T - /* USER CODE BEGIN SysTick_IRQn 1 */$ q# ?8 d! d+ b
- ( U+ H& H! `1 j# t4 y
- /* USER CODE END SysTick_IRQn 1 */) h+ ~0 P5 v: v/ F8 g7 F- |
- }
复制代码 9 M7 I: H0 |' z4 P/ U# G3 Y3 p
修改时钟部分* y5 L5 E& X6 A
在mian函数中,有HAL_Init()和SystemClock_Config()函数,用来在系统开始的时候初始化HAL和System时钟。但是当我们使用rtthread后,第一个执行的函数不是main()。而是rtthread系统的初始化函数,并在board.c的rt_hw_board_init()中进行硬件初始化。
: M: {. p1 X7 Z$ x9 p3 G 我们将HAL_Init()和SystemClock_Config()放到rt_hw_board_init()最前面,保证在用户代码运行时,时钟时我们希望的样子。6 c7 h2 r' |7 h5 g- u
- void rt_hw_board_init()! F) c: o& A2 Z% z1 c! X) W8 c- M
- { + q5 p$ w' e& x
- /* System Clock Update */6 s% T& p" h, B/ J3 z$ _
- //SystemCoreClockUpdate();
$ j6 \7 T8 s! [1 `: G - HAL_Init();8 v( h8 o* J$ I
- SystemClock_Config();- s2 s7 q7 p# K f, ~) q
-
3 ]; E( i0 a' g2 e j! U8 Q1 x - /* System Tick Configuration */
1 ]6 O' z7 L1 F8 G6 X - _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
) }( i' E5 k. F) {" S2 @! V4 t - / Q4 U1 n0 j. \2 b4 x
- /* Call components board initial (use INIT_BOARD_EXPORT()) */
1 a( @/ n/ F) W4 t+ R% l. W2 G - #ifdef RT_USING_COMPONENTS_INIT
, z4 [, v+ }# f+ J3 i: o& ` - rt_components_board_init();" D' [' g/ q* d
- #endif E- \& ^& @; }8 d0 o5 ^
- 8 ?* z& p( i& q* g/ ]1 [
- #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
K) L( u7 U& _! Z+ q& o - rt_console_set_device(RT_CONSOLE_DEVICE_NAME);9 S4 i) \0 V5 {+ G; o5 r
- #endif; d, S6 ?& {. Q+ ~# v- B! G( f2 I: r
. P6 T! S7 f; N/ ], {+ Y- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)& o* k2 N3 ~) g" ?- y' W$ t8 u
- rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());# a. F D6 X9 _0 [" |2 h- ]: h& P
- #endif
. R- k2 {- S* { o - }
复制代码 由于我们屏蔽了stm32f0xx_it.c中的SysTick_Handler(void)函数,SysTick_Handler(void)中的HAL_IncTick()也一同被屏蔽,我们将其移动到board.c的SysTick_Handler(void)中。, ~6 ?# k( a8 y( K# I% F
- void SysTick_Handler(void)
: E1 z5 m+ r% c+ s - {( p) _% ^0 m# q; G0 T. p
- /* enter interrupt */7 y7 ^/ g& j* H
- rt_interrupt_enter();3 j* |; ?1 [5 Z/ m/ U; o5 S
9 ?! a: Q4 G8 e4 X- y- rt_tick_increase();+ b2 l* x: o$ ]: O2 x
- HAL_IncTick();; v5 V8 M* m% R4 ?0 ^3 B
-
; a# V: X* g: W$ ? - /* leave interrupt */) w; p1 g" a4 t K7 t6 } Q9 ]4 @/ e3 {
- rt_interrupt_leave();
9 L. m3 T. U9 b+ \3 T" X3 q3 y# H - }
复制代码
, a( m5 R/ P1 e. l' J g+ |3 H- t增加用户代码
) d' k* j5 H0 a/ M - while (1)
3 @1 o' g8 _( ?/ z# o5 W' Q9 B- g - {
]& R; n: @* {% ^6 x; l - /* USER CODE END WHILE */
/ R5 E2 R) X8 E e) n$ t - HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_RESET);
: F/ f3 ^$ q2 g, n - rt_thread_delay(500); # {; i$ t, g* \4 w. ]' S
- HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_SET);
* j/ F5 j' R" Z, i' W6 k; w - rt_thread_delay(500); 7 B4 j# {/ }' |$ L! O
- /* USER CODE BEGIN 3 */# Y) [ G3 ^& p2 @
- }
复制代码 - t6 m `1 {: k- z
编译测试3 t5 u1 Z1 C: X3 {
1.使用ARM Compiler version5 进行编译,结果如下:
: V5 t2 ^/ M8 f" w+ u
+ ^8 ~/ E0 n9 E8 Y! B
7 y8 e t0 _+ L& r, v( Q
1 a+ T; O8 r8 P/ o% v$ V) P2. 使用ARM Compiler version6编译,结果如下:
1 S" E1 ?* ?2 s$ i; f i) O4 p2 Z& B$ D# G# b
# \1 M( z1 }3 W2 t. f I+ u
! X3 {$ r/ ]! {/ }. J9 p 相对于我第一次写关于ARMCLANG的博客,已经过去很久了,目前很多中间件,以及STM32的HAL库都已经能很好的支持ARMCLAGN,推荐大家使用ARMCLANG编译器进行编译。( S# ~, q3 w7 \& W/ a/ J
/ E5 Y- B: y! Q% H3 ^: G7 C
9 }+ |- Z$ ]( Y' z5 Z2 z |