Android Studio设计APP实现与51单片机通过WIFI模块(ESP8266-01S)通讯控制LED灯亮灭的设计源码【详解】

目录

一、前言

二、效果展示

1、APP界面展示

 2、C51硬件展示

三、Android Studio APP源代码

1、AndroidManifest.xml

1、请求联网:

2、开放明文传输:

2、MainActivity.java

3、Layout页面布局文件 activity_main.xml

四、Keil C51单片机源码

五、WIFI模块(ESP8266-01S)注意事项

六、后述     

一、前言

        本文将详细介绍如何利用Android Studio设计 APP 实现与C51单片机通过WIFI模块通讯控制LED灯亮灭,本人也是新手刚入门,找了很多资料,但都不得要领,最后终于靠着摸索学习实现了手机与C51模块的WIFI通讯,特来与大家分享,希望对各位能有所帮助。废话不多说,先看效果。

二、效果展示

1、APP界面展示

36df57fcdb6a4eb8ae422fcc8ae46535.gif

 2、C51硬件展示

4fb11a2edbd246d394959b9921674597.gif

        可以看到,该APP基本实现了手机与C51单片机之间的WIFI通讯,手机端可以发送和接收数据,可以选择直接给WIFI发送数据,也可以将发送的数据的发送代码固化为按键,比如我上面的四个LED按键其实底层代码就是按下分别发送“1”、“2”、“3”、“4”来控制四个灯的亮灭。本app只是用来实验手机与C51单片机之间的WIFI通讯,目前来说算是成功了,后续可以通过修改调用该程序实现更复杂的内容,目前我也在朝着这个方向努力`(*>﹏<*)′

 

三、Android Studio APP源代码

1、AndroidManifest.xml

首先需要联网别忘了给 Android 添加网络连接权限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.tcp_led">

    
    <uses-permission android:name="android.permission.INTERNET"/> //需要对WiFi进行操作,所以需要设置网络权限

    <application
        android:usesCleartextTraffic="false"   //开放明文传输
        android:allowBackup="true"
        android:icon="@drawable/bh"
        android:label="@string/app_name"
        android:roundIcon="@drawable/bh_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.TCP_LED"
        tools:ignore="UnusedAttribute">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

1、请求联网:

 <uses-permission android:name="android.permission.INTERNET"/>

2、开放明文传输:

android:usesCleartextTraffic="false"

2、MainActivity.java

package com.example.tcp_led;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class MainActivity extends AppCompatActivity {
    String a;
    int b;
    connectthread lianjie;
    TextView receive;
    Socket socket=null;
    Button connect;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EditText ip=findViewById(R.id.mEtIP);
        EditText port=findViewById(R.id.mEtPort);
        EditText out=findViewById(R.id.mEtOut);
        receive=findViewById(R.id.receive);
        connect=findViewById(R.id.mBt1);
        Button send=findViewById(R.id.mBt7);
        Button LED1=findViewById(R.id.mBt3);
        Button LED2=findViewById(R.id.mBt4);
        Button LED3=findViewById(R.id.mBt5);
        Button LED4=findViewById(R.id.mBt6);
        Button Clear=findViewById(R.id.mBt8);

        // 连接 按键底层代码
        connect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                a=ip.getText().toString();
                String c=port.getText().toString();
                if("".equals(a)||"".equals(c)){
                    Toast.makeText(MainActivity.this,"请输入ip和端口号",Toast.LENGTH_SHORT).show();
                    receive.append("请输入ip和端口号" + "\r\n");
                }
                else{b=Integer.parseInt(c);
                    lianjie=new connectthread();
                    lianjie.start();}
            }
        });

        // 发送数据 按键底层代码
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //子线程中进行网络操作
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if(socket!=null){
                            try {
                                String text=out.getText().toString();
                                lianjie.outputStream.write(text.getBytes());
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();

                            }
                        }else{
                            runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                            {
                                public void run()
                                {
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
                                    receive.append("请先建立连接" + "\r\n");
                                }
                            });
                        }
                    }
                }).start();

            }
        });
        // LED1 按键底层代码 其实就是发送数据按键代码基础上修改的,后面三个按键都是
        LED1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //子线程中进行网络操作
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if(socket!=null){
                            try {
                                String text="1";
                                lianjie.outputStream.write(text.getBytes());
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();

                            }
                        }else{
                            runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                            {
                                public void run()
                                {
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
                                    receive.append("请先建立连接" + "\r\n");
                                }
                            });
                        }
                    }
                }).start();
            }
        });
        // LED2 按键底层代码 
        LED2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //子线程中进行网络操作
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if(socket!=null){
                            try {
                                String text="2";
                                lianjie.outputStream.write(text.getBytes());
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();

                            }
                        }else{
                            runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                            {
                                public void run()
                                {
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
                                    receive.append("请先建立连接" + "\r\n");
                                }
                            });
                        }
                    }
                }).start();
            }
        });
        // LED3 按键底层代码 
        LED3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //子线程中进行网络操作
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if(socket!=null){
                            try {
                                String text="3";
                                lianjie.outputStream.write(text.getBytes());
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();

                            }
                        }else{
                            runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                            {
                                public void run()
                                {
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
                                    receive.append("请先建立连接" + "\r\n");
                                }
                            });
                        }
                    }
                }).start();
            }
        });
        // LED4 按键底层代码 
        LED4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //子线程中进行网络操作
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if(socket!=null){
                            try {
                                String text="4";
                                lianjie.outputStream.write(text.getBytes());
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();

                            }
                        }else{
                            runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                            {
                                public void run()
                                {
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
                                    receive.append("请先建立连接" + "\r\n");
                                }
                            });
                        }
                    }
                }).start();
            }
        });
        Clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                receive.setText("");
            }
        });

       // onCreate
    }
    //子线程中进行网络相关操作
    // 联网子线程
    class connectthread extends Thread {

        OutputStream outputStream=null;
        InputStream inputStream=null;
        @SuppressWarnings("InfiniteLoopStatement")
        @Override
        public void run() {

            //连接
            try {
                socket=new Socket(a, b);
                runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                {
                    public void run()
                    {
                        // TODO Auto-generated method stub
                        Toast.makeText(MainActivity.this,"连接成功",Toast.LENGTH_SHORT).show();
                        receive.append("连接成功" + "\r\n");

                    }
                });
            } catch (UnknownHostException e) {
                // TODO Auto-generated catch block
                runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                {
                    public void run()
                    {
                        // TODO Auto-generated method stub
                        Toast.makeText(MainActivity.this,"连接失败",Toast.LENGTH_SHORT).show();
                        receive.append("连接失败" + "\r\n");
                    }
                });
                e.printStackTrace();
            }catch (IOException e) {
                e.printStackTrace();
                runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                {
                    public void run()
                    {
                        // TODO Auto-generated method stub
                        Toast.makeText(MainActivity.this,"连接失败",Toast.LENGTH_SHORT).show();
                        receive.append("连接失败" + "\r\n");
                    }
                });
            }
            if(socket!=null){
                //获取输出流对象
                try {
                    outputStream=socket.getOutputStream();
                    outputStream.write(123);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                try{
                    do {
                        final byte[] buffer = new byte[1024];//创建接收缓冲区
                        inputStream = socket.getInputStream();
                        final int len = inputStream.read(buffer);//数据读出来,并且返回数据的长度
                        runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                        {
                            public void run() {
                                // TODO Auto-generated method stub
                                receive.append(new String(buffer, 0, len) + "\r\n");
                            }
                        });
                    } while (true);
                }
                catch (IOException ignored) {

                }
            }
        }
    }
    // MainActivity
}

3、Layout页面布局文件 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="#f1f3f4">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TCP客户端"
            android:textSize="50dp"
            android:background="#ffffff"
            android:gravity="center"
            />
        <EditText
            android:id="@+id/mEtIP"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:inputType="textWebEditText"
            android:hint="请输入服务器IP"
            android:drawableStart="@drawable/ic_tree"
            android:drawablePadding="20dp"
            android:layout_gravity="center"
            android:textSize="20sp"
            android:autofillHints="" />
        <!--端口 -->
        <EditText
            android:id="@+id/mEtPort"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:inputType="date"
            android:hint="请输入服务器端口"
            android:drawableStart="@drawable/ic_tree"
            android:drawablePadding="20dp"
            android:layout_gravity="center"
            android:textSize="20sp"
            android:autofillHints="" />
        <!--发送 -->
        <EditText
            android:id="@+id/mEtOut"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:inputType="date"
            android:hint="请输入发送数据"
            android:drawableStart="@drawable/ic_tree"
            android:drawablePadding="20dp"
            android:layout_gravity="center"
            android:textSize="20sp"
            android:autofillHints="" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center">
            <Button
                android:id="@+id/mBt1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="连接"
                tools:ignore="UsingOnClickInXml" />
            <Button
                android:id="@+id/mBt7"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="发送数据"
                tools:ignore="UsingOnClickInXml" />
            <Button
                android:id="@+id/mBt8"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="清除"
                tools:ignore="UsingOnClickInXml" />

        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center">
            <Button
                android:id="@+id/mBt3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="LED1"
                tools:ignore="UsingOnClickInXml" />
            <Button
                android:id="@+id/mBt4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="LED2"
                tools:ignore="UsingOnClickInXml" />
            <Button
                android:id="@+id/mBt5"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="LED3"
                tools:ignore="UsingOnClickInXml" />
            <Button
                android:id="@+id/mBt6"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="LED4"
                tools:ignore="UsingOnClickInXml" />

        </LinearLayout>
        <TextView
            android:id="@+id/receive"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

布局预览:

ac40dc883e7944d186c14943b6515612.png

        如此app上位机端操作就基本大功告成了,接下来就是下位机C51方面的程序了。 

四、Keil C51单片机源码

#include "reg51.h"
#define uchar unsigned char
#define uint unsigned int
	
sbit SW1=P1^0;    //S1按键
sbit LED1=P1^1;
sbit LED2=P1^2;
sbit LED3=P1^3;
sbit LED4=P1^4;

//ESP8266  EN、vcc脚接 vcc 3.3 GND 接地,必须和51共地
//ESP8266  TX 接P3^0, RX 接P3^1


bit flag=0;

uchar SendBuf[9]="LED1 ON! ";
uchar RecBuf[15];
uchar RecNum=0;

void delay_10us(uint us); //延时
void delay(uint n);   //延时
void UART_Init();   
void UART_SendByte(uchar dat);
void ESP8266_SendCmd(uchar *pbuf);
void ESP8266_SendData(uchar *pbuf); 
void ESP8266_ModeInit(void);    //WIFI模块初始化
void UART_Irq( );    // 接收信号

void delay_10us(uint us)
{
	while(us--);
}

void delay(uint n)
{
	uint i,j;
	for(i=0;i<n;i++)
		for(j=0;j<100;j++);
}

void UART_Init()
{
	SCON=0X50;				//串口:工作方式1
	TMOD=0X20;				//定时器:工作方式2
	TH1=0xFD;	    			//波特率:9600
	TL1=0xFD;
	ES=0;				  	//禁止串口中断
	EA=1;				 	//使能总中断
	TR1=1;					//启动计数器
}

void UART_SendByte(uchar dat)
{
	ES=0; 			    		//禁止串口中断
	SBUF=dat;       			//串口发送
	while(TI==0);   			//等待发送结束
	TI=0;           			//发送标志位清零
	ES=1; 					//使能串口中断
}

void ESP8266_SendCmd(uchar *pbuf)
{
	while(*pbuf!='\0') 				//遇到空格跳出循环	
	{
			UART_SendByte(*pbuf);
			delay_10us(5);
			pbuf++;	
	}
	delay_10us(5);
	UART_SendByte('\r');				//回车
	delay_10us(5);
	UART_SendByte('\n');				//换行
	delay(1000);
}

void ESP8266_SendData(uchar *pbuf)    
{
	uchar i=0;
	ESP8266_SendCmd("AT+CIPSEND=0,9");  //发送数据:AT+CIPSEND=<id>,<length>
	for(i=0;i<=8;i++)
	{
		UART_SendByte(*pbuf);
		delay_10us(5);
		pbuf++;	
	}
}

void ESP8266_ModeInit(void)    //WIFI模块初始化
{
	
	ESP8266_SendCmd("AT+CWMODE=3");    //设置路由器模式 1:Station,,2:AP,3:Station+AP
	ESP8266_SendCmd("AT+CWSAP=\"百行\",\"12345678\",11,0");  //设置WIFI热点名称及密码
	ESP8266_SendCmd("AT+CIPAP=\"192.168.4.2\"");   //设置AP的IP地址
	ESP8266_SendCmd("AT+RST");                  //重新启动wifi模块
	ESP8266_SendCmd("AT+CIPMUX=1");	        //开启多连接模式
	ESP8266_SendCmd("AT+CIPSERVER=1,8080");	   //启动TCP/IP 端口为8080
	
}

void main()
{	
   P1=0x01;
	 while(SW1);       				//等待S1键按下
   LED1=LED2=LED3=LED4=1;
	 UART_Init();      				//串口初始化
	 ESP8266_ModeInit();
	
	 ES=1;             			//允许串口中断
	
	 while(1)
	 {
		 if(flag==1)
		 {
			 flag = 0;
			 ESP8266_SendData(SendBuf); 
		 }
		 delay(10);
	 }		
}

void UART_Irq( ) interrupt 4   // 接收信号
{
	if(RI)
	{
		RI=0;
		RecBuf[RecNum]=SBUF;   //接收到网络数据:+IPD,0<id>,1<数据长度>:F<接收的数据>
		if(RecBuf[0]=='+')
			RecNum++;
		else 
			RecNum=0;
		if(RecNum==10)
		{
			RecNum=0;
			if(RecBuf[0]=='+'&&RecBuf[1]=='I'&&RecBuf[2]=='P'&&RecBuf[3]=='D')
			{
				switch(RecBuf[9])
				{
					case '1': P1 = 0xfD;break;   
					case '2': P1 = 0xfB;break;
					case '3': P1 = 0xf7;break;
					case '4': P1 = 0xef;break;
					default:P1 = 0xe0;						
				}
				SendBuf[3] = RecBuf[9];
				flag = 1;
 			}
		}				
	}
}

五、WIFI模块(ESP8266-01S)注意事项

        相比于编写代码,硬件方面就简单多了,就是有一些需要格外注意的事项,也是我在实践中遇到的问题,现在分享给大家。

d6b66b16c77141bca296837fe0db63d5.png

ESP8266-01S WIFI模块 接线
                    TX RXD(P3^0)
                    RX TXD(P3^1)
                    EN 3.3V
                    VCC 3.3V
                    GND GND

        这里需要特别注意在TX和RX中,TX代表WIFI模块发送数据,应该和单片机串行数据接收端RXD相连接,RX代表WIFI模块接受数据,应该和单片机串行数据发送端TXD相连接。EN、VCC必须接3.3V电源,另外WIFI模块工作时会发热,属于正常情况。GND接地需要特别注意,WIFI模块必须和51单片机共地,否则单片机将无法正常读取数据。其他引脚悬空就可以了,也就是说WIFI模块只需和51连接三根线即可,两根串行数据线,一根共地线。

六、后述
      

         以上就是今天要讲的内容,本文简单介绍了如何利用Android Studio设计 APP 实现与C51单片机通过WIFI模块通讯控制LED灯亮灭,由于本人也是刚开始学习,本文还有很多不足的地方,目前我的程序也还在开发中,后续我会随时更新文章中不足的部分,欢迎各位有需要的订阅我的这个专栏获取最新内容。

代码已开源:(其实以上就是全部内容了)

Github 源码资源免费下载https://github.com/SHUGEX/TCP_LED

CSDN 源码资源积分下载https://download.csdn.net/download/weixin_45694843/85238966

猜你喜欢

转载自blog.csdn.net/weixin_45694843/article/details/124486464