硬件介绍" \ r( d$ C: _! c
我手上开发板使用STM32F030F4P单片机,无外部晶振,所以直接使用内部晶振。开发板上有3个LED灯。
" j; `# H" I+ q J! |- l8 U2 W; h0 V2 c# M4 o. N
& [7 y0 C T1 N; j
6 s# M6 p* v* x- W2 n$ u4 E
安装rtthread_namo包! b) S$ m/ @" P9 J; T& Q n& P
在操作前,需要安装MDK5软件,以及STM32CubeMX,并安装好STM32F0的Pack
1 Z- E1 o* G3 |8 m7 a, ?
# g! i! r# n9 K2 O6 v5 o1.打开MDK软件的Pack Install工具,选择RealThread:RT_Thread进行安装; u! n% a+ Y5 K2 R) T% J) p0 e& F5 Q
( N7 h7 ?8 j3 {& u3 Q
) [4 R* g! K" R3 }8 O u! F& d- E4 q$ }
8 x4 `7 W0 ]1 k. X( k
3 H& V! i' v6 [- c2.在弹出的节目中选择Next,等待安装
) t4 u8 S8 m" s2 C0 H
: J+ P$ ~' f0 o0 s, L9 e# w( Q0 ~; Y6 `6 q
' ~( p0 W( K8 \8 ~9 z
3.安装成功后,Reload Packs即可。3 x' E4 g! n/ _! v3 B' Y6 d- h
/ @8 F" {% L \: o# s. e7 }! w: x# A4 E; M& F
, z! p h0 a! f: T; [创建工程
/ n/ a. w" \9 u2 Z1.选择芯片STM32F030F4P6
- Y8 p* T' P7 n) k: O8 x& V6 k7 S+ \7 A* E. E) I' m& H
- l: D$ m% Z! z; @; A
! M$ H. m; A O) H& L" A: Y2.Manage Run-Time Environment5 J9 t) g0 q6 p
; Z/ b* c. N; ?, W6 O( g- t0 c3 W6 Y9 M7 u E( `
7 ?! ` K% j( D0 \$ u/ I
按照图中进行勾选,由于我们芯片资源有限,而且这次的电路并没有接触串口,所以在RTOS部分,我们没有勾选shell。
: O7 Z: f+ {/ X. U. B4 j6 s3 S9 m* |( t( U' h, b# o3 f! J
3.Start STM32CubeMX
) H5 g/ v8 S3 {; E, Q9 j" f
, J- E" o* c1 F* e9 D. L1 {. i
4 ]9 f" r; e$ N5 q) f5 W8 S0 Z# m- z5 W) r: n4 T c" e
勾选完Run-Time Environment后,会自动弹出启动STM32CubeMX的窗口,我们打开STM32CubeMX进行配置。: e6 L5 m P; P* f. y+ z) p0 x, i
?: i: x8 Z$ v; t+ | f8 u( d/ _
4.STM32CubeMX配置Pinout&Configuration' X1 q! z" x/ g% C9 L
& C9 w' \, C/ m# N) h6 P
. b8 T. Q, b2 b' r3 p, I* X
2 a3 t% K- G; [% }/ g7 h. ]* I" f9 v4 I
- w8 s" T, f$ Q3 r* K
5.配置时钟
( D. K& F2 ]) I' n6 k
/ v$ f/ C# u- L# X0 h$ q6 w8 ]3 s; ~6 u
$ I/ |, p5 ]$ g
6.单击生成代码
/ T+ ?; Y# r& J$ Q2 e) F& a
) c I0 x3 P; i% K
, D: b, ?3 [1 i- b: g& M. i
$ O, D6 z+ ^2 S4 T, U+ i9 ~7.生成代码如下7 r8 j" c% X# m+ d/ b
( J3 L% n/ C7 b& U2 j' q
* t/ k4 |; J2 F
5 f0 h# l8 `+ O! T9 y Z
配置工程
; q: F* @$ Y- K; P# t2 f$ N7 x1.选中RTOS下的rtconfig.h文件,使用Configuration Wizard进行配置8 l1 O1 t$ J, m7 ?" H1 v! m
2 A# L \8 S1 W8 b$ D) r
* \6 J0 D; g! A5 r6 W% i) y. t( A9 Q) t; a( K% Z; A& o4 t1 Q( Z
2.内存管理设置6 v' H2 x7 x# W' k: {( b1 I
! t1 R u0 ^& G j6 B; E9 X, G$ S' X6 h/ V, R4 [
7 U: U# z) u1 h$ Q( D/ q! U
由于芯片内存很少,我们取消Dynamic Heap Management。勾选上using small memory。' J0 h Z$ [$ m% v1 ^7 h
! b* l* j3 K, z' L# V5 J7 R3.关闭console和Finsh& u! R4 @% ]7 _4 ]- r7 ~
, E& y! I% [* X/ H* l/ g
8 P& x4 o; P) c. j, Y6 s
$ `1 a" @5 F2 d1 G6 L: C 由于我们并没有接出串口,所以关闭串口相关的内容。
n+ ^$ g3 ?4 R; J& \" b2 b3 a& x
6 r/ y: R( v7 [7 [修改代码,测试9 ^" g: ~2 x! a% v6 x
修改stm32f0xx_it.c文件, P) v) w3 U* @. c
由于rtthread重写了部分中断服务函数,所以我们需要将stm32f0xx_it.c中部分函数设置为weak。
0 O$ r/ ` j1 `% p& U5 [0 f% Y- /**' R u8 S! ]! Y
- * @brief This function handles Hard fault interrupt.1 I9 \6 q. M3 C2 S4 h
- */1 @4 y4 L- [1 d+ _' ~
- __weak void HardFault_Handler(void)9 x6 e3 d& W% \' O6 P
- {. r% N- e! r4 N
- /* USER CODE BEGIN HardFault_IRQn 0 */
/ A4 i5 p8 c# c0 { - - y+ g5 Y' N5 B; a
- /* USER CODE END HardFault_IRQn 0 */
3 ?0 R5 n7 i- q) C - while (1)
8 S: ~. _/ _ l% h$ F; v& j - {' d P6 Z, `& r) K
- /* USER CODE BEGIN W1_HardFault_IRQn 0 */
: z$ \+ {' |! G - /* USER CODE END W1_HardFault_IRQn 0 */
# Y4 H9 R+ i5 ~4 E7 x - }
5 G. W# ~0 ?; U6 u - }
& E$ V8 N( e; q, S, W2 F' w. s
' V% j% Y3 t L# [- __weak void PendSV_Handler(void)1 B1 `8 D! S6 f, M4 P2 J2 J
- {& \0 A" b% W2 O) X8 M, P
- /* USER CODE BEGIN PendSV_IRQn 0 */
6 l/ ^# F: T6 E5 z4 A2 z1 T7 K - 4 O- X1 J) U4 ]
- /* USER CODE END PendSV_IRQn 0 */ [$ D7 n7 ?& M
- /* USER CODE BEGIN PendSV_IRQn 1 */
* M; S) v: ?- I z
& M H3 n" d. Q1 M+ [5 _: C- /* USER CODE END PendSV_IRQn 1 */
2 d. j1 w! ~; y" q; \1 s/ o6 h - }* @2 @% ~+ a2 S. X) q4 Y( [
% _8 M4 h+ n) N! y! R6 T! L {" ~- __weak void SysTick_Handler(void)
% y7 P" ^. d q- w1 s - {
9 s [/ }1 M' ?& ?( c7 }) G' s - /* USER CODE BEGIN SysTick_IRQn 0 */% M3 V j$ ^/ Z' E3 j
- 6 Y3 ^0 Q. T$ p0 a
- /* USER CODE END SysTick_IRQn 0 */
7 e4 ]7 c) t$ W& T' @7 H - HAL_IncTick();
4 H, {, k2 H8 }. W# n - /* USER CODE BEGIN SysTick_IRQn 1 */
9 h: i. b% [5 M8 q; U; a
, ?" f1 c ~2 r4 V: M- /* USER CODE END SysTick_IRQn 1 */8 ]" |6 j- Z$ g( @+ w, C( ~
- }
复制代码
4 d3 ~4 n* |! q: r修改时钟部分" E! x$ ]2 [& u7 O \
在mian函数中,有HAL_Init()和SystemClock_Config()函数,用来在系统开始的时候初始化HAL和System时钟。但是当我们使用rtthread后,第一个执行的函数不是main()。而是rtthread系统的初始化函数,并在board.c的rt_hw_board_init()中进行硬件初始化。/ a' S. J6 q; {$ ^2 K- y
我们将HAL_Init()和SystemClock_Config()放到rt_hw_board_init()最前面,保证在用户代码运行时,时钟时我们希望的样子。
$ z4 }9 W- E E5 l1 C; e- void rt_hw_board_init()
0 I$ u; T0 i, x/ o' L# u6 X' C% U - { & Y5 c( q, ^! O7 W) q( |, P; ?
- /* System Clock Update */, G6 {( z( O$ A( K; j( `
- //SystemCoreClockUpdate();2 K' N) J. B$ N' V9 I' `5 O+ U
- HAL_Init();
: }9 P$ b& j$ L7 G0 Q) { - SystemClock_Config();
' \2 J: F6 @8 H! r, \& N- k0 n, Y - # @) j5 i3 U1 j; T0 J
- /* System Tick Configuration */
, y7 {- u& Y* i8 U3 M - _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
5 e: j' Z/ s! ^ - 2 {& X8 { y( q0 k. s6 y
- /* Call components board initial (use INIT_BOARD_EXPORT()) */
' t5 H3 o* d1 y- ^( \! Z7 p - #ifdef RT_USING_COMPONENTS_INIT
1 p* |" ?' J0 s5 k) S - rt_components_board_init();
' i# Y: `& R# z& P3 G t T* ? - #endif2 i0 c9 G7 R! y0 q/ W. s
, R1 H2 a1 v7 ?0 V" H* N- #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
+ x+ {! P( L. V$ G% T - rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
7 j* n- k, u9 P" ]) a9 B% } - #endif) i @3 y& j; {) p+ ?5 Q. T4 u
( ?7 _6 c, }0 t0 T% K9 n- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)1 K0 ^6 i; m: A5 r- C
- rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());7 i+ w, G0 b6 T2 u3 f% v
- #endif
+ k0 z8 ^$ L6 o" C! D! S - }
复制代码 由于我们屏蔽了stm32f0xx_it.c中的SysTick_Handler(void)函数,SysTick_Handler(void)中的HAL_IncTick()也一同被屏蔽,我们将其移动到board.c的SysTick_Handler(void)中。* _& p" s9 [, J( Y- ~/ p: n
- void SysTick_Handler(void)0 q- ~7 x" T+ y3 T! A! _+ i$ U
- {6 ~% a5 c( g( h$ l
- /* enter interrupt */
5 \5 \. F( _ E6 q - rt_interrupt_enter();
" i) ]6 l4 y% [# Q, m
& n7 k* S, O! G4 W3 p. [7 j K- rt_tick_increase();
1 u4 g' U3 P. x0 w( ~" a - HAL_IncTick();
5 Z; R) ?/ H W -
% r0 g, M# O! `4 |: p' d& Q* q - /* leave interrupt */1 w8 T. a' v$ `1 T$ g+ T
- rt_interrupt_leave();+ i t) B3 M6 }+ A: h4 Z
- }
复制代码 . R# c- X) `2 X4 k; W
增加用户代码- L* r0 p9 X" R7 X! a4 L t: R9 l
- while (1)
" D$ S ?5 f6 s - {5 {+ S- o: j0 \9 L8 q' T3 C
- /* USER CODE END WHILE */6 z, a& l7 J2 ^
- HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_RESET);
# C# l' m9 q2 {5 T/ S - rt_thread_delay(500); 0 s) X# Q" h7 Q- M) ~7 [
- HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_SET);
( B5 D. z% @" ~6 D! p - rt_thread_delay(500);
9 q+ u `, D. B# T' }' B% R& K, s( G - /* USER CODE BEGIN 3 */
2 V- l, Q0 R' V2 m( x8 o. Q - }
复制代码
- H! b8 O4 D$ c# r编译测试
. J4 ?: h2 I5 f2 N$ H: T1.使用ARM Compiler version5 进行编译,结果如下:
! Z' U' {' ]. f( I
; Q% {9 J5 j1 q. G/ s5 S# N8 x) |- V' l' j$ Z( q/ w$ `
1 d: l; j% b. b& U2 b- j
2. 使用ARM Compiler version6编译,结果如下:
" o4 u9 L6 ]' _9 ^" a4 c" S
+ M- ?. `: ^/ j% u/ `- @2 g e4 m; @& y) z, `+ E
7 r( i, G4 V2 l
相对于我第一次写关于ARMCLANG的博客,已经过去很久了,目前很多中间件,以及STM32的HAL库都已经能很好的支持ARMCLAGN,推荐大家使用ARMCLANG编译器进行编译。6 C+ E* ^* Q: ]% r9 Y
( g+ o: V: }' e7 d0 M5 z
- d8 T1 l6 Z4 \
|