|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
51单片机智能窗帘控制设计(源码+AD画的PCB与原理图)
- X. O7 T- q2 n" e* B! ^+ U+ T- V$ I& O8 M3 `9 b
" O& |1 m0 P9 g0 [给论坛的朋友们分享一个基于51单片机的智能窗帘控制系统(带51单片机源码+ad软件画的原理图和pcb工程文件),这是我的毕业设计,大家多多指教.
7 T; ?: J( ]* V" [% @
1 z+ {6 f( Q9 O智能窗帘的原理图(ad画的 需要用ad打开):. d8 o; T: i" M5 G
1 P- O( N6 y# z% E8 _, G
2 B+ N# G- k9 J智能窗帘的pcb工程文件:
( f0 A; U& P/ b3 a4 U- ?3 M
* j" _, }3 C! @9 j+ ^/ A) M$ c$ S3 Q/ J1 ]1 o
单片机窗帘主程序:
6 F! Q# P) b- z7 p: Z# t" ?1 p6 @#include <reg51.h>//51头文件
: {; K/ E$ F) F#include<INTRINS.h>
, @8 X" \2 b$ e6 j2 L6 U' o#define uchar unsigned char
r# D1 P7 q' ] ]: Z a }/ F#define uint unsigned int //变量宏定义0 Z4 B- P( F! K& V
#define ulong unsigned long //变量宏定义. |9 d! e7 y. X
uchar count,s1num,shi2=0,fen2=0,shi3=10,fen3=10;//全局变量
7 ` T5 m: k5 n: r+ n9 J% Auchar miao,fen,shi;//时间变量
: {2 l/ D# a3 `8 t2 |9 H# Puchar c,v,l,i;) b6 q$ |% x- w3 f" ~ g5 r8 y% G# W
& w7 D0 d" `5 S/ H* X
ulong AD_ad1,AD_ad2;& \* Z: n& t7 y# s7 [ R
float JiZhun_AD=2.5;
4 {% {: Z9 v8 J: |& G+ Yfloat AD_Data=0.0;! s! P% q* s1 h: d& L, M$ V7 Q
ulong AD_ad=0;
$ ~, E% R+ R' o* x& y# C" C1 v5 i% buchar dianji;4 ^7 w% I7 u1 W( H! T5 x, k
: H0 a9 i2 J# B- ~9 p% j* m% {sbit rs = P0^5;//数据,命令选择端(H/L) & \4 ~; F* ]! K- w4 |
sbit rw = P0^6;//读,写选择端(H/L)+ ^4 ~# m( l l6 @' @* P1 E
sbit e = P0^7;//使能信号5 o$ b" r9 ] ^4 p* v6 T
+ q3 c& d% @- Q% Z
sbit CLOCK = P1^1; //lcd
6 w" ?5 j. c4 z$ N2 U( Isbit D_IN = P1^2; //lcd* q U* A. B3 h2 K5 ^9 s
sbit D_OUT = P1^3; //lcd 1 N5 I! @7 }) b$ Y$ Y* V
sbit _CS = P1^4; //lcd
4 |" u$ y+ W2 J0 H( h0 y- v) C3 o% _6 n: U) q
sbit menu = P1^0; //按键//P1^3
5 K2 L6 ]% c' G0 L6 ]' M' G' Bsbit add = P1^7; //按键//P1^4
% c {& h7 D4 [5 W) Zsbit cut = P1^5; //按键# L: Z1 I8 M7 L1 H& H7 p+ b: d+ P. n
sbit yes = P1^6; //按键% b* c/ v7 k' q# ]: u! u1 j
; z% ?! Z, n+ i# Tsbit ma = P3^0; //步进电机
! m2 e5 v! j' T) L5 ^) ^sbit mb = P3^1; //步进电机( D7 w/ L% C1 k5 g1 U0 b) h
sbit mc = P3^2; //步进电机: P7 _. c; g, m: P# ~) Q5 j
sbit md = P3^3; //步进电机
9 q4 k( Z' Q6 W: wsbit led1 = P3^4; //LED1
$ Q# f; x! S1 R% w* |3 Csbit led2 = P3^5; //LED2% w% \$ _/ L6 V2 J* r+ L1 |. B! g
sbit spek = P3^6; //SPEK- t& ~8 @" W) R
9 W- O/ r5 D8 ]) K/ ouchar code table[]="shut-00:00|ray:0";. {0 S3 ~! G4 j2 t' @
uchar code table1[]="open-00:00|00:00";//数据字符表
; @3 j& m9 y9 D$ X/ Z. tuchar data display[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
$ A) y1 Q3 X8 r* o9 T //显示单元后台数据,1分2时现在时间,5分6时关闭时间,3分4时打开时间,7亮度级数 //
* r H; C# G" _3 H# l% z5 w//****************延时*****************$ j' Q* M* k1 l0 O1 A5 }) k# E
void delay(uint z)
7 }+ Z0 N3 S% }% S3 d# w{
! |2 T P/ H6 M- P" A uint x,y;
5 }% g( l& W# z. k for(x=z;x>0;x--)
$ i! n7 |; J8 C9 i+ S for(y=110;y>0;y--) ;
0 I' [; c% U0 {( _. m}- \- }" o2 v6 ?1 ?/ t
//****************写液晶指令*****************' r1 c, C9 Z( Z9 _7 y. H8 f, o
void write_com(uchar com)7 P$ v* W' z% h, O8 k1 g1 u% _1 ]
{
4 c- _/ j0 w6 S* p rs=0;
2 ~7 \! m R; h, z3 {1 w4 a4 Q; R e=0;
- j; u* r* E5 a P2=com;
6 {, \; V6 F, T" F+ A5 ` delay(5);
; u3 M# ^0 g) m9 j e=1;+ z8 w1 J- t! P' l- m
delay(5);( [! `3 e X1 m4 o
e=0;
, D$ Y/ D) W9 T4 C; H" t7 h} o' c- q ~! X" J2 o3 O1 f
//****************液晶数据*****************
2 H) `4 x# |4 m3 h) c% s o Tvoid write_date(uchar date)
- c. B2 [$ F) b' g! N2 X5 i{
) r* r* j; R* ]. ^: T rs=1;
7 W: K( `4 S8 C* t U+ S e=0; y9 S( P1 K+ R6 ^+ o5 K) v
P2=date;6 a' Z" k+ Y3 x! B3 t
delay(5);
* K5 {$ b1 ]; k8 s& b* L- ^% M e=1;
3 }2 {/ Y! |2 H1 ?! \0 t7 i, i& \ delay(5);5 P* \/ l# B' j2 }
e=0;( w: N! x4 I: O% n6 N
}
I0 J) q+ Y9 { T! _$ p//****************初始化液晶定时器************3 z: h7 Q$ Z9 w Z
void init() //
0 F2 b3 C3 i& Q v ^{! E- K3 ~+ q1 T) k
uchar num;( v9 {# [/ c% G$ A2 a: r/ P5 L! S# W
rs=0;
: d/ J! _0 @1 |( R; e2 }, G rw=0;+ {6 L# d$ d2 g0 O3 r4 U
e=0;//锁存关闭
3 p4 f$ |. \2 i# a& X8 M0 Y write_com(0x38);$ V6 r- j- |) \' F9 w
delay(5);. S7 s4 ]( \# D1 Y# t( z9 F
write_com(0x0c);//
& w* ]3 w8 V9 Q6 m delay(5);" f% g5 J, I- y2 }7 T8 v$ A
write_com(0x06);7 G& k# r Y$ H
delay(5);1 X% [; D, m5 S. M0 \% s& K/ ?* x
write_com(0x01);" w, G9 n3 l$ A3 R! a: N
write_com(0x80);//第一行开始写
0 H/ H9 a9 {/ t% B# L8 {7 J" v) b) d for(num=0;num<16;num++)- C, k$ `* A8 T% \; H, c
{& p% G( n$ C. Y
write_date(table[num]);
4 f+ @/ x' @+ I6 U' e- q8 Q delay(20);
+ j s$ u8 ?) V* s$ y) I4 O }1 M# J' t& l1 ~% s; J) y- r# F
write_com(0x80+0x40);//第二行前一部分,也就是时间开始写: A* {( |# l# R+ @, F, J, k2 ^
for(num=0;num<16;num++)
0 e, ~9 |. i1 A* k* L' o {
# [* ]+ n& p; X1 Y; {; R write_date(table1[num]);
# J; e" P: S- Y7 u delay(20);
& E0 n( e! w2 h( u% u% H' h3 v- d }. m. b8 q! Q( `5 O
TMOD=0x01;//定时器0的方式1& |+ X0 {! f6 \2 C& P' f( D
TH0=(65536-50000)/256;//求模2 z S/ K5 ]# a$ A
TL0=(65536-50000)%256;//取余" z; s+ a+ Z2 a/ o9 f. X; ~
EA=1;//开总中断4 F9 {3 X8 L1 @4 N+ q* m
ET0=1;//开定时器中断* I0 p9 m# M' q4 t. \- E
TR0=1;//启动定时器
4 }- _( ~$ f6 D}3 }: K4 |5 [; I
//****************地址数据变量**************
- C3 p: z* D- J( t$ lvoid write_sfm(uchar add, uchar date)( v+ H6 v2 M1 y7 L1 \
{
, J6 B' m) i7 J5 O+ a7 Z uchar shi,ge;
3 W5 x2 Z$ L1 J0 d: f- z shi=date/10;7 z1 h/ H6 n7 t) ?5 G; ?( X
ge=date%10;& w. J8 m& H2 v& ^) T( [ t/ k( l
write_com(0x80+0x40+add);, D/ l8 R8 `2 t' K: y2 v4 M
write_date(0x30+shi);
; C0 L/ N" I M# Q0 w write_date(0x30+ge);! z7 J: X6 R1 K( X% D: S
}
) x5 V4 J0 o' tvoid write_sfn(uchar add, uchar date)
" e3 X8 N; l3 }; w: o1 r{# Y. g- v9 ?% Q! d: j, M. m0 M
uchar si,g;
) L8 D I; M- ]) j si=date/10;
& W: O/ l) @ _, W8 ^5 S g=date%10;8 ?3 z2 d! l( ]( q+ b
write_com(0x80+add);
6 B! Y; A8 k5 s- O7 J8 g, B write_date(0x30+si);! D+ \5 r$ q% k5 l7 r9 s
write_date(0x30+g);
+ I1 S' F$ E2 A% h }, m+ j. q' e9 s2 k3 o! n- Q- K
6 \5 l$ g# h- o
//****************按键函数*****************: D/ x/ W/ F6 u1 x
void key()
. Z$ s: e z" K3 N; P; f" z{
5 w/ l0 E, [$ ~ @8 @ if(c==8)c=0;2 Y1 J& z K( r V
if(menu==0)! N5 [6 w: k) J3 n" X3 F
{0 D+ a4 P6 ` D }9 J7 B
delay(50);
$ Y4 j; w3 j: M' b9 S& g if(menu==0). X4 `; T8 }; @0 q5 V* @% i
{/ X6 W4 w* z0 |
c++;spek=0;delay(50);
: A$ L0 i2 C) h* |- x while(menu==0);spek=1;
4 i8 R" `' L. m- w7 z3 Q }3 T8 `- v9 r9 P) l+ {; G8 l
}
4 u; K( J6 I. K% d' e% } if(add==0)2 B& N. [8 I1 i) L% b8 O+ B5 n3 k* L
{4 a" U4 a" F. V6 l
spek=0;delay(50);) X. v0 W& u. j4 \3 y; Y8 W
while(add==0);/ k& |4 Y2 o8 A/ [( V5 J
spek=1;
) r. N# f8 a- B9 R, ]4 I, S* f6 y display[c]++;
$ q$ j/ {7 _( }/ O; ~. c, x" ~ write_sfm(14,display[1]);//分针位置
" W3 R+ \, [+ N+ }5 p ^. h9 G4 M write_sfm(11,display[2]);//时针位置 4 x. ^" o1 `2 {5 {6 _
}
* z- B" Q: G7 l) A# \ _ if(cut==0)# b. J' ~6 h% S T+ H4 ?& s& u
{$ p+ J* J) G8 }* e# `+ M7 K+ ]
spek=0;delay(50);4 r# _+ t# {% S( F+ k2 S
while(cut==0);( _. ~: A% S6 ]; l/ j _2 x
spek=1;
* }. p" h3 N6 F& A& f* s1 \ display[c]--;( G9 d# w4 U* Y, U5 z' J+ |. \ j
}0 i* P+ B) ]* ~# K" I* l& @
if(yes==0); I; S% z4 ?* t4 S/ M [: q/ S9 k& D8 g
{
# a! b, f: {5 Y. r$ Z3 ~- H+ q0 P4 ^ spek=0;delay(50);+ u* o6 O+ j1 I0 Z: x
while(yes==0);
! { ?7 a6 z; l$ u. B spek=1;
: d& T! n% |/ [8 x3 J. w$ i( c1 B c=0;. F% i' T$ r1 X/ z/ Y
}7 O* Q. d5 I: {
write_sfm(14,display[1]);//现在分针位置% P2 H3 u2 C% p5 ]" }. A" t
write_sfm(11,display[2]);//现在时针位置
0 b7 Q" S' W) k/ n1 f write_sfm(8,display[3]);//打开分针位置$ N, p$ k$ f' c/ X" V
write_sfm(5,display[4]);//打开分针位置
. r: z7 }' D4 D write_sfn(8,display[5]);//关闭分针位置
' G$ d" d5 k! D9 i! ` write_sfn(5,display[6]);//关闭分针位置% K( {5 s: j. l& j$ Z* A
write_com(0x80+15); //亮度级数8 F. Y/ A) _/ H) s/ @4 W: Z1 z
write_date(0x30+display[7]);//亮度级数位置
. ]8 N& U1 A+ Y+ A1 G) ~6 ?6 w}0 ^2 I }' ^/ q1 q
//****************步进电机函数*****************3 t/ H) l" x" V! x7 A K
void motorzen()5 G/ @; L3 S# U6 l% y" z1 p( X; X
{
+ Z6 c$ V7 }# D! U* }9 [; z while(v)' s6 Q% i' a1 d C9 }7 y* P
{
2 q; x3 v8 O4 F, @; E5 o led1=0; 5 D! m, y6 V) C2 B
ma=1,mb=0;mc=0;md=0;delay(3);7 ^$ s% x0 Y4 f$ u+ l
ma=0,mb=1;mc=0;md=0;delay(3);& }6 A: K* L" @, G# ^
ma=0,mb=0;mc=1;md=0;delay(3);' Z: V' i4 Y1 d" i* _; h% ^: [8 m
ma=0,mb=0;mc=0;md=1;delay(3);$ n d5 A5 q" x
}
3 Z0 X q, k2 a; l2 t- i led1=1;
6 O7 @$ H$ ~* Z6 q' p}
8 h( Q! g5 K, v7 Nvoid motoRFan()
3 e' B. [" w1 C. _{ 7 M7 I. A+ B* w" m) M/ s* j) ?
while(v&l)
1 w9 o. y6 b" s3 ]' G; i {) Z4 ^/ H: c, z5 ` j& C
led2=0; ; I, E" L* G7 V7 P1 T- h8 X4 C) i
ma=0,mb=0;mc=0;md=1;delay(3);' j5 Z5 t0 _* o$ p9 p
ma=0,mb=0;mc=1;md=0;delay(3);
3 @0 }' {* v- a' [' L k$ @6 M ma=0,mb=1;mc=0;md=0;delay(3);
2 w7 B7 H4 m4 A/ V ma=1,mb=0;mc=0;md=0;delay(3);$ X! e" B5 ?/ ]# j
}8 x9 N7 s! L e1 }0 I9 f
led2=1;+ ^! z+ d- t$ N
}
+ E: d0 h7 n1 g0 F; ^" r/ U$ n# g* l
//****************A/D*****************
( Z# Q# p7 x% r% R# puint read1543(uchar port)
/ w+ ^; N: u& L F5 B {
& g+ K2 A% @0 v# ?9 u8 \- Z uint ad;
0 Q% L. ^' Y* J, v8 l/ _" m' I0 Z uint i;
+ o H6 t* N/ q4 y uchar al=0,ah=0;+ Q6 a2 o3 W/ n) Y1 N9 G
CLOCK=0;
# {" j( k3 |+ h _CS=0;
) z* N& V S4 \; s( i& M port<<=4;4 A" D. C& L. t4 o- U
for (i=0;i<4;i++) //将四位通道地址送1543
& T! J& ~0 Y8 S1 h& Q* m {# j5 J% P- F) a/ Y* A. O6 J8 x" P
D_IN=(bit)(port&0x80);CLOCK=1;CLOCK=0;- N, p4 W5 O3 ~
port<<=1;4 ]# K, u3 z2 ?9 G i5 |
}
- Y& {% ]; P6 D# T9 n' ] for (i=0;i<6;i++) //填6个CLOCK信号
8 O$ g* L$ r; B! n3 w {
9 i# `9 m i, c8 h- L CLOCK=1;CLOCK=0;7 v5 ^6 b Y i% A- }1 m' a2 A* s
}
/ v L" }* B; M6 C _CS=1;
( U ~% ?( L7 B: x _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
8 V1 H% g5 o9 K: O) { _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();% v! S& s* U" n2 M0 X* G/ V% A$ Z
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();2 D+ M3 b- M: B! A+ S* p
_nop_();_nop_();_nop_();7 h2 c1 J6 R" K
_CS=0; //等待AD转换结束3 s1 l$ @' ^% d
_nop_();_nop_();_nop_();
+ P/ f j& x! ^5 ?5 cfor (i=0;i<2;i++) //D9,D8
% U S8 z% l& ]; ] ~5 N& c { % e8 I% ^' H& J" x, s) {! _
D_OUT=1;CLOCK=1;ah<<=1;
& R+ Y6 c$ U) d if (D_OUT) ah +=0x01;' B& x7 S4 F4 W0 q" \0 f' j% r
CLOCK=0;
/ L" _5 F: A6 K( s4 X1 `- f } 0 D* w+ k+ ^. X- J# c, _/ C
for (i=0;i<8;i++) //取出D7--D0; I( g3 p ~% Z, X J
{
# l+ H$ R) U! e8 t7 n6 v( J, C D_OUT=1;CLOCK=1;al <<= 1;
: B- P) |; k4 t+ N, g6 }4 X8 U4 T if (D_OUT)
( B0 M$ g1 s& c% V0 p al +=0x01;9 c# p4 v) S, d( q
CLOCK=0;! S2 ~9 S6 L7 ` k; b2 @! {1 J1 a
}
, ^: k# P2 p0 p# h1 i; y_CS=1; 4 ?9 Z: b* e* _( e3 M& ^
ad = (uint)ah;
0 A6 `: Y9 _; U2 [/ W/ m+ b: ]ad <<= 8;4 t. U" x* d5 n `+ l
ad +=(uint)al; //& I9 f/ f5 J6 T/ E; z
return(ad);
' l2 F# ?( q# ~5 x' a9 V) m1 i}
& q3 i Y% N, I5 x$ i6 G* K m0 | D2 E2 b
//****************亮度测试*****************
4 K0 `* N9 v: i- l0 [8 P+ R5 r8 A8 hvoid liangdu()
7 _& d. U, X5 ]{
8 ]. _6 D t* ?" q) I, u1 R+ p i++;& y1 a8 k$ ?+ E3 p2 i+ r6 `" f' J* a
if(i==30)
+ y& L5 K! L. q6 F' R; L {, s# G; U" L: d9 t, K
i=0;" a: ]7 ~( C( R. f9 U
AD_ad1 = read1543(0); // (通道0电压正端): ^+ [( X5 Z1 ]0 B4 c& i! o
AD_Data = ((float)AD_ad1)*JiZhun_AD*2/1024+0.005;//0.15经过实测需要加0.15减少误差 w+ s) {$ ], L) l
AD_ad =(AD_Data*100);
3 m1 s3 U8 N, s9 j if(display[7]>AD_ad%100/10)3 K, ?& t: q# ^ r1 K* Q
{7 ~* s3 n! g5 _1 c# @9 d( g
if(dianji==0)
3 I1 E# A- W5 I0 c9 I8 t) B& b. t {4 ~2 D; c1 a. d2 g& f6 u( q4 M
spek=0;delay(50);spek=1; ^* b$ M4 k# P5 e
motorzen();/ O) D; ~0 `6 z5 P5 C1 Q+ R- ]: N4 K
dianji=1;
f, r% g& r. t* N }8 k) B' c6 x; a. H. B+ o' i
}- N9 l6 W" G( I' o
else% ^2 z! [/ v% _4 i+ O
{
) u0 b j+ T7 [- [5 f: ` if(dianji==1)# u! w( d4 c: h) K3 E- b
{
b7 I( b! m) M4 T. ]) A; F, q spek=0;delay(50);spek=1;6 W2 e1 w4 ]$ n3 C
motorfan();& y, @3 _1 A7 k& n0 ^
dianji=0;0 y8 A( L) n- m- }& p" T6 m" c) C# x& i
}- c- L I% `% C* ]/ ]
}
* N7 U+ A; A0 s+ Q# S }
# r$ {- Z$ a, J3 {& c& B# j: O }, D/ v* g' Q: \( p$ V1 z$ \8 S- r% @( f
//****************主函数*****************' T8 \3 A/ X+ s2 Z# D$ R
void main()
" n* R3 }2 ^. N: R, a7 c$ g. O{
5 e' ]; r# z9 C spek=0;delay(50);spek=1;
5 p- ^! {( K& C9 x3 H5 v display[4]=8;# h* b: s) [ p0 m7 j I6 D0 e
display[6]=20;5 `0 }: [( I7 T1 W8 f! h( ?
display[7]=50;
( v K2 [( W) C; _8 E spek=1;* M% Y, T* L% o# _0 ^8 g
init();
. t+ f" X2 P+ } while(1)! b5 y0 N; \+ Y( q8 B
{
# k% y! Y" D0 }& }3 l' R$ z3 j key();liangdu();
9 t" @ z4 z4 \, `7 }) ~8 o if(display[2]==display[4])//时间判断关闭窗帘6 _+ s9 }2 d1 K! R
{
; i1 M0 M* Z* L5 @; @$ i e( ]; }) J, B if(display[1]==display[3])//与打开时间一致动作/ M0 O" y" O: @! i n3 |
{1 n6 j9 V: t3 Z- b
if(miao<5)
' s9 q% ^2 v3 y$ [) \7 I {8 w K* c+ T- q& {
v=10;' j6 ^" @( H% ?3 h; B. s; P' o
spek=0;delay(50);spek=1;, f1 A0 p- \# q. ^( x1 t
motorzen();0 v# j6 i& F- |; ~( k. Y
}: i# B4 m9 }# o+ r: a, I* M
}
, W, p3 d* s* G+ F& P. Y" x }8 }" a5 F* n# x
if(display[2]==display[6])//时间判断关闭窗帘
9 J0 n+ Z) \+ d+ f* a2 U {
% L |# X. n) o' E$ K if(display[1]==display[5])//与打开时间一致动作7 _. N- M* H& ]2 i
{
( A7 f* q5 ^% ]+ V: y if(miao<5)
( g0 o. t/ N Y% h% ~ D5 T {
! e2 P2 Q `, Z/ R8 i3 W v=10;
" G9 k, T8 F* P spek=0;delay(50);spek=1;
$ v1 p( u) R x% e O motorfan();
( f- g6 F1 A6 d& @ }
, E8 R5 j( H$ p: S; g( a2 Q( m3 k }( |5 T9 K2 R; A
}
2 F9 A8 I; S7 C8 L. \8 r& V }
6 e ]- ^3 e- [6 s E}% ]" G9 t& S4 v9 j7 S; @
- q- c+ R* @- f$ c
void timer0() interrupt 1 //定时器0中断服程序, s8 K9 B( E/ G( y! w
{$ W u4 b% L6 I; w3 y
TH0=(65536-50000)/256;//求模
3 K0 z: x1 e# c5 x TL0=(65536-50000)%256;//求佘& O( v; I$ V4 @ L% l1 y
count++;//变量2 u5 @/ x/ M5 @& S5 a7 L
if(count==20)//此处为时间基准调节,20为走一秒7 y! A2 Q, s# z5 b
' e+ v* _. i) o/ H5 j" Y
( L; \5 x( \+ G( B…………余下代码请下载附件…………* R. ^1 v. O/ u8 W/ s
- B! x( t. |1 m7 X4 p/ s+ L下载:& d8 g5 @+ e% S$ v7 K) n, M5 X) x, F
' t! h5 u! M0 V+ |
- S. d5 b; _! v* o1 \
|
|