你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。
chrome
firefox
safari
ie8及以上
ST
意法半导体官网
STM32
中文官网
ST
全球论坛
登录/注册
首页
技术问答
话题
资源
创客秀
视频
标签
积分商城
每日签到
【安富莱】【RTX操作系统教程】第19章 SVC中断方式调用...
[复制链接]
baiyongbin2009
发布时间:2016-2-3 17:08
文章
文章封面:
-
文章简介:
-
【安富莱】【RTX操作系统教程】第19章 SVC中断方式调用用户函数
ãRTXæä½ç³»ç»æç¨ã第19ç« SVC䏿æ¹å¼è°ç¨ç¨æ·å½æ°.pdf
(710.21 KB, 下载次数: 75)
2016-2-3 17:08 上传
点击文件名下载附件
第19章
SVC
中断方式调用用户函数
& P1 @8 b- a3 `3 r Q' e$ i2 Z
本章节为大家讲解如何采用SVC中断方式调用用户函数。当用户将RTX任务设置为工作在非特权级模式时,任务中是不允许访问特权级寄存器的,这个时候使用SVC中断,此问题就迎刃而解了。
本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407。
19.1 SVC中断
19.2 RTX中SVC中断方式调用函数方法
19.3 实验例程说明
19.4
总结
9 L7 k" h! F! ?; A3 f# s- `9 C3 J
: c; h0 m3 ~2 @2 r0 D* z$ @
' J) {6 f: x1 |3 N% b1 X' E+ K
19.1 SVC中断
+ [7 O5 ?6 Z* `, [
19.1.1 SVC功能介绍
SVC用于产生系统函数的调用请求。例如,操作系统通常不让用户程序直接访问硬件,而是通过提供一些系统服务函数,让用户程序使用SVC发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件。因此,当用户程序想要控制特定的硬件时,它就要产生一个SVC异常,然后操作系统提供的SVC异常服务例程得到执行,它再调用相关的操作系统函数,后者完成用户程序请求的服务。
SVC这种“提出要求——得到满足”的方式很好:
(1)
它使用户程序从控制硬件的繁文缛节中解脱出来,而是由OS负责控制具体的硬件。
(2)
OS的代码可以经过充分的测试,从而能使系统更加健壮和可靠。
(3)它使用户程序无需在特权级下执行,用户程序无需承担因误操作而瘫痪整个系统的风险。
(4)通过SVC的机制,还让用户程序变得与硬件无关,因此在开发应用程序时无需了解硬件的操作细节,从而简化了开发的难度和繁琐度,并且使应用程序跨硬件平台移植成为可能。开发应用程序唯一需要知道的就是操作系统提供的应用编程接口(API),并且在了解了各个请求代号和参数表后,就可以使用SVC来提出要求了(事实上,为使用方便,操作系统往往会提供一层封皮,以使系统调用的形式看起来和普通的函数调用一致。各封皮函数会正确使用SVC指令来执行系统调用)。其实,严格地讲,操作硬件的工作是由设备驱动程序完成的,只是对应用程序来说,它们也相当于操作系统的一部分。如下图所示:
SVC异常通过执行”SVC”指令来产生。该指令需要一个立即数,充当系统调用代号。SVC异常服务例程稍后会提取出此代号,从而获知本次调用的具体要求,再调用相应的服务函数。例如,
SVC 0x3 ; 调用3号系统服务
在SVC服务例程执行后,上次执行的SVC指令地址可以根据自动入栈的返回地址计算出。找到了SVC指令后,就可以读取该SVC指令的机器码,从机器码中萃取出立即数,就获知了请求执行的功能代号。如果用户程序使用的是PSP,服务例程还需要先执行MRS Rn, PSP指令来获取应用程序的堆栈指针。通过分析LR的值,可以获知在SVC指令执行时,正在使用哪个堆栈。
注意,我们不能在SVC服务例程中嵌套使用SVC指令(事实上这样做也没意义),因为同优先级的异常不能抢占自身。这种作法会产生一个用法fault。同理,在NMI服务例程中也不得使用SVC,否则将触发硬fault。
5 Q+ E# q2 }" Y' a9 j$ A% u2 t8 X
19.1.2 SVC触发方式
SVC的异常号是11,支持可编程。SVC异常可以由SVC指令来触发,也可以通过NVIC来软件触发(
通过寄存器NVIC->STIR触发软中断
)。这两种方式触发SVC中断有一点不同:软件触发中断是不精确的,也就是说,抢占行为不一定会立即发生,即使当时它没有被掩蔽,也没有被其它ISR阻塞,也不能保证马上响应。这也是写缓冲造成的,会影响到与操作NVIC STIR相临的后一条指令:如果它需要根据中断服务的结果来决定如何工作(如条件跳转),则该指令可能会误动作——这也可以算是紊乱危象的一种表现形式。为解决这个问题,必须使用一条DSB指令,如下例所示:
MOV R0,#SOFTWARE_INTERRUPT_NUMBER
LDRR1,=0xE000EF00 ; 加载NVIC软件触发中断寄存器的地址
STR R0, [R1] ; 触发软件中断
DSB ; 执行数据同步隔离指令
...
但是这种方式还有另一种隐患:如果欲触发的软件中断被除能了,或者执行软件中断的程序自己也是个异常服务程序,软件中断就有可能无法响应。因此,必须在使用前检查这个中断已经在响应中了。为达到此目的,可以让软件中断服务程序在入口处设置一个标志。而SVC要精确很多,SVC指令后,只要此时没有其它高优先级的异常也发生了,SVC中断服务程序可以得到立即执行。
- L4 h9 p3 Y) j
19.1.3 SVC的使用
SVC是用于呼叫OS所提供的API(
RTX是采用的这种方式
)。用户程序只需知道传递给OS的参数,而不必知道各API函数的地址。SVC指令带一个8位的立即数,可以视为是它的参数,被封装在指令本身中,如:
SVC 3 ;呼叫3号系统服务
则3被封装在这个SVC指令中。因此在SVC服务例程中,需要读取本次触发SVC异常的SVC指令,并提取出8位立即数所在的位段,来判断系统调用号。
+ |3 ?. E" a' S: B9 J- C' \$ A. U
19.1.4 RTX使用的SVC中断服务号
SVC
的0号系统服务被RTX系统占用,即SVC 0,用户只能使用从1开始的服务号。而且用户使用的时候一定要保证从1开始,连续递增使用,范围1 – 255。
. X. j6 {! X8 ]! y
* T3 J7 Z/ R5 R8 Z
赞
0
收藏
0
评论
8
分享
发布时间:2016-2-3 17:08
举报
请先
登录
后回复
8个回答
baiyongbin2009
回答时间:2016-2-3 17:19:40
a0a.1 32b0c
19.2 RTX中SVC中断方式调用函数方法
用户实现SVC中断方式调用函数方法如下(下面以添加两个SVC中断为例):
第1步:
添加SVC_Table.s文件。
我们在前面讲解RTX的源码移植方式时这个文件已经加上。
! C8 E- h: I8 s
第2步:
使用属性__svc(
x
)声明函数,x从1开始,范围1-255。函数名随便命名,但是x的数值一定要保证是连续递增的。
void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t*_arg4);
void __svc(2) SVC_2_FunCall(void);
( V" _5 h& [& x
第3步:
写上面两个函数的实际代码,并将函数名更改成__SVC_x格式(
统一改成这种命名方式是为了跟RTX系统的调用方式__SVC_0统一
),x是从1开始,范围1-255。上面声明的两个函数不要动,这里修改的是实际函数名。另外用户可以根据需要加上中断开关操作,因为SVC中断可以被其它高优先级的中断抢占。
/*
******************************************************************************************************
* 函 数 名: __SVC_1和__SVC_2系统服务号
* 功能说明: 被SVC中断所调用的__SVC_1和__SVC_2
* 形 参:无
* 返 回 值: 无
******************************************************************************************************
*/
//
这里的__SVC_1就是函数
SVC_1_FunCall
void __SVC_1(uint8_t _arg1, uint16_t _arg2,uint32_t _arg3, uint64_t *_arg4)
{
__disable_irq();
printf("_arg1= %d\r\n", _arg1);
printf("_arg2= %d\r\n", _arg2);
printf("_arg3= %d\r\n", _arg3);
printf("_arg4= %lld\r\n", *_arg4);
__enable_irq();
}
//这里的__SVC_2就是函数SVC_2_FunCall
void __SVC_2(void)
{
__disable_irq();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
__enable_irq();
}
- D+ ]" s m" J$ H* a: g
第4步
:
将定义的两个函数添加到SVC_Table.s文件里面
首先使用IMPORT命令声明下,类似C语言中的extern。然后添加到SVC_Table列表下,整体添加后的效果如下(红色字体是用户添加的):
AREA SVC_TABLE, CODE, READONLY
EXPORT SVC_Count
SVC_Cnt EQU (SVC_End-SVC_Table)/4
SVC_Count DCD SVC_Cnt
; Import user SVC functions here.
IMPORT __SVC_1
IMPORT __SVC_2
EXPORT SVC_Table
SVC_Table
; Insert user SVC functions here. SVC 0 used byRTL Kernel.
DCD __SVC_1
; user SVC function
DCD __SVC_2
;user SVC function
SVC_End
END
: e: Z3 |: o# l, R6 M
+ ?6 |9 ^; P, H4 D% _/ L
至此,RTX中SVC中断的调用就实现了。实际应用的时候,用户只需调用函数SVC_1_FunCall和SVC_1_FunCall即可,这两个函数就是在SVC中断里面实现的。
7 O" |* d, I# I) G" f; J
赞
评论
回复
支持
反对
baiyongbin2009
回答时间:2016-2-3 17:38:43
a0a.1 32b0c
19.3 实验例程说明
8 s1 `- i+ N8 u
19.3.1 STM32F103开发板实验
配套例子:
V4-419_RTX实验_SVC中断方式调用用户函数
实验目的:
1. 学习SVC中断方式调用用户函数
实验说明:
1. RTX支持配置所有任务工作特权级模式或者用户模式,宏配置在文件RTX_Conf_CM.c文件里面
#defineOS_RUNPRIV 0
配置为0的话,任务工作在用户级,配置为1的话,任务工作在特权级。本实验配置为0,所有任务都工作在用户级模式。
2. 本实验演示SVC中断号调用方法。
SVC指令带一个8位的立即数(范围0-255),可以视为是它的参数,被封装在指令本身中,如:
SVC 3 ; 呼叫3号系统服务
SVC0被RTX系统所使用了,用户只能使用从1开始的服务号。用户使用的时候一定要保证从1开始,而且需要连续的使用。实验中使用了SVC 1和SVC 2。
实验内容:
1.K1按键按下,串口打印。
2.K2键按下,向消息邮箱发送数据。任务AppTaskMsgPro接收到消息后进行消息处理。
3.K3键按下,调用SVC的1号系统服务。
4.摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可以在中断中设置NVIC。
5.各个任务实现的功能如下:
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX
配置:
RTX配置向导详情如下:
Task Configuration
Number of concurrent running tasks
允许创建4个任务,实际创建了如下四个任务:
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
Number of tasks with user-provided stack
创建的4个任务都是采用自定义堆栈方式。
Run in privileged mode
设置任务运行在非特权级模式
RTX
任务调试信息:
程序设计:
任务栈大小分配:
staticuint64_t AppTaskUserIFStk[512/8]; /* 任务栈 */
staticuint64_t AppTaskLEDStk[256/8]; /* 任务栈 */
staticuint64_t AppTaskMsgProStk[512/8]; /* 任务栈 */
staticuint64_t AppTaskStartStk[512/8]; /* 任务栈 */
将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
RTX
初始化:
/*
" q; n4 W. G z, A9 [# P$ S
*********************************************************************************************************
( D5 K d/ W. C- k
* 函 数 名: main
, z$ D0 Z* A& A: _7 _
* 功能说明: 标准c程序入口。
, t! L) f K2 C9 L
* 形 参: 无
# R' f: |) A+ O. N0 ^2 n& x
* 返 回 值: 无
, L& H8 ]9 k' N$ {
*********************************************************************************************************
3 V& p4 |. j4 Q$ h
*/
* `* d1 t7 K2 g+ Y7 Q5 J
int main (void)
- _) e( c# ^5 ?" E
{
8 ^' z1 A [0 Q( j9 x
/* 初始化外设 */
, v! b; ]1 S; m* R7 W
bsp_Init();
6 t% V5 A8 A# Z; }* I- v* n7 s
! \2 t% Y6 `" t6 n
/* 创建启动任务 */
) W$ N9 \" \+ _1 j7 N; W
os_sys_init_user (AppTaskStart, /* 任务函数 */
% g: g* v6 O* _. H6 ^6 [
4, /* 任务优先级 */
* A# t5 `; K) d2 u ~6 z1 B: \
&AppTaskStartStk, /* 任务栈 */
% r3 H7 n6 Y) w4 l* D% t
sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
8 V% M. v' U7 E0 ?) A9 C$ I
while(1);
0 C9 w# x U* w. L
}
复制代码
) r4 ?/ O3 ]5 S: s" D
RTX
任务创建:
/*
2 M8 @" C2 S! B, l: h6 R
*********************************************************************************************************
- ~ k8 I; y. D' B2 }) C. m+ X
* 函 数 名: AppTaskCreate
. u/ i* t. i6 M# r
* 功能说明: 创建应用任务
( V' s w, Z& b# N7 C; ~
* 形 参: 无
/ q! R% @6 m( R! k1 J7 j0 S* ~
* 返 回 值: 无
8 q d: n0 k4 F2 f! B. o
*********************************************************************************************************
' u' g8 ]2 |4 S7 `* I
*/
) y! c! A4 t/ u& H- }
static void AppTaskCreate (void)
i5 H& q) I. L, m* `* Y6 a/ H
{
1 H! n; ]! q5 y% C/ R! N9 ?
HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF, /* 任务函数 */
! h% u' T5 i! p1 F3 H5 p, C
1, /* 任务优先级 */
: |0 x+ y% }. C3 A7 s) r
&AppTaskUserIFStk, /* 任务栈 */
/ t" d* ]# z" ^3 Z6 q* h% {6 x9 {' Y
sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
. \3 P5 h" @* E! B5 y. x
$ j/ s. p' f. Y( {5 Q
HandleTaskLED = os_tsk_create_user(AppTaskLED, /* 任务函数 */
: {- b- l; ?3 v! ~
2, /* 任务优先级 */
; U5 G" C" p( l4 J% r- P
&AppTaskLEDStk, /* 任务栈 */
! s) n" f$ ~2 A4 ?
sizeof(AppTaskLEDStk)); /* 任务栈大小,单位字节数 */
# d+ _7 [9 y* X' t# M
9 r, R" O0 G, F' ?. Z6 c, |
HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro, /* 任务函数 */
$ g; y) ]5 a: X
3, /* 任务优先级 */
& c* j+ H" Y) i a3 S2 ?# h+ A
&AppTaskMsgProStk, /* 任务栈 */
. n) n: W0 @5 x( d
sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
5 Q4 r1 Q M! Q0 Y, z/ k
}
复制代码
1 \; o& A0 S) ~5 J
消息邮箱的创建:
#define PoolBlocks 10
5 z, m- J9 w2 t1 ?9 r X
#define PoolPerBlockSize 8
) ]: S( l" i& P! I
( e! Z2 {+ E% m* K
/* 声明一个支持10个消息的消息邮箱 */
0 d5 F" {/ _, v" R* J$ C
os_mbx_declare (mailbox, 10);
; O5 y: W/ b3 z# g" F8 K
3 |! ]- A$ k" ]6 J3 v6 y# }
/*
- Q2 `- I4 o* L$ R1 {* a' E$ v
*********************************************************************************************************
) `( R3 ^, _: Z& M
* 函 数 名: AppObjCreate
" G. G' P! F5 z
* 功能说明: 创建任务通信机制
* ~$ E$ M3 Y" F5 W, e
* 形 参: 无
! N' q" q z& }6 m( A- t2 _3 }
* 返 回 值: 无
# ?6 s; u7 q! X" `- P
*********************************************************************************************************
3 j" G6 o8 v1 B. `+ F
*/
9 R2 \1 h) }2 \! F$ A
static void AppObjCreate (void)
9 }4 S* U) X% h: N
{
. e- l. Z4 T! Q+ [$ A
/* 创建消息邮箱 */
" a9 ^% O0 h1 ~ B( a- L/ h! f4 }
os_mbx_init (&mailbox, sizeof(mailbox));
8 K8 K h$ x7 @% \$ v' d
I4 l' S$ N% Q* }/ D5 q/ I
}
复制代码
" x' t5 `, e2 M7 h
SVC
中断函数的创建:
void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);
/ L! K y$ o) Y2 H% N5 G
void __svc(2) SVC_2_FunCall(void);
3 L# R* U6 _$ v% z$ h
, {7 m/ N M% w% E( y! x8 U) |! z* f
/*
. c5 F5 n. {0 L
*********************************************************************************************************
" n( C$ c! l/ b$ J' y7 J' a6 O
* 函 数 名: __SVC_1和__SVC_2系统服务号
% e3 Z( u$ y5 [% T
* 功能说明: 被SVC中断所调用的__SVC_1和__SVC_2
" N) ]( v$ e' I; R, P- V1 f4 G
* 形 参: 无
. A; z. l+ ?5 o5 n8 `* Q+ B4 T
* 返 回 值: 无
W" U: T' b1 o9 e5 `. {
*********************************************************************************************************
# A; k8 |# N' X, K* g( u$ N* R/ _
*/
- x' T9 c) Z0 R, c3 e4 i
void __SVC_1(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4)
$ F) B7 D2 i; ^ \4 W6 ~
{
' W0 S$ W( s! }0 N) Y8 v: ~
/*
+ o6 b4 Y, p6 f, d
1. 实际应用不要在SVC中断中调用串口打印,太影响实时性,这里仅仅是为了演示
. U/ N, B7 O( d5 S, L: J3 @
2. 根据需要做开关中断操作。
9 z5 ^2 ]- r; |7 i3 B' z+ O
*/
3 d4 m6 g# o3 Z9 J
__disable_irq();
, m8 D$ W) F: V$ O% X' X5 \ [
printf("_arg1 = %d\r\n", _arg1);
% [5 ?! {4 R% i1 P% @+ x
printf("_arg2 = %d\r\n", _arg2);
8 p8 L- `1 X6 p7 C; w1 [
printf("_arg3 = %d\r\n", _arg3);
8 b, c( T( S& v4 q
printf("_arg4 = %lld\r\n", *_arg4);
) a% I/ P4 X; F& ~9 [. ]0 I6 @5 U* m
__enable_irq();
! t5 p- m$ W6 b) W! }. g! u
}
- K- n! v7 p+ B6 y+ G; s
; u7 Z7 B% v# M
void __SVC_2(void)
0 z5 s4 ]8 l4 Q: n6 K8 g
{
* n1 g$ E6 M* T5 w
/*
* M7 c0 P* z2 [5 K I
1. 根据需要做开关中断操作。
) v5 k! [. W; ~/ R, x
2. 本实验所有任务都是工作在非特权级,中断函数都是运行在特权级的,此函数是在SVC中断里面运行。
3 P* c5 X1 _0 u1 k4 \
所以可以在此中断中设置NVIC分组。
2 G* `) I! @7 i& k
*/
2 O! v9 N3 b6 _; k: z J
__disable_irq();
& f8 S; k2 a3 ~( ]5 H5 R
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
( ]$ V) Y; E Z# y6 | ]6 h8 d
__enable_irq();
. M: q( U5 U# _' ^3 g7 K
}
复制代码
% f; N6 w: E7 H- }' Y( m
SVC_Table.s
文件中SVC中断的设置(红色字体是需要用户添加的):
void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);
" `- m# c0 b2 @$ G: Q5 j7 \
AREA SVC_TABLE, CODE, READONLY
; q- ?( T& ]- A t
6 f* U6 d) b% N- w0 W4 y- v
EXPORT SVC_Count
Z! h* M+ b$ B. B7 Q) @' L
+ \) @; n2 f3 c4 q: z( _6 L
SVC_Cnt EQU (SVC_End-SVC_Table)/4
# D( S* n) Q+ v7 a" c7 u% F. s
SVC_Count DCD SVC_Cnt
6 C, V$ o( L+ h$ z
* D6 r. ]% z0 n* N
; Import user SVC functions here.
/ ` |) d6 p1 I
IMPORT __SVC_1
4 T( z# u* G$ e* r. S9 |0 T) J/ z* R
IMPORT __SVC_2
% z; k/ M; E! h- z
" A* V& d5 a0 S2 X8 Y" n: T3 |
EXPORT SVC_Table
8 v4 y3 t, y% c
SVC_Table
2 }- @' W0 [$ Y2 j9 g. T
; Insert user SVC functions here. SVC 0 used by RTL Kernel.
% n' N; Q& s5 a2 J
DCD __SVC_1 ; user SVC function
# @9 Y* O) J& Y; o
DCD __SVC_2 ; user SVC function
/ H9 `& ]: V3 E0 G: n! ~( T; f
! `! Z- w, L7 B- i9 L1 S% P1 U
SVC_End
4 |% J) X# u+ k& [! G7 r1 u
, z1 o" D6 E( A# L
END
复制代码
, T6 ~ o: U! {# T
四个RTX任务的实现:
/*
7 `: ]5 J2 _5 Y0 Z4 ^8 p% r3 |2 l
*********************************************************************************************************
" i- H) ~& u' r) X
* 函 数 名: AppTaskUserIF
6 A4 }; ]6 Y9 l! C
* 功能说明: 按键消息处理
; T1 ]8 Y0 {% ]
* 形 参: 无
. T" @! [, i8 N# y$ H5 l5 `; I
* 返 回 值: 无
, E3 U: g2 d. @# w
* 优 先 级: 1 (数值越小优先级越低,这个跟uCOS相反)
) `' q3 S+ L d _9 W+ }
*********************************************************************************************************
4 k" D& N# t8 D; _& P) O( F2 H
*/
, R% E" Y4 f9 H" q
__task void AppTaskUserIF(void)
- v5 o c. O) {/ N2 `
{
9 ]* K/ n" S7 { u& G9 }0 s
uint8_t ucMsgTra = 0;
9 v( a9 {0 g6 ]% E& m" ]
uint8_t ucMsg = 0;
* E, h+ j* z" Q2 D7 n' |% C6 W
uint16_t usMsg = 0;
8 \6 E; r5 }* X- i; T- M; _& c* w/ `
uint32_t ulMsg = 0;
# T& d9 k: H# @- P
uint64_t ullMsg = 0;
. }9 i. ^8 Y) e% k' d
uint8_t ucKeyCode;
P+ s( \8 `' O; w7 B3 Z
6 u1 P2 Y4 @' O5 ]& o
while(1)
1 U5 `2 u& X- W0 P
{
5 J! C/ m; K$ r$ |3 ]* h' p
ucKeyCode = bsp_GetKey();
% x: ] G8 U: [7 t8 P7 a
! L* C$ c# v o, D: Z1 `) Y9 `
if (ucKeyCode != KEY_NONE)
7 n8 Q$ H& C, Q: O# r
{
* J& q$ w: G! i8 z7 e# \
switch (ucKeyCode)
" u8 Q5 K% y+ {7 t
{
# Z. [% i3 e5 V8 M
/* K1键按下,打印调试说明 */
! u7 |( V1 C" Q+ C/ {$ G
case KEY_DOWN_K1:
O: p, Q! B+ |4 N
printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
7 K) b% Z: u8 \7 G0 X; B
break;
" i9 e# z) T; |3 ^2 w- M) [. L
) F2 B8 l# p9 w5 @2 X
/* K2键按下,向消息邮箱发送数据 */
6 W9 n! z s0 R, |! o8 I
case KEY_DOWN_K2:
- H8 Z" j5 V9 H% i9 P3 ]
ucMsgTra++;
# T. |. p: O) l/ E
5 d6 ? r, S# \! k! }+ l
/* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
" y, b( Y4 D. B! @- u% ^0 Q" C
if(os_mbx_send (&mailbox, &ucMsgTra, 100) != OS_R_OK)
" L" r* k" u' H4 s" J* b1 T2 t
{
0 G1 v6 v6 v$ ^1 d8 U: J* r
/* 发送失败,即使等待了100个时钟节拍 */
" R( b) n' O! T% M6 Q s
printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
+ R# f! e! [$ J$ W {' g' t* l
}
8 G4 O( v/ Q( @
else
- x0 n/ X. ^# \' N, h5 o
{
" O( P4 q! ]! |
/* 发送成功 */
# j3 E2 }- j: y5 L
printf("K2键按下,向消息邮箱发送数据成功\r\n");
5 t$ h6 i2 h, Q' Y& W- f8 J1 r% ?3 U
}
' Y& Z. v, O" Q# z. S8 j
break;
! ?: n/ g! X0 z" \* k, i
H# z8 }) b4 I& r* T) y
/* K3键按下,调用SVC的1号系统服务 */
* q/ K# Z! U- w! @! J F1 b- t
case KEY_DOWN_K3:
! j( |, n4 S. o9 Z! `" h
printf(" K3键按下,调用SVC的1号系统服务\r\n");
; ^4 [+ B% Q) r# Y$ X
ullMsg++;
M1 @0 _# F+ ~8 [% d; t- @5 a7 _
SVC_1_FunCall(++ucMsg, ++usMsg, ++ulMsg, &ullMsg);
7 m, L9 U8 M8 E G
break;
/ o- y; y2 w, X! p
5 Z |0 ~, z6 O' _
/* 摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可中断中设置NVIC */
) _8 B0 j' O* H/ x* t+ G! L
case JOY_DOWN_OK:
, V! P0 d1 W' f0 R% f5 J
printf("摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可中断中设置NVIC
( {9 O8 I; P; _! ?! ]$ s
\r\n");
+ J. ^8 A! i3 y
SVC_2_FunCall();
% T5 T& b B" Y, W8 r
break;
- z! \, m% a8 ?7 l/ u
' t+ d% |; w v/ g
/* 其他的键值不处理 */
3 x! |( b( ^3 V# D7 P3 Z
default:
' m' o) v, @# Z8 Y5 y4 v
break;
4 \ `3 x# a' }! p( t
}
/ a( ]1 ]( a- H$ A
}
: E; }# ?+ M. @
4 j. j( T! `+ Z% j }: I
os_dly_wait(20);
( W9 Y# u0 z0 Q; W; O! \
}
( B H. q/ ?% d
}
1 G5 @5 T ]" Z/ ?2 O# l v; \) q
! \; T1 \ R! Q. T
/*
0 P. b/ T! \( G# a8 g
*********************************************************************************************************
$ r% y3 m! O0 G6 T
* 函 数 名: AppTaskLED
( p* J5 i' G* [1 I2 p1 ]2 o; C
* 功能说明: LED闪烁。
# J; R9 O; U1 p) G8 k' }& C' m+ F
* 形 参: 无
5 r1 }+ E# u! J/ }. k9 l
* 返 回 值: 无
/ h/ F* Z9 u: b2 d
* 优 先 级: 2
$ Z; H- m, q: i2 s# @7 f5 w; J
*********************************************************************************************************
$ P+ C3 a: z2 E2 x( Q" J2 ~6 [
*/
# f. C. k2 s* V6 @$ y3 U
__task void AppTaskLED(void)
' k0 S0 R1 ]3 S; e
{
0 P5 n+ V9 |8 Q! z
const uint16_t usFrequency = 200; /* 延迟周期 */
$ C8 t8 ^' G# ^" Z( t! y& \
1 I7 s, M0 N# G/ E: d( Q
/* 设置延迟周期 */
* x0 q' G& S* C$ N% {# S1 i
os_itv_set(usFrequency);
+ ?/ e( W- M i+ x1 ]* ^
7 Z6 L! K' G' } ~* u. s C
while(1)
3 J- r; g1 G' v* E' Q
{
- U' z% t, M; y7 v$ k- ^* P) d
bsp_LedToggle(2);
) i; O: o6 j, t" ^' o% i
bsp_LedToggle(3);
* d! `6 ]2 B0 Z8 C; [0 r5 J
) t1 I4 g+ Q5 N) X4 E h2 x
/* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
- C0 l0 k. u2 ^( R
os_itv_wait();
! e4 _" d3 p, j6 A/ O) \& E4 K
}
7 `$ d* f. o1 ~
}
* ]2 ^7 X% T" e) L- Z% ]
, y8 _& k& j4 g9 x% p" @& d3 ?3 [
/*
& n4 M" D% ~; A" f, z) u; N! j
*********************************************************************************************************
3 Q( f# _& V) S" p3 D7 z
* 函 数 名: AppTaskMsgPro
. v) J1 T: w. W0 x& |6 Q, v
* 功能说明: 消息处理,等待任务AppTaskUserIF发来的消息邮箱数据
) }: I6 @: z. g$ R
* 形 参: 无
/ C8 g6 q% ?0 k9 K/ o
* 返 回 值: 无
7 o$ u! b9 Z. K9 h4 R
* 优 先 级: 3
! j0 t% t* s: k6 L) Y- R
*********************************************************************************************************
& ], w6 l$ m$ ~- y& s
*/
. J& |' }2 D$ e( J( D4 ]
__task void AppTaskMsgPro(void)
! \, D3 ~& ]& l* j1 k) s+ U
{
& V2 B. |# F8 [; X
uint8_t *pMsg;
, x* _0 d% P% W$ H& U0 b$ U6 B
OS_RESULT xResult;
1 d8 X+ {6 y, `& E- @
const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
- T3 b+ Q- h" U8 s' I! P
4 O$ g, S/ U8 }6 R4 n( y% U: }
while(1)
! V; b5 K$ J, g! X0 t
{
. ]! Q3 E5 l) R1 |. F, m
xResult = os_mbx_wait(&mailbox, (void *)&pMsg, usMaxBlockTime);
+ j/ P% `+ u# d& ?' c
+ W3 ^; t$ [& ]/ C2 }; ^6 |
switch (xResult)
" w. y2 R& l! _! W. F* c0 c* \, D7 B
{
+ G% t. g/ y: x. h" t7 U; D9 {0 b
/* 无需等待接受到消息邮箱数据 */
. C3 M ^9 ?" K) ^+ A G# p
case OS_R_OK:
j2 E/ n9 k4 M7 J, b1 Q I8 j
printf("无需等待接受到消息邮箱数据,pMsg = %d\r\n", *pMsg);
8 _: Z) L& v7 ] w! t+ X* W3 F
break;
2 h+ t. @' {3 ]* ~( F0 r) {7 c' }
5 J1 }5 n; L# d" Z F
/* 消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据 */
9 l* t" u* x# I4 V0 Y
case OS_R_MBX:
* ]$ _2 H7 M. Q
printf("消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg = %d\r\n", *pMsg);
. p, w% S+ ~- F
break;
; K8 o, A4 z2 Y G: Y5 Z
, I H6 _2 [1 [
/* 超时 */
/ ~, \1 b# r0 J1 @4 S
case OS_R_TMO:
( N/ i3 W0 n) h* Q' y1 r
bsp_LedToggle(1);
3 ~$ j( m+ O8 W7 f
bsp_LedToggle(4);
1 T! L1 Y$ f& M. W+ i7 Q# Y
break;
$ h- [ Q0 h3 o2 E5 s0 L' u
& B; B) M$ Z# T. {6 z
/* 其他值不处理 */
. ~2 x# v& u- V1 e. o! c7 c* |4 L
default:
4 d @2 _5 m# ]* b
break;
& w y( d5 a! Z8 _
}
/ k& }1 S% |- H* `0 U
}
' U# t- N5 F. ~. I
}
0 F3 y# C H7 d4 w# a
* ~ ]% O: u g2 W7 U7 c. X# \
/*
1 p( I4 M9 O1 [, V! x
*********************************************************************************************************
) ^! g( m1 f# \
* 函 数 名: AppTaskStart
. P: r3 z4 p; u4 N/ @
* 功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
4 R+ c* `& p" ~# Y; I' u, r2 M( K& o
* 形 参: 无
. h/ d1 a z; i; }# T1 k9 L
* 返 回 值: 无
- y' e3 d2 S ?- | Q0 n0 t- @
* 优 先 级: 4
9 Z/ N5 L& _/ f7 S9 i
*********************************************************************************************************
' {4 y; ~% R3 D! l( y
*/
# i( k% v+ J+ s+ ?; b2 O
__task void AppTaskStart(void)
5 Z' k' ?: B6 ?0 A# M8 i
{
7 @+ X9 L% m% L) D
/* 创建任务 */
. O: A6 J! E/ g7 |& U
AppTaskCreate();
, `4 K3 S! N+ \! i
6 _- L4 @! N# b
/* 创建任务通信机制 */
9 \$ z) B( Q3 S" s2 z5 h
AppObjCreate();
1 M$ G8 B* E1 R
2 h( L! Y$ C5 a) r- Q
while(1)
( Y) D0 O# W4 j7 f- `
{
6 P" D5 U9 u( L; l
/* 按键扫描 */
8 G. W+ d* _1 h$ O) G
bsp_KeyScan();
3 i- q# z) b0 t! Z0 y5 f x
os_dly_wait(10);
) z. X8 _ R8 x+ X- l+ Y
}
2 G+ h' S( t3 l# U: c" X
}
复制代码
* B0 k; `0 W: g
W* i1 e' c2 P
赞
评论
回复
支持
反对
baiyongbin2009
回答时间:2016-2-3 17:43:49
a0a.1 32b0c
19.3.2 STM32F407开发板实验
配套例子:
V5-419_RTX实验_SVC中断方式调用用户函数
实验目的:
1. 学习SVC中断方式调用用户函数
实验说明:
1. RTX支持配置所有任务工作特权级模式或者用户模式,宏配置在文件RTX_Conf_CM.c文件里面
#defineOS_RUNPRIV 0
配置为0的话,任务工作在用户级,配置为1的话,任务工作在特权级。本实验配置为0,所有任务都工作在用户级模式。
2. 本实验演示SVC中断号调用方法。
SVC指令带一个8位的立即数(范围0-255),可以视为是它的参数,被封装在指令本身中,如:
SVC 3 ; 呼叫3号系统服务
SVC0被RTX系统所使用了,用户只能使用从1开始的服务号。用户使用的时候一定要保证从1开始,而且需连续的使用。实验中使用了SVC 1和SVC 2。
实验内容:
1.K1按键按下,串口打印。
2.K2键按下,向消息邮箱发送数据。任务AppTaskMsgPro接收到消息后进行消息处理。
3.K3键按下,调用SVC的1号系统服务。
4.摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可以在中断中设置NVIC。
5.各个任务实现的功能如下:
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX
配置:
RTX配置向导详情如下:
Task Configuration
Number of concurrent running tasks
允许创建4个任务,实际创建了如下四个任务:
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
Number of tasks with user-provided stack
创建的4个任务都是采用自定义堆栈方式。
Run in privileged mode
设置任务运行在非特权级模式
RTX
任务调试信息:
程序设计:
任务栈大小分配:
staticuint64_t AppTaskUserIFStk[512/8]; /* 任务栈 */
staticuint64_t AppTaskLEDStk[256/8]; /* 任务栈*/
staticuint64_t AppTaskMsgProStk[512/8]; /* 任务栈 */
staticuint64_t AppTaskStartStk[512/8]; /* 任务栈 */
将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
RTX
初始化:
/*
/ {/ V$ S+ g$ Z0 D
*********************************************************************************************************
5 [5 [4 ]; u3 G% ^
* 函 数 名: main
" w% d2 H) ~5 `, B, F$ L
* 功能说明: 标准c程序入口。
/ t0 d9 L# l' u. w- r: Q
* 形 参: 无
3 S& |- N/ o+ B* q* j
* 返 回 值: 无
7 C) c9 L/ e6 x+ T% b
*********************************************************************************************************
8 Y' s! @6 b+ a# w
*/
. m; q/ ?* `# A, z
int main (void)
6 I. G7 R* F* x6 l
{
* B1 y( F' c* K1 g' _* c
/* 初始化外设 */
9 }% J; G/ R7 S+ ~5 [0 T8 N; Q; p V$ Y
bsp_Init();
- K: q- l7 f! K! F k
' M H. ^9 b- v$ T* b/ `9 L
/* 创建启动任务 */
7 R; @6 {3 a$ n. B9 y3 j' f7 t9 O
os_sys_init_user (AppTaskStart, /* 任务函数 */
" t$ m+ ^) y) \: ?+ i& @7 v4 y4 e
4, /* 任务优先级 */
6 ^1 X. y% U; O$ g6 ?, J
&AppTaskStartStk, /* 任务栈 */
3 G* G- C3 ?% ~2 L0 H* A; \
sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
8 R3 T/ i" ?$ W) u; S6 Y0 `5 X+ F
while(1);
3 m( R' I2 I* b) X' |% e. a" K
}
复制代码
, z, i' _ v1 R4 K s) q9 ~
RTX
任务创建:
/*
7 N: j' i- k7 R; M$ r" Y
*********************************************************************************************************
8 t' V) Y) a! E7 }2 I3 }! q$ \2 |" P% b
* 函 数 名: AppTaskCreate
V/ C3 `+ f! E- R# D% m& [
* 功能说明: 创建应用任务
6 a1 h) y& i" t# L- g# Q
* 形 参: 无
2 j# H- D3 ]- S7 y+ G. K' C/ {
* 返 回 值: 无
1 Y" S k$ Z p- j% F, O
*********************************************************************************************************
, t/ ?% W, \, j6 v1 D) d
*/
$ P7 [( K% j( p, J1 Q" n
static void AppTaskCreate (void)
; d9 H" h, ^5 O& h
{
M; \+ B% n" E; ?8 z" E& P* k
HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF, /* 任务函数 */
, V% g+ `2 X# C$ p) A1 u% A. T
1, /* 任务优先级 */
# a% Z9 ?: l. h6 M
&AppTaskUserIFStk, /* 任务栈 */
+ P* e% c+ f8 \# [/ x
sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
! m0 L. [5 ]7 x% d0 Q0 q5 A; p+ d
- m2 F/ P4 Q. s9 f
HandleTaskLED = os_tsk_create_user(AppTaskLED, /* 任务函数 */
' |/ Z8 {3 J# a" }& X j6 u7 D
2, /* 任务优先级 */
1 x6 C/ z% s9 e8 z
&AppTaskLEDStk, /* 任务栈 */
2 r1 E. r$ s4 H; W+ }; y4 z. [6 E
sizeof(AppTaskLEDStk)); /* 任务栈大小,单位字节数 */
, G$ M' V4 u" b' x( {5 q( E6 u M
8 I1 p. E$ M" B& Y' o7 @8 j0 i
HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro, /* 任务函数 */
0 z d- f# z @* q; n; P% c
3, /* 任务优先级 */
" c* x8 O( u9 J2 v4 n A. X- }6 v
&AppTaskMsgProStk, /* 任务栈 */
6 L7 ^, @& g5 ~8 R
sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
( E4 w- n |6 P7 Q6 \
}
复制代码
1 e$ m$ |5 B I) [# l8 x5 C4 I( c5 K
消息邮箱的创建:
#define PoolBlocks 10
" P! S9 R, p7 u/ h- S: P, c
#define PoolPerBlockSize 8
$ H" Q+ n3 i9 E' G# E5 S, r
6 S9 O o T! R" ?2 x: R0 U
/* 声明一个支持10个消息的消息邮箱 */
: S% l7 ]- {: o; i2 j2 {) W& o" t. W |
os_mbx_declare (mailbox, 10);
5 q' k: b& f$ |1 t
5 _8 q9 V8 }2 \& W, \) v9 e
/*
7 S- [ a4 e9 q& [% l
*********************************************************************************************************
6 P" h7 v7 Q$ Z8 T. C* p
* 函 数 名: AppObjCreate
1 }3 i$ x% T" p2 B
* 功能说明: 创建任务通信机制
; J5 i8 Z# V: d# |. Q
* 形 参: 无
% Y1 |4 p: e0 |" u
* 返 回 值: 无
X) k( `5 i. ^3 [4 H
*********************************************************************************************************
4 a9 ? G* Q0 M# J! x% O* W6 G: `- ~- ], b
*/
2 o/ I% D0 ^8 ~6 y V+ e7 H
static void AppObjCreate (void)
7 T9 A+ p- y2 t
{
) [2 N5 f( R% F8 i
/* 创建消息邮箱 */
g! Z2 Z9 w# u% S% `$ P
os_mbx_init (&mailbox, sizeof(mailbox));
* g4 `1 h3 d7 a: U6 A! p5 ?' {
2 \7 H$ h& Q( V# [ Z% `$ ~& c
}
复制代码
- h" N" x; {9 F# g/ Y
SVC
中断函数的创建:
void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);
4 h' q# O* e2 j+ _
void __svc(2) SVC_2_FunCall(void);
, u) ?3 `" G3 H; D' O% ^3 K8 I# [
( i/ R" n" Z+ e. i! Z1 G
/*
+ W. ^; x2 s* o/ t( k& E' X
*********************************************************************************************************
" {6 B/ w5 s5 D3 s2 E( W2 j+ D
* 函 数 名: __SVC_1和__SVC_2系统服务号
6 y* }0 U Y1 X3 k3 p
* 功能说明: 被SVC中断所调用的__SVC_1和__SVC_2
% V; w: O$ T# R
* 形 参: 无
' F$ Z7 z1 y' F8 Q5 j! Q
* 返 回 值: 无
1 ^2 t' _. z) Q W. c. C$ f4 L
*********************************************************************************************************
/ @; t7 G' ~1 j0 o9 Z! U
*/
+ t; a6 V" u' y" t8 {# q- i! g
void __SVC_1(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4)
1 ] ?$ C- Z1 Q4 L0 `
{
3 x5 b8 }6 ?' d2 }$ m7 ^: X/ g
/*
' ?9 n+ O; e% O7 j G+ ]. S0 J
1. 实际应用不要在SVC中断中调用串口打印,太影响实时性,这里仅仅是为了演示
3 O- A" I& a& w" o
2. 根据需要做开关中断操作。
: v `' v, H E8 q& C; R
*/
$ Y' T4 U8 ] @6 Y$ H3 q Y5 _
__disable_irq();
n* q- L; O6 F
printf("_arg1 = %d\r\n", _arg1);
# B5 F" v2 P/ Z4 L% @: z( M
printf("_arg2 = %d\r\n", _arg2);
# `) Y# D, | N' @& ~% }. `
printf("_arg3 = %d\r\n", _arg3);
/ U7 J4 I/ @& I3 e9 b3 t# J
printf("_arg4 = %lld\r\n", *_arg4);
/ t& j+ q5 W+ N! H4 ^7 y) B
__enable_irq();
" h q1 Q- R0 s4 p, b& j
}
. c3 L* B$ Q2 B- x I9 k
) P; @2 l ?2 h& Y# f
void __SVC_2(void)
4 P% T2 N' K. g' p1 q1 N
{
* b, V+ K* @) `' I" r" a7 A
/*
- Z& I4 R4 e2 H: t, ]
1. 根据需要做开关中断操作。
$ t. `0 W* F* X
2. 本实验所有任务都是工作在非特权级,中断函数都是运行在特权级的,此函数是在SVC中断里面运行。
( n! w1 k: G: I- Q; f
所以可以在此中断中设置NVIC分组。
! ?& B' |2 B' N& k
*/
* l4 g! S! T/ {: U8 V2 p s
__disable_irq();
1 N! _# k- Y% ~7 |. r
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
1 ]" @- C, p( o' B4 h) s2 q
__enable_irq();
) m* h4 L! K+ o5 S r( m9 I3 u
}
复制代码
* ?+ e* _: R7 v1 x$ v
SVC_Table.s
文件中SVC中断的设置(红色字体是需要用户添加的):
void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);
- Q9 c+ R! r2 O* n8 ]% O
AREA SVC_TABLE, CODE, READONLY
7 T l4 F4 V0 y, F Y
. o9 |0 n. N+ h% V
EXPORT SVC_Count
, K0 v/ `: W F
- l. J" q7 [' r9 o
SVC_Cnt EQU (SVC_End-SVC_Table)/4
9 a: T* q* J+ P6 e3 v
SVC_Count DCD SVC_Cnt
" \: E; X$ n! G2 Z, A3 z
6 ^ p# ^! X5 C$ r5 }4 S6 v
; Import user SVC functions here.
3 \' o; z2 c n( j* E5 q
IMPORT __SVC_1
3 Y" v2 \9 `" b# V1 `9 g `( X% r
IMPORT __SVC_2
0 V% W- A9 k% a
: M$ N$ C6 r* k4 X3 g
EXPORT SVC_Table
* Y, `+ s/ }; R. j
SVC_Table
w- ^: A* h ]- k9 k, {
; Insert user SVC functions here. SVC 0 used by RTL Kernel.
% r8 R) L" F$ `
DCD __SVC_1 ; user SVC function
: k5 R% X+ u% s
DCD __SVC_2 ; user SVC function
/ a% c4 j4 F" K4 j* o J- Z: i
4 u& F1 |, i1 k* E0 d4 E; \8 y! o
SVC_End
+ A O/ g$ L. l5 }4 R( z0 N( S: _7 c
3 @; A' T3 k+ c
END
复制代码
8 s, r/ y7 @- E9 Y5 y
四个RTX任务的实现:
/*
; B- V l2 L% {4 R
*********************************************************************************************************
$ A( S) P& u- T* H* Y
* 函 数 名: AppTaskUserIF
- X1 E6 E6 n" S4 }- W, I
* 功能说明: 按键消息处理
! u# J) a \) w4 L* h# |6 Z% S
* 形 参: 无
! m2 d5 L* K4 J" i e+ b
* 返 回 值: 无
1 e/ M+ W! ~; \7 N3 j4 e
* 优 先 级: 1 (数值越小优先级越低,这个跟uCOS相反)
6 H. @" w: x- y% X$ i$ J9 N" Z# @
*********************************************************************************************************
, L0 w9 ^ R9 J' Y$ S( D8 N
*/
: N0 J4 [: [: c0 y$ ~, P
__task void AppTaskUserIF(void)
, ]! V% Q" j5 A9 L y
{
f* D" D k9 f9 `3 i: M
uint8_t ucMsgTra = 0;
, d4 p" p1 Y' [9 W7 s
uint8_t ucMsg = 0;
; ^% Y* B( z, J1 K5 L" L
uint16_t usMsg = 0;
6 B5 y* b; |5 ~: D1 P
uint32_t ulMsg = 0;
0 ^' ~1 O0 V, c) m" l. \% [0 v
uint64_t ullMsg = 0;
7 d1 S4 |( l9 y H/ a
uint8_t ucKeyCode;
1 B$ H5 F, J6 P q# g" U! _, N
0 _% G5 C: `( P$ P2 O/ S# N! ?
while(1)
# u7 j) |' A, c. y
{
' ~$ i, w* ]) k4 d8 F0 V1 b% _
ucKeyCode = bsp_GetKey();
( K" F; I1 \* k
( n8 G0 k* j# P! s# C
if (ucKeyCode != KEY_NONE)
- o; E" U. i/ _% B/ I
{
- X1 t( s! Z6 P$ G2 |8 _- o: q
switch (ucKeyCode)
" v) C" E3 J. T( C5 u5 _: ^# b% d
{
n' W+ v t2 f* j
/* K1键按下,打印调试说明 */
# `% @0 \ {4 @9 [/ p6 h- @7 y" V
case KEY_DOWN_K1:
8 ?5 R2 Z4 z- V0 k+ U2 j
printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
1 `% _5 n, ^ |
break;
$ F3 N5 c- A, u; z! ]
# }, F! k; A0 e) L8 ~1 C, i" ^" ^
/* K2键按下,向消息邮箱发送数据 */
* o) B5 d# Q# S4 o4 [1 G2 h
case KEY_DOWN_K2:
. J9 t$ L- j6 M) q( [6 A
ucMsgTra++;
! a1 Q) D& t" m- h4 I- J: Q. A
- |. d2 t( T& P& `( L
/* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
' o$ z9 S7 W3 B2 u7 p5 e# N
if(os_mbx_send (&mailbox, &ucMsgTra, 100) != OS_R_OK)
|$ R6 |' E; S8 `4 z1 j4 }
{
! H \! P+ f% X7 y
/* 发送失败,即使等待了100个时钟节拍 */
, }1 }5 P% q7 ^6 e
printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
7 C5 m0 A* }3 U( _% M9 S
}
: X" Q7 f5 o$ E
else
# R4 n9 z* y3 y
{
8 v5 o7 T0 E6 A7 w, o8 D
/* 发送成功 */
. j& S0 c" p6 z( ~
printf("K2键按下,向消息邮箱发送数据成功\r\n");
, U9 Q6 b c! p& F
}
1 ?. W+ a& R5 j3 A
break;
" h7 l3 u' X! h4 L |( e2 |
% o6 B) L% ?7 u. D H; V$ w" H
/* K3键按下,调用SVC的1号系统服务 */
9 k9 w1 E& B7 G# c4 ?' J9 A8 P
case KEY_DOWN_K3:
! f) A5 V/ z- n1 l, c, M( T' l
printf(" K3键按下,调用SVC的1号系统服务\r\n");
; i' Z, H v+ w5 ]
ullMsg++;
0 e' N4 n0 H+ I, d
SVC_1_FunCall(++ucMsg, ++usMsg, ++ulMsg, &ullMsg);
" d3 `2 w' o& t k! A
break;
) r) b$ b' `- T5 G4 p0 x! u6 ?
4 o/ E7 n' q: J0 T' O
/* 摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可中断中设置NVIC */
& s, @& U. x5 O% c
case JOY_DOWN_OK:
- L/ {0 m! P$ X" m
printf("摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可中断中设置NVIC
: F2 `6 f0 b1 w/ z1 o, }: l" W
\r\n");
0 v* q, h5 B. z
SVC_2_FunCall();
( w, S5 X+ F; a+ _; j2 ]# Y
break;
" O) X s2 } \$ Q/ B* G M+ v7 i
; f" X% U" i# s0 {: _0 [6 y
/* 其他的键值不处理 */
6 i7 c! J B* ^+ E
default:
$ f b& b5 P# J4 w
break;
2 J! }& T& ~0 s: [. [9 |
}
( W& f5 N- d4 v1 a
}
9 u, e0 m: s c: `/ X
W( ?' q0 F h$ H+ Y; E
os_dly_wait(20);
6 G) X. U; V* A1 e- v& Q9 q
}
' f# a/ u# E5 C1 d a
}
& _* ~( B( S2 H* d. K
5 W7 D+ m9 M0 T* E. A
/*
; m2 H- `1 J0 I$ e
*********************************************************************************************************
S7 [, I4 d1 U8 l; }, w
* 函 数 名: AppTaskLED
" I6 _+ f5 `) D8 u
* 功能说明: LED闪烁。
9 S% E. Q( f2 i, r- [9 E
* 形 参: 无
; ]: w p0 f" e; o& |
* 返 回 值: 无
3 z8 q$ F4 E, d6 y% K
* 优 先 级: 2
( E( l7 ] o$ C0 z
*********************************************************************************************************
, m4 n+ P( z$ E
*/
; R; j. D: x2 Q0 H9 x% L
__task void AppTaskLED(void)
: ?$ n* E: B2 q% b+ B0 k( C
{
7 d! a+ z: z1 b1 F5 @, g
const uint16_t usFrequency = 200; /* 延迟周期 */
+ t; ~3 S0 L4 n, V
4 _/ z( ^8 _' U {
/* 设置延迟周期 */
! Y1 G4 }. l7 q# x# H$ I, ~
os_itv_set(usFrequency);
\" h( V0 R: q& k% \! f& [
9 e7 o2 W6 V" D
while(1)
& k* x( z$ P% y- [9 z
{
* K9 d' E+ m7 X( D5 v( O0 x/ `/ ?
bsp_LedToggle(2);
, O& F( j! T3 B! _
bsp_LedToggle(3);
# X6 \2 z( M+ V( Z( q2 r
# ~/ j3 a! Q" H& o. [1 y; K
/* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
$ W1 u, w7 j @5 q2 h8 c/ V, l8 o
os_itv_wait();
% S/ d! _8 @' ~4 ~0 ^6 R
}
; g5 I1 Y! u7 P S) Q" ]
}
9 _6 ]( K" w, H8 G/ Q6 }# G) w( J
4 J5 _9 \- F/ L, S
/*
1 S+ u, r' D0 s: n' ^
*********************************************************************************************************
3 e9 K2 g# a0 Q4 K2 @
* 函 数 名: AppTaskMsgPro
' P" V) g6 N& z
* 功能说明: 消息处理,等待任务AppTaskUserIF发来的消息邮箱数据
0 I- E1 m3 O+ S- A
* 形 参: 无
; y" V }2 ?, D @$ p) a0 g
* 返 回 值: 无
' ^ k/ C3 z! f1 M/ F& c
* 优 先 级: 3
4 P5 O4 X' S: L
*********************************************************************************************************
7 H; `8 J( F1 M- y8 I# y. R
*/
& W0 h0 M' b6 K* m
__task void AppTaskMsgPro(void)
/ x& _8 \( @& e% D o6 r
{
& {; L; t4 e' X' M8 d
uint8_t *pMsg;
1 a8 S! {3 R1 V* l! F- D9 }) i
OS_RESULT xResult;
# C' h5 T! ?' K ]7 V# i
const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
& }- k8 G9 z# Z
/ }& p# Z! V* r
while(1)
; n: p( |! @ a7 ^
{
3 T) N$ ]) x. E6 l
xResult = os_mbx_wait(&mailbox, (void *)&pMsg, usMaxBlockTime);
/ d2 b* K! v5 t% ~
# N9 i6 X! |$ k0 h Q; J, Q
switch (xResult)
/ F- |2 A! p5 E+ l& e4 j9 ]
{
- {$ Z3 [4 g* G6 G6 b, B- y* K
/* 无需等待接受到消息邮箱数据 */
; ~+ f0 F: N* U Q5 j3 I% x
case OS_R_OK:
7 U& Y8 ]) n' A2 d, W1 d0 s
printf("无需等待接受到消息邮箱数据,pMsg = %d\r\n", *pMsg);
" B, A: f: @# [; V
break;
* K) ~! s8 P/ v( W
- H [" ]; Q+ p/ P1 S
/* 消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据 */
( X5 \3 `# V N, ^$ u2 r+ U7 G
case OS_R_MBX:
% h" q/ J5 B/ c' C( x
printf("消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg = %d\r\n", *pMsg);
1 W- S- l7 Y4 A' ] F) |+ ^" Z
break;
4 v0 D9 b2 C Q* } L! s
" q, R2 X& K/ z$ ]. N3 o
/* 超时 */
w$ L( V n. v4 `2 ~" q
case OS_R_TMO:
/ ]: p& z- a' B( V4 ?
bsp_LedToggle(1);
3 {0 |3 v0 N, I" x' ?3 i
bsp_LedToggle(4);
6 K/ c$ E; U4 X
break;
; d, L g D+ m9 S" t
/ t# O1 K3 M9 O& ]
/* 其他值不处理 */
+ m- d/ V/ l" W* ^$ w5 ]: L* a% I
default:
/ g! n) A" e- O' ]
break;
) Y4 H& H* t$ Y2 L6 K
}
/ g+ J. h& _% E
}
4 ~" K; O0 z1 h! ^. P1 v
}
4 i) b# e; ^; D* ?
5 k- W+ u/ E$ ~3 b% ?3 _. T3 q6 N
/*
5 @4 F* N% y3 N2 Z
*********************************************************************************************************
, D6 _- b* D i( p I' m
* 函 数 名: AppTaskStart
3 a7 ?! o, ^* H. P$ ^; x
* 功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
+ c% l1 K/ Z$ h }- c3 F7 c- x
* 形 参: 无
9 I$ d0 C( v# v/ m; N
* 返 回 值: 无
. H, o) L6 }- l5 b( G
* 优 先 级: 4
9 y, U: y* ?% |0 N
*********************************************************************************************************
9 @+ v3 ]4 j( j Y( y
*/
( |$ s- r9 z T4 c9 x) F
__task void AppTaskStart(void)
3 U- B+ x3 ?/ _6 M" ?
{
@, Y5 i, C6 z3 ?
/* 创建任务 */
$ p( t( N, s, X* S2 Z i* B
AppTaskCreate();
# z3 n, X- ]0 S K! t6 q- E3 m
& J' w% r, G8 w6 n H
/* 创建任务通信机制 */
) o2 b( l3 [7 b" E- F4 j ~; r: X5 [
AppObjCreate();
) r( C1 H6 A/ |: _- A2 N$ I
* ]2 M0 I# z6 p. j
while(1)
, t6 O" M" q9 d8 x# [
{
- J8 ]- x( a# J, y) W: {" R( Y
/* 按键扫描 */
8 h! s9 g0 q/ y& q+ i
bsp_KeyScan();
/ G* O' Q) F# b
os_dly_wait(10);
2 t* M9 f! G* v+ F2 [
}
! e- K5 f1 _5 ]. N2 Z
}
复制代码
6 W1 h, F O- R( ^- T+ Q5 y# B; m
6 X# k4 ^7 c$ L
赞
评论
回复
支持
反对
baiyongbin2009
回答时间:2016-2-3 17:44:39
a0a.1 32b0c
19.4 总结
本章节主要大家讲解了如何采用SVC中断方式调用用户函数,更多SVC中断方面的知识可以看Cortex-M3或者M4权威指南。
/ j; e4 O k9 i' L% b* z, |7 j$ o4 R- s
赞
评论
回复
支持
反对
zhangdaijin
回答时间:2016-2-3 21:09:38
a1024a.1 32b0c
谢谢分享
赞
评论
回复
支持
反对
niexiaohui
回答时间:2016-2-4 09:45:25
a0a.1 32b0c
好样的。楼主幸苦!
赞
评论
回复
支持
反对
党国特派员
回答时间:2016-2-6 09:08:29
a0a.1 32b0c
楼主,有没有完整的PDF?
赞
评论
回复
支持
反对
feixiang20
回答时间:2018-1-15 20:54:26
a0a.1 32b0c
篇幅可真长
赞
评论
回复
支持
反对
所属标签
关于
意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号
手机版
快速回复
返回顶部
返回列表
19.3.1 STM32F103开发板实验
W* i1 e' c2 P
6 X# k4 ^7 c$ L