前言
- I" Y1 [7 S6 j/ }& l1、由于很多同学反馈如今STM32F4价格昂贵,制作成本太高,于是我又花费了近一个月的空闲时间来研究用最低的成本制作拥有F4智能门锁一样甚至更多的功能STM32F4版本智能门锁7 |* l3 S# A( x0 C6 g: ~( _
' j7 R% Z `: Q& z一、项目简介
' ]+ Y( A2 t2 [8 t" T9 d8 U I) O(一)功能概述
; `# j8 J( B' hF4版本:' [. Q# Y( n% w# [7 `
1、可通过指纹模块增删查改家庭成员的指纹信息,增删查改是否成功的相关信息显示在OLED屏幕上/ E# W. k: a* E3 O) y P4 A% N
2、在指纹匹配过程中,如果采集的指纹与指纹模块库相匹配,OLED显示匹配成功,并转动步进电机一圈
, ~1 A% I* i4 a& M/ x3、可通过按键设定智能门锁密码,密码可设置为两个(密码六位),如果匹配两个中的一个成功,即可开锁,也可通过按键修改密码,所有的操作过程显示于OLED中
m I/ X7 O0 l# u5 m# m4、实现RFID与手机解锁(蓝牙解锁)! b7 F* t! ~ _( p+ `4 _6 k r
5、扩展:虚位密码解锁(虚位密码:自己百度)
+ H. M2 C4 ]. V0 ]" s' V; t$ oF1版本新增:( n3 Q2 |, S) p, B m* t
1、可录入10张卡片
% W" Q- ], o _+ ?' {' m2、开锁顺时针转动步进电机一圈,关锁逆时针
C8 D0 Y4 a1 T# K8 U8 |3、新增蜂鸣器提示
0 y7 Q5 ^; \2 C4、新增解锁错误提示; C$ `& K6 [" D
7 v: W* K$ A, k/ f1 s
(二)项目所用到的主要技术* |4 `# H ?: [* m! g
F4版本:
. R! p {5 ]( `! g1、IIC协议、SPI协议、串口协议
( r1 P3 p# ? m& v2 _2、外部flash驱动、SD卡驱动
) L* @+ A7 g* Y6 P3、FTAFS文件系统; v8 N/ o! o' H# U, q$ i4 w( x0 L
4、RTC实时时钟
: N4 t# \( M5 g5 S' \) ]- x3 x1 O4 nF1版本:
' a# Q0 v' B8 \5 y1 {$ E+ _1、IIC协议、SPI协议、串口协议
, c2 D6 I8 p5 R, _+ X2 N5 m% ~2、GUI界面设计,汉字显示$ U1 Y& c2 q. w% ~0 p* e
3、RTC实时时钟, s. G( V2 m/ `* b& @" \) m
5 Z: Z+ S/ O# S. z3 g6 F* ~
(三)本次项目的特点* ]1 T* P* Z/ | G8 x
1、选材根据经济8 i' w" s& O4 L" ?& V. ?
4 ]9 r* z1 k8 G- [. L
材料最贵的是指纹模块40元,单片机仅10元" ^5 @, _6 j$ p: d
+ e1 n/ x( N5 C2、减少不必要材料; T; T9 o/ n3 L% g$ O m; |
+ m9 B" E5 p% s& I
比如外部FLASH,SD卡模块,单片机晶振3 i, j% o8 i1 p) A/ q2 K: s
; E- D! t; V( [7 x7 m7 Y2、使用PCB,拒绝繁琐接线- p0 V+ M' U4 a y' \, M1 P
8 a( v0 s8 x6 N/ l* X/ p制作更方便,学习更简便
' z6 ^+ ?8 s2 S: k8 x5 d+ M0 j
) P; D8 s1 ~; }+ r3、功能强大; C7 _+ L; ?7 f9 L2 H/ H* Y; s' v
. \, \5 f. U9 A拥有4种解锁方式、汉化界面、有修改与录入操作、有手机APP控制
9 x2 q3 E* D) M( Z9 `8 h
- o3 x8 o- {+ E, T* I4 ?4、材料功能利用率高
3 z" J7 S. O6 C5 k
3 d5 |- H/ X; e% g单片机引脚(48pin)利用率>90%,单片机内存(64K)利用率>70%
1 j# ^ r+ X K* C# q0 ?+ T. I" C: q! W% {5 }& S5 s
5、代码精简方便,逻辑性强- s8 m- f0 C2 Y9 C6 w
4 t" }+ C) g- f' X) ^; f8 Y
Show_Str(12,13,128,12,"智能门锁系统hzc123",12,0); //显示汉字、字符一句搞定
/ P* c, ^2 E9 l" H, j5 h: O2 t- ?/ p2 w
二、材料选择" f( h% [5 \& t) r
1、主控STM32F103C8T6 (可以用兼容产品CH32F103C8T6代替)
) R9 d( f$ c8 [# `
/ J" g. B5 M; H( f" U( Y- i
/ r$ Z3 y% m U9 V5 O u$ J7 t& ^* u. T8 a; b8 r
2、步进电机(带驱动模块) X2 e/ [' @* ]" m9 ~" K' U
型号:28BYJ4+ULN2003; S7 q$ T0 N/ S* B3 c5 G
/ a1 @; h" N6 D$ J! G
; x2 x' t& T- |1 Y0 Z/ m9 b2 H$ ]
1 X1 ^5 U5 }& f: C* H3、4X4矩阵按键
, n, P) B8 T# t6 I: Z4 z
O! t+ C' o$ e3 S5 G5 j
& O; f: v9 ~9 _4、指纹模块AS608(串口控制)
9 Q/ X' w& I4 Q
7 o" @. ]3 m) Z r: m0 W3 h5、0.96寸OLED显示屏(IIC)
, X: i0 b/ a% Z4 ?. R4 p型号:7针( s" |! C6 ?3 ~$ E) o" h6 _
9 c3 ^) i9 p9 `9 H* k' V/ U
$ y3 n5 a0 A+ \! p$ d0 ?& J
1 w/ Z. [2 M; @6、RFID RC522 射频模块(带一张卡片)
% {) w. J4 e v. j: W! N6 H# |0 e) y6 ?% [
3 u* @$ c! }0 I. c( y! r; X, L' f& A3 t
) r# z1 h# h* M$ W/ j7、杜邦线、排针、电阻、电容、三极管、电位器等7 J& z/ d2 Q# u$ T8 C, a6 E
9 U4 n1 |4 {6 M. J* u三、原理图设计# q8 o3 B8 h. t) O& |
采用最简的硬件电路,做更多的功能
' ]3 f& _# \: N# K3 a5 C2 ]! s# _(截图模糊,可下载资源查看)
& q9 A! n8 g% N0 o! p8 B( w6 E7 P1 Y3 ~9 }7 X% g, @3 @: F
- k ]- B$ k9 P( F/ o, Z3 q
: N8 p4 s, u6 i' [, R四、PCB设计' B% g; Z6 x+ c
采用最便宜的双层版,10cm*10cm设计
) i$ h0 M3 e. S6 {* d% L4 |" H3 _3 f; {) Q6 e/ v n
7 V4 U% H+ C5 s
* N2 E5 `; o3 ^7 b, Y4 @4 s
五、源码设计7 |4 t' g# w% W9 W4 ?9 E; X
源码为F4版本智能门锁移植而来,修改了一些不兼容的功能与增加了新功能
$ ~; d! l0 H$ L# m" z' J! Z, i/ T, v
- $ [7 F/ S: d0 B2 j9 b1 J
- void DisUnLock(void )
; ^ R# K) r6 a8 ~* C9 @; v - { l" i" C$ _& N$ o% G
- OLED_Clear();
% F, b4 `9 ]1 L0 N4 O3 E/ u& f - Show_Str(20,10,128,24,"解锁中...",24,0); . L' S: O. R5 E6 j* ^, `
- OLED_Refresh_Gram();//更新显示
/ _: U8 a0 X$ A# M6 i# s - Walkmotor_ON();
" t- g& @# e/ Z0 Y: B* E - Show_Str(20,10,128,24,"已解锁!",24,0);, D# I! T1 X6 |4 H8 i6 P& g
- OLED_Refresh_Gram();//更新显示9 x( o8 \; k; c0 h) B
- delay_ms(1500);
' o1 f% j% Z8 w- p8 Q; K - }: ~7 t* q1 q1 @; }7 V1 M
' R% O7 P1 v5 a2 ?' h3 U) v+ n8 J3 ~7 ~- void DisLock(void )4 Z8 {7 y/ ^& X" O, T$ T: I
- {
) Y. s0 H& T& X9 I3 u - OLED_Clear();
5 C9 b+ j" T' M `' X: { - Show_Str(30,20,128,16,"锁定中!",16,0);9 I- f: Q/ @7 A$ _. h
- OLED_Refresh_Gram();//更新显示
1 {: C4 O0 `$ ^/ A) L - Walkmotor_OFF();9 r4 y# w# O3 m5 m( R0 W6 n
- Show_Str(30,20,128,16,"已锁定!",16,0);9 I, A) ]2 R+ R3 O& Z
- OLED_Show_Font(56,48,0);//锁3 A/ R) I# x3 Y) m( o2 ^
- OLED_Refresh_Gram();//更新显示+ i: L5 ]6 i2 A8 @
- delay_ms(1000);' m g# ^- I \8 O; B% o
- }3 p( t9 o" _% e5 ^( c" i* b) [$ Y
- int main(void)
7 W: f4 H; f1 f3 E# Y, u3 w$ _& o - { 7 B( b1 H# t) F2 y; ^: q; z
- u16 set=0;
, Q- }, x" }% l" [; u. Z - int key_num;. ~# w. c7 ^; K- Y! Z% J, \5 y& F
- int time1;* W3 n% H0 |' ~' R
- int time2; //锁屏时间9 T* m- |: V- W3 ^( g* u& }3 W# `
- char arrow=0; //箭头位子- o5 Z# v5 l) N% L2 O+ x5 E
- //SysHSI_Init();
1 f. i+ W c; `1 V, W9 @/ q. U0 Y7 b" w - delay_init(); //延时函数初始化
( ~. x& O' a- w4 } j - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级/ L, d" B) x* h; H8 k
- uart_init(9600); //串口初始化为9600
& ~. F, B. |. a" i! t - printf("串口功能正常\r\n");
8 K! d* n$ h$ T/ w( Q8 u - Button4_4_Init(); //初始化与按键连接的硬件接口% V1 N5 j/ W$ k! U; m
- OLED_Init(); //显示初始化' X0 p; s7 g8 t s7 n0 }: C) D
- Walkmotor_Init(); //步进电机初始化$ H; T& f7 X" H
- BEEP_Init(); //蜂鸣器初始化
6 {. m( e) r0 M! C8 p - usart2_init(usart2_baund); //初始化指纹模块! Q0 t0 ~- ~" v. u7 v; Q
- PS_StaGPIO_Init();
1 M& B/ D$ i5 X - OLED_Clear(); * P1 c+ a4 v" G; n7 {" a7 s# z9 \
-
9 c! j( F+ K0 |. J* v - starting();//开机信息 logo
4 r! b% I, g2 c) G% I5 k3 Y. Q' z - RTC_Init(); //RTC初始化" }$ \5 |; }2 d+ x! O: B' v7 X" z0 y# g9 C
- SysPartInit(); //系统参数初始化 # W& V$ H1 \; |+ J* g
- while(1)
( t0 [$ p! o# k7 ^( c G8 A - { v4 ^! j" e9 t9 Y( I* @3 Y0 x
- //锁屏界面; H6 ]8 k: T/ k, w3 x# y% r5 a
- MAIN:
x- \+ t! \8 c, _; @% G2 X# ^2 U - OLED_Clear(); * }5 C* | b# L) B
- OLED_Show_Font(56,48,0);//显示锁图标
% Q" [8 E, H' U$ h8 T& a8 M% Z5 [ - while(1)
6 n6 W: U' C2 V3 h z8 ] i - {
" l" H- q6 I$ U( H3 J: S; `+ d8 ~ - time1++;Display_Data();//时间显示:每1000ms更新一次显示数据" q6 f" V8 m' k$ @+ k Z
- $ }0 ~4 [8 P$ x0 f( [
- if(DisFlag == 1)
0 E1 t' v; s8 Z7 A. q" W1 Y! W" z - {: S) Q# \1 i" Y3 A8 Z8 e1 J2 B+ \
- DisFlag = 0;% T6 Q) b9 N$ @5 c8 J
- OLED_Fill(0,24,16,63,0);* s( B' O0 s3 d- v' O3 v5 O' @
- OLED_Refresh_Gram();//更新显示
0 G C7 z# n; E1 k' Z$ d - }
2 K/ B9 X. u/ G# Q1 d -
% N. @2 B& N3 M! F9 K- e - if((time1%100)==1)( @& T3 r8 i5 \1 Y4 Q3 u
- {/ u6 l3 V9 }: N4 M! B
- //MFRC522解锁! n4 G% ~! {" w1 U: Z( \
- time1=0;
2 H" f$ K4 M# @% m7 O! x - MFRC522_Initializtion(); . E7 \% e. Q$ S) H: Y# J
- Error=MFRC522_lock();
1 k* I3 k4 W3 O) b. @- I - if(Error==0)% X! o& d5 B: W, S1 x D
- {( k1 b+ @& D* e* R
- goto MENU; / Y" V R7 h* s% C
- }, S9 d, l$ W ]3 J: X
- else ) b% a8 |7 B0 N% f( }/ U S
- {2 y! S4 c4 F& Q8 \$ I! L
- OLED_Show_Font(56,48,0);//锁
! m: ], T. ?; ^' ^/ O6 d - }
% `& h- l- u6 K1 F8 H l - " f: ^" Y5 g0 C6 w/ ]
- //手机蓝牙解锁密码1( Y& e* e. _& y
- Error=usart1_cherk((char*)sys.passwd1); 8 g9 ^7 P9 P+ p0 f
- if(Error==0){
! D6 m8 ?2 F4 |% y) }+ Y - OLED_Clear_NOupdate();
1 W( Z3 R+ ^# T5 y3 F* A" m3 K - Show_Str(12,13,128,20,"蓝牙密码1:正确",12,0);
6 Y$ y; X- k+ M& a - OLED_Refresh_Gram();//更新显示
( Q8 h; I4 ]3 H, |5 s, }2 f - delay_ms(800);
( W3 ?0 K4 C) e - DisUnLock();# W8 Q4 F6 T! Y/ J0 u1 E( k4 K
- goto MENU;
% v* m% t: ?8 ] - }
0 C! j, {+ R+ }$ P+ k; \ - //手机蓝牙解锁密码2
G& M# @) e$ E: B2 G# Z - Error=usart1_cherk((char*)sys.passwd2);
- d/ Q( W# P3 M- ^, v: g6 l - if(Error==0){% t X) N' D, M, x7 Y& |
- OLED_Clear_NOupdate();% T- u. u: U$ D# r3 d
- Show_Str(12,13,128,12,"蓝牙密码2:正确",12,0);
, A& W& C9 v, X, U* Z2 M - OLED_Refresh_Gram();//更新显示
* p/ u/ _% |6 s' s - delay_ms(800);2 F1 m3 `' ^ Y* R3 h
- DisUnLock();! [9 D( d" E. Z0 p0 W* V* Y
- goto MENU;
3 j0 ]' W) f e# f - }
) d2 L G. ]9 |' I$ `# s4 } - }/ O& e2 m6 r5 {8 a' o8 }
- //指纹解锁9 _, u, y0 w/ k* b8 p: a7 X
- if(PS_Sta) //检测PS_Sta状态,如果有手指按下8 N2 v( Q( p& a% F
- {' _+ {# t# r6 l; l: [" E5 ^; D
- while(PS_Sta){" r, L4 J9 Z! S9 G
- Error=press_FR();//刷指纹2 u1 M. C' V2 J& n6 C" k+ p
- if(Error==0)7 [9 W+ `/ j3 _) r4 J0 i: N
- {6 R _+ P. s9 I+ L( q- q$ @
- //DisUnLock();
$ Z9 P$ H- V5 W# ]; ~ - goto MENU; //跳到解锁界面2 @4 r$ O3 I' t3 Y! x8 h
- }
; |5 F, O, ]0 m: H2 k; x- |& y! { - else
+ z1 U$ ]4 t- u! S' L; g - {4 a* w, P7 h# m3 ]( q# C
- OLED_Show_Font(56,48,0);//锁
$ K A, a2 s3 J$ `4 B; K - }3 U, `' [) x# O: G& l5 r: S; W$ [
- }
6 K3 k. g: e! s) t' F' D# o5 L, h - }$ x. x% c6 F2 i
- //密码锁8 U/ f% j* ^" u& n/ N6 R
- key_num=Button4_4_Scan(); //按键扫描+ f$ D- O# C* L' h, {8 b: @
- if(key_num!=-1)
$ Q& e9 a: u- f* [4 N7 c - {: q1 M& m' Z1 c8 J, S4 d0 D0 w
- Error=password();//密码解锁函数
6 G2 O! X I% ~ - if(Error==0)9 \5 p9 t2 k2 N* ?) a
- {7 o Q4 {* e+ P' s; w7 B7 b
- goto MENU; //跳到解锁界面% H! h) |" h$ u6 ]$ a( \9 O' S
- }
& f; M) G1 R% P$ ^: D - else 9 L$ i" s. q4 N9 V r8 Z! \
- {; q% S$ ?: r; ]/ W: \& I
- OLED_Show_Font(56,48,0);//锁
8 D7 S4 K. \4 ~ - }$ X9 q# @0 m" I% E
- }9 X- W: Z2 R0 Q9 d& H2 G* }
- delay_ms(1);
! L/ r4 u$ g2 ]( i% t0 z6 S# l2 t - : ~$ _1 N7 `9 W' {
- }1 s& c2 y! B' H( Q1 a5 p- z
- /********************主界面**************************/
. Q% E+ Q( g8 I& A
1 M" C/ a( I% o' v$ N- MENU:6 q, m2 e5 ^4 P* }
- OLED_Clear();
' P4 o9 b0 p- b9 F2 H - MENUNOCLR:/ P2 H$ P1 V+ n
- OLED_Fill(0,0,20,48,0);# p* w+ a2 w4 W: W( ?' ]: D
- //主页菜单显示
( d& ^$ m' v! p! S7 B - if(arrow<3){, b0 S6 H8 i6 J& B9 B
- Show_Str(5,arrow*16,128,16,"->",16,0);//显示箭头' o$ p0 Y+ _, B- C8 A9 ^* o0 Z
- set=0;}
5 L! z+ e7 _3 `0 E3 D( ? - else {4 E% s) X5 S8 ?" O$ a" E
- Show_Str(5,(arrow-3)*16,128,16,"->",16,0);
) x& E% w; B2 M a# A7 l0 | - set=3;}
" r$ n6 F1 k3 ]/ Y* e* B - Show_Str(25,0,128,16,setup[set],16,0);
( ~. y' z+ I( f$ `3 V; R - Show_Str(25,16,128,16,setup[set+1],16,0);
6 r, [; X5 [8 S( q) L* V4 z - Show_Str(25,32,128,16,setup[set+2],16,0);5 W6 P2 D6 x2 ^( M& S! j; N
- Show_Str(0,52,128,12,"上 下 确定",12,0);
8 [2 D0 p- d! p/ P, g/ U - OLED_Refresh_Gram();//更新显示
! C4 P: v. i- l4 P, J: q [ - time2=0;
' l% p/ f* `6 L. l9 ^2 T% z - while(1)
# U/ m5 ~7 U' H: [ - {( e8 r w1 M" d! e) l
- //超时锁屏 s$ k' p# y% ~0 X
- time2++;$ U+ @+ c$ [& L
- if(time2>10000 | key_num==4){
- r* I9 \2 K" h, @/ | -
4 _; z$ W+ y- H) X - OLED_Clear();
) ^& A% i. J: Z - DisLock();9 n- }4 S* [* O. {* M
- if(time2>10000)beep_on_mode2();
1 g" x9 Z; Q+ a6 J - time2 =0;* j6 n6 w5 b2 q* H2 K! @
- OLED_Clear();8 _2 p) r0 G1 m4 r, E% S
- goto MAIN;
) k7 d7 g$ l% r2 V - }
$ f" ~- y; _6 ~3 n9 Q - //手机蓝牙锁定: g& K. }. e5 Z h P; O
- if(memcmp(USART_RX_BUF,"LOCK",4)==0) {
, ?, ~& }( T/ Y - DisLock();
9 V2 {* ~4 }% B0 }( x - goto MAIN;
, U: {: d: X3 J; x! x# i( J6 j4 ?1 e - }5 {- D5 F+ X1 s. T7 i
-
2 e% V/ M ^" Y( z - //功能选项选择! a' x: ?5 ]0 W9 ]8 N& F- X6 @
- key_num=Button4_4_Scan(); : V' u D9 {' h p3 s/ ~
- if(key_num)
0 A7 M6 b- u3 Z1 d4 g/ } - {4 l+ I! g8 \5 E: ? K7 i9 g1 J
- if(key_num==13){' i9 A9 }( z; M% } v
- if(arrow>0)arrow--;6 b/ H+ H- K3 O! a
- goto MENUNOCLR;0 W7 |- l& G/ T( y9 o
- }, M8 c- P k! `4 C; C( {
- if(key_num==15){, r+ e8 C. D0 |( `0 ^/ R
- if(arrow<5)arrow++;& k0 G. q8 J5 Y1 T$ w! x# B
- goto MENUNOCLR;
0 b# p9 R5 m) A5 b$ l T - }' S8 M/ v! l! |4 E
- if(key_num==16){
$ i, o' l$ _) {- s0 H - switch(arrow)- n, D" P9 U4 a" e( [
- {9 r+ a, k: B4 y+ }9 \, _; |9 A1 y( X
- case 0:Add_FR(); break;//录指8 r* d( d# y5 F: a
- case 1:Del_FR(); break;//删指纹
( E" N1 r1 O8 n9 g7 a' I - case 2:SetPassworld();break;//修改密码
2 M' v: ^/ L/ h$ F3 }. p! N - case 3:Set_Time(); break; //设置时间6 o, W6 ^+ P1 j7 K, h
- case 4:Add_Rfid(); break; //录入卡片
* F" e8 \* ^' | - case 5:Massige(); break; //显示信息 5 y0 V0 q ~$ a9 [/ \) R! K
- }
; g" d y' Q0 z5 m* Z" k6 f( { - goto MENU;5 h* V) I! e1 Y
- }
* \" h7 L; r y8 G1 j% f* {2 G - }delay_ms(1);) L4 }5 x* g9 @9 V$ b# G
- }
) F. g1 F) K q; X% _$ h# H - }
, c# h9 ?/ M8 y3 N - : a' h5 S$ K: N( f/ |; S
- }' O8 K7 Q' E. p' F: T/ a* N
复制代码 + b+ @, {# j7 Z1 k, ]0 O, b, k" O
六、安卓APP设计
6 k6 w: m! H9 }2 }( X1、图标设计6 w8 Q0 z2 j- `7 m- P0 l/ _
& \0 Z7 C( I3 l# n! w
8 `' t v. H* P$ p0 C
" y6 L. I) u3 {5 v# U b+ x2、主界面设计
M% N! k6 E" ^: w: X/ p使用方法:①进入APP,等待3-5秒,自动连接智能门锁
4 f# M \1 y& n5 B9 ?2 G②左上角显示已连接后,输入密码,点击OK即可解锁
/ \5 U6 k) U3 E, b7 s' r# p& L③无法自动连接时,点击连接按钮进入手动连接界面
; z! e) s( {& R+ T
9 o! o) R/ n: g: Q
% }; k- v$ z; {! V8 t7 L
" l! P8 ^1 U, O: [; u3、连接界面
2 J: w: s; E/ C. y" n& Q使用方法:双击进行连接操作2 b9 H' \, B+ Y- V( t
, P: {/ C4 }( x; l9 R( E
# I& b. d- [( M6 F/ v: N1 Z
% @1 b: }$ I, W4、信息界面设计6 ^% R! B0 K3 m. C
1 c: V1 _, D3 ]) z7 S
- K% |0 e# ^; S2 l |3 H5 L七、成品展示3 J; c/ j+ {/ {; d4 ?; J( ?
1、开机界面/ Y( y+ M) o. ]
在这里插入图片描述% T! K5 O5 i. k" D; Y
0 N8 L7 O; U5 D/ A1 V# [2 v7 ]
- [+ V. s) _. |' I. I
9 S; m5 q( ]2 d7 d" Z( Z2、锁屏显示时间: y5 \- @1 v3 v2 h
; K( |2 f5 W$ {; U# ?9 I) H
' Y: J" j! G6 c: N6 D* r
* D$ R$ {9 B( |, H3、解锁显示菜单& q4 X$ g/ a$ z7 C
! x7 K y& N ?4 v! h, t3 h
5 k4 u5 J% D- P$ E2 @) J# V
, A$ S5 @+ x( o/ G, T; U, d8 X
2 u9 Z" V+ ?7 r9 m
|