硬件介绍
3 B2 ~7 t9 @) o% \" E 我手上开发板使用STM32F030F4P单片机,无外部晶振,所以直接使用内部晶振。开发板上有3个LED灯。
$ y8 b! w, E9 _" S0 ?: T& w' j
% D- c U" u6 r! |, H: |+ a7 K7 u0 @/ y
+ Y" y. Z8 S* V0 V0 |2 b$ B3 ~
安装rtthread_namo包
( |. v8 f) l; r$ ?! n在操作前,需要安装MDK5软件,以及STM32CubeMX,并安装好STM32F0的Pack, A# v( d5 I9 a3 Q; m
# S9 o) E+ q: G) `! k) u' d( {1.打开MDK软件的Pack Install工具,选择RealThread:RT_Thread进行安装# e( k* i- @8 @' w8 q- I" g' |5 G
6 c$ K& ?; q2 C8 \- v6 S9 r% i
$ v# F( Q4 f0 s5 M5 [! B9 t' P8 C. u% u! d) h) ~
2 a2 L6 }( i: T, q5 n0 M
8 P( P. X7 p* d2.在弹出的节目中选择Next,等待安装
% e) W, V7 U( H% A+ r& C, [% ? T- G; v" b
8 V9 V$ X5 I9 s6 ?8 r1 G& F0 D7 B: e; w, P
3.安装成功后,Reload Packs即可。
2 `. [5 O i7 L7 ?2 T: \8 o7 q' v2 e) b% p& M C
7 x* ?" f& w5 b
0 }4 G$ Q* Y# |7 Y6 L9 E创建工程
9 j( G/ p8 [- ~0 d1.选择芯片STM32F030F4P6" b& O* w( y& P( g
d, P" T! B% }3 V7 ]
9 |7 |- d6 K# [6 q- B5 F
; v5 a4 t o3 v3 C% D. k2.Manage Run-Time Environment
" t+ D. }+ {) E+ h2 W: m/ N+ u$ v: s
$ ?7 G6 r; k9 o$ b- Q. R# l2 G
0 @6 }" s- |$ k' f7 M6 g 按照图中进行勾选,由于我们芯片资源有限,而且这次的电路并没有接触串口,所以在RTOS部分,我们没有勾选shell。
6 n( n* c- p" {$ o3 s! h& \
( k6 C% D- H8 y1 b3.Start STM32CubeMX
1 i5 z% g1 {$ z. O) e& t3 d0 E, g+ B; R- Z7 F) |7 R5 N# m
% r$ O7 t v( k9 E+ m
" }3 c% h) D6 b$ x5 D" F" V2 R 勾选完Run-Time Environment后,会自动弹出启动STM32CubeMX的窗口,我们打开STM32CubeMX进行配置。6 n( B- O2 z0 g% y6 I
$ J# a( f' ]! w/ ~4.STM32CubeMX配置Pinout&Configuration
: S+ `% l& E! o: a ^" S X0 m# ]
& u$ h4 t( V; J3 g
6 v+ L7 s0 P1 |- e# D' B, j, h+ h8 ?9 w. j* y) m
- [. X: T7 o9 s
0 |. Q. F+ u+ M9 p& c5.配置时钟
9 E+ [4 y, E" {# h+ A- C6 f% G, M
9 A1 s( q7 i1 u V G1 o, {, f2 d
/ U1 X' U; [8 D7 G) e* [7 Y ^6 O9 ]: v' C: |% R
6.单击生成代码
3 P, r$ T- \, y" \+ D6 r4 Z" b6 r$ b- ~9 S/ b5 z$ K* _! s6 ^
4 k! |) q; L9 Y3 Y' C" |7 |. w! |. ~# `% m0 D9 B9 y) N9 q
7.生成代码如下! q8 k- A) y" u) v: @
/ M1 \0 M; S" s& e2 W
! W/ W `% ], F" T3 }2 S3 P+ V* R- \! b1 {* @. C- v0 \6 o! I. W
配置工程
) p6 j, @5 W, L: c1.选中RTOS下的rtconfig.h文件,使用Configuration Wizard进行配置/ i+ t' b4 J) v, R0 _
( G2 x) u. u( s0 N) ]
6 N$ t+ d, E' q* A+ X
0 ?: U c2 H; |- @" n2.内存管理设置8 Y- S) x6 x' r6 m$ X( c
( |! D3 P) ^" u
- U& y* D* V8 I6 y
1 _: d5 ~6 W& q1 u* _5 J7 `5 Q 由于芯片内存很少,我们取消Dynamic Heap Management。勾选上using small memory。
. Z9 q$ m5 `. [/ M. _" e. A4 j- \9 W$ Q5 z* n+ s
3.关闭console和Finsh
9 R8 i2 _6 e% R; v( O" x% e3 }+ Q9 _$ `3 l/ ?4 a S
x4 B0 v6 U" h5 I7 b/ k+ E C
8 d$ S0 p3 ~1 m' Z 由于我们并没有接出串口,所以关闭串口相关的内容。
k% l! s' X* z( ^+ B. s9 F; T8 d5 I1 ~9 `
修改代码,测试
* B+ u' |+ u/ ?修改stm32f0xx_it.c文件. A4 p6 V+ ~7 n$ U
由于rtthread重写了部分中断服务函数,所以我们需要将stm32f0xx_it.c中部分函数设置为weak。
* f- t( t$ j5 [0 g' k+ ?+ L) ?0 C- /**
. W* W* Z: q2 j9 g& i1 H+ O g - * @brief This function handles Hard fault interrupt.. p* J! e1 D( I0 }5 w# o4 _
- */; X/ `: V3 A+ V; M0 H. s! k
- __weak void HardFault_Handler(void)3 I3 d6 u( b0 u& e4 k
- {
: ` D, g C9 G- d - /* USER CODE BEGIN HardFault_IRQn 0 */
, N; \) i- K8 P& k% N: z
* `0 s1 C4 d- X: p" _# G- /* USER CODE END HardFault_IRQn 0 */
6 {- a0 H, Y1 L6 }' I1 E1 ? - while (1)
8 |& b: B- Y7 i7 B; F, k - {
$ K5 W4 T" e8 f6 S# ? - /* USER CODE BEGIN W1_HardFault_IRQn 0 */
4 X# r [: y, l: D4 M* V: ] i0 q - /* USER CODE END W1_HardFault_IRQn 0 */3 Q: J- p3 o, A+ k4 w
- }
+ F0 w: \) h2 h* w& @- N, A5 {& \; \ - }5 M; E# @( \8 `" R& D2 T
- 1 l6 H8 M9 d/ p
- __weak void PendSV_Handler(void)
* E! O6 }7 ?. e) Q4 s - {
- v9 m- Z. u/ q - /* USER CODE BEGIN PendSV_IRQn 0 */. N% g7 S) q. c3 X
7 G& E2 S7 _# K- /* USER CODE END PendSV_IRQn 0 */8 E( \2 `4 C6 @
- /* USER CODE BEGIN PendSV_IRQn 1 */ N2 L7 ]/ G0 U% R
- 5 I9 }& w/ e u9 g5 x. ?' \# T6 D
- /* USER CODE END PendSV_IRQn 1 */% w1 j0 V/ \* M7 A* ]% N8 W5 j
- }
9 V3 {- h+ D0 `: p6 u6 j4 ^# y& m
3 V9 w. b9 P, ]' G$ q: }% H- __weak void SysTick_Handler(void)
: ?% S5 J: @. p7 G - {& M5 ]4 s) _. h: {
- /* USER CODE BEGIN SysTick_IRQn 0 */
( ~& [- r0 W2 ]6 R m- e* A
, Y, ?2 _" I( M; W/ \ y0 W- /* USER CODE END SysTick_IRQn 0 */( S1 J8 u+ p5 i; M
- HAL_IncTick();
! D# ~3 W; K" @2 _7 R b A - /* USER CODE BEGIN SysTick_IRQn 1 */
4 P; }5 O' k% {$ C/ `
' ?& ?: t, w" P9 |1 J- /* USER CODE END SysTick_IRQn 1 */
5 R) T& x2 x1 j2 B1 D5 l3 ^ - }
复制代码
' H. T8 r% z3 U/ q" S5 T修改时钟部分& e8 y: a7 g1 g4 }4 P. X. i$ K
在mian函数中,有HAL_Init()和SystemClock_Config()函数,用来在系统开始的时候初始化HAL和System时钟。但是当我们使用rtthread后,第一个执行的函数不是main()。而是rtthread系统的初始化函数,并在board.c的rt_hw_board_init()中进行硬件初始化。: @* w! s1 O9 _8 D8 p: O/ M, |+ G
我们将HAL_Init()和SystemClock_Config()放到rt_hw_board_init()最前面,保证在用户代码运行时,时钟时我们希望的样子。
9 @, I! M) N: s9 ?+ q- void rt_hw_board_init()4 S3 u( p3 v ]) \8 y
- {
3 p* M/ w; A: {9 C4 r - /* System Clock Update */
K) U; u+ g& L2 \- Z - //SystemCoreClockUpdate();
& C4 z9 g3 n+ s0 m; [! u4 F - HAL_Init();" Y2 ?/ c! H- P, Y* K/ p% K
- SystemClock_Config();
: Y1 P2 E4 o9 w' F% Q. | -
% x: T/ e8 y1 E - /* System Tick Configuration */3 Z! t2 _8 y S$ p% H5 k$ K! {, s
- _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);5 f- {8 a; R' _" _9 V3 r
- / D/ a: G, I& M+ z* T
- /* Call components board initial (use INIT_BOARD_EXPORT()) */ A: X+ l4 ?$ V1 t# G8 A+ R2 N: C5 o
- #ifdef RT_USING_COMPONENTS_INIT
+ o) Z% p; S9 J, ?1 ^6 ? - rt_components_board_init();
0 f* H5 c. l: \* x3 B' | - #endif
3 Q# ] ~7 D( P% T3 q6 z& ~4 }% \ - , m' L' T' s/ _+ j y0 ]
- #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
' v* m+ O4 a" U! o/ V& l5 n N$ Y8 N d - rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
$ t. g) \8 s0 e- F3 P* r; j - #endif
8 A9 S7 H, w& Z4 U0 b* ^! n# [ - ( I9 j! y/ h5 s: H* E( R5 x$ o
- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)* |+ u5 f! F( d
- rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
$ z4 E1 |& q8 x - #endif
. {. Y& W' r- Y; u( A2 U - }
复制代码 由于我们屏蔽了stm32f0xx_it.c中的SysTick_Handler(void)函数,SysTick_Handler(void)中的HAL_IncTick()也一同被屏蔽,我们将其移动到board.c的SysTick_Handler(void)中。0 s; |9 X3 d/ f4 S2 s" G: q
- void SysTick_Handler(void)
5 @& e: V( k/ |8 C+ i0 o% C - {
7 Q8 F8 M% j0 @4 P" K - /* enter interrupt */0 \( ]7 ^' o' z
- rt_interrupt_enter();" {( o9 Y5 @- |4 K7 l
- G8 Q/ [4 a% I$ m6 V
- rt_tick_increase();
{" ?+ l; H' c2 j3 Z4 f8 M2 A - HAL_IncTick();, o# k' |- `7 F
- ; R* ^. f# X/ t
- /* leave interrupt */
; Z" B4 @$ G5 A7 B1 n- a - rt_interrupt_leave();% _3 \% [; M9 \' r- K
- }
复制代码 9 E. m' q* {$ q+ J( z5 k
增加用户代码
E- m# a9 n. ~9 G' X - while (1)' ?7 S: U" ?) T9 G) n# e
- {$ a& g5 u" |, ^2 `+ U# K; ?5 z
- /* USER CODE END WHILE */
7 H$ r2 m, X& U( ^6 ?+ v) ~ - HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_RESET);
7 P$ z; X7 w7 I3 i- @5 f* M - rt_thread_delay(500); ) q1 l6 s3 T7 x5 A, F2 B
- HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_SET); ! j- v1 ~, }" U O3 t+ J1 Y
- rt_thread_delay(500);
# |, U, H, F% C/ B0 I. z - /* USER CODE BEGIN 3 */
5 e+ i1 w( {8 Z - }
复制代码
# b! f0 n/ z6 b6 a编译测试
4 B9 V/ u- G% H% v1.使用ARM Compiler version5 进行编译,结果如下:: J+ r; n, O. V* I. Y* n$ g- T
' y" ?2 v9 @8 r8 s& \9 E! {3 D* d3 E3 R8 |8 F
' }0 q' C% q; c2 g$ w) k7 v' S
2. 使用ARM Compiler version6编译,结果如下:
( g+ L \' L* ^( S3 a- n
& |! [, Z0 o; o7 k
0 x! v4 @, M7 \ K
( J, I% y. q1 P0 {: F! v+ [0 c 相对于我第一次写关于ARMCLANG的博客,已经过去很久了,目前很多中间件,以及STM32的HAL库都已经能很好的支持ARMCLAGN,推荐大家使用ARMCLANG编译器进行编译。
1 {: D( y# Y: F, M5 w6 Q
# | L$ b- i' m7 m
. G. K e; f/ ]4 R* v. V |