硬件介绍& g- Y1 o+ N6 [6 V; j
我手上开发板使用STM32F030F4P单片机,无外部晶振,所以直接使用内部晶振。开发板上有3个LED灯。0 p; a/ s, Q A3 Q3 {! Z' m
: L1 |3 t1 M3 R6 u! d1 Z
% g+ O7 g# T" {7 z! h$ {
+ m) D+ T) z. S; E7 e) J/ G' O* F安装rtthread_namo包
$ z1 _" K- V0 B在操作前,需要安装MDK5软件,以及STM32CubeMX,并安装好STM32F0的Pack, H K8 X/ @" Q7 ]$ n1 K" Z
2 i/ S) h& }* ^/ X3 E1.打开MDK软件的Pack Install工具,选择RealThread:RT_Thread进行安装( z7 Z" B' `6 g2 M. d/ v4 w
9 J `9 E# H8 z& F3 Y/ m5 j! b, J+ `: i$ [* H, Y' } o7 I X. J: A
* f0 ]2 ?: ]+ _) Z8 n
. l! f G+ g# z9 @9 D
: k- k8 `4 G0 F" F7 J2.在弹出的节目中选择Next,等待安装3 n1 ]( }" N! A$ F
" _/ `/ z* ~ o
! k, D# f3 u! N. o# ?. ?1 B- S j$ Z" G r
3.安装成功后,Reload Packs即可。
0 y6 T9 x, v' ~8 w; J
4 U* F5 n/ O* M% K3 \/ i/ X) ^ {1 p4 @( [# x/ l1 c: E; D; p
3 {! P9 c( w) ~+ ]创建工程
6 D7 m* r! ?2 i1 u* l! ~* `1.选择芯片STM32F030F4P6
" D* S3 X% Z; _* U
. x8 l2 k5 J X3 z& L0 l/ n' e6 C9 t6 @. D) C) R
$ |: z2 A6 `* g: i" E
2.Manage Run-Time Environment
% v; ~6 d5 H" W9 ]% Y: \- n
5 \9 b7 {" p+ U
0 E. q" g* n9 I5 ^. v( h* k. f; U0 l: z$ a# s
按照图中进行勾选,由于我们芯片资源有限,而且这次的电路并没有接触串口,所以在RTOS部分,我们没有勾选shell。
5 z/ T1 X% i0 n3 i8 c4 j! w" @5 c$ |- k7 h7 w) k7 }8 g6 ~% n
3.Start STM32CubeMX0 H6 G0 o- r: i2 h( g' e& a
7 K9 }" R4 A* z1 e' m+ ~6 A( p2 e) x! z: S d- O' C( Q
" t @9 c; {' }8 [% S+ z
勾选完Run-Time Environment后,会自动弹出启动STM32CubeMX的窗口,我们打开STM32CubeMX进行配置。$ {2 D0 J1 i# H: @
( S V* I8 p3 N0 V" p$ n- a0 [2 {4.STM32CubeMX配置Pinout&Configuration
5 ?. v* Q5 V8 q% U7 d/ |$ `4 a) O: z9 p" `, @' }7 R
/ p Q* ?. S7 B7 v5 c$ B7 y! F j0 f, J+ l! [# p
( F1 f9 U9 {1 E; N% ?7 Q& H9 ^4 t* Z7 _' r1 j: ?1 ]
5.配置时钟
$ \/ E9 K$ V @+ N: Z! m6 ^1 G3 A) _2 _( D
- g* S, {& o2 P% J5 S% y
D J; H/ J1 Z6.单击生成代码 C7 q; I' Y/ O( \) L/ h
: r5 s% B. H( c0 E# w
% Y0 W% t: u2 l3 ^- n6 s% H8 y# _* y9 ^2 ?3 ^$ t
7.生成代码如下* j, ?( W. g: k9 E% n
b; V. m5 Z1 M* }
1 Z" F& _3 N# |/ {* B) B o
; l+ u- f& ^4 I! v, g0 u# p
配置工程* F$ j' b- @ h+ B3 s( ~ O1 o
1.选中RTOS下的rtconfig.h文件,使用Configuration Wizard进行配置( ^% v' m% C$ s2 H8 C
1 |3 k( T- q8 p7 q- q7 ]8 Q# |
' q2 v) r$ i& _1 u; [; n
# B" g8 c6 t. o( R
2.内存管理设置- Y$ o2 K/ _, d2 J
9 z) j# l, {6 @! L" P
; t' D2 O8 C5 n E
7 f# k" w( V+ M! u: N% d 由于芯片内存很少,我们取消Dynamic Heap Management。勾选上using small memory。
6 \ u+ R0 m5 Q6 {
( f I& v$ L# Y5 u0 D/ C3.关闭console和Finsh n( G7 ^ C" O' f8 R
7 ?) ^" @1 I# v
2 \: U0 ]( e h3 g
- a9 S0 `8 p+ S) f5 V 由于我们并没有接出串口,所以关闭串口相关的内容。
2 y9 }4 F- ], N& {- r9 G$ p4 Q: h% Z5 b3 Q4 {; W
修改代码,测试/ T/ _% ~& i* \6 V6 |$ Q
修改stm32f0xx_it.c文件" X9 j5 m' f% n8 |! C. F
由于rtthread重写了部分中断服务函数,所以我们需要将stm32f0xx_it.c中部分函数设置为weak。/ H- P) K+ ] s3 Q( p
- /**
, I/ X8 z+ b8 P* h3 j- k y - * @brief This function handles Hard fault interrupt.
; e/ i5 @: t- T/ E9 k2 R3 U& e1 X - */% o- t/ M" Q' L
- __weak void HardFault_Handler(void)5 B! q- [5 d* M4 Q$ w
- {, O$ f7 ]+ ^* B- c, t& }
- /* USER CODE BEGIN HardFault_IRQn 0 */4 R1 d$ V4 P6 g% n8 v
- * e) g& d3 Q& J p% l
- /* USER CODE END HardFault_IRQn 0 */
: ^) _& H0 ]( y/ k* o7 b2 }( G - while (1)
' Q, P$ r- i) m, \: Q+ i8 ~ Q - {; M' y0 @) [$ f( ]+ ]2 ^ i) U
- /* USER CODE BEGIN W1_HardFault_IRQn 0 */
( ]( I5 t+ A7 W- F( z - /* USER CODE END W1_HardFault_IRQn 0 */
+ {$ @* T0 t8 P - }5 U) d( D$ [% E
- }
! K# { j3 J* |9 m5 A2 e% q+ V - & k. L5 V8 A+ W
- __weak void PendSV_Handler(void)- c7 G2 a K Q, w
- {
% E% c1 \0 R. O5 @ - /* USER CODE BEGIN PendSV_IRQn 0 */) Z: \8 [# O& h
0 S5 A3 b0 O& N! Z2 O; q, d- /* USER CODE END PendSV_IRQn 0 */
7 M7 j8 f0 u3 y - /* USER CODE BEGIN PendSV_IRQn 1 */
( M" Z0 L0 M" O$ ~! { - 0 d' D G5 W+ i/ ~8 G m K
- /* USER CODE END PendSV_IRQn 1 */
: o, T; i C R L+ \# v, y - }
( O* O( e8 t" R5 @' {' T - 4 J- }) ]: n% v1 m0 Z
- __weak void SysTick_Handler(void)0 D- w& i/ X9 ^3 i+ `2 D& w: M
- {# y# M1 y- i' o' f, S
- /* USER CODE BEGIN SysTick_IRQn 0 */
$ X' v1 I* S2 z9 @) P5 C8 S' ^2 P
2 \ q# }- i- M9 S1 l- /* USER CODE END SysTick_IRQn 0 */
* y" } m0 ?2 A2 r* W6 D, p - HAL_IncTick();8 e. v& B0 e' Z
- /* USER CODE BEGIN SysTick_IRQn 1 */
; h6 l( Y' ?% P8 h" C1 y' i - $ Y4 ~1 m2 J& @
- /* USER CODE END SysTick_IRQn 1 */
; w3 m' V2 l3 s/ l8 Q - }
复制代码
/ V) B9 n. F! r, t! K( ~) | K r修改时钟部分
2 X" C+ n' X$ K3 _; c- y) s 在mian函数中,有HAL_Init()和SystemClock_Config()函数,用来在系统开始的时候初始化HAL和System时钟。但是当我们使用rtthread后,第一个执行的函数不是main()。而是rtthread系统的初始化函数,并在board.c的rt_hw_board_init()中进行硬件初始化。
" `" ?. X4 s ?; @# ^ 我们将HAL_Init()和SystemClock_Config()放到rt_hw_board_init()最前面,保证在用户代码运行时,时钟时我们希望的样子。$ \5 q2 w# ^1 ? Q; F' H
- void rt_hw_board_init()+ Y9 U( t/ `8 K0 x
- {
/ d" g0 y2 O3 d3 }" w( ~ - /* System Clock Update */. g7 k: e8 Y0 l
- //SystemCoreClockUpdate();
' N! \2 w$ Z2 i* f+ p9 Q. i" d( Z - HAL_Init();$ v: s% T8 } A) F* q
- SystemClock_Config();. j! w z. z4 v7 [3 _' x& y6 B
- + V$ c% s4 o' a1 ]) L d
- /* System Tick Configuration */
7 e% n! _, @1 @9 ]3 ~& L - _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);& i7 p$ L3 w. t: E
- 1 `$ \# K% {" ]( u
- /* Call components board initial (use INIT_BOARD_EXPORT()) */
' {" Q* ~' S1 }/ Z8 z# a* c3 G - #ifdef RT_USING_COMPONENTS_INIT
* g8 k6 i5 ]3 r; {" \+ m - rt_components_board_init();/ p8 \$ M6 D" u" s/ e. o( _- q) k
- #endif, i2 [( N. E w) d) p- f
# e0 X; R- ~, V- O- #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE): F9 T( g% H9 i/ i, H8 G
- rt_console_set_device(RT_CONSOLE_DEVICE_NAME);: z) M ~9 g9 q3 }# [. r
- #endif
0 R1 K5 L; @; e. M% d - - U3 a* L( [; W
- #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)7 u, Y7 ~4 a' x+ ~1 Q
- rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());- n0 {- e) W, W7 ]% w/ p
- #endif# P$ k& o$ q- N& m1 p& I
- }
复制代码 由于我们屏蔽了stm32f0xx_it.c中的SysTick_Handler(void)函数,SysTick_Handler(void)中的HAL_IncTick()也一同被屏蔽,我们将其移动到board.c的SysTick_Handler(void)中。
! g. s: e- X h: v- |- void SysTick_Handler(void)
: Z: [& U' W# ]) Q. J, r" W - {' l! ^+ n3 n/ f t8 h% [3 ^
- /* enter interrupt */
" A! `0 D. m0 t) t - rt_interrupt_enter();1 q( Z0 B& ]4 _5 @% m; I- L
* [5 b* v- L/ `1 V& E' G% Q- rt_tick_increase();0 f/ c4 K: I0 S! @
- HAL_IncTick();
3 F1 E7 E9 ~. }( ?2 i! s - 6 r* O* d9 e1 N2 T% x& r1 F o
- /* leave interrupt */
` s4 j! _5 J0 d - rt_interrupt_leave();
: m+ ? D4 Q1 L+ \ - }
复制代码 , _- a3 H3 s3 `1 ? q/ G
增加用户代码6 V+ O6 _' u( x9 x+ [
- while (1)
. N% u+ @! Q, X$ T) f1 i" z - {
) ?5 u1 d8 E/ j& D1 y/ Y - /* USER CODE END WHILE */
, h9 n; P# h" I- J, M. z2 L. m4 k - HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_RESET);9 d, E+ y1 |7 j# @
- rt_thread_delay(500); 9 w& v$ @# i7 u7 c9 ~& M8 J5 X
- HAL_GPIO_WritePin(GPIOA, LED_R_Pin|LED_G_Pin|LED_B_Pin, GPIO_PIN_SET); : a6 l' L& W `0 ^0 G: a
- rt_thread_delay(500);
" T& R5 w# r# O/ b8 K- `- O3 d - /* USER CODE BEGIN 3 */3 X1 ?1 S$ E! t8 H* t
- }
复制代码 # Z- Y* I1 u; H4 J
编译测试- X# `- |1 E" C% ^) E6 [
1.使用ARM Compiler version5 进行编译,结果如下:
9 f7 E0 W- F6 N( u
$ O' k x3 h0 g4 Z
& H4 q! c5 ?! ?/ K+ B1 |7 ~
- ^5 u/ x" S/ N' h) s" ?% L" o7 Y2. 使用ARM Compiler version6编译,结果如下:# i( h) b1 y7 O5 \6 _
5 U4 ~$ T( P2 K/ I4 n& a
" D8 F( A" W2 F6 b+ ]
8 B3 I D. h4 X7 }6 f6 j. {1 i0 q 相对于我第一次写关于ARMCLANG的博客,已经过去很久了,目前很多中间件,以及STM32的HAL库都已经能很好的支持ARMCLAGN,推荐大家使用ARMCLANG编译器进行编译。
7 ]; x& ~& L* D$ _6 T3 d5 @* o. j/ z
$ ~/ A7 K9 v) T9 s |