1. 准备工作
7 N0 V4 ~6 i4 h% b0 i1)FreeRTOS源码(选择所需要的即可)。2 o4 V7 I/ G5 T3 l4 R6 V
6 a6 [" \+ L3 a$ c2. FreeRTOS移植# I: c0 E Y6 |3 q- x6 |
2.1 添加FreeRTOS源码1 y3 M' M$ N& Y8 R/ C
在案例文件夹中新建一个FreeRTOS文件夹,以后将FreeRTOS的源码添加至该文件夹里。根据前一章的知识点,portable文件夹里只需留下keil、MemMang和RVDS三个文件夹,其余都可以删除。
6 L, S8 a( \+ P( |3 i, z
/ v ~" n ?: t
* S" c0 C- E- L/ c0 G! i
2.2 在工程分组中添加文件- z" w: E" O+ c/ L. L! P, s
打开案例工程,新建分组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,表示五种不同的内存管理方法。
5 y0 X; Z& ^) @2 p, |4 h' K6 v- }% @
8 i2 ]% Q1 h$ t3 V4 H
3 h4 ^' f5 Z2 E# J2.3 添加头文件路径
9 e1 L6 R: R) @( O; Z" G. t如下图所示添加头文件路径:
. p& I2 l" s8 _; N1 {( i* o! W
8 T2 E$ v+ I0 y! k
1 s& n1 n, E4 n: y% U% M- E
' } E; z4 l/ s头文件路径添加完成后编译一下,有如下错误,提示打不开“FreeRTOSConfig.h”。& P9 h2 X' ~$ c4 L- X
这个文件可以在FreeRTOSv9.0.0–>FreeRTOS–>Demo–>CORTEX_STM32F103_Keil文件里找到。# X, h; @5 ~( f- \
3 l( V9 E/ q2 x7 h. Q5 D. ~5 U
3. 修改SYSTEM文件夹里的文件% _, I( K, a' n5 N/ J: e8 V2 m
SYSTEM文件夹里有三个文件:sys、delay和usart三个源文件和头文件,这是正点原子团队开发的,但不仅限于战舰v3开发板。2 y# O* [7 [' R5 w
2 u+ `( @1 M1 l5 @% ^; z3.1 修改sys.h文件5 N1 k( S, d5 G1 n# X4 { c0 r
sys.h文件里面用宏SYSTEM_SUPPORT_OS来定义是否使用OS,具体代码如下:
% a8 c- u) u/ s; f ^
) q3 U Z; N+ N% x; e- #define SYSTEM_SUPPORT_OS 1 // 定义系统文件夹是否支持OS,0,不支持;1,支持
复制代码
' o% k) ?0 x& c6 w3.2 修改usart.c文件
% U& ^+ X' h$ lusart.c文件有两个修改地方:9 V7 B8 v2 E( n9 X: I- K
一是添加FreeRTOS.h头文件:
/ |: C6 s4 g3 @* C$ u8 K! S9 n+ l# g, K4 h2 p( A, ?/ m4 ~# `( u) I
- #if SYSTEM_SUPPORT_OS
/ @" `) o/ q" q - #include "FreeRTOS.h"
' i, Q- E9 B; Q# o; w+ T- h - #endif
复制代码
* i# A( O8 G* Q$ M二是USART1的中断服务函数:6 y+ M8 f9 g2 i0 K% `$ |& b, o
) c) @# ~7 V6 Y* H; @! Y. A2 T- void USART1_IRQHandler(void), K4 ?$ B) H+ \5 R. A0 }
- {
! B S2 t3 S; A6 W* l& W - u8 Res
6 ]& x/ S0 F; B) e& X - if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)2 \$ {; ]' X. `. f" e# ^1 s
- {+ z& Q9 E: k' I* h
- Res=USART_ReceiveData(USART1);8 ?1 i6 M% Z3 Z5 ?* A
- if((USART_RX_STA&0x8000)==0) // 接收未完成
5 W. K3 j F; T- S. r - {7 }+ l: h; B/ T5 Y' K2 r$ Q
- if(USART_RX_STA&0x4000) // 接收到 0x0d
5 O# g: ^1 J- }0 q3 k* y* a. [ - {
9 K: ]' D8 z- x - if(Res!=0x0a) USART_RX_STA=0;
9 Z5 ?4 m# d; b1 _) P - else USART_RX_STA |= 0x8000;1 w9 f& k( g% R
- }
) B1 D) a0 r& R2 v1 p6 N! v% a - else // 还没接收到0x0d
" s: W8 o$ m( c' F - {7 ~2 o# @ ?, F0 r: P' c" j
- if(Res==0x0d) USART_RX_STA |= 0x4000;) I) ~4 S& I. O' R+ y& ~ C
- else/ I. Y4 R: W5 U+ o' W2 ~$ S0 Y/ o
- {& b) z& F7 A0 Q6 v8 b
- USART_RX_BUF[USART_RX_STA&0x3FFF]=Res;+ k3 ]$ u+ f- Q- }; M) d# {0 d H
- USART_RX_STA++;
0 u* j5 o* b/ R! g' t) k: S - if(USART_RX_STA>(USART_REC_LEN-1)) USART_RX_STA=0;
3 k0 _8 {; i0 d3 T+ m) r2 x( S - }- Y9 F. o1 x* Y0 R
- }
$ a' c$ P. T$ U w6 c - }
5 L" _/ E/ s: k- P- {5 z - }/ @( S! ^/ Y5 H" t* Y3 T$ g! O
- }
复制代码
+ ]; A/ E: a' v. D" u( |$ \2 w- _* H( J3.3 修改delay.c文件
' f- w0 u1 B3 p4 e' Z9 Adelay.c文件修改地方比较多,因为涉及FreeRTOS系统时钟:5 e0 w W! ~2 y0 O; p$ \; u
1)SysTick_Handler()函数/ ]' m7 C# S9 ?+ q. S' [
2 k. G: g, F4 x$ U; M. z- extern void xPortSysTickHandler(void); // systick 中断服务函数,使用OS时用到
4 r+ ~; Y+ a( i1 |0 B8 X- A - void SysTick_Handler(void). N0 _( ?. A4 v7 t0 Q
- {
$ @; P5 l) t/ I+ G' V - if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED) // 系统已经运行
/ A# G& I: V# c7 m) `3 w - { xPortSysTickHandler(); }
5 O4 ]- l9 b' X k0 J0 Y0 H& T - }
复制代码 ; X' [# c( U6 C. H
FreeRTOS的心跳是由滴答定时器产生的,根据FreeRTOS的系统时钟节拍设置好滴答定时器的周期,就会周期触发滴答定时器中断。其滴答定时器中断服务函数中调用FreeRTOS的API函数xPortSysTickHandler()。9 U6 v& K3 E& h7 i& I
, g% f- I0 H- O( i2)delay_init()函数
* l+ ]& c! D; u( `7 x, Y. n
4 [& B, Z# M( a6 ~- N* ] B- void delay_init()
$ l n0 j% X8 r4 D5 G - {' ]) R* Z& f4 B0 d* K
- u32 reload;/ h" J: h3 S2 \
- SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); // 选择外部时钟HCLK i6 p: n( x" V6 t
- fac_us=SystemCoreClock/1000000; " {* y' Y2 i( e& t
- reload=SystemCoreClock/1000000; // 每秒钟的计数次数,单位M6 V# q9 A/ Z3 O# q& T0 b" u
- reload*=1000000/configTICK_RATE_HZ; // 根据configTICK_RATE_HZ设定溢出时间reload为24位寄存器,
* a, c! ^1 S2 h! _$ V# g - // 最大值:16777216,在72M下,约0.233s左右) Q; g8 r) H: ~" x0 |/ H" d
- fac_ms=1000/configTICK_RATE_HZ; // 代表OS可以延时的最少单位; i3 B G" ?9 Q4 ] u3 u
- SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; // 开启SYSTICK中断 9 v! l4 b. X! k" w0 y8 `7 x
- SysTick->LOAD=reload; // 每1/configTICK_RATE_HZ秒中断一次
( z' t! t4 I, W8 ], N. H - SysTick->CTRL|=SysTick_CRTL_ENABLE_Msk; // 开启SYSTICK, a% U5 G0 e2 F. K4 {7 z
- }
复制代码 3 F/ u7 C$ k4 S& O
delay_init()用来初始化滴答定时器和延时函数,根据FreeRTOS的系统时钟节拍初始化滴答定时器,其节拍由configTICK_RATE_HZ来设置,其值可自由设置。
1 W4 x& `, [2 x0 y3 M2 `$ X) S接来下是三个延迟函数:7 y5 z$ c! {+ q a2 Q
6 W" B. ^2 P1 W: B/ R
- void delay_us(u32 nus)3 x( T$ ?/ V8 u f' Y1 P4 i1 S
- {
4 ?/ @: R4 J" d& ~9 S, h2 w# s4 T - u32 ticks;% N) H7 }* t& r, q3 H) M
- u32 told,tnow,tcnt=0;" m! x9 f7 _. c8 x/ \
- u32 reload=SysTick->LOAD; // LOAD的值5 f$ \# H+ x( o+ Y( @5 D
- ticks=nus*fac_us;
; ?& r1 }. m+ Z8 S - told=SysTick->VAL; // 刚进入时的计数器值
2 [% |9 \ ]6 o7 {: B* ^; X3 b$ H - while(1)
% ]$ T5 b* T& n( f2 ]) _( {6 O; A - {! q; a2 ~. q" ~+ i! @' I% l
- tnow=SysTick->VAL;
+ X ?" G" |+ m! x% b - if(tnow!=told)
w F0 d. k$ }! D% L - { // 这里注意SYSTICK是一个递减的计数器
7 V. a0 R4 L3 \( {" p. y - if(tnow<told) tcnt+=told-tnow;; e0 s- }3 l8 W) `# m
- else tcnt+=reload-tnow+old;: O# F+ L$ W/ C( V
- told=tnow;! j8 l: c6 u+ r N ]" I) t
- if(tcnt>=ticks) break; // 超时
4 g# C; g/ [% x: |7 a# c; H - }6 y* p# ?; H1 R# q0 X! S& Z
- };/ E4 `; R- i: ^& ?
- }
1 P3 H' p: j" L% h% G - 8 B: F/ W9 e, k' p
- void delay_ms(u32 nms), R" [, G8 F" ?# ?- f- c7 C
- {
# L+ W$ B: ]* L1 d; S* z - if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED) // 系统已经运行+ E% Q" W) W: {
- {
/ j$ n$ H; N+ l$ `, ?+ D' q - if(nms>=fac_ms) { vTaskDelay(nms/fac_ms); } x' Q5 u9 r$ B- r' C
- nms%=fac_ms; // OS已经无法提供这么小的延时了,采用普通方式延时; Z! J8 m5 }) m; _
- }1 D! Z4 K; g" b a
- delay_us((u32)(nms*1000));$ Y4 g& Q3 u: C9 N& M+ p3 {
- }
5 }! [' W; h/ B- I
; B+ f- q/ F9 S- W B* r- void delay_xms(u32 nms)
$ n# ?: c% p/ U! l; q - {: |% D( M& U* T9 d: B B _. _
- u32 i;
& s/ R' _6 j" w - for(i=0;i<nms;i++) delay_us(1000);3 R6 v; B5 \1 U7 ]8 J
- }
复制代码 . K9 F9 Y, T' S. T$ N
delay_us()和delay_xms()不会导致任务切换。delay_ms()是对FreeRTOS中延时函数vTaskDelay()的简单封装,所以在使用delay_ms()时会导致任务切换。
4 n. C8 C% O% n6 Z$ Z6 O3 o" y7 ?delay.c修改后编译一下,如有错误提示在port.c、delay.c和stm32f10x_it.c中三个重复定义的函数:SysTick_Handler()、SVC_Handler()和PendSV_Handler(),这三个函数分别为滴答定时器中断服务函数、SVC中断服务函数和PendSV中断服务函数。可在stm32f10x_it.c中将这三个函数注释掉。% d; Y! c+ |& P4 z) Y5 V
* R$ o* z! F% K4 L' K5 m* ~4 B
$ ]# y9 k l( T8 i
5 e b( t, l, K8 [" N至此,SYSTEM文件夹修改完成。
6 Y$ K7 d' w4 i; M; @/ k/ q————————————————+ U. F3 N/ _- b' w
版权声明:天亮继续睡
9 P1 ]2 B* g; Q" v( o# B, N1 ~4 x; z/ t2 Q) K- D
' I- I1 K( A& z3 g' u- Q( N
|