1. 准备工作
9 {/ Y; s/ p6 K: Q- i& J# ~1)FreeRTOS源码(选择所需要的即可)。
% u% E3 \! V, f7 v
- o5 O, w( ~" N. ?( N( q/ }2. FreeRTOS移植
: t8 {$ T3 E3 \. _+ w: Y* Z2.1 添加FreeRTOS源码) Z/ C: _7 ~9 n( t4 g( V
在案例文件夹中新建一个FreeRTOS文件夹,以后将FreeRTOS的源码添加至该文件夹里。根据前一章的知识点,portable文件夹里只需留下keil、MemMang和RVDS三个文件夹,其余都可以删除。
6 r! X( _# f0 y0 O1 n2 G$ t
$ H D) i' T7 l& s- A+ I) s
H0 `6 L( }2 n- {! P+ Y2.2 在工程分组中添加文件3 d" G @: Y6 Z. y
打开案例工程,新建分组FreeRTOS_CORE和FreeRTOS_PORTABLE,然后添加文件。 FreeRTOS_PORTABLE分组中,port.c是RVDS文件夹下ARM_CM3中的文件;heap_4.c是MemMang文件夹里的。MemMang文件夹里有heap_1.c、heap_2.c、heap_3.c、heap_4.c和heap_5.c,表示五种不同的内存管理方法。
" o- W7 n- t& t, D- S
0 d9 u/ ~3 ~$ d) @1 n c
# k/ F9 R+ r( L5 ~3 W, |2 B" V. k }$ k* W
2.3 添加头文件路径2 R0 v9 o- C4 i( Q0 `- I
如下图所示添加头文件路径:) o% @3 |3 j/ e2 @( |$ ]# X
V+ B: ]. B: e
+ ]3 @+ P2 s& K) _( _
+ V6 s! z7 r6 S* A2 I6 L
头文件路径添加完成后编译一下,有如下错误,提示打不开“FreeRTOSConfig.h”。
0 ?6 S5 v/ Z' A9 e- \) ?这个文件可以在FreeRTOSv9.0.0–>FreeRTOS–>Demo–>CORTEX_STM32F103_Keil文件里找到。
9 U. f8 Y- q/ O8 D: ]& k. ~
# @0 D. o& W( H/ `- f8 N' }" u4 R3. 修改SYSTEM文件夹里的文件0 @+ E4 ?9 M. H. V+ P5 Y3 ]3 K, }
SYSTEM文件夹里有三个文件:sys、delay和usart三个源文件和头文件,这是正点原子团队开发的,但不仅限于战舰v3开发板。
7 P# k( ]. e; O* V4 J$ e8 p6 N9 J! m; f. ]* K" x: W
3.1 修改sys.h文件
' m+ H+ U' K" @4 xsys.h文件里面用宏SYSTEM_SUPPORT_OS来定义是否使用OS,具体代码如下:
# ~( Q1 u2 `/ d* T$ G* w# U' P; i7 K y- _ C& M
- #define SYSTEM_SUPPORT_OS 1 // 定义系统文件夹是否支持OS,0,不支持;1,支持
复制代码 & N- }6 Q. V+ ^
3.2 修改usart.c文件 ^7 l5 |! ~: j' E# P
usart.c文件有两个修改地方:6 M% K: a1 O4 Y) F! X4 m
一是添加FreeRTOS.h头文件:
) C$ u* s3 p9 Z; U6 J
% X9 a5 g- t& Q& r" k& [- #if SYSTEM_SUPPORT_OS
& I+ N; T! q# z& p* X( O0 A - #include "FreeRTOS.h"3 T+ T7 M3 w! Z7 q) B$ S( F
- #endif
复制代码 . S# F0 ~+ m/ [( i+ e. E8 F9 M
二是USART1的中断服务函数:8 A1 W3 k) v$ W* k A) s
$ v) Z: t3 J+ G1 i
- void USART1_IRQHandler(void)
& I% E9 Z* [5 W - {) H) Y$ [+ [8 ?3 w' i; ?( H
- u8 Res
/ Z/ q# g- U9 @; v2 Z! Y" y q6 D - if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)* C/ F9 Z' f% c; s
- {
9 K4 N1 V. L+ p y3 }2 l) V4 Q! p - Res=USART_ReceiveData(USART1);
8 v1 _" R" g5 W$ L/ O+ Q6 x - if((USART_RX_STA&0x8000)==0) // 接收未完成$ H' t3 q+ p$ o7 j6 i
- {
) F" v' I3 B' h ], g - if(USART_RX_STA&0x4000) // 接收到 0x0d
9 d; \# F# z! b# p/ x/ D* s - {
: X( a/ L* z0 k7 [+ U - if(Res!=0x0a) USART_RX_STA=0;
1 O. `: N6 D* b2 ?: V - else USART_RX_STA |= 0x8000; f6 t9 _4 V$ K
- }' ?) W0 g6 { d0 k7 V7 t
- else // 还没接收到0x0d' n5 v& ^2 }$ P
- {
0 u! O+ |& v2 v) M8 V5 y( g, k - if(Res==0x0d) USART_RX_STA |= 0x4000;, r; w8 d \) w6 ]
- else1 N; ?: F4 O w! k% J
- {7 O, K- g: z$ N" q% Q
- USART_RX_BUF[USART_RX_STA&0x3FFF]=Res;! } ~: V# y3 X8 K w1 A
- USART_RX_STA++;. d1 F p6 Q0 z$ L3 {8 s% k+ [; Y
- if(USART_RX_STA>(USART_REC_LEN-1)) USART_RX_STA=0;
' q6 z* e& T6 P5 {; A( H - }
- |& Y- g; B; J6 W - }& P" q: x; X) m0 y4 L0 p- `
- }
9 h/ E/ _- J6 ~, e5 w* K - }9 G* J( ^( ~- J! }+ f1 h2 z
- }
复制代码 ; f$ Q# g9 s) F7 J+ z0 b
3.3 修改delay.c文件
" Q8 K- N* E+ }9 u pdelay.c文件修改地方比较多,因为涉及FreeRTOS系统时钟:1 a) N9 x* H/ q d# p
1)SysTick_Handler()函数1 S, h: T( Y: i* }& K; R! R0 `
$ W" C+ a! b8 L2 n- extern void xPortSysTickHandler(void); // systick 中断服务函数,使用OS时用到
2 w) n( k2 ^/ J) ?& H6 b - void SysTick_Handler(void)% x2 Z! d, V, P/ [. q
- {
5 s# Q/ D! g9 C8 S - if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED) // 系统已经运行" |; i: p; D; q4 Z
- { xPortSysTickHandler(); } ~6 r6 D7 ^! R- N; m- Z
- }
复制代码
* J% G: R( S5 a, KFreeRTOS的心跳是由滴答定时器产生的,根据FreeRTOS的系统时钟节拍设置好滴答定时器的周期,就会周期触发滴答定时器中断。其滴答定时器中断服务函数中调用FreeRTOS的API函数xPortSysTickHandler()。
( `$ o2 g- K* J2 s# J; V6 F9 r5 [" i, e% D0 W
2)delay_init()函数
; b, U2 R/ f. u' n) q
; K# u" I( o) J; f F( O- void delay_init()
; L3 a u5 q% K. ^8 h1 K - {$ k8 n; Y3 r" v8 ]4 k
- u32 reload;
1 R2 o) n2 x! d( q: q - SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); // 选择外部时钟HCLK
1 [) d/ X5 _7 P6 } - fac_us=SystemCoreClock/1000000; : ]+ o. v# M8 X" C5 w. e4 D7 D
- reload=SystemCoreClock/1000000; // 每秒钟的计数次数,单位M
) z7 p, W- ~2 V1 Q6 }* G - reload*=1000000/configTICK_RATE_HZ; // 根据configTICK_RATE_HZ设定溢出时间reload为24位寄存器,( p# U }5 e! E: ]: w4 S, Z9 T! r
- // 最大值:16777216,在72M下,约0.233s左右
8 o) ~9 T3 V' _ - fac_ms=1000/configTICK_RATE_HZ; // 代表OS可以延时的最少单位1 j* S, n* Z8 e
- SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; // 开启SYSTICK中断 7 p% {7 u0 N3 W7 B
- SysTick->LOAD=reload; // 每1/configTICK_RATE_HZ秒中断一次
" O* g p5 l0 _2 M5 k) V6 b - SysTick->CTRL|=SysTick_CRTL_ENABLE_Msk; // 开启SYSTICK: ?! i) o# e4 M, o
- }
复制代码
* k# C! L# E9 w" _" e. Ndelay_init()用来初始化滴答定时器和延时函数,根据FreeRTOS的系统时钟节拍初始化滴答定时器,其节拍由configTICK_RATE_HZ来设置,其值可自由设置。4 A- U( I2 P, z* G" f( [* X
接来下是三个延迟函数:1 ?$ v( b* p) _2 ?* n. J3 F
9 u' w( A4 K' [3 y' i7 x
- void delay_us(u32 nus)7 }% u o4 X% v5 p* }8 X
- {
1 z, A3 l. [6 r9 z9 N% c - u32 ticks;/ I5 x; f- x) b, S% h
- u32 told,tnow,tcnt=0;4 ^/ V7 w' V% [( P6 |! _* c
- u32 reload=SysTick->LOAD; // LOAD的值 O% ~3 a& l: e# ~: U6 R* ]
- ticks=nus*fac_us;/ b& N0 D4 s- C4 y/ G- |% ?; j
- told=SysTick->VAL; // 刚进入时的计数器值4 [) J. V) G+ D
- while(1)
6 P) O: Y7 e1 E1 n - {
/ ]! v8 h* f, N - tnow=SysTick->VAL;) G4 i3 p8 X$ J" t# I
- if(tnow!=told)
+ V) V" s# ^" X" m - { // 这里注意SYSTICK是一个递减的计数器$ p+ e, j1 M5 |4 T# N. Y) I+ [
- if(tnow<told) tcnt+=told-tnow;
6 W( ~2 s! K& S X! n( K/ V: F - else tcnt+=reload-tnow+old;( E( Z4 `2 |1 O
- told=tnow;
+ F: z+ a- k! b2 t( } - if(tcnt>=ticks) break; // 超时
2 K9 q# i) ^) E; A - }9 M/ @, d0 K* y- n
- };( _3 H+ z* ~: C7 m1 S
- }
. G9 X* q- _7 U$ [ - ; T! Q* J& T) C9 ? @! v
- void delay_ms(u32 nms)
- f: s! g0 a2 k/ V - {
9 v1 u" x4 f& h. i8 ] - if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED) // 系统已经运行& i6 B* g7 Y D/ G: ~( w6 p
- {7 `8 t- W1 f# X9 |9 g- w7 Y" \
- if(nms>=fac_ms) { vTaskDelay(nms/fac_ms); }. C: K) [2 ^+ ?6 u
- nms%=fac_ms; // OS已经无法提供这么小的延时了,采用普通方式延时! N T; H. u7 A9 l" U: M) l$ o8 n
- }# J, ?' E! {' D6 t' [
- delay_us((u32)(nms*1000));! t) p1 K) [; ^) o7 i
- }! f q) x9 E; f/ e6 Z& E" p
- ( c' v* [) B8 D, f4 D
- void delay_xms(u32 nms)3 c1 b* Q5 A2 N, v _" t7 @
- {, j) ^+ {' w7 }* w+ @
- u32 i;
2 g$ t- P1 w: P% z7 X% y* [. Y1 ] - for(i=0;i<nms;i++) delay_us(1000);6 K: }0 B( _& T" m. u
- }
复制代码
: P5 q% K4 ^5 O! D M3 Y Z* edelay_us()和delay_xms()不会导致任务切换。delay_ms()是对FreeRTOS中延时函数vTaskDelay()的简单封装,所以在使用delay_ms()时会导致任务切换。2 A x# }' C- P. D" U
delay.c修改后编译一下,如有错误提示在port.c、delay.c和stm32f10x_it.c中三个重复定义的函数:SysTick_Handler()、SVC_Handler()和PendSV_Handler(),这三个函数分别为滴答定时器中断服务函数、SVC中断服务函数和PendSV中断服务函数。可在stm32f10x_it.c中将这三个函数注释掉。
5 B9 i6 D+ |- c" N
7 C @! W. o# W. }
& ^ h, ]: }# w% w) H8 b) t
) _; Z- a8 U4 Q至此,SYSTEM文件夹修改完成。* t. c" o7 ~: n4 E5 T7 ?+ _
————————————————
) d- i4 M; U! q% ?版权声明:天亮继续睡
1 W0 x- c. R! C$ l E
0 O9 r! v9 X0 }* A# B7 r+ X7 k9 Y8 A" ?& w9 d% p* b
|