一、外部中断(EXTI)—简介6 L; W/ M1 V$ d7 {4 P
EXTI (External interrupt/event controller)——外部中断/事件控制器。: _% k" k; H6 F: v. T
互联型STM32有20个能够产生事件/中断请求的边沿检测器,STM32F103系列有19个能够产生事件/中断请求的边沿检测器。& d8 y# `5 o$ x
每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。
1 m' K3 c5 M) h0 i7 |" V0 [每个输入线都可以独立地被屏蔽。挂起寄存器保持着状态线的中断请求。
) J8 S8 B8 ?5 m/ U8 N) m
" {1 J4 Z" ^/ m+ u' n1 e o二、外部中断(EXTI)—框图
! k: P/ Q% F k3 A) R7 f
3 S# z0 e+ B& \
$ u& z' I: b# z+ x8 l2 [5 C
; n) P/ M/ f& N( N0 a! {
三、外部中断(EXTI)—线路映像0 K# E" g, D1 T: F b
通用I/O端口以下图的方式连接到16个外部中断/事件线上:! I2 C8 ~8 `/ U, c
' K4 g& j0 K/ R* |( W4 ?* e
0 Q7 y6 P" a" \# t3 f: e; M4 d5 c! K8 f
8 V1 w! {4 m5 {5 \, Y2 @
0 u/ [ X9 s4 }3 h' x四、外部中断(EXTI)—寄存器: t1 @+ S9 m) v. A6 a& [
从外部中断(EXTI)结构框图可以知道,外部中断功能由六个寄存器配置。
" |! I" O5 y5 `% x
& p% m/ C- Z, u3 ^/ x y( y8 H1. 中断屏蔽寄存器(EXTI_IMR)
6 c2 `. z- X+ c( E; r6 A
" m' T! W, j# S5 n) x6 [# {
. G. c8 N: B$ N1 G
/ f+ ^/ R( b( a9 f$ H2 ~
2. 事件屏蔽寄存器(EXTI_EMR)9 ?( q6 y' a" g9 e; t0 l5 x
5 L: [4 l8 w1 J$ x" x9 o z2 ^
& D( Y8 M! }: Y+ E
! }" H1 K3 o. W2 V# h! d# U
3. 上升沿触发选择寄存器(EXTI_RTSR)7 C4 L3 @* \7 q9 O
8 }4 X1 X* G3 ~1 x' K8 {8 x
4 i# N, x: j& a% N, g) }
( |% W# `2 r6 J4 m. E: @( [
4. 下降沿触发选择寄存器(EXTI_FTSR). C: c) ^% Z. b0 n: O( g/ ^ {/ Z
7 J, c3 @. j/ N- I
# [3 c9 W3 s( E; S2 c' u0 i* R( S- S( Y9 ` u) U4 M
5. 软件中断事件寄存器(EXTI_SWIER), U# o4 G, y6 s
" a- e0 R0 I" b4 v1 E! x6 V
' k" F' I; l, @5 K2 A2 ]9 |
8 X+ R# N% V7 e/ x$ d! v: b
6. 挂起寄存器(EXTI_PR)1 T- B6 \/ g# I9 b, v1 E
. Q4 n+ i6 C8 A& `0 A# Y$ M% q B
& n( l' [( @/ i! F* ^# R5 n4 N8 s, M% ~+ r
五、外部中断(EXTI)—配置7 p! r. f! `* D2 A& o
1. 外部中断(EXTI)—映射关系
+ z# `6 g* a; I2 I; A, |( W. D7 }3 S$ n; d# L- H& i: X& t
) S" v0 u; ~! r$ F( p- Y
2 V4 x* h0 w5 ^2 |' |# ]2. 外部中断(EXTI)—GPIO引脚配置
3 A7 L. x; j/ f
2 O0 ~, z4 b9 a! O7 G
0 E' X( F3 K' f5 Q& g. [
' p, z) Y! W6 d( F- G2 o o由上图可知,外部中断的GPIO引脚可以配置一下三种:- GPIO_Mode_IN_FLOATING //浮空输入3 l1 N/ [' ]# k
- GPIO_Mode_IPU //上拉输入3 P' r e5 K( n j' X4 i8 q1 d. }
- GPIO_Mode_IPD //下拉输入
复制代码 ) E7 T- l& b, {
3. 外部中断(EXTI)—触发方式- B6 B- K1 p: V
外部中断(EXTI)有三种触发方式:- EXTI_Trigger_Rising //上升沿触发
6 U- T' y6 _- }3 B1 m- n: @ - EXTI_Trigger_Falling //下降沿触发
: }) ^7 u. l ?- c4 m/ Y - EXTI_Trigger_Rising_Falling //上升沿和下降沿都可以触发
复制代码
% @" C8 \! G/ X, ~; f L六、外部中断(EXTI)—程序, ?* M6 D# x. O/ M- V2 {% B4 Y) m2 V
外部中断配置程序# S/ f5 \+ E! V! L. Q
- void EXTIX_Init(void), B. R' y% A+ \( f
- {0 p" W Y2 T5 o% v% Q+ a1 g) d
- EXTI_InitTypeDef EXTI_InitStructure;
! K( |! F F0 H5 K! z - NVIC_InitTypeDef NVIC_InitStructure;& C% g T7 T2 o$ ]# ^* ~9 T, K# h
- GPIO_InitTypeDef GPIO_InitStructure;
( T! c9 X, O c: u& s. u/ Z - //初始化时钟9 J- m @2 q1 S) S7 t$ u& Y
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
2 t; t; ^" z9 g6 Y: t! C, n# R: e - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);//使能PORTA,PORTB,PORTC时钟
. U0 O2 C O u: x9 m - //初始化GPIO端口
7 e; P. O% }2 T. V; B& b- q - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_4; //PA0,PA44 s; A" p* E. f9 | z% j
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //PA0设置成浮空输入,默认下拉 " w6 U+ s: l) w& B
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //最高输出速率50MHz
5 @& Q! f) @8 c5 I4 Z1 `+ `2 i - GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA5 s( g* X$ w! a/ s0 H ]1 Y
- 5 U! J% s! ]# d: E2 ?' `
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_8; //PB6,PB8% w* ^% U# a+ N9 Z4 a; o
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入,默认下拉
! L$ t! v- q' W - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //最高输出速率50MHz+ T1 v6 N3 d: u. F& a$ v
- GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB
/ Q B5 A. H3 g - ) M( K7 V' o2 Q( O R+ i) I
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_14; //PC12,PC14/ h$ |) g' o4 R. |7 _/ [
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置成下拉输入,默认下拉
5 v% j+ `7 y0 K/ G - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //最高输出速率50MHz$ Y' w0 t% i; y* B
- GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化GPIOC. ?& q; O' J# ]) [
- . {+ ?( l& J6 F1 J. H8 Z E* a
0 b' Q B8 y; }1 \; E6 N) N( N- /*GPIOA0中断初始化配置*/
* D: r" K( N$ n' k5 w - EXTI_ClearITPendingBit(EXTI_Line0); //清除线0 IO口中断清除挂起位(清除中断标志位)
/ y4 e+ x0 g. g0 `( w/ ?7 ?8 Z- x7 K - EXTI_InitStructure.EXTI_Line=EXTI_Line0; //中断线选择, |* f3 K8 S) k) u+ _# m! [
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI为中断模式 S/ O% `. r* l2 Y/ E3 U
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发& P' \& N! ?% C
- EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断
8 ~9 `- s' B3 K U5 e3 r) r* j - EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器7 i/ p5 x ^9 i7 U. U) T6 }8 }
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //将GPIOA0挂到中断上: D" h0 ^' E( `. K, \3 j
- 7 o1 l0 L+ _1 w7 j
- /*GPIOA4中断初始化配置*/ 1 O/ s2 \3 d% m# \
- EXTI_ClearITPendingBit(EXTI_Line4); //清除线4 IO口中断清除挂起位(清除中断标志位)4 C7 e" n6 [( \4 i; A, ~+ y
- EXTI_InitStructure.EXTI_Line=EXTI_Line4; //中断线选择
. E0 ]. H( ^, `" J/ O; f% g* H - EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI为中断模式
, v0 c* F! k. [0 \ - EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发0 g. b" k7 h! U% p' i2 K
- EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断
\& U' } |' `9 O- v1 A% X1 r1 a - EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
6 {0 e- H6 z% F - GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource4); //将GPIOA4挂到中断上
! q$ Y+ l. x. Q7 [ A7 }4 g7 v6 I - 8 e- i0 y0 Z/ F9 t
- /*GPIOB6中断初始化配置*/ 8 T3 m, T, e& Y) `+ P
- EXTI_ClearITPendingBit(EXTI_Line6); //清除线6 IO口中断清除挂起位(清除中断标志位)0 F! f* P" s" w# t- [- r" H
- EXTI_InitStructure.EXTI_Line=EXTI_Line6; //中断线选择# v3 k/ M7 g/ H1 K* Z8 E K
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI为中断模式
2 u1 H" O3 r' G! C! E+ h - EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//上升沿和下降沿都可以触发
) w+ K5 B) ~1 ? p; z2 l& b* o& l" M$ p - EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断7 b3 m: o7 E/ {& ^2 ?/ K
- EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器: D* y! h( ] F$ M- `3 E8 j
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource6); //将GPIOB6挂到中断上
+ `& ]" |& Z0 d4 h4 t - . z- @5 ~5 E5 c" o9 Y* Z
- /*GPIOB8中断初始化配置*/
$ K8 h: W0 R8 C4 U6 o - EXTI_ClearITPendingBit(EXTI_Line8); //清除线8 IO口中断清除挂起位(清除中断标志位)
0 ? U# _, S* X% A& E8 b - EXTI_InitStructure.EXTI_Line=EXTI_Line8; //中断线选择
" N9 o3 Y6 A: m- v, @ - EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI为中断模式
t e, v! r- Z& K! P' ~, F - EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发7 j* U b- E+ g% {' I. b* R1 F
- EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断
+ A* M" H4 |) Y) T2 U - EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器8 g5 \* s2 }/ W6 [: h
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource8); //将GPIOB8挂到中断上
/ p3 O. I/ O' }2 w) e3 w9 w -
! S/ Y9 g/ J, y% E6 _ - /*GPIOC12中断初始化配置*/ / ?+ {, u- y2 P( d
- EXTI_ClearITPendingBit(EXTI_Line12); //清除线12 IO口中断清除挂起位(清除中断标志位)
: `7 ~$ k3 @% ?" o0 e - EXTI_InitStructure.EXTI_Line=EXTI_Line12; //中断线选择$ J4 |4 z: s! T+ b" Q% s
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI为中断模式1 c! Y( ^+ D! s
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发1 z( Y' l) |3 N; b
- EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断
0 N- @2 s9 V! Q - EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器 a$ k" Z7 P4 |
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource12); //将GPIOC12挂到中断上
2 C# N* P, D8 v* w - 9 ]7 k0 l) w* B% t7 |0 k- |" j
- /*GPIOC14中断初始化配置*/
4 q# W- j0 k; \% w5 D - EXTI_ClearITPendingBit(EXTI_Line14); //清除线14 IO口中断清除挂起位(清除中断标志位)3 Y6 w; A4 \$ i1 U. A$ D5 E
- EXTI_InitStructure.EXTI_Line=EXTI_Line14; //中断线选择! m8 e* [% ~9 Z8 {
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI为中断模式0 I7 d4 F i# S4 |, @
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//上升沿和下降沿都可以触发
" z" y) Y7 j( U$ s) X - EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断( O* a. c: w5 ^! L1 c( M
- EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
* k V: j" v7 x2 i8 X& ]9 T9 u - GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource14); //将GPIOC14挂到中断上- D' S2 \5 C: \" T" M( u
- & J% z; \ N$ ^/ V) I6 H
- /*NVIC初始化配置*/
+ C* Y& O1 d3 f5 l - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //配置NVIC优先级分组为0+ \$ y5 g/ E0 v. e+ q' x2 B7 E
- 9 H" Q# c2 v9 t$ e* t
- NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能线0所在的外部中断通道3 S4 _9 f1 Z' }" q. }3 c
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0 b4 A0 i6 g: D$ v" d
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级36 P: n' W+ d& T) {, G7 d7 w
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道6 H6 d( c5 H% O( {2 G# h
- NVIC_Init(&NVIC_InitStructure); //初始化外设NVIC寄存器
* M, A3 |% G6 }- @: ` - 5 i0 t6 ~; a2 e& @( ?3 E8 h6 r
- NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //使能线4所在的外部中断通道
1 p- r0 m2 ?& \3 @ - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0
$ H/ H, R$ z+ v8 Y6 X - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级2
1 E9 C B1 z- g2 @6 ~8 w3 f - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道0 E, g8 g P K% o, h. z% \) ~. L
- NVIC_Init(&NVIC_InitStructure); //初始化外设NVIC寄存器/ V0 p, Y ]4 N. V9 k3 D# G" ~% g
-
. I9 s% i% W& ~( w, r5 \' Y - NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //使能线9到线5所在的外部中断通道+ ?! U6 S( t4 u$ q
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0,
% R7 Y/ _( Y, E& E - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级1
- o/ g3 p4 z7 i. X) i$ E6 J - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
/ k: v0 m* M6 Q: ^ - NVIC_Init(&NVIC_InitStructure); e: f( Q4 Q* M3 x9 C
A+ W2 {( [7 [- NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //使能线15到线10所在的外部中断通道; W& o0 d V, P$ b/ {9 [+ V3 }
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0
4 P0 G7 o% R0 F" s' g4 v9 J - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级04 S$ b' C; L. O
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
0 i* ~ G5 q6 U5 S- H - NVIC_Init(&NVIC_InitStructure); 8 T1 F' |; C# j" w* I! ]& b8 }+ g
- }
复制代码 - a2 d8 O v7 X
外部中断服务函数( }* u2 r8 b k! l8 m" F8 `6 \* X& S
- //外部中断0服务函数 4 \: p/ S4 ?, r9 I3 S V; `0 ~
- void EXTI0_IRQHandler(void)
! P$ o# ~9 S3 ^* g- q1 x - {
3 e( d9 {0 x: }# F3 o" c - if(EXTI_GetITStatus(EXTI_Line0)!= RESET)//有中断申请
) p9 V+ ?. U( t& { x' X3 A7 G - {
' |0 U( L/ H, T9 i9 s9 D) ] - /**5 e: q7 S/ N" V9 r; `: ^& U4 U6 v" M
- 其他功能程序+ R- q( [: c% h
- **/( M! [4 U$ l6 S7 e
- EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位
, V3 F; c1 E) P* Y( u% B! o5 i - }, `9 p2 f- E( T! d
- }
& f9 ]% Z- ^8 l. F* O6 K! F - 4 I5 u- ~. p1 {' k- |! B+ ~" h
- //外部中断4服务函数
. A$ x8 ~8 l8 w0 F M3 _& N: _ - void EXTI4_IRQHandler(void)) I( \2 j$ L2 U8 @! g$ A( g# ]" e
- {4 Z& }& |/ |& ^8 }, e5 W
- if(EXTI_GetITStatus(EXTI_Line4)!= RESET)//有中断申请
+ n- o. t, J i3 U7 ~. V) O - {
3 O, {# D# v2 N - /**; M% A# V& y p# O* m3 o5 B
- 其他功能程序
1 T1 N. i) b5 k( G j J - **/% I4 a% @7 v0 I V
- EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位
9 x3 Q/ C% ?( N5 R# h2 w7 s# X0 r - }# L9 {+ m; ? _, w/ T [7 m3 A+ E
- }
. n% m, G. s4 l+ s' s
' ^- F/ s- z' M
9 p% @, P& U) j: j- //外部中断9_5服务函数 6 n6 O! C: U r
- void EXTI9_5_IRQHandler(void)
: \9 p! R: t. J: N! O5 b1 B. l - {
* T( y0 A" t" p) f. B" J - if(EXTI_GetITStatus(EXTI_Line6)!= RESET)//有中断申请
0 \0 w: A% @/ K9 Y7 O# J - {" C4 H7 y* x0 V" C3 |1 y" N0 J
- /**
, u* h3 o; M) ~/ U - 其他功能程序
3 v3 }% K. U% Q) n9 ^/ ? - **/8 p" r6 Q4 {% t& F+ U
- EXTI_ClearITPendingBit(EXTI_Line6); //清除LINE6上的中断标志位 $ x! O& G, B7 m- A
- }
* U7 }; ]- f$ I9 |# \% K9 Q; G! ] - 6 D, f+ H- W1 E: ^" Q
- if(EXTI_GetITStatus(EXTI_Line8)!= RESET)//有中断申请
" L4 ?& F# l7 D! q7 T# Q0 D5 z B - {" j8 r- O9 a8 a( ?. E! D: q: B0 }3 `
- /**2 Q; q0 f4 c' R. P! s
- 其他功能程序
* R; ~2 v% b4 A& ?" ?" | - **/$ V, Y% W' j) t" C* ~0 u
- EXTI_ClearITPendingBit(EXTI_Line8); //清除LINE8上的中断标志位
/ w1 j4 r0 v% P! z" c1 _ - }& }. t/ {- E9 a! A3 R8 }& L
- }
$ o3 |* `1 ]2 e- `9 Y) [9 D - 4 A- P l- p! w3 W
- $ g( C* I5 X6 N9 [
- //外部中断15_10服务函数 5 f3 ]) c0 ]3 [7 _- z) O' R" s
- void EXTI15_10_IRQHandler(void)0 D7 ]6 L# I( u( y* a
- {
' n9 U. n; m7 k7 P - if(EXTI_GetITStatus(EXTI_Line12)!= RESET)//有中断申请
' b( ^& N$ `4 I8 m0 U d - {' ~6 N, Z' K0 @
- /**
# T" e) R* g V @) s- b - 其他功能程序! Y2 x. ^# z- O" V" w0 C, Y
- **/2 Y9 U# b" t0 ^ }
- EXTI_ClearITPendingBit(EXTI_Line12); //清除LINE12上的中断标志位
. f0 q2 s1 G' t5 F8 s5 e8 Z$ ] - }
7 r) Z2 Y/ [- k8 s% C E0 ~ -
2 H0 h* H1 h, w2 T2 ] - if(EXTI_GetITStatus(EXTI_Line14)!= RESET)//有中断申请
$ X5 S- S1 z3 e; t3 y - {
% ~2 m! b& r3 Y8 M6 a3 L8 S - /**7 V2 ]$ I7 F2 _! Y! C0 H3 ~
- 其他功能程序! f3 ^1 i1 L7 f( }4 P" r7 C; n
- **/
: T a6 s; i, {% U Z9 x - EXTI_ClearITPendingBit(EXTI_Line14); //清除LINE14上的中断标志位
. u- p1 F! z1 X, X, Y4 ` - }! Q6 r2 x$ Y0 R e9 A" ?
- }
* f+ J3 U, Y- p% I
! v( V. q3 S) c' v, {7 J' L* C% c- - w$ m2 s; [4 N
复制代码 3 m, }. i. o# n" ?
|