硬件介绍3 r9 t8 a* z$ S& t/ T( g
我手上开发板使用STM32F030F4P单片机,无外部晶振,所以直接使用内部晶振。开发板上有3个LED灯。' I/ u+ N- i0 T0 C Y
( U! u1 a+ |/ \3 \ u S) N# D
, e4 L5 g/ @4 C/ @* b# E
; E$ x. r7 }. C
安装rtthread_namo包2 U4 F: `4 |: ` Z- M
在操作前,需要安装MDK5软件,以及STM32CubeMX,并安装好STM32F0的Pack
6 \! t% z" A! V0 x0 ~) r& n$ j
7 N4 Y- P* ^# s( I2 e# }; [1.打开MDK软件的Pack Install工具,选择RealThread:RT_Thread进行安装' w* T# a/ ^0 _
+ X2 ~* R, z: [% B0 p" |
! K" v0 e; @. F* j8 O7 q9 C' a8 f- O2 _) d0 i. @
* ]. t/ s5 ^" P/ i/ L' x a# d' ^- _) q. S! g
2.在弹出的节目中选择Next,等待安装
# w8 l1 f7 H: l, J. m
$ h5 Y+ N9 q& y/ Y! ~. f: }, S% ~9 F4 D+ i
% J0 d$ {' g x/ b& Y; X3.安装成功后,Reload Packs即可。0 x* \# r( f) ]7 P0 ]+ ~7 q9 I
. s0 Y% T9 z' j9 p2 D5 k D2 y) j/ l) [) i4 o
! D7 L! ^( Y/ @7 e) e9 n" j
创建工程- X( u3 C# }1 V: T* v* Y* M+ p
1.选择芯片STM32F030F4P6) z1 ]& U Q H2 m3 Q
6 F0 B. Q u4 M/ C1 v9 d! E/ B! ]1 c" D! r" D. c
0 E- g V. O! W6 r
2.Manage Run-Time Environment
" E5 Q3 D1 q5 f. n
, P5 C) o. Q" q- O$ F" b* R4 @, \1 {, D4 D
& E0 _" a! ]5 h" O y- G 按照图中进行勾选,由于我们芯片资源有限,而且这次的电路并没有接触串口,所以在RTOS部分,我们没有勾选shell。, N1 N0 k U: _+ S
) N$ D0 r/ d/ J+ E; i( z0 C8 }3.Start STM32CubeMX4 i4 N! g- g, N$ Y: r
5 ]% v7 n2 K; Y0 l
3 V# X6 r+ b! l3 _
" F+ ^# D- q# \0 x5 a
勾选完Run-Time Environment后,会自动弹出启动STM32CubeMX的窗口,我们打开STM32CubeMX进行配置。& g4 n- T a9 i9 S2 }8 S' {
3 {+ G! H, J6 k7 Q! x
4.STM32CubeMX配置Pinout&Configuration
4 v& R. K3 O- S9 d" A0 v. I# Y0 F3 v* j t/ e% E/ i# h* d
, u% t; r* I: q
% x, W1 K5 W s9 {) l4 q/ s# f& L, R3 ~1 [
8 G0 c, h6 M& ]: H7 d) P
5.配置时钟
! a8 x0 a3 Q9 Q6 _! a& v9 \( F9 g
0 O; X) v0 c [' L8 j/ ^" c
6 O$ W% E5 r( D6.单击生成代码" E; c7 z5 W2 L8 Y" L: {
4 q& t: V: P1 N* u; e
1 m& m5 b1 V+ p3 X9 X
$ \* C" {) y' d7.生成代码如下, `& i" f: Y( j* a5 k
# i; R8 r" i5 a% K( `
. U( V0 H; g8 J
1 `) A5 V" h: L6 e( J6 r
配置工程. X, C1 i |/ S* a4 ?" |3 J- q! E
1.选中RTOS下的rtconfig.h文件,使用Configuration Wizard进行配置; r, i: d$ A* Y# [. G
% R6 U! c6 H# G5 o
8 V* K; O$ B7 X R+ k
. ^" ~ {4 a; D% U- R% L, T e
2.内存管理设置
7 O0 D. n0 o' \: ~% E6 T; Z1 \
& O# }& }( ]! C. V# t
! Q( N# p9 i4 S- f! F) e' m7 k+ u
. Y3 y. @- \. i1 e5 B8 L L8 L 由于芯片内存很少,我们取消Dynamic Heap Management。勾选上using small memory。
$ z9 ]/ `) S9 T6 I+ j8 b
3 a9 H5 V; r6 ?$ o* F) S% b3.关闭console和Finsh
# W/ M$ h+ j! Y" _, g4 N& V P4 I$ N8 F' Z- |7 z
. n+ w% A, c+ w" z, m8 D
9 j9 ^0 Y: U9 P: B: S
由于我们并没有接出串口,所以关闭串口相关的内容。* N3 @0 _) }6 P: V* A Q
2 c. W6 `% q; y* C5 @9 m( B5 K4 D修改代码,测试4 }. R( X: D3 ~4 Q! G2 A0 H' L, |/ `
修改stm32f0xx_it.c文件1 V( T2 N# P9 }+ g$ K1 D6 c# L
由于rtthread重写了部分中断服务函数,所以我们需要将stm32f0xx_it.c中部分函数设置为weak。
4 p4 ]: u+ O& c3 I ?- /**
& Q! |* R; m" N4 a1 j% A+ v - * @brief This function handles Hard fault interrupt.
; g% C+ j$ q0 H* F$ Q% h5 s - */
- V# Y: O. h X; t- o" Y - __weak void HardFault_Handler(void)
+ g9 l/ n8 {' l7 q2 k) B - {1 `9 `2 z% h2 Z6 i" j# j
- /* USER CODE BEGIN HardFault_IRQn 0 */
. F- Y* n: \3 ?" w - 8 B3 U; N% z1 A9 t0 g9 v0 n2 a+ t
- /* USER CODE END HardFault_IRQn 0 */
& H7 `! }) I0 \8 I3 m' n - while (1)
: d( b) t( z0 b( n" [& Y - {2 W P2 B- H* x4 {" A
- /* USER CODE BEGIN W1_HardFault_IRQn 0 */
9 I5 P, j- C# }0 l6 G( Z - /* USER CODE END W1_HardFault_IRQn 0 */
" v% E1 X, N1 U7 f" j2 P - }
* X9 z' n8 N: w! c$ Y- ^ - }
& w0 W W g8 D% c" k" v
v+ r# s% @. j& B- __weak void PendSV_Handler(void)
) H& M' m: k7 n. X N5 U6 C - {
9 g6 O, {+ j& u- a w U* ~$ T - /* USER CODE BEGIN PendSV_IRQn 0 */
n6 Q7 I4 z9 k1 a, d
! D) V4 ~2 R/ L- j/ A1 p- /* USER CODE END PendSV_IRQn 0 */; V8 {( q0 [' T6 d8 u% \2 e
- /* USER CODE BEGIN PendSV_IRQn 1 */
0 s- z. ^0 i) }. m c5 g! L
3 `3 m5 W2 F% x2 g; j- /* USER CODE END PendSV_IRQn 1 */
2 E+ b! ^5 ]& d4 b( R% u1 f - }2 R/ ^( f5 T6 P+ S) d$ \% N
- 4 m3 j d/ [" b; E! f2 V
- __weak void SysTick_Handler(void)8 c; g+ ?+ U! e$ e1 @. Z
- {
) W$ G' G1 s. i3 d3 h- k) {/ w" j' H - /* USER CODE BEGIN SysTick_IRQn 0 */
) T. s. s/ ?9 S* C+ c" z
) h7 f! X" l' R" ?- /* USER CODE END SysTick_IRQn 0 */
5 S' q7 \+ h6 f0 N/ o: F - HAL_IncTick();% X+ q1 p+ E6 Q% O8 Y s$ c
- /* USER CODE BEGIN SysTick_IRQn 1 */+ U3 P) N; S; h o! R
5 |3 T, M0 m+ N- k0 P- /* USER CODE END SysTick_IRQn 1 */
, H* y/ d6 f4 c$ [ A - }
复制代码
* Q# F" x: Z) `. v修改时钟部分
) l/ P+ ^7 h3 v6 i* K5 n 在mian函数中,有HAL_Init()和SystemClock_Config()函数,用来在系统开始的时候初始化HAL和System时钟。但是当我们使用rtthread后,第一个执行的函数不是main()。而是rtthread系统的初始化函数,并在board.c的rt_hw_board_init()中进行硬件初始化。2 G; h/ V( m2 U8 u
我们将HAL_Init()和SystemClock_Config()放到rt_hw_board_init()最前面,保证在用户代码运行时,时钟时我们希望的样子。
7 i5 g6 d, }. @& a6 M9 i- void rt_hw_board_init()1 a( i7 |- y( Z
- { / {% Y7 t* Q) z) l9 Y5 N5 A1 `) l6 t
- /* System Clock Update */
5 `7 l1 ]( P5 c# ` - //SystemCoreClockUpdate();+ X: b( O3 ?3 U R8 W, r
- HAL_Init();
! Z+ G( t' A/ b8 T - SystemClock_Config();. O( C; A: j" b1 }
- . x, v$ N! |2 T1 _& P$ c
- /* System Tick Configuration */
! g/ I( j! m6 B - _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);. z9 h, M3 Q2 [ i. y; K
) Y; D1 b2 [' c; _& K8 x0 T" M# w- /* Call components board initial (use INIT_BOARD_EXPORT()) */7 I+ g: Y6 I* s
- #ifdef RT_USING_COMPONENTS_INIT7 y5 J! ^; W. {7 v8 z F' z
- rt_components_board_init();1 D5 e+ F Y3 z/ @7 e
- #endif% ~/ A2 N* m/ u, H5 \. b' n
: Z( \7 s, j9 X* s7 [' ^- #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
z- ^+ m7 u; T8 } k - rt_console_set_device(RT_CONSOLE_DEVICE_NAME);1 h y3 R2 k1 F9 F. t- N1 A
- #endif: T% H% y: J( y0 e& z2 H
- 5 O; B8 Z5 G& R
- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
" U! \2 X8 T& R7 A7 K: d - rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
: H5 E9 V* U2 d" K* z# F' [" U - #endif
. `0 ?4 |' G8 T l. _* H - }
复制代码 由于我们屏蔽了stm32f0xx_it.c中的SysTick_Handler(void)函数,SysTick_Handler(void)中的HAL_IncTick()也一同被屏蔽,我们将其移动到board.c的SysTick_Handler(void)中。
a& V% a4 ]3 O# W' h0 G- void SysTick_Handler(void)
J* N$ S1 p" W8 r5 Q - {% T4 h, ]6 I9 G
- /* enter interrupt */6 p& L) b: [0 w" C/ R9 g7 R
- rt_interrupt_enter();
. }+ v9 E4 g! Q7 n; |( h6 U
1 {0 B, g6 U Y- rt_tick_increase();; R" T8 \9 f) q/ b9 j: J6 k* i$ J
- HAL_IncTick();
1 m- J. S* C" H' y2 R - ( s. i' h; f8 Q. P7 `9 v# |
- /* leave interrupt */
x$ {5 a8 N2 P9 C6 u - rt_interrupt_leave();
6 ]- R: w& q% l1 z" y( S - }
复制代码 1 [" F: Z" Q" c
增加用户代码
. I1 W1 q- ^1 _# j% m - while (1)
: e7 y- {( e5 J# J" g( E - {
; s3 G8 P. L0 k1 A2 l# M - /* USER CODE END WHILE */
7 {3 S; I- z, R) T4 x4 n - HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_RESET);
" a' r$ o" S5 @ - rt_thread_delay(500);
4 l' Q. S& |1 i/ }9 ~ - HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_SET); 2 G- ?. M9 u. s" q$ Y. e" `
- rt_thread_delay(500); ; D' A" k5 G5 x' Z4 N6 ?
- /* USER CODE BEGIN 3 */
+ O1 N+ ]! ?* Q# N - }
复制代码
# ]) q7 \$ P% I, M; v* h0 i编译测试3 P* {& ^4 Y% q- c
1.使用ARM Compiler version5 进行编译,结果如下:
8 E9 E' Z% A3 @0 I6 D0 n4 ] R- X) U2 E, B* ?
% C3 i* `. F C* p
1 O2 z( |, H m2. 使用ARM Compiler version6编译,结果如下:8 M+ U+ c2 g5 e: A
5 U9 X# t) J+ M; f$ C" s1 q4 B1 {) i# A
1 u4 r3 u# j* g5 z/ q$ Y. C0 h 相对于我第一次写关于ARMCLANG的博客,已经过去很久了,目前很多中间件,以及STM32的HAL库都已经能很好的支持ARMCLAGN,推荐大家使用ARMCLANG编译器进行编译。
( `/ K) [* T" v/ ]+ I: f0 J# [9 O% b+ e4 r
: t0 S' i1 y8 ^% G. z! { |