本帖最后由 雷精灵2046 于 2019-6-14 09:28 编辑 3 U b9 ?& w, S7 `) l
! t9 f' O+ w1 V. B6 T3 E& V没有用复杂的分立元件搭建发射接收电路,直接用的现成的2.4G无线模块jdy-40。
# Z0 v9 r) c2 Z/ o( r8 Z& g- e7 n& Y
( w% b) K& V! x1 t9 h2 v. @" G发射端靠3.7V锂电池供电,用了一片SOP8封装的STC单片机,负责产生连发脉冲,同时负责检测电池电量,电压低于3V左右的时候触发低压中断,低压指示LED就会亮起来告知该充电了。平时发射模块和单片机均处于睡眠状态,有按键按下才会唤醒,从而实现省电。实测睡眠状态下整机电流约1~2uA。板子洗了一下稍微干净了一点。因为对于微功耗设备来说,焊接残余的助焊剂可能会增加漏电流。
- t1 V8 k3 p0 T/ B8 B, V
' J% a' p" }* `2 T4 i- Y) h/ {; O买了一个火花的FC山寨手柄,去掉里面的牛屎板子,并修正一下塑料挡板,把锂电池和充电模块装进去。& w" `* z0 |( s' n1 t5 ?# g" M/ A
为了减少体积,充电模块裁剪得十分小,并且更换了充电电阻使之适应这个小小的锂电池。这么小容量的电池,也不需要多么大的充电电流是吧?3 {+ w8 f7 z7 l A6 u* m
然后统统用热熔胶粘上。充电电流比较小,所以发热很少,不会熔化热熔胶。 A5 i/ N' j/ @# K6 c8 |! W$ |
; W5 ?# |6 M2 a2 I1 R+ R0 P
" V; ~9 K* Z) ?' H7 E! M
% N2 E6 h0 h( e6 [
最后把按键、导电橡胶和电路板装上去。
0 d; E, j6 n* k( k* ]精心裁剪了电路板,正好扣上,不会阻碍其他元件,也不会影响后盖和拧螺丝。
6 y+ }8 w* k. g. C2 f
; V4 o) I; U# V v" ? [1 `2 U6 Y' d h" J0 }+ v7 _1 ]9 }
完工!5 s8 z+ J C6 s2 `4 D
9 h6 N5 K h+ w' x# X
8 g9 H) r# [- r这是充电的MicroUSB插座。旁边的小孔用于透出低压报警LED的光线。# [/ p- L, @, l9 t' M. ]' N, [
# x/ \% x: Q4 Y* R/ `) G7 y
3 W6 q5 l: O+ w2 C' S2 }接收端用一片DIP16封装的STC单片机模拟CD4021。为啥要用单片机模拟而不是直接用CD4021?因为jdy-40模块接收端在有按键按下的时候输出高电平,无按键按下输出低电平,和普通手柄正好相反。当然我也可以用两片74HC00或者74HC04之类的逻辑门进行反相,但那就增加了芯片的数量。对于FC手柄这种工作频率并不高的设备来说,STC单片机完全可以胜任模拟工作。2 D( I" J: k: x3 p7 |
6 r! a9 a3 u; t5 Z; j2 {. \
& H" G) j( \ k' ^& U% g7 D# @4 X2 D* B/ Z$ X
电路设计有点小小的错误,所以有几根飞线。原本设计使用低压差LDO是XC6206,结果在做这个接收模块的时候,买的LDO居然找不到了!无奈只好用了AMS1117。幸好对于接收模块来说是5V降到3.3V,1117可以胜任。要是发射端手柄的话,3.7V降到3.3V,那就非得用6206不可了。 y/ g; ?$ }# A
% l G0 Q# v2 t# y7 Y; f& m7 E
实测十分灵敏,延迟极小几乎感觉不出来。可惜这山寨手柄的手感并不佳,尤其是方向键,软塌塌的。看来我得买个剪线手柄改装。7 k) N* ]/ n) w& W+ R D
5 O' S1 R; `! s: I3 x2 h! L; W6 f这是电路图,有兴趣的朋友可以参考。
; C4 F* y; j; P' H3 i& N0 ]% Z, V: W0 D2 A. H, w5 a
- y, t/ o2 a5 `6 ` _: r
我信奉开源主义,十分痛恨把技术藏着掖着。好东西大家分享嘛!所以两个单片机的源代码大公开!& Y& e/ e! E {8 J/ a$ W# {
编译器:Keil 51。
3 i* Q* @. g2 y6 r5 f) {
1 l8 H, d4 P% i: q4 G发射端:
7 U1 u9 D3 [8 O- #include <INTRINS.H>6 e9 U2 p, o, g n% O2 h5 e
- #include "STC15W.h": R0 P* V5 \ C- r# w, e
2 ~9 o. U' _! A( N, a+ o7 ?) A* }- ' A* T2 v O) @0 ?4 ?' g4 D
- /*2 R0 A' f( ~8 Y0 u! `
- --------------------------/ X7 S9 @, j. S- l' r5 }% z
- |1 (OUT) \__/ (INT1) 8|
; X, _( C& ] I) p3 e& a! o - | |
" K0 H) ?, D2 I3 x; S3 K - |2 (VCC) (INT0) 7|+ R, Y2 Y; m+ `* g( }' P
- | STC15W204S |. ^9 R$ o% ?* c' E, E6 }
- |3 (LED) (TXD) 6|/ Y/ @9 {& k4 r0 ~6 E' E
- | |
) J) Y$ M) `* T2 V( @6 x$ y - |4 (GND) (RXD) 5|
7 p$ k. t4 U" J; r - --------------------------
+ `7 ]2 \1 D: a, b* S
" X; J, I( ?/ z- B& \- LED ---|<|---[===]--- VCC) F( ~; j1 @& V# `, Y
- Red 3303 R1 q q0 P& B+ C/ ^5 r/ x
# ^ R; l$ c$ {% ?$ `- Fosc = 6MHz2 R- G R/ e5 Y# v7 f# T: r5 ?% h
- */' n: v# r5 A I+ g
- & @ o+ Z+ B8 O0 Y
- 7 `% F/ B4 ]7 c- @( k
- // 矩形波输出脚
2 ]% n5 h& B4 T( S& i - sbit OUT = P5^4;" R7 r8 c$ d4 A9 X1 O
- // 低压指示灯引脚+ A: ]& n/ j( x2 w# L, A8 D
- sbit LED = P5^5;
) O7 ~; d% _9 ?. R: h, ` Z8 s+ ? - * P( Q, R, D: _+ L
- // 停机标志位8 Z, ?4 i, Y& g8 G9 J, [
- bit isReadyToHalt = 0;8 C. x6 c/ E$ g3 O# M
- * d3 B1 t6 n8 ~% x7 X( {2 f
- // 矩形波次数累计
% P1 J( r0 [- a$ Q: E7 o - static volatile unsigned char count = 0;
) W2 E; G$ `1 x6 [- y6 R
! k N- l+ _* G6 I& ~. [- ' p( \+ O/ u) n& q
- static void GPIO_Init(){
; P. L' y' z) T3 _" y0 g - // P3口设置为准双向,默认靠内部弱上拉输出高电平
# H1 U1 w, ?' Q- |& l - P3M0 = 0;7 q$ p: n9 ]1 K! G# K/ i
- P3M1 = 0;0 |" P9 ^! @8 Q: ?3 \) C `' y
- P3 = 0xFF;* g, y: u: l% Z$ \
- // P5口设置为准双向,默认靠内部弱上拉输出高电平7 {$ r/ I2 B/ y- ^: e1 s/ ?$ L+ @
- P5M0 = 0;
: [& f6 A9 F- e1 v2 H! B4 a - P5M1 = 0;8 |( ^1 }4 H+ D2 `6 \6 ~
- P5 = 0xFF;
; s4 ?5 l- \- j) e - }
# v& _! z. ~2 }+ @$ b6 m1 k) l
# n- G* A3 `* S4 N( d, o- static void Timer0_Init(){
: X9 Q5 U+ E* x1 Y9 j | I8 Z - // 16毫秒@6.000MHz0 c" n* P4 Y# |4 a+ y. P
- AUXR &= 0x7F; // 定时器时钟12T模式4 v( ?" h6 u, k# s
- TMOD &= 0xF0; // 设置定时器模式
$ O! p3 K! D/ A# N - TL0 = 0xC0; // 设置定时初值
/ t$ |9 u6 Z; L' T% n, V! ] - TH0 = 0xE0; // 设置定时初值% n8 R! L& H3 D, c
- TF0 = 0; // 清除TF0标志
t2 s8 {4 v1 C! l5 X- I8 O - TR0 = 1; // 定时器0开始计时
% K9 [; w- O- w! U' b6 X - }9 t V1 t- Z8 B, h* d
- @# h, D, d' C$ y( E2 |9 a- static void Interrupt_Init(){
) S) T. l) T3 a$ C0 U9 D - // INT0中断触发类型为下降沿触发5 F6 u* R8 I8 h# M* ]. O: R
- IT0 = 1;
% o3 P9 x/ T3 ]( @" f - // 允许INT0中断
. y- C3 ]$ X: r/ h/ W - EX0 = 1;
, g! a2 `' `) s+ d - // INT1中断触发类型为下降沿触发
3 ]) F6 B6 t E' _1 s6 L) C - IT1 = 1;
" O; z) o; G$ y* d! z; {6 M - // 允许INT1中断
6 i3 j% }. q( V) p" p( E' @6 Y - EX1 = 1;% k* n- Q! b1 ^6 T. A- \+ U5 [
- // 允许定时器0中断# M( g& Y: @2 I' ~' ]6 E
- ET0 = 1;
( M% L1 Q4 s2 [: I - // 允许全局中断& W2 `2 e/ T# \% G7 t0 V+ ^3 z
- EA = 1;9 T" j+ o; t% k( R
- }
1 }# P& m' }; k6 N
! C8 }- W4 ?9 x2 R% y- static void INT0_Isr() interrupt 0{2 a1 t r$ E# h) l) K
- // 矩形波次数累计归零
% |+ f1 u2 g) w4 n, `( F' z - count = 0;
3 y! z& @! i1 B' E5 U' I* m - // 重开定时器0中断
( m6 e+ n; a: {* L - ET0 = 1;
+ j% e7 f' K0 J - }
3 M, e5 @- V; x% a5 K - , C" [4 F- Q6 Q0 |4 K) L
- static void Timer0_Isr() interrupt 1{
& A9 m' }6 Z8 k5 `5 M+ l# \ - // 输出矩形波
`- V# i4 C. n5 H3 \8 S - OUT = ~OUT;# F1 ?1 P0 o) b! a9 I
- // 累计矩形波次数6 A2 _3 ~2 p4 r9 }
- count++;. k! [7 w1 e! y2 w# q# _
- // 超过250个矩形波,准备停机' m' X/ M3 t$ @; t+ h
- if(count > 250){8 g+ f& @7 \7 r2 X. b6 @/ f
- count = 0;
6 i% j! j P. a } - isReadyToHalt = 1;
. d; F" d5 l' _6 ` - }
9 G% v) T8 P5 a7 K+ J! J2 s# Y - }. d0 V$ u: `7 S5 S$ f% [8 E
- : T5 q2 ~+ {# ] y( k
- static void INT1_Isr() interrupt 2{9 z5 n' f* A: f! z" V' c3 j, P
- // 矩形波次数累计归零
7 U6 W' c4 K, s4 ? - count = 0;
1 t) S0 `# ~" v) M+ F- ] - // 重开定时器0中断' o! U. Z) _1 w3 M* a4 z1 c. r7 F4 k
- ET0 = 1;
' q( d# X0 ?: J! L' ]3 O - }! r* P0 ~& l3 d9 s5 ?( M
- * h: `5 B5 h7 q! _: W
- 4 n2 t9 \2 E2 s' p" ?9 B9 z
- void main(){( Z1 o8 n" I+ }
- // 初始化P3和P5口: O- l; _! i4 T0 w$ O
- GPIO_Init();7 }. M2 L8 E8 q6 |; R/ K
- // 初始化定时器0. s5 i9 b# }) s* }
- Timer0_Init();
! o# r% [* f2 X2 E& T5 b9 L0 F* e - // 初始化中断3 r5 _8 `& @+ X2 o' E
- Interrupt_Init();$ G7 S; F8 J' j. n
-
: V3 k/ Y$ k' J5 |' l ?+ @ - while(1){1 e0 B/ G2 l9 O
- // 检测电量
5 H0 L3 n* D( x, J: N3 k - if(PCON & (1 << 5)){
& U- E/ B$ o! E4 E$ E - // 如果电量低,低压指示灯亮
! l f1 B! W/ d# }8 M5 M - LED = 0;: _; W |4 a1 G) P7 b( d
- // 清电量检测硬件标志位& ?+ B4 h, t5 N1 o
- PCON &= ~(1 << 5);
3 m2 ^3 w2 q/ _; J' B8 K - }else{- R! v7 L* y' }9 }9 ?
- // 电量正常,低压指示灯灭
6 j# G( g5 g7 h; v. e - LED = 1;
2 W6 z& n0 u# p* l* T& a - }
+ U: ~0 t5 M1 l4 b% a7 S, r' {# J
! B0 s( s# v% t# o8 w0 t- // 检测到停机标志
6 E8 f Q6 Z& O7 {) _ - if(isReadyToHalt == 1){2 W& h0 s, r2 A; c2 f& \8 v
- // 暂时关闭定时器0中断8 j2 U& V! B+ I6 H' K
- ET0 = 0;
6 |+ g2 \+ z8 K$ ]0 O% ~ - // 停机之前先把矩形波输出脚置低电平,以方便INT0和INT1唤醒CPU$ }6 C- p- C7 q/ \ m. z$ h% f
- OUT = 0;
* y' b/ S7 y0 }& n& Q - // 停机之前先把低压指示灯灭掉,以省电8 m0 ? C, r# Z. k" C
- LED = 1;
# z- Z0 P, K( e$ o3 C+ | - // 进入停机模式4 N8 G0 R" U) r
- PCON |= 0x02;6 {1 K- W; B/ W- ]" I
- _nop_();
4 s9 ]6 \$ d# y1 x - _nop_();
2 }+ Q: X/ p3 r$ a - _nop_();+ @0 o( Y, k( l% T/ ?8 `& Q+ i, H
- _nop_();0 p, P8 X" Y6 S' j6 x
- // 唤醒,清标志位
& F# _7 p" M- {4 h6 ~/ u - isReadyToHalt = 0;5 L2 }; x$ D+ I5 t4 p: f, F
- // 重开定时器0中断8 V) {, ` E7 B% P7 [9 ]+ {
- ET0 = 1;
+ |, _' V/ U) E/ H% c0 s - }. g! J* E: W6 n4 U- E
- }9 ^4 `5 w- ~0 s! Z+ i9 r, d y- m
- }1 |, T9 y( k& R, e) g( c( ^
复制代码 & W( A& B# \+ m1 d# B
硬件参数配置:
) `* ?; w, I; Y4 P0 V$ ]. _
5 b- v# |$ V2 m. ^1 S; |+ L! _: _
8 ~1 {$ m5 w# L* y接收端:) s/ [8 t0 N# n' P7 m7 G8 g
- #include <INTRINS.H># s8 g) n, o$ ?5 v/ ?( z1 e
- #include "STC15W.h"1 B* g' `6 i& d/ L$ z
: W2 p0 f1 X# S$ a
1 W$ W- d* i2 V5 P) b( ^8 e- B* ]! k+ x- /*
9 x |- r4 ]+ Y/ @2 `9 I
4 Q1 a, h8 ]5 D1 I- *---------------------------*
3 @3 p3 [6 J3 N( ^" c - |1 (GPIO2) \__/ (GPIO1)16|
' z* c" a- v* a+ M5 ~6 s% k - | |
" N% r8 r, C5 O+ n# e3 M) h' T - |2 (GPIO3) (GPIO0)15|
: _" z1 H: y3 ] - | |, L) j9 R% Q' {5 W9 ^4 q& a# l( v
- |3 (GPIO4) 14|: J% U! p {: q3 }4 _+ u
- | |
: x, l+ E- `" a. P2 F5 c - |4 (GPIO5) (DATA)13|- r( `; I3 J1 u3 R
- | STC15W204S |/ Q- s& _7 K' I# U1 b
- |5 (GPIO6) (LATCH)12|# U+ J$ F$ U6 D9 d- N5 s- `; k$ a
- | |5 K# y0 ~9 X: ]- x2 L6 |4 L
- |6 (VCC) (CLK)11|
" r# C$ H" i: e5 F9 \8 _% k: [ - | |
- ]" d5 H& L- {: T8 ?* V0 v- Q - |7 (GPIO7) (TXD)10|
* c+ ^7 G, ~. L4 j6 F2 U$ R - | |0 t8 F" W6 I. V6 W# W6 E( ~1 i
- |8 (GND) (RXD) 9|8 Z4 c; O, U' f R4 r1 ^' y- _" j
- *---------------------------*9 R4 K5 ?; o y2 |% ?' j) ]' n/ @5 w
- Fosc = 12MHz
6 s0 U! k: \* r8 o6 o: t0 f - ' E1 l& D5 q2 O
- P1.0 -> 上
& X; w5 B6 E/ H - P1.1 -> 左
3 Q: ?" v4 L) \8 L - P1.2 -> 下1 F i9 Y0 \! s5 C$ ^ Z8 w# a) p( _1 B( F
- P1.3 -> 右
& { t, F" }1 T- i - P1.4 -> SEL
. P2 \( _1 y% R `6 r$ [6 k - P1.5 -> STA) ?8 F( `0 ~- U9 Z, _
- P5.4 -> B
* h$ C6 j3 y9 o: I! I2 c, O) w - P5.5 -> A9 O/ N- v' k/ j8 |2 C
- " g# l3 \5 w! ?+ @: r3 a# u- _
- */
2 S' a3 T0 a% ?2 L( w. H/ \: r - % m% L) J9 K) {5 o( r
/ n% y6 @. [% P5 g4 u- sbit CLK = P3^2;
& |1 g4 Z( q8 k; j+ \; u7 n - sbit LATCH = P3^3;
/ ~, q- E. a# Y/ j - sbit DATA = P3^6;
" s, I& u0 b* r) w8 e$ X" l - , _+ f+ N) V2 x7 ~- b! p$ W/ C# m: V
- bit isReady = 0;- C+ S, a0 O l6 {
- static unsigned char key = 0;2 o2 d7 I1 R* K6 @) y
- static unsigned char buf = 0; // 双缓冲。这个缓冲区保存从P1和P5组合而来的键值% |% q( L; n1 _& ^
- static unsigned char bufReady = 0; // 双缓冲。这个缓冲区保存上面那个缓冲区的备份! M% O1 ?: U8 W8 j5 @) z- N1 t
- static const unsigned char data mask[] = {0x80, 0x40, 0x10, 0x20, 0x01, 0x04, 0x02, 0x08}; // A B SELECT START UP DOWN LEFT RIGHT。为提升速度,这个表放到RAM中
; C# X& e2 O9 z# d% e: ?5 J - static unsigned char idx = 0;
[0 P; L; n# _$ r. s0 l& i i7 v - " C) i" o2 w# i( H1 n4 {2 \) O6 S) L& d
6 }7 W- J$ k4 q0 w( s- static void GPIO_Init(){$ i, b/ Y t) y5 H7 I! Y b
- // P1口和P5口用于接收并行信号,全部初始化为准双向,依靠内部弱上拉输出高电平
- |, Q; ^' z3 u1 _% ?7 \% h0 i - P1M0 = 0;3 ~9 L2 l" T$ j0 `) x+ m0 {
- P1M1 = 0;, Y" t9 w6 X; i5 m! P4 N
- P1= 0xFF;; }% X0 G5 {9 H ^- v' J; O
- P5M0 = 0;
4 r( |2 ~2 K+ G4 t4 G - P5M1 = 0;
1 ?4 K! ^% k7 v0 T# h8 _/ Y9 [ - P5= 0xFF;
; _0 U, H; w) N7 I8 T - // P3口初始化为准双向- x; Z! Q( J* p8 x4 N
- P3M0 = 0;+ I# J0 o* c6 E$ J& X" v
- P3M1 = 0;& l( L7 B j& ?2 s( M, @2 Q
- P3 = 0xFF;
$ @3 K/ l5 }) M; W, W - }
9 w5 i2 h1 C6 X% [3 _; }& }+ A
& b& K% }& k0 z* x7 T- static void Interrupt_Init(){
( F) \$ l6 x& a9 D - // INT0中断(CLK)触发类型为上升沿+下降沿
+ T: I+ J$ @2 g d+ Q% t8 F - IT0 = 0;
% ?- ~1 D# m& T4 N' z+ q - // 允许INT0中断
# K+ y O9 w& b/ w! x) o' [5 @4 j - EX0 = 1;! j7 t5 C0 F% v4 C
- // INT1中断(LATCH)触发类型为上升沿+下降沿/ m; t ]5 Z( n* |5 l3 p& D8 l
- IT1 = 0;
! ?/ C0 F' d# ]. | - // 允许INT1中断
5 I% `! O; H3 F! G( @ - EX1 = 1;$ z) r% H. c! P/ A. ?8 t) L
- // 开启全局中断
& X3 E6 a0 u8 V* e3 w3 r/ a - EA = 1;3 a* t; T/ q0 r7 r; o
- }3 e- |7 Y( O1 X5 m; V1 y" w
- 4 ]3 x: [) r1 z6 R- ~1 ]
- static void INT0_Isr() interrupt 0{7 b# ~- t G. S7 ~
- // 只有已经成功锁存才允许CLK移位
1 a+ i( l. S9 g- U. {2 X - if(isReady == 0)+ Z, B; f5 P% k; l+ ?* c* t* u
- return;
/ M1 t1 `* c8 E/ I# m j - // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断7 Y: n, ~" ~2 ]9 w# f c6 D7 v8 k
- if(CLK == 0); R3 z2 m! B! a0 u: h: \ q" v7 w
- return;4 o3 x# l8 ?# R' j4 R* ?
- // CLK上升沿到来的时候,取锁存值的下一位输出& r2 ~" O# c$ m7 d$ ?2 F
- idx++;
i& M, b# b3 K" M J. |% W% b - DATA = key & mask[idx];0 Q4 Y H1 q) R0 ]7 ]( ]) `
- // 如果已经完成7次移位,则一轮读取完成
" f& E3 J0 g% k! S- F/ { - if(idx >= 7)6 N5 A( K1 m! A1 b+ t; \5 N
- isReady = 0;1 J4 J3 x% s6 c4 q+ f- W* l
- }
6 M; n2 F/ s2 X- O
4 H$ K1 J# U+ R, g) h+ p- static void INT1_Isr() interrupt 2{
1 b. d! t; o* y. t6 l$ O - // 读当前引脚电平,如果是低电平则说明是下降沿,此时直接忽略该中断/ _" J( Q$ J: H7 I' n p
- if(LATCH == 0)
* r" x1 ~5 c! _. p - return;
. @3 H" u: @% _- [+ u- o - // 当LATCH上升沿到来的时候,锁存所有按键状态,同时把键值A输出到DATA9 ^1 m" u$ M' {( ?
- key = bufReady;) j! r' I% n; o: J
- DATA = key & 0x80;//mask[0]; // 为了加速运算,直接取表中的值而不是读表
* G8 N# m* N8 D) y4 q( ?! B8 S - idx = 0;4 Z0 d( i& |( [ b+ @
- // 允许CLK进行移位* Q& J6 Q; ~: R% N W. q/ H
- isReady = 1;
5 {' W3 k4 {) G3 L - }
$ ~" {( I+ u2 _8 L; h/ G% | - 0 h* y8 r$ I+ H
- void main(){( _( N: n8 k; Z }; `( s
- GPIO_Init();
9 E) o' _+ I6 e4 k - Interrupt_Init();' {# K# C( ?$ Z# ^5 | ^, P
- / f( p4 S; c" l% J; H6 Y* Y+ m
- while(1){
$ i- x) a% R N - //PCON |= 0x01; // 进入省电模式
. ?# V3 ?4 x/ X - //_nop_();' K( @4 e2 e! `6 v. E
- //_nop_();
/ f" S9 h3 q* D( P4 e' o - //_nop_();
' a; [. i; }( D# C/ A - //_nop_();
1 O- Z: U6 c$ a' R5 R - buf = ~((P1 & 0x3F) | ((P5 << 2) & 0xC0));
- W3 s3 o' @. e2 R& r - bufReady = buf;
% r; X& c$ [9 [# N( `5 ?$ s - }
^( J! |: r9 Q) g; b( {/ e - }
% C+ f* n n; m% |
复制代码
# N/ W8 Y. h! d0 b硬件参数配置无特殊要求,晶振频率选择12M即可。
( S8 U& E+ L' [7 O: ~
% b6 w, W: d7 m) c3 q这是编译好的固件。 |