一、前言
二、效果展示
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通讯,特来与大家分享,希望对各位能有所帮助。废话不多说,先看效果。
可以看到,该APP基本实现了手机与C51单片机之间的WIFI通讯,手机端可以发送和接收数据,可以选择直接给WIFI发送数据,也可以将发送的数据的发送代码固化为按键,比如我上面的四个LED按键其实底层代码就是按下分别发送“1”、“2”、“3”、“4”来控制四个灯的亮灭。本app只是用来实验手机与C51单片机之间的WIFI通讯,目前来说算是成功了,后续可以通过修改调用该程序实现更复杂的内容,目前我也在朝着这个方向努力`(*>﹏<*)′
首先需要联网别忘了给 Android 添加网络连接权限:
//需要对WiFi进行操作,所以需要设置网络权限
android:usesCleartextTraffic="false"
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
}
布局预览:
如此app上位机端操作就基本大功告成了,接下来就是下位机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,
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,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;
}
}
}
}
相比于编写代码,硬件方面就简单多了,就是有一些需要格外注意的事项,也是我在实践中遇到的问题,现在分享给大家。
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