1. 实验目的
4 m0 v. t* F% a n: ^( G% tFreeRTOS可以屏蔽优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断,不会屏蔽高于其的中断。本次实验就是验证这个说法。本实验使用两个定时器,一个优先级为4,另一个为5,两个定时器每隔1s通过串口输出一串字符串。然后在某个任务中关闭中断一段时间,查看输出情况。, |# ~. z, y! E
1 W! Z4 S, i% O$ S! j" ^2. 实验设计7 h6 g% y9 L) _/ ^- B, f' S
本实验设计了两个任务start_task()和interrupt_task(),这两个任务的任务功能分别为:& c# _* o6 H& R7 e M
start_task():创建另外一个任务;
6 W+ _6 K y: K% M0 O* W, Einterrupt_task():中断测试任务,任务会调用FreeRTOS的中断函数portDISABLE_INTERRUPTS()来将中断关闭一段时间。( Q! J, k& t) j7 c8 f
$ A0 t/ V/ Q c+ g+ F
3. 硬件. k% c3 [0 w: z5 Y
3.1 正点原子战舰v3开发板(其他板子应该也可以,主要涉及USART,TIM3,TIM5,LED);
( c; z% K* e3 Q2 \, w6 Y3.2 JLINK仿真器。4 B; @' ^7 b, N I' F8 p: v
0 c& L X9 x$ T; ^9 \( r4. 代码解读
* ?5 H1 H9 \/ S4.1 timer.h和timer.c
# m3 D+ `3 y" j- }% t: I因为用到2个定时器,这里选择TIM3和TIM5,其定时器初始化和中断函数如下:
: f9 H) ?3 s; _) X# j' U; [- P; b7 S9 b& K
- #ifndef __TIMER_H R6 g* B( `5 P3 ^1 P; y2 a& }
- #define __TIMER_H* S. |5 v5 q' v* b
- #include "stm32f10x.h" ( k) D7 e0 s5 \ {
- void TIM3_Int_Init(u16 arr,u16 psc); // 优先级4,认为高优先级
# F1 I+ }, T. V! e - void TIM5_Int_Init(u16 arr,u16 psc); // 优先级5, 认为低优先级
6 l! b8 }2 N# o7 j, d - #endif
复制代码- #include "timer.h"
7 ] A3 V* e! r+ w' r& H7 ] - #include "usart.h" : l* z5 i% {1 f% q+ t3 ]+ {
- // 函数名称:通用定时器3中断初始化
; q0 O& u" p* N. K5 l- U( [! J - // 入口参数:arr:自动重装值;psc:时钟预分频数& I; s; |5 X/ {2 g+ j* G; S7 \
- void TIM3_Int_Init(u16 arr,u16 psc)
7 H2 n0 N/ Z5 ^1 t8 I: Q5 q- I, P - {# ~; D* y, v$ u6 n! `& w5 }
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;2 _: f. z- N: j) q3 h
- NVIC_InitTypeDef NVIC_InitStruct;& X! \* O6 }! T0 W3 }
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
$ r/ a5 J( e R! U5 [% b3 x2 V) l; Z - // 定时器TIM3初始化0 i0 a$ r7 J. q0 R- K2 h9 F
- TIM_TimeBaseStruct.TIM_Period = arr; ' A% L) r( n1 I d
- TIM_TimeBaseStruct.TIM_Prescaler =psc; / C9 C/ \% {- U5 J- }
- TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1; 2 `2 G, v/ l7 C/ i
- TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
8 @* ^5 h2 `8 K$ s - TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct);
& o5 l% L8 [7 k) _7 K7 Q - TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); / c) K! P/ |6 K( Z7 s" s* W, ^
- // 中断优先级NVIC设置6 c2 H, ^" H% U3 t: f7 [
- NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
' ?. [5 v, l2 m7 O - NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 4;
! l7 k. Y# ^8 v% ~8 @/ @9 z, D8 d - NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; " B, Z% }6 L2 S2 m% j% \
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
+ P. g% q1 Z1 ]7 y# U; I. Y - NVIC_Init(&NVIC_InitStruct); " @$ m) z; V v( p& j. J0 E2 B
- TIM_Cmd(TIM3, ENABLE);
( `* B$ c. i8 p' W/ j5 s - }
R: o% n# A8 i0 b( P% \% B - // 函数名称:通用定时器5中断初始化
; p$ D& I- E8 l" M/ }& c - // 入口参数:arr:自动重装值;psc:时钟预分频数
6 D6 M8 K2 t) Q* j! u2 g' ~ - void TIM5_Int_Init(u16 arr,u16 psc)* s+ B$ j2 @# O' C2 b" K8 O7 E
- {
0 }' Z2 f |+ i1 D1 W# \3 o& A - TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;% ?4 v: T! L6 e; }% O! c9 Q
- NVIC_InitTypeDef NVIC_InitStruct;/ w6 J8 J# y) K! ~# D2 O: F
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); ' Q+ D R7 q0 r4 f7 U
- // 定时器TIM5初始化1 ^- x& I& `- g
- TIM_TimeBaseStruct.TIM_Period = arr; 6 ?, Z" B8 c5 |
- TIM_TimeBaseStruct.TIM_Prescaler =psc; + N: u( J6 T$ R5 j# _
- TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
4 k/ L0 w" p1 \6 P, z$ _ - TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; 0 g8 q' B$ v( P% J# z9 ]7 e
- TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStruct);
& n# z+ [( ]' p( D5 N' s$ v3 ?4 w - TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE ); 7 o+ P, }( V1 c6 I
- // 中断优先级NVIC设置1 N/ S. b( x+ p5 c
- NVIC_InitStruct.NVIC_IRQChannel = TIM5_IRQn;
' _4 U: i1 d4 S. v {/ L - NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 5;
* Q3 L3 [: _: B$ r* A$ ?, p - NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; 4 f- Z5 t7 W5 s3 r+ c8 ?/ P7 \
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
- O) Q2 w" J, I0 X6 d0 B9 q( ^ - NVIC_Init(&NVIC_InitStruct);
0 h6 r: @. O2 L& x9 I1 {/ k/ x - TIM_Cmd(TIM5, ENABLE); " l8 Y+ r! b- v; a5 U
- }/ k0 ^( r Y% G) |1 k t
- // 函数名称:定时器3中断服务函数- }1 m M4 P! O( p6 L5 u( o/ ?
- void TIM3_IRQHandler(void)
; \1 m( `3 D% w# ~# K - {
6 k% P7 m# N. P& y0 o7 l0 L2 b - if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) / H- e: W# P$ W* z* m
- { printf("TIM3输出.......\r\n"); }
# @# a$ p8 j" @ - TIM_ClearITPendingBit(TIM3,TIM_IT_Update); 5 B5 R/ [ v/ i( {
- }
3 X2 ^! ?" \+ d8 e6 {0 W - // 函数名称:定时器5中断服务函数) F* F( h% \& h8 {! F8 i
- void TIM5_IRQHandler(void)+ V5 a+ h' E' r3 Y1 e
- {, G p; B* a' ~% i4 L4 m
- if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET)
- r6 u9 \# e- P - { printf("TIM5输出.......\r\n"); }7 j- ^5 T& @3 G$ c
- TIM_ClearITPendingBit(TIM5,TIM_IT_Update); ) j' l, T- P* x& c8 p- p" E* l) D
- }8 T7 g& ?0 Z! U% [% E
复制代码
3 t; E$ O! o6 H$ ]7 x4.2 main.c文件代码
$ r% _- P" U" a2 p- }! T& m* I5 f
- #include "sys.h"
7 `* A! z1 `7 A$ M) V! s: i& u3 A - #include "delay.h"
" v6 U0 {. R+ d& H7 d2 ~; Q4 l8 L - #include "usart.h"
( A4 D8 R6 W6 ~! C& H - #include "led.h"
8 g1 R4 Z+ d( W. g- K6 [1 F) Z - #include "timer.h"
8 }9 G) |7 ]$ H+ @ - #include "FreeRTOS.h"
7 L; A! [5 j7 m9 u9 w" `; j - #include "task.h"
; K: y2 v3 U; k. B6 f* T4 T - // 设计第一个任务start_task()
+ B4 K# q( e/ X: |7 y - #define START_TASK_PRIO 1 // 任务优先级; i. J/ e. x* y4 z% `3 ]; L
- #define START_STK_SIZE 256 // 任务堆栈大小 " O# L' D) O% M9 W* J' [: E3 I
- TaskHandle_t StartTask_Handler; // 任务句柄
: w" `2 B1 W+ ~! ?# F' l - void start_task(void *pvParameters); // 任务函数
& a2 [2 y# E( t( a5 I' s2 r - // 设计第二个任务interrupt_task()
* {# A% W' A6 c4 C) n0 b - #define INTERRUPT_TASK_PRIO 2 // 任务优先级
+ y# l$ X4 ` C( N/ U7 {$ I - #define INTERRUPT_STK_SIZE 256 // 任务堆栈大小
+ `; W. k7 K% }5 x - TaskHandle_t INTERRUPTTask_Handler; // 任务句柄
" {1 S0 p) @- |. `( q - void interrupt_task(void *p_arg); // 任务函数
( ]7 m- A' v4 u0 ^3 T
5 s$ G8 c- o- q. w R9 ^ x. g- // 主函数) a7 E* E) ?* e( }/ c
- int main(void) ~' `3 g" d* B6 ~$ F
- {, _; m$ ]6 {2 V& U
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 设置系统中断优先级分组4 1 H! F( |" @( `+ v" D. v% g- _
- delay_init(); // 延时函数初始化 4 z6 Q3 ` a% D4 w3 l2 x
- uart_init(115200); // 初始化串口4 j! A, E! r0 u7 O8 @* g4 b
- LED_Init(); // 初始化LED
- }8 n6 Z0 R+ B$ V/ J! O, t - TIM3_Int_Init(10000-1,7200-1); // 初始化定时器3,定时器周期1S9 O% u) r, r. ?, j; f* n0 O& C
- TIM5_Int_Init(10000-1,7200-1); // 初始化定时器5,定时器周期1S/ }8 Q/ W3 F. c! n1 f. k
- // 创建开始任务
+ A! d* Z h p7 b% c# P - xTaskCreate( (TaskFunction_t )start_task, // 任务函数
3 p5 X- X5 D: y* i7 z/ W& x - (const char* )"start_task", // 任务名称
1 ]+ d# h6 }+ W4 C - (uint16_t )START_STK_SIZE, // 任务堆栈大小& h! Y% q% }3 G" @7 N z w* D4 J
- (void* )NULL, // 传递给任务函数的参数
1 k2 t9 f8 P7 h. g. A! m E- e - (UBaseType_t )START_TASK_PRIO, // 任务优先级; |; {3 J. z5 W6 `
- (TaskHandle_t* )&StartTask_Handler); // 任务句柄 - k$ P! g" t% _. K2 L0 j$ z
- vTaskStartScheduler(); // 开启任务调度
( w1 W+ B5 @4 L' c; S" R# q0 ]* { - }
- P6 r5 s9 c: | ~2 a) _1 Z
9 a! [+ L& U4 `4 a- // 主函数里创建了第一个任务函数——开始任务6 |8 ~1 q6 H, J8 F5 N: {$ x
- void start_task(void *pvParameters)
5 s% m/ M" _0 N# c7 [ h - {. y$ e# G5 @, _6 _3 m
- taskENTER_CRITICAL(); // 进入临界区- ]4 q8 q2 S( v/ s- ?' e! i
- // 创建中断测试任务,用来执行开关中断操作
+ {1 B0 {/ @" a - xTaskCreate( (TaskFunction_t )interrupt_task, // 任务函数4 `+ v6 a( ^, G" n
- (const char* )"interrupt_task", // 任务名称
( j/ C y4 c* |: j9 y% c* T - (uint16_t )INTERRUPT_STK_SIZE, // 任务堆栈大小- i8 T4 A& ^9 P
- (void* )NULL, // 传递给任务函数的参数$ `+ Z/ f7 ?8 H+ j
- (UBaseType_t )INTERRUPT_TASK_PRIO, // 任务优先级) d7 b1 |$ i! ?. Q, B) F
- (TaskHandle_t* )&INTERRUPTTask_Handler); // 任务句柄3 f [; v, E/ W6 n9 S, h
- vTaskDelete(StartTask_Handler); // 删除开始任务
1 X3 d$ J# s0 m( o2 ` - taskEXIT_CRITICAL(); // 退出临界区, x; f. s+ g0 t' _' ]( s, p1 w
- }
) t2 Q" I M; j4 ]" @ - 0 @% X5 m0 s! X) X
- // 开始任务里创建了第二个任务函数——中断测试任务 / `" f! p, i) T
- void interrupt_task(void *pvParameters)2 C9 n F! A# k* n4 T3 y4 ~
- {: \ E! z; {2 u# i8 ?' Q+ x
- static u32 total_num=0;' C% W- o9 ^4 n* h( R' _8 g
- while(1)
) }0 }1 n9 f; p, U1 Y - {
; [( A1 w% g. P1 m! K. l, u - total_num+=1;
3 Q0 @ f8 l8 z) f' G9 n% P: L! a - if(total_num==5)
5 @. n& x- [( y _: u/ n. B6 e - {
B9 C8 ^5 z0 l" A - printf("关闭中断.............\r\n");
4 a" a1 D; a7 H. w$ X7 u' W - portDISABLE_INTERRUPTS(); // 关闭中断
# h/ S, _* {2 Y) u+ o - delay_xms(5000); // 延时5s4 ^7 H4 t( K, `" x, Z9 y
- printf("打开中断.............\r\n"); // 打开中断# M; q3 ~9 D0 }4 w4 N* M
- portENABLE_INTERRUPTS();
7 u7 t; \3 X# v6 _ - }+ d, M# @& F+ R& n: v0 ~
- LED0=~LED0;
% K2 ], {- t" F3 R - vTaskDelay(1000);8 e/ N& S* P' t6 E F* T
- }* O" U5 A( M- H
- }
复制代码
5 {, F ]+ R9 N: D% u: a4 H5. 实验结果5 m3 j% i6 L/ I& F- v% |
& |0 E+ M. g* A( I! q
# _ O& @ \9 G, d6 n- z
1 P% n4 T) X/ Q5 r. t# L s运行一开始,TIM3和TIM5都有输出,当运行5次后,关闭中断,这时只有TIM3有输出(因为优先级为4,高于configMAX_SYSCALL_INTERRUPT_PRIORITY),而TIM5优先级为5,与configMAX_SYSCALL_INTERRUPT_PRIORITY相等,被关闭了。待5s之后,重新打开中断,此时TIM5恢复运行。
/ Q2 u4 M0 }# B- D! l
6 p* Y/ I. G! M/ j M6 L" e最后回顾下一个知识点,configMAX_SYSCALL_INTERRUPT_PRIORITY值在哪里定义的?在FreeRTOSConfig.h文件里!
. P/ W6 `$ }) \! e6 m) B. o$ _! r5 y* |
6 P7 S2 z- Z+ v7 k! g) D; B
# t0 k2 w( D; ~6 _9 |
. V9 R9 ?0 B% e2 o如果将configMAX_SYSCALL_INTERRUPT_PRIORITY改为4或更小,则TIM3也会被关闭。8 a+ n# ]- m! O6 }
————————————————
' _' N9 x a0 q版权声明:天亮继续睡
' l2 ~* `" Y5 j
, {; N% q* ?7 c* o! W: r |