硬件介绍9 i* s' d7 @, U$ |5 {, r3 }& X
我手上开发板使用STM32F030F4P单片机,无外部晶振,所以直接使用内部晶振。开发板上有3个LED灯。. f) {3 S2 N2 k6 b/ I' x* n
" g0 f9 f+ s' t- l6 Y
5 l& V3 p! L$ e; E
5 v7 L8 a- h5 _* m( W安装rtthread_namo包: z3 I4 T6 S' z
在操作前,需要安装MDK5软件,以及STM32CubeMX,并安装好STM32F0的Pack7 ^" V- z8 I1 _1 H0 `5 ]
# {8 _( k8 Y1 X4 A+ w3 R" S8 a
1.打开MDK软件的Pack Install工具,选择RealThread:RT_Thread进行安装
3 ?3 U6 m" |5 _ I) P* K
* o! j- G+ j: t8 A/ S9 }5 Y ?" |0 ?+ C+ W0 H7 e
H; g8 s# W2 P3 d6 i4 |
5 r3 v8 d8 ?% X% Z7 _' E+ ], [& X' q2 e- U9 f9 k: o' ` [
2.在弹出的节目中选择Next,等待安装
) L, k# e1 {1 |% d2 o6 t1 B K2 m! F
0 s* c# f/ k$ x+ ^0 \% }7 K9 G& {/ S( d# J l
3.安装成功后,Reload Packs即可。
8 B `3 W* ?) F, H% K, y, p+ M6 c- t- Q2 D
7 i+ @+ O R0 Y7 O
" N( |" ^/ l7 ~: f- a创建工程
9 n* w) P P% E1.选择芯片STM32F030F4P6
8 _! m2 p( c/ q5 \2 v, Y5 G0 R" c0 U9 m6 [
7 l6 [$ K" R& R7 L6 z
4 N4 `. y- i% U ]# }) Y: v2.Manage Run-Time Environment
$ ]% N2 V7 |2 J h* S
8 W7 t0 w0 s8 r n4 o8 }) C8 Q0 u9 X- A# l# ?0 _% d; w
+ G$ w. i6 [7 o* {0 z$ g% ^5 `
按照图中进行勾选,由于我们芯片资源有限,而且这次的电路并没有接触串口,所以在RTOS部分,我们没有勾选shell。
0 G, c4 Q2 L9 m4 n! Q- F3 m4 q8 G( Y% N1 w
3.Start STM32CubeMX1 ?8 ?, ]7 z% K n; {; v
/ H. W4 E7 h! E
3 j( w3 T3 L w0 P7 i9 n
* T1 u. O4 V& |" o 勾选完Run-Time Environment后,会自动弹出启动STM32CubeMX的窗口,我们打开STM32CubeMX进行配置。
1 B* J& Z+ z) \+ C; O6 d( T; o0 `3 o3 f a; w6 o
4.STM32CubeMX配置Pinout&Configuration
5 S3 O" Z$ c3 A+ r4 J7 Z' ?5 H+ Q
: u |4 C/ \0 ~" F
" N7 g/ Z/ B7 q' I1 O: b% [, { }2 X9 i( }; B) h, B6 W1 j
+ a. m, J7 {, ?2 J5 W' V0 y5.配置时钟# K' ] C1 L8 k2 n. L: J' R4 }6 i+ \
6 ]2 G2 k5 T1 T; L+ [4 `
' y& g# F& o/ ]1 |8 z& n7 Y) S3 M6 r& G! u' T
6.单击生成代码
4 }: ? m# }) n T0 l9 M# ]4 d0 [5 e1 r! q$ i3 K3 w
) S# Q: i, G; b& M6 ?, f
3 _. b9 g7 Q# W+ C6 l: d2 x
7.生成代码如下0 n8 c7 N3 E0 J: G
5 T; t9 u3 G: ]% K; J- o+ Y0 w- G. Y+ @' t3 Z+ R% k1 j
7 {- ]' r4 r$ E2 R& `/ Q
配置工程
" h/ f. ?# _7 g/ m1.选中RTOS下的rtconfig.h文件,使用Configuration Wizard进行配置! i: J2 I, Z- C# ]
" w0 b! m! ~% D; q
! D0 e. W$ R. M( f
9 R7 Y2 f J/ N( c! T2.内存管理设置6 l: i8 b: P5 l2 Z
* @, H- z( \4 P* S! x0 _
9 t1 D/ {% h, q+ X6 } ?. E/ I. \! z$ U. q; _3 F: ] v
由于芯片内存很少,我们取消Dynamic Heap Management。勾选上using small memory。8 w" m* A, }0 O1 O& [" v/ t7 V
2 l _" k0 E3 ]( i0 @4 F+ o) ~
3.关闭console和Finsh
8 L! s+ c* w$ k. d* S2 j# x3 v( w1 N$ M. b: ]# B
8 G/ H0 g5 T# Q& o: n( y
1 x( U3 W, F; Z* q
由于我们并没有接出串口,所以关闭串口相关的内容。
& c$ |3 y( r2 ?8 z% K
4 `: M; j# p/ l% V/ Q# C修改代码,测试
3 p) \( e& W* a+ p$ `修改stm32f0xx_it.c文件' J5 x4 r' [( O- F
由于rtthread重写了部分中断服务函数,所以我们需要将stm32f0xx_it.c中部分函数设置为weak。
$ U6 O5 L) d- [! ^! i- /**
$ W+ a \( C0 n4 e, i! A - * @brief This function handles Hard fault interrupt.
: U! V! P" i* e9 j# _, g - */
' [$ l C, H% d - __weak void HardFault_Handler(void)
0 u+ G5 c& o- B( o - {
5 P( H7 A+ i' J4 X - /* USER CODE BEGIN HardFault_IRQn 0 */) e; ~$ L: v* O* q3 g, H
) L* y/ H; F9 U/ H- /* USER CODE END HardFault_IRQn 0 */
8 G& N. K% S! K8 F - while (1), T! b: J* g' Y6 u
- {( ]% G! Q! W7 ]5 U! T4 Q5 j8 Y
- /* USER CODE BEGIN W1_HardFault_IRQn 0 */
6 o; p5 p# \+ l- W- `% b, U. X - /* USER CODE END W1_HardFault_IRQn 0 */
+ X: b6 L) O; v9 X i1 ? - }0 a) a3 _% V* ?" y9 {) }1 h, U" [9 _
- }
4 z- W% ]# Z$ C* g: z - ; p h1 |8 [) j6 T: e
- __weak void PendSV_Handler(void)
8 E& Q* n' F2 ? - {
: q8 z+ O5 G7 s; b) { - /* USER CODE BEGIN PendSV_IRQn 0 */* Q: J+ Z* W1 F. i4 l
- 6 T! l; u% x& D8 t' i
- /* USER CODE END PendSV_IRQn 0 */
2 J, \. S: b4 Q) Z& b: _ - /* USER CODE BEGIN PendSV_IRQn 1 */
- [$ P* q `2 Y3 Y6 c1 N - 5 f$ C2 U: S) i9 w3 G" F
- /* USER CODE END PendSV_IRQn 1 */
# K) _5 n0 Y/ W5 P - }
' f1 E7 G$ x7 R: e! _8 E - . ]1 T Z' ~& c
- __weak void SysTick_Handler(void)
L& h; O9 K- x* [9 P; a3 | - {
9 d. l/ P( A4 [( l% U/ `- u3 o - /* USER CODE BEGIN SysTick_IRQn 0 */. g8 w+ a K% d
# c7 k, I0 ^6 p0 E- /* USER CODE END SysTick_IRQn 0 */( W4 r; ?$ Q! {4 p
- HAL_IncTick();
* s& g& w/ e$ T' T5 e - /* USER CODE BEGIN SysTick_IRQn 1 */ ^. x* B* {+ _* D
# L% o0 T4 g. t3 q3 |' e4 M' O- /* USER CODE END SysTick_IRQn 1 */
) K1 s0 x; b. B/ V% }8 @+ l - }
复制代码 / H- T: n( E/ I- ]" F
修改时钟部分
( w& l/ F& B" v7 q& r1 N2 \ 在mian函数中,有HAL_Init()和SystemClock_Config()函数,用来在系统开始的时候初始化HAL和System时钟。但是当我们使用rtthread后,第一个执行的函数不是main()。而是rtthread系统的初始化函数,并在board.c的rt_hw_board_init()中进行硬件初始化。- E1 Y& H v/ U& a1 u* M9 j
我们将HAL_Init()和SystemClock_Config()放到rt_hw_board_init()最前面,保证在用户代码运行时,时钟时我们希望的样子。
& i" E- }* ]4 p0 f, R' W* G& d q" L- void rt_hw_board_init()# }- `+ C8 f. k: T9 E" l
- { , g$ Q1 S4 S* k9 Y% q- T4 T3 ]* Y3 G
- /* System Clock Update */& @4 S9 Q+ L n( X; Q( ]
- //SystemCoreClockUpdate();
i: m. J b2 K# B; |2 s - HAL_Init();
8 b% n- s! t* @ - SystemClock_Config();
7 U% ?% d" A& o6 V' @# K: K -
5 E, h- g, P' h - /* System Tick Configuration */: e- s% f$ q u: ?8 E3 @
- _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
" G1 E. A& D( E; D& u - & h" b; P# l6 ~, a5 u
- /* Call components board initial (use INIT_BOARD_EXPORT()) */
. m S, Z$ {1 _ - #ifdef RT_USING_COMPONENTS_INIT7 Q0 F3 C, _% K% _
- rt_components_board_init();0 l( ^, P3 _9 u7 H3 U7 l d n# l
- #endif' C: _: ? ~+ _) _9 _$ b
- 6 Q/ \$ ~6 \; [& X5 c+ W
- #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)# \+ K1 y8 y6 z4 [2 ?
- rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
- p" x4 m) k! g2 s - #endif
+ q3 Q7 i; x. X5 R: V/ _ - / ]- ?, K/ k$ E$ `' p' k
- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
0 Q9 s+ z' W* U9 ]+ D8 L - rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
1 ]- }, e8 E" G8 l/ b2 f6 c, ~7 |" z" ~ - #endif5 a) w" y9 Q4 k' z2 f, K0 U
- }
复制代码 由于我们屏蔽了stm32f0xx_it.c中的SysTick_Handler(void)函数,SysTick_Handler(void)中的HAL_IncTick()也一同被屏蔽,我们将其移动到board.c的SysTick_Handler(void)中。, {4 h5 D- x. `7 [5 Z
- void SysTick_Handler(void)
/ I+ J$ D* w5 m" S3 p - {8 |3 @( V* Z: G8 a7 j- a* ]
- /* enter interrupt */
( u- d* ~2 K) B R - rt_interrupt_enter();
4 P1 f7 o1 w" t0 X3 M6 Q
. {- l- a" l1 m+ i" y- rt_tick_increase();1 V2 A8 W8 _# f+ G( |3 b
- HAL_IncTick();% t9 v5 ?. Y% [: J3 Y
- 0 ?$ n8 C4 \6 z2 v. h, [
- /* leave interrupt */- K% A) f" U' E2 y
- rt_interrupt_leave();
% A" [" B( H( U/ S8 T/ O5 e* G - }
复制代码
2 f' ]2 |/ J# u3 v增加用户代码
4 J& X6 s# @/ N, e - while (1)3 S8 D# y* t5 W% Q, b2 O) ^
- {
9 f2 ^: h, U# h4 I6 n) W4 | - /* USER CODE END WHILE */
2 T0 V7 A, k( B* h4 N8 s2 e - HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_RESET);( j/ R9 w/ `+ s
- rt_thread_delay(500); ) A' o& ]) ~5 @1 Y/ K. V& A5 w
- HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_SET); 1 i0 G: J5 o: R. P: [
- rt_thread_delay(500); " ]+ N2 R$ A9 p$ p M
- /* USER CODE BEGIN 3 */5 m% z: O0 j- q& q9 s$ M6 M+ r7 ?
- }
复制代码
. p M3 g: I! P8 }- S! F% {编译测试2 X# X% Y# t/ c* }) E( O% M
1.使用ARM Compiler version5 进行编译,结果如下:
7 x3 K) B$ y9 {; y6 p
2 x5 f$ Y# S5 C* @9 ^" Y7 A
; L5 W2 G: V* _& E0 R0 T, k+ F6 Z( }* E
2. 使用ARM Compiler version6编译,结果如下:+ S$ b3 p S( ^( x6 z+ I; H# w
. K8 J, F4 V% i5 C5 ?# f. i" y" O' d( f4 ~+ V
/ A; a5 n, x: u+ G& D$ ? 相对于我第一次写关于ARMCLANG的博客,已经过去很久了,目前很多中间件,以及STM32的HAL库都已经能很好的支持ARMCLAGN,推荐大家使用ARMCLANG编译器进行编译。* p k& u9 m* C2 `) D
" B5 O1 x$ u: c2 p
, ]+ l7 W/ P# P, N |