找回密码
 注册
关于网站域名变更的通知
查看: 513|回复: 4
打印 上一主题 下一主题

51单片机通过WIFI模块ESP8266控制LED灯

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2021-9-17 11:16 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
一、系统方案) B2 e! A& _: N. t; H
! D9 p( r& m. c3 M3 L: |: x
: w6 G" A$ k! @. A/ O. h+ X
手机APP通过ESP8266 WIFI模块与51单片机通信控制LED灯的开关。下位机由单片机、ESP8266模块和LED灯组成,上位机由Android手机APP承担。我们在APP上发送LED灯的开关控制指令,ESP8266将收到的数据发送给单片机,从而实现对LED灯进行开关控制。
; y5 i8 p- n0 E3 {
6 {2 C- U5 d0 w! Q# O
' s0 _9 U- l0 D: O2 c

" k# K. Z4 l0 I# V. t: ~6 d8 C3 N. t
6 X& \! |' H: `: m" w  {
设计好的实物是这个样子:
9 H  S2 y) X4 I% i4 p% U% t4 y0 X" @+ r, ]
5 k/ u8 Q, z8 O& |) T8 J+ ?' N

7 [, r; x& ~, B7 u( g" ~
: i% ]" o' F5 k  b; i( o/ s
二、硬件设计- b% x9 U2 {; s

4 {5 T" s" N& r- Y, H

# o) I' w# ?* B- w4 _1 r& P5 SESP8266模块作为一个透传模块使用,RXD、TXD分别连接51单片机的TXD和RXD,VCC和CH_PD管脚接3.3V电压,GND接地,只需要连接这些管脚,ESP8266模块就可以正常工作了。在单片机P2口上连接了三个5mm的LED灯,分别是红黄蓝三种颜色,我们的目的是通过手机APP上的开关控制着三个LED灯的亮灭。
3 ]& q( [& T, |; M2 b/ j+ }
& C( c5 ?' g9 g

8 {2 d& b9 F3 R% J; G. _) N- S

# R! S$ Y3 j7 o, K
+ |6 b. E0 a7 [, ~
ESP8266实物管脚图% R: k# x/ }2 @5 o
/ T& q+ O" D0 D- }/ e

3 a  q. q: p0 j4 }+ @* @+ h9 F1 E
- w- \6 e) G" o% k9 ?( X2 ^" w4 u
5 M+ m3 v3 W. R! h9 p
三、单片机软件设计9 x  U1 y0 T4 Y0 d0 S/ K

( ^. h# h" A6 z9 I- h: [, F( \( r
) w3 Y4 D% `# s1 i: S% h* O, y
硬件的连接不复杂,接下来主要是单片机和手机APP代码的编写。
+ y* d! X+ Z% q7 E( `
5 \+ w+ ?3 U. `) H% e

: A5 ~' q% E  w, S" h1 Z# g3 }单片机代码主要是串口初始化、串口中断和ESP8266的初始化。首先是串口初始化:
6 h2 S7 O& ~- z7 G6 {6 l) b+ f$ w- N( L# b4 n9 T+ l7 ^

; P; {8 d9 D/ O0 f        TMOD=0x20;                //定时器1工作在方式2) i1 ^# L8 g7 q4 h* y8 z* }
        TH1 = 0xfd;                //波特率9600
0 K* r2 E% {* o6 q! c        TL1 = 0xfd;
* T) p+ J' b/ p        SM0=0;                  //串口工作在方式1
9 Y7 k# U0 V+ [        SM1=1;" C* z& Q) U; f2 T% V+ v
        EA = 1;                        //开总中断
7 K/ f5 W8 i' g, |8 }  t: `2 e( r        REN = 1;                //使能串口
9 X+ r: H! a8 E! u' f/ P% ^& E        TR1 = 1;                //定时器1开始计时- a5 _0 c* H' t9 L
然后是ESP8266初始化:4 x* r! z- v& u% E7 c' G: h9 M

4 V2 Y5 i9 }. n5 f# h* \" E5 X

7 K3 G9 }( w2 \        delayms(1000);                        //延时
0 O" z6 p/ V  Q  C* |        sendString("AT+CWMODE=2\r\n");        //设置ESP8266工作在AP模式下
2 T" p* U" @5 b9 T; l+ E        delayms(1000);        3 J& f: `  p/ T3 g
        sendString("AT+CIPMUX=1\r\n");        //允许多连接* D8 N$ Z( f; p3 G& p- C
        delayms(1000);        7 g4 V/ @1 T5 R
        sendString("AT+CIPSERVER=1\r\n");     //建立服务器1 Z  [( x' z# e9 }& P: f' \' X
        delayms(1000);       
% P$ J! l! d) ?! \2 S        ES = 1;                                      //esp8266初始化之后开串口中断
5 J9 G! ~% G8 p9 h5 h贴上51单片机负责串口发送的两个函数:0 o: f/ T" z4 I
  [$ u( O/ [; L- x* R$ e
! j7 l1 _$ H, r+ x/ d# m
//发送一个字节5 ^  B2 t0 d6 o$ [3 _
void sendChar(uchar a)$ o( B: Q* k) z' P
{
$ i; S+ B9 q( n- _7 _8 G* o) Z        SBUF = a;+ W+ ^9 {: ]! P" E
        while(TI==0);
7 F' m% o8 j7 f% t& G5 Y- Z( z        TI=0;
/ w6 s  Q7 ~* W$ R6 R       
, I6 R" j' ]: P+ x( z  \}
7 t6 A$ o, u( `5 V 4 G( X6 i3 q# g, o! j
//发送字符串7 O, {5 J* f* k  v9 `2 s
void sendString(uchar *s)
7 o* |1 |4 _1 D: q4 W+ k{
9 c& N: ^/ `# b4 o3 V        while(*s!='\0')
8 a8 W+ Z8 D( w; |% ?/ ^9 h        {9 B; S' u) b1 z+ @6 _: D
                sendChar(*s);9 Z2 x# l! m+ P
                s++;8 y8 n5 g+ }% s1 Z# U
        }
$ D! F( E1 Z+ r- B0 H                $ A) N( ?% e9 ^0 B
}5 k+ a$ \6 K- l) A  ?1 l' E( {
在串口中断中处理接收到的数据:
# T! v2 E2 N& M: M0 }8 K& }: K  f& T6 h+ F9 A( W) E: a6 c

! k. \1 H1 N, G$ B1:打开红色灯    2:关闭红色灯7 N/ `6 t" H, [0 W; E4 }: [5 H5 I2 ]

. F! [: ^; y$ q" H7 N' B
# }1 i! s$ S; ^2 j! B4 q7 J
3:打开黄色灯    4:关闭黄色灯2 l7 P9 s' ^4 G$ z- i1 U; Y% R( Q

, g0 E/ J( @' V" R1 \! [; y) V
0 H( k" G; y; X
5:打开蓝色灯    6:关闭蓝色灯
' ^3 }4 q( c9 V
3 n+ R0 Y( C) G: o$ O' f  G6 v

% d8 D, R" M5 u! ?) a+ \esp8266在收到数据并转发给单片机时的数据格式:+IPD,<client号>,<收到的字符长度>:收到的字符,比如+IPD,0,5:hello,其中+PID是固定的;0代表的是TCP客户端编号,esp8266最多支持5个客户端同时连接,也就是说客户端编号是0到4,在本设计中由于只有一个客户端与esp8266相连,所以客户端编号是0;5代表收到的字符长度;hello是收到的字符。在本例中esp8266发送给单片机的数据是+IPD,0,1:1,我们把接收到的字符串缓存到字符数组中,所以在处理收到的数据逻辑中,首先判断是否是以'+'开始的,否则视作无效数据,然后判断数组中的第十个数据,因为第十个数据才是上位机发送过来的数据。1 `2 h" `+ C: r8 {' z$ b

8 m: l5 U: T0 {

0 ]! O- B% t( u# a8 Wvoid uart() interrupt 48 O* S6 X  E" A5 o; ?
{$ L8 F3 o! @! A3 c5 e* R8 a* g
    if(RI == 1)   ( V9 ], j1 y7 J0 y
    {
/ |7 E) q! |9 Y1 c: {9 j! e& p8 O        RI = 0;     //清除串口接收标志位. v4 ?5 K" N* K- k& r& [* Y4 R
        receiveTable=SBUF;
% \0 W' T/ f) e: g: |        if(receiveTable[0]=='+')
- y: L1 Z1 S7 R, |4 \0 Z1 {        {0 \# Q7 U0 o+ F/ z8 I& \
                i++;
5 R" S% J6 \% \) o        }
: ^- C  o0 b! s, K( N        else* p% B" L# z$ B+ @* w; l# A+ O
        {. s. U8 s6 O; b- e0 n
                i=0;; [8 q0 _4 c6 j7 l( m3 R: f
        }
% Y6 b2 \3 o7 `/ V5 l        if(i==10)6 @. i; m- n0 B& n
        {
- t. m5 e' Z2 v& ^& x                i=0;4 }( j7 I; J- m, s3 k
                switch(receiveTable[9]). g/ z/ \1 \1 N  h3 D
                {' W( m" G' m4 r
                        case '1':
* S. V* x2 s1 c9 \, W% B# }                                RedLED=0;( ?) |; y" B4 J" j1 V2 U2 U1 o
                                break;
- v; @) Z) e' Q9 N, B                        case '2':
( Q4 b6 C$ O) n2 `8 P7 w* F                                RedLED=1;+ ]) y0 n& k( o+ @4 I/ h
                                break;
- }  S3 U% H9 W' }0 g- B! b6 h                        case '3':
, V" k( r+ y+ W( i) y1 V                                YellowLED=0;$ g" E5 n7 i) y
                                break;
8 \7 A5 F9 ~$ F: Q6 s% B. z                        case '4':
2 B& F7 e! n& c3 g! g" G3 x                                YellowLED=1;
9 h( e. V& y1 q; a( q                                break;
6 e) @, }' C) y( M- |% v                        case '5':
: a! O& n) |0 x9 ?+ H                                BlueLED=0;& y  l( ]- B" m% u# d
                                break;
- X% O7 V; q: `; k, s% ~, C                        case '6':, f$ r) K8 G6 q
                                BlueLED=1;
' ]/ f, ^3 ~+ F2 Q                                break;
$ Y% T2 M4 w  }) [0 p4 J# [. @                }
1 H9 h3 n% q' A8 Z        }# h* Y! B) Y, I. c! J
    / ~+ {" _4 q8 [2 `$ l
  }
, T3 o; k- ]: U, Q) Q' w' Y+ f}
3 ^# W. g# M3 m4 v7 r% s. Y% h- {四、Android APP软件设计
6 {! g8 T3 a3 o: s- A4 H; {$ o. c2 R) ]: d8 k- b$ M

5 g% h: C; f. [+ h/ e' F8 u$ {Android APP是借助Android Studio来开发的,界面比较简单,通过编辑框输入esp8266的IP地址和端口号,esp8266默认的IP地址是192.168.4.1,端口号是333,这些都可以通过AT指令进行修改。布局页面的xml代码我们就不贴了,熟悉Android开发的读者很快就能根据截图编写出来,放上一个APP界面的截图:
! V7 y& [5 ~3 n9 r2 a( T! p) ]9 [) p5 N9 N

( f4 V' z1 Z$ b
# K! I% T, r% P

0 M7 Y1 h# `. y( L. d' _  E3 q! H) i7 E7 m, s/ v  u" G  f

9 l5 W2 i0 \. n( Q% @. k* V" u我们主要看一下逻辑代码部分:
  l) H! X6 }% z% C6 `3 f2 d. R
" E& j! L9 L( e9 ^

% i  I* }* |0 Q6 q) D首先是控件的初始化和按钮点击事件回调的绑定8 A( Q/ |+ m; z: t2 ~
0 O1 P9 M) L4 w6 p: E
3 Z! U7 ]8 d3 d% v+ P% F) Q' _
    @Override
; m) [5 s8 b1 y( [; L2 L    protected void onCreate(Bundle savedInstanceState) {2 z# Y" g: c/ m6 z2 f. f" G3 T
        super.onCreate(savedInstanceState);* }+ L# d+ M: R  B# g6 B. C% L
        setContentView(R.layout.activity_main);! U) d: [9 K- f" i1 s
        mBtnConnect = (Button) findViewById(R.id.btn_connect);
3 G7 N8 O2 ?* g( m9 n/ V8 a3 F1 u        mEtIP = (EditText) findViewById(R.id.et_ip);7 D* Z% d- @) x: a
        mEtPort = (EditText) findViewById(R.id.et_port);
0 m+ U* j7 x' H% h7 G+ D) _* s        mBtnRedOn = (Button) findViewById(R.id.btn_red_on);/ B4 E0 y/ b3 T9 p& J2 w5 O
        mBtnRedOff = (Button) findViewById(R.id.btn_red_off);
) E! F; @; g7 K1 J8 Z        mBtnYellowOn = (Button) findViewById(R.id.btn_yellow_on);
. u7 f0 H! M# x" }. K5 ?        mBtnYellowOff = (Button) findViewById(R.id.btn_yellow_off);
6 x2 G( D: p  e' U/ r* B        mBtnBlueOn = (Button) findViewById(R.id.btn_blue_on);# r! T# v% d2 J' i2 H
        mBtnBlueOff = (Button) findViewById(R.id.btn_blue_off);
9 ?; f5 b/ k* x: f* C/ y/ R        mBtnConnect.setOnClickListener(this);
' C1 y* U2 G3 f7 C        mBtnRedOn.setOnClickListener(this);
1 l$ S( U; o5 n, i  y) O$ K2 s        mBtnRedOff.setOnClickListener(this);
! B( j& c0 i/ h- @3 X7 c        mBtnYellowOn.setOnClickListener(this);
; ?" j2 j1 i. W9 C+ a        mBtnYellowOff.setOnClickListener(this);2 L- A* m+ z& u5 x- H: K2 Y
        mBtnBlueOn.setOnClickListener(this);$ u3 ]  q* S, y. C2 l: z3 I
        mBtnBlueOff.setOnClickListener(this);
3 E$ D1 I" u/ [; N
! g+ o1 z8 \4 S/ U. S( M' _( f' M  U/ r    }! C( H) f$ ?; p; R5 w
按钮的点击回调方法:
& A# s/ j  c3 S8 o* D9 d/ o
5 V/ I  {1 j  E) d$ x+ K
- Q$ W' i! s0 b  N5 `" Q
    public void onClick(View v) {9 T* q4 Q! ?! Q0 U/ D$ K! E' B2 e& `  |
        switch (v.getId()) {
" p0 X( R. F/ x9 t            case R.id.btn_connect:
6 U1 ]% R0 I$ n% O7 W% |3 i# J                //连接9 |  Q9 ]9 l( E& t
                if (mSocket == null || !mSocket.isConnected()) {
' Y6 |" V2 [/ N& ?8 |# K  B                    String ip = mEtIP.getText().toString();
& X) y2 Q8 \: ^9 V                    int port = Integer.valueOf(mEtPort.getText().toString());( a, g. d  {6 C8 \3 }! g" t
                    mConnectThread = new ConnectThread(ip, port);
! Y/ e( U* j2 ^6 t                    mConnectThread.start();1 R& A5 g& @8 N6 i  I
                }) |% |9 k& j* o+ o
                if (mSocket != null && mSocket.isConnected()) {
1 v$ m* d, u$ l* c8 D: L! O0 B# }0 z                    try {
+ t6 k9 T2 W5 _                        mSocket.close();
! b7 Z! _% n2 g5 e; Z                        mBtnConnect.setText("连接");" `3 _, @- @' Y! m) d* i
                    } catch (IOException e) {
$ y# }. B/ ?. q) F                        e.printStackTrace();
! Z2 h- s6 ~7 z                    }: v* d. t" o3 k# P6 c
                }
2 b6 W. |+ `1 Z6 T& e   U; F1 w$ c9 l8 W+ q" l) \/ o
                break;
) K- S4 F4 I* @' v' G( B8 Y7 V' ~            case R.id.btn_red_on:         //开红灯
& R* o$ c7 {0 x8 b( K                if (out != null) {8 g% M6 u$ r8 j- {  u" W: r$ V+ V0 X
                    out.print("1");$ `8 u0 O) w0 m: j+ \0 }, Y5 A
                    out.flush();
' f& K, M/ r' Z2 {# q/ ~                }5 C- Y) \1 g, k3 @3 c+ @; Z7 |
                break;2 O1 I1 T9 H& c* k  e% J$ H  E
            case R.id.btn_red_off:        //关红灯0 }) q) r2 p1 @6 K+ O' G
                if (out != null) {
, y4 Y7 g/ J. k# W                    out.print("2");
/ m  U! z% O. H                    out.flush();
* L. N( c2 ?( z% P* Z4 x                }- ?, }  a) J1 v" M( n3 t1 p
                break;
& H3 d9 p) V2 v/ l8 b            case R.id.btn_yellow_on:, U( k6 j& q9 p2 i% s
                if (out != null) {
9 M6 R: V: k/ W( e                    out.print("3");
7 C" S8 q- N/ k9 u                    out.flush();
* U) {2 S- ^9 O# g) d+ \                }
' _# m0 `5 y1 f  _- Z  J3 f                break;% x. n- D2 x2 p9 V: W
            case R.id.btn_yellow_off:" O, ~8 N* ^( V& l5 e
                if (out != null) {
- M1 t; d) m; V5 p0 U                    out.print("4");
3 Q9 G8 H1 a! Z! K% M: g                    out.flush();
9 x( L9 c# w& ?& N" T                }9 K) A! D9 C! d: B1 N$ E) f
                break;
# N5 L7 |4 q) p. d            case R.id.btn_blue_on:+ q# o% s; B$ x/ ]9 X) A( ~
                if (out != null) {) h  w7 D: t, n( z+ O# Z
                    out.print("5");0 y! p' Y1 M; J3 R& V5 ^
                    out.flush();
  V" g! y: M2 b4 ^3 ~  K1 l* K                }
; J. _( X' o; H+ X9 S' k2 X% z                break;
# g, H- s5 d6 C# a% J            case R.id.btn_blue_off:% S$ i/ L7 O* G# y% b! O' ~3 ^% g
                if (out != null) {
0 N, G  J- Q1 z, Z4 G3 L                    out.print("6");) L6 U# t6 \, t5 u
                    out.flush();
+ Q5 a7 {: f6 P" m                }
1 d8 ?* y6 a9 Y' F' x5 q9 S                break;2 I4 X+ s8 z6 ?& V# c& _+ x& @6 z
        }4 j- y% ?( }& h6 e9 H
    }
: \% d" a& ?, v' a 6 t9 ?) ]% x! H# U$ U
负责连接esp8266的线程:
5 b: \! o6 `3 a, v- m
4 c5 J/ c' A# ~5 g

. A, o& Y" V& o* p+ t" I, `private class ConnectThread extends Thread {
+ i7 I. B3 O' W5 j        private String ip;' u6 B8 m% ]$ J: A: z$ }: l
        private int port;2 R- t+ b% N$ o: R. u) b* o  g. O

/ b) J% y' u+ W- z2 X- T/ G        public ConnectThread(String ip, int port) {0 t, ]9 }& C8 u( [/ w
            this.ip = ip;
) M( b" x$ s) y3 T1 r: J( b            this.port = port;* n- N/ T( [. v, O9 P* k  N
        }
, z! X- v; u7 J3 b! o! s 4 @7 u3 X, |* W. Z
        @Override
( s6 B! G) t# X2 e. f2 _3 l        public void run() {" }4 b/ \6 C8 f5 t4 P" L
            try {6 z! N" V+ P# T
                mSocket = new Socket(ip, port);
- m7 z. s' D* E5 a9 F$ d( G                out = new PrintStream(mSocket.getOutputStream());
/ b+ l; g1 e  f  |                runOnUiThread(new Runnable() {) W- u+ Y. N1 K1 u( w+ O: s
                    @Override# e, r4 a7 p4 B+ P1 Q6 n9 |+ R
                    public void run() {
5 A% m* y1 `: y( A; X2 D                        mBtnConnect.setText("断开");9 u$ j; w' Y7 z! o* M% ^1 Q/ Z
                    }9 r7 o; G. T; W
                });1 y3 R6 Q( I; y
                new HeartBeatThread().start();& }2 }7 h+ o. |' u9 E
            } catch (IOException e) {4 u- o) ^; M3 v# U; R; b
                e.printStackTrace();: n0 L* [, x1 V- e' l
                runOnUiThread(new Runnable() {
5 N* L% Z' ^4 j8 |                    @Override
, `9 @+ h# j6 B7 O: M0 M  F, \6 @                    public void run() {% o1 [4 ]! K; m6 P
                        Toast.makeText(MainActivity.this, "连接失败", Toast.LENGTH_SHORT).show();
7 p% e1 |' {, O                    }
6 j* m9 y- b' {) U' g, p                });
9 U& e6 A; l. r! ]1 ?) s, v            }9 E& ^+ l( w! k  C
        }7 d( U" g% d9 O! f; i
    }' Y" t. |' y# x

( {/ E  l" m7 Y
8 A5 j, W/ [% z! {% X0 O7 w1 U
$ ^, y/ }7 v; a! q$ d- d
1 t/ y4 J% i! l7 P

该用户从未签到

2#
发表于 2021-9-17 11:28 | 只看该作者
通过APP控制灯的亮灭成功率高吗

该用户从未签到

3#
发表于 2021-9-17 13:54 | 只看该作者
是怎么进行通信的呢

该用户从未签到

4#
发表于 2021-9-17 13:59 | 只看该作者
学习了  感谢分享
# S, X, x1 t$ c4 Y0 k  y/ C

该用户从未签到

5#
发表于 2021-9-18 11:01 | 只看该作者
强烈支持,谢谢楼主分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-8-17 11:27 , Processed in 0.156250 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表