使用一片ESP-01S,用Android Studio开发了一个APP,手机安装后,立即变身为单片机的大屏显示器。淘汰的手机终于有用武地方了,成本不到10块钱,而且wifi无线连接。
手机做单片机显示器
需要软件工具及硬件:
1、ESP-01S模块,单片开发系统,USB串口线(TTL电平,安装好驱动),手机一部(驱动装好,可以正常连接电脑)。
2、安信可串口调试助手(厂家配套,推荐),网络调试助手。
3、java编程工具idea64,安卓开发工具Android Studio。
具体步骤:
1、ESP-01S设置好UDP透传模式
ESP-01S 是由安信可科技开发的 Wi-Fi 模块,该模块核心处理器为ESP8266 。接线参考下图。
接好串口线,MCU_RXD与MCU_TXD两个引脚接入串口线对应引脚。3.3V 供电(VDD)要求较高,外部供电电源输出电流建议在 500mA 以上。在电脑上使用安信可串口调试助手,波特率选择115200,连接正常的情况下ESP-01S上电后如下图。

发一个AT+RST(复位命令),要勾选发送新行选项,如能正常复位,这时就可以按下面步骤配置模块透传模式。
a、AT+RESTORE 初始化
b、AT+CWMODE_DEF=1 设置当前 Wi-Fi 模式并保存到 Flash (不开模块热点)
c、AT+CWJAP_DEF =“abc”,“0123456789” 连接 AP,保存到 Flash (AP 的 SSID 为 “abc”,密码为 “0123456789”)
d、AT+SAVETRANSLINK=1,“192.168.3.3”,440,“UDP” 保存开机透传到 Flash(UDP模式)(远端UDP主机地址、端口)
e、AT+RST 复位
复位后,串口助手显示同上图一样,不同的是点击发送命令模块不会反馈如何信息。这时发送“+++”(不选择发送新行选项)会退出透传模式,各种命令才起作用。
这时可以在电脑上打开网络调试助手,选择“UDP”协议,填写对应的IP地址(电脑的IP地址),对应的端口(440)后,点击打开,这时按钮变成红色,表示连接已建立。

这时可以尝试互相发送消息了。看看吧!

2、Android Studio上开发通讯app
这里的代码与视频显示不同,我做了简化。代码如下:
2.1 AndroidManifest.xml代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.ww01">
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
xmlns:tools="http://schemas.android.com/tools"
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Ww01">
<activity
android:name=".MainActivity"
android:exported="true"
android:screenOrientation="portrait"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2.2 activity_main.xml代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#46857070"
tools:context=".MainActivity">
<LinearLayout
android:id="@+id/linearLayout14"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="15"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="15"
android:orientation="horizontal">
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="5"
android:orientation="horizontal">
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="15"
android:orientation="horizontal"></LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/textview_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/hello_first_fragment"
android:textColor="#E80F42"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/T12"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="40dp"
android:text="TextView"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginTop="56dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@+id/textview_first">
<LinearLayout
android:id="@+id/linearLayout22"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_weight="10">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:gravity="right"
android:rotationX="1"
android:text=" IP地址:"
android:textSize="20sp" />
<EditText
android:id="@+id/mEtIP"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:autofillHints=""
android:inputType="textPersonName"
android:text="@string/_192_168_3_66"
tools:ignore="TouchTargetSizeCheck" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout23"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_weight="10">
<TextView
android:layout_width="100sp"
android:layout_height="wrap_content"
android:gravity="right"
android:text="@string/post"
android:textSize="20sp" />
<EditText
android:id="@+id/mEtPort"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="textPersonName"
android:text="8800"
tools:ignore="TouchTargetSizeCheck" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="98dp"
android:layout_marginBottom="48dp"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@+id/linearLayout3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="2"
android:orientation="vertical"></LinearLayout>
<Button
android:id="@+id/mBt1"
android:layout_width="128dp"
android:layout_height="45dp"
android:layout_gravity="center"
android:text="创建连接" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"></LinearLayout>
<Button
android:id="@+id/mBt12"
android:layout_width="128dp"
android:layout_height="45dp"
android:layout_gravity="center"
android:text="关闭连接" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="2"
android:orientation="vertical"></LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="70dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="15"
android:orientation="horizontal">
</LinearLayout>
<Button
android:id="@+id/mBt2"
android:layout_width="108dp"
android:layout_height="45dp"
android:layout_gravity="center_vertical"
android:gravity="center"
android:text="开"
tools:ignore="HardcodedText" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="10"
android:orientation="horizontal">
</LinearLayout>
<Button
android:id="@+id/mBt3"
android:layout_width="108dp"
android:layout_height="45dp"
android:layout_gravity="center_vertical"
android:text="关"
tools:ignore="HardcodedText" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="15"
android:orientation="horizontal"></LinearLayout>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/textView"
android:layout_width="89dp"
android:layout_height="22dp"
android:layout_marginStart="24dp"
android:layout_marginBottom="110dp"
android:layout_weight="1"
android:text="通讯控制"
android:textColor="@color/teal_700"
app:layout_constraintBottom_toTopOf="@+id/linearLayout3"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="89dp"
android:layout_height="22dp"
android:layout_marginStart="24dp"
android:layout_weight="1"
android:text="LED控制"
android:textColor="@color/teal_700"
app:layout_constraintBottom_toTopOf="@+id/linearLayout3"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
这个布局文件代码有点长,主要是为适应手机屏幕做了不少多余布局,好在也不用仔细看,哈哈。
2.3 MainActivity.java代码
package com.example.ww01;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button mBtnConnect; // 连接
private EditText mIp;
private EditText mPort;
private TextView Text12;
private String info;
int AN1 = 0, AN2 = 0, AN0 = 0, Switch = 0;
String AAA;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtnConnect = findViewById(R.id.mBt1); //UDP服务器开
Button bBtnConnect = findViewById(R.id.mBt12); //UDP服务器关
Button mMotorZ = findViewById(R.id.mBt2);// 按钮LED灯开
Button mMotorF = findViewById(R.id.mBt3);// 按钮LED灯关
// IP
mIp= findViewById(R.id.mEtIP);
// 端口号
mPort = findViewById(R.id.mEtPort);
Text12 = findViewById(R.id.T12);
mBtnConnect.setOnClickListener(this);
bBtnConnect.setOnClickListener(this);
mMotorZ.setOnClickListener(this);
mMotorF.setOnClickListener(this);
Text12.setText("myapp");
}
@SuppressLint("NonConstantResourceId")
@Override
public void onClick(View view) {
view.getId();
UDPServer mUDPServer = new UDPServer();
switch (view.getId()) {
case R.id.mBt1:
if (AN0 == 0) {
AN0 = 1;
//UDPServer mUDPServer = new UDPServer();
mUDPServer.start();
}
break;
case R.id.mBt12:
if (AN0 == 1) {
AN0 = 0;
runOnUiThread(() -> {
mBtnConnect.setText("创建连接");
Toast.makeText(MainActivity.this, "端口正在关闭", Toast.LENGTH_LONG).show();
});
}
break;
case R.id.mBt2:
if (Switch == 0) {
AN1 = 1;
Switch = 1;
}
break;
case R.id.mBt3:
if (Switch == 1) {
AN2 = 1;
Switch = 0;
}
break;
default:
throw new IllegalStateException("Unexpected value: " + view.getId());
}
}
class UDPServer extends Thread {
// 1.创建服务器端DatagramSocket,指定端口
DatagramSocket socket; // 套接字
String as = mPort.getText().toString(); //获取EditText的PORT数据
{
try {
socket = new DatagramSocket(Integer.parseInt(as));
} catch (SocketException e) {
e.printStackTrace();
}
}
byte[] data = new byte[1024];// 创建字节数组,指定接收的数据包的大小
DatagramPacket packet = new DatagramPacket(data, data.length);
@SuppressLint("SetTextI18n")
public void run() {
runOnUiThread(() -> {
mBtnConnect.setText("UDP服务开启");
Toast.makeText(MainActivity.this, ("等待客户机接入......"), Toast.LENGTH_LONG).show();
});
if (AN0 == 0)
socket.close();
while (AN0 == 1) {
try {
socket.receive(packet);// 此方法在接收到数据报之前会一直阻塞
} catch (IOException e) {
e.printStackTrace();
}
info = new String(data, 0, packet.getLength());
runOnUiThread(() -> {
mBtnConnect.setText("连接成功");
Text12.setText(info);
});
// 1.定义客户端的地址、端口号、数据* 向客户端响应数据
InetAddress address = packet.getAddress();
int port = packet.getPort();
//AAA = info;//发送数据,返回接收到的数据
if ((AN1+AN2)>0) {
if (AN1 == 1) {
AAA = "1";
AN1 = 0;
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "已经发送‘1’,成功", Toast.LENGTH_LONG).show();
});
}
if (AN2 == 1) {
AAA = "0";
AN2 = 0;
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "已经发送‘0’,成功", Toast.LENGTH_LONG).show();
});
}
byte[] data2 = AAA.getBytes();
// 2.创建数据报,包含响应的数据信息
DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
// 3.响应客户端
try {
socket.send(packet2);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
2.4 string.xml代码
这个有点东西,也放在这里
<resources>
<string name="app_name">myapp</string>
<string name="action_settings">Settings</string>
<!-- Strings used for fragments for navigation -->
<string name="first_fragment_label">First Fragment</string>
<string name="second_fragment_label">Second Fragment</string>
<string name="next">Next</string>
<string name="previous">Previous</string>
<string name="hello_first_fragment">连接方式:UDP</string>
<string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string>
<string name="abc">abcdz</string>
<string name="ip">ip地址:</string>
<string name="ip1">textPersonName</string>
<string name="post">端口:</string>
<string name="_192_168_3_66">192.168.3.100</string>
</resources>
3、实际使用效果
3.1 进入后显示

这里的IP地址没用,不用动,端口号也可以不动,也可以自己改一下。
3.2 重新设置模块网路连接,连接目标定为手机端
查一下手机的局域网IP地址,然后将上面所述ESP-01S的UDP设置重新来一遍,
d、AT+SAVETRANSLINK=1,“192.168.3.3”,440,“UDP” 保存开机透传到 Flash(UDP模式)(远端UDP主机地址、端口)
这行把IP地址位置改成手机的IP地址,端口号440改成8800或你在上图输入的端口号。ESP-01S设置好后重启。
3.3 点击上图的“创建连接”按钮。如下图,按钮显示“UDP服务开启”,准备接收客户端信息。

3.4 这时在串口助手中发送数据,手机中间的文本显示区就出现了该数据信息,按钮显示也变成了连接成功。

3.5 实验手机按钮发送信息
点击屏幕“开”“关”按钮,后在串口助手任意发一个信息、则可以收到0和1的数据,注意按钮操作需交替进行,连续按一个按钮只在第一次有命令发出。

如勾选定时发送则每次按键后数据都会传到串口助手。

4、连接单片机系统
将串口线拆除,模块连接到MCU串口,后面的工作就在你自己的单片机系统里进行了,这些我就略去了。
我分享的这个app的实例也只是验证通过ESP-01S做无线数据传输,及手机实现设备控制的功能,具体大家的使用跟据自己喜好完善。
全部工程文件下载链接:https://download.csdn.net/download/wdzh018/86881367
本文介绍了如何使用ESP-01S Wi-Fi模块和Android Studio创建一个APP,将手机转变为单片机的显示器。通过设置ESP-01S为UDP透传模式,并配置相应的Android应用,实现了手机与单片机之间的无线数据传输和控制。用户可以通过APP发送指令,控制单片机系统,同时接收单片机的反馈信息。
8210

被折叠的 条评论
为什么被折叠?



