CSDN话题挑战赛第1期
创作模板:
注意:请将本模板中对于模板本身的说明文字删去,替换成自己想要表达的内容
现在的时代中总是可以看到人们拿着手机看着手机,甚至在这个网络时代大家无论是开灯,开洗衣机洗衣服,开电视,很多很多电器以及玩具大家都可以用手机来控制,那么接下来我们就聊一聊关于手机如何实现控制电器,需要什么准备以及什么网络协议。
在这里,写下实现你绝妙的想法需要的硬件物品。保证清晰的情况下不限制表现方式。(使用单、多行文字,无序列表,有序列表,代办,表格等形式均可)
序号 | 材料 |
---|---|
1 | ESP8266模块一块 |
2 | STM32开发板一块 |
3 | windows操作系统电脑一台 |
序号 | 软件 |
1 | keil(MDK环境)软件 |
2 | andriod_studio软件 |
需要准备一个串口软件,烧录器ST-link或USB-TTL或者j-link都行
首先准备好上面的东西,那么就开始写软件部分的实现以及配网协议的过程,最重要就是andriod的实现,因为只有做好了手机的控制,其它的都是比较容易的。
打开android先创建一个APP页面
点击新建然后点击新建项目
新建之后得到这样一个页面,然后点这个空白框,然后下一步。当以也可以选其它样式的框
点完到这个页面,第一个是APP的名称,2存放的目录不可以右中文,3使用的编程语言,4手机支撑的最高版本。,选完之后就到点击完成。
之后可以得到好很多文件夹,但是我们最主要的就是看三个文件,下面的图片指出的每个文件在那个目录下,
首先我们看第一个是.xml文件这个是可是化编程,就是这样的一半页面布局的代码,一面是显示手机页面的ui布局,这两个是关联的,然后三个小箭头是,一个是code全代码编程,一个split是版半代码半图形化,最后一个是全图形化编程。
,接下来看这个页面是怎么搭建的呢,就是点击这里的组件直接拖到页面就好了。等布局好就点击魔法棒,左边圈是组件,直接拉到空白页面,布置好位置,就点击魔法棒就好了。
那布局做好了,我们要怎么让这个布局动起来,点击那么就让它产生一个事件,然后把这个事件传给设备,让设备识别到了这个这个动作是干嘛的。那么产生事件这个就需要后端事件java代码编译了。
就是这个文件
打开这个文件之后我们就可以看到里面的编译规则是java。那么接下来就实现一下 Java的代码。实现java的代码执行前,我们先了解一下网络协议TCP也就是WiFi这个功能他们之间是什么关系以及什么传输方式的。
tcp就是客户端以及服务端之间的沟通,当我客户端与服务端产生连接的时候。那他们就会相当于在空气中连接了一条线,但是这条线是用地址码来代替的,每个WiFi都要它自身的地址端口。
ESP8266的默认地址端口就是下面这个。
public static final String IP="192.168.4.1"; //地址
public static final int PORT=333; //端口
还有知道端口号呢。我们就要知道他们的网络协议。这样才可以通过协议才与这个地址端口连接
,不然没有规定编码协议就好像,敲代码没有规定的语法。谁知道你敲的是什么东西。所以我们只需要在这个文件添加这一行代码那么他们之间沟通的协议就会达成一直。
上面讲完这么多,下面就开始写事件的java代码了。
首先我们要为它们创建一个线程,也就是创建一条空气中的线让他们连在一起
public static final String IP="192.168.4.1"; //地址
public static final int PORT=333; //端口
//连接线程
private class ClientThread implements Runnable {
@Override
public void run() {
try {
//1、连接无人机IP地址,端口号
socket = new Socket(); //通用TCP接口
socket.connect(new InetSocketAddress(IP, PORT),3000);//连接地址和端口
//2、调用输出流发送数据
out = socket.getOutputStream();//获得输出流
out.write("GEC\r\n".getBytes()); //设置要发送的数据
out.flush(); //清空缓存
//3、关闭网络通信
//scoket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
搭建好线之后我们就要把我们需要让它识别的数据发过去。也就是端口号啊,地址号啊。产生事件的数据协议这些。这个data就是我们创建的数据。
//线程
private class SendThread implements Runnable{
@Override
public void run() {
try {
while (true) {
out = socket.getOutputStream();
out.write(data);
out.flush();
Thread.sleep(50);
}//发送通信数组给端口
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
上面写好了,那么我们就开始让页面的组件控制了,组件名称可以之间点击我们的图标就可以在代码那边之间跳到名称id
首先我们要让连接按钮产生事件把这些数据发到ESP8266那边去这样才会产生连接。下面的是这样的线获得button这个组件,然后组件的产生事件就是把上面的线程发送过去。这样就可以连接这个指定的线程了。
private void init()
{
Button bt =findViewById(R.id.button3);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Thread t=new Thread(new ClientThread()); //指定线程
t.start(); //启动
Button bt=findViewById(R.id.button5);
bt.setText("已连接");
bt.setBackgroundColor(Color.parseColor("#00ff00"));
}
});
}
连接了我们就是要使用启动组件把数据发过去。可以看到我们下面就是数组协议,当我们STM32与ESP8266写的识别协议就是下面的数组协议。
private final byte[] data=new byte[4]; //通信数组 用于存储启动数据
private void initData(){
data[0]='X'; //协议固定值
data[1]='C'; //协议固定值
data[2]='0'; //协议固定值
data[3]='0'; //赋值为200的高八位形式
}
//启动
public void btnStart(){
Button bstart=findViewById(R.id.button);
bstart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Thread t = new Thread(new SendThread()); //启动线程
t.start();
}
});
}
那么有了启动组件就要有停止组件也就是退出,不然就不够完整了。退出很简单就是把线给掐掉,把socket流给关掉即可
//退出按键
public void btExti(){
Button btexti =findViewById(R.id.button2);
btexti.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(socket!=null){
try {
socket.close(); //关闭Socket对象
} catch (IOException e) {
e.printStackTrace();
}
}
finish();
}
});
}
整个具体框架就有了支撑,所以剩下的就是操作符的控制,那么就可以用到这个控件功能来识别按下和手拿起这个操作来对数据发送以及接收,这个bt.setOnTouchListener就是触摸功能当按下和手拿起来还有用手移动都会有一个事件产生。所以当你需要操作的时候就可以发送协议好的字符。
//向前
public void touchpro(){
ImageView bt=findViewById(R.id.imageView3);
bt.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int x=motionEvent.getAction();
if(x==MotionEvent.ACTION_DOWN)
{
data[3]='1';
TextView td = findViewById(R.id.textView); //显示油门值
td.setText("正在向前移动");
}
if(x==MotionEvent.ACTION_MOVE)
{
TextView tx=findViewById(R.id.textView);
tx.setText("正在移动");
}
if(x==MotionEvent.ACTION_UP)
{
//flag=false;
data[3]='0'; //赋值为0
TextView td = findViewById(R.id.textView); //显示油门值
td.setText("");
}
return true;
}
});
}
//向后
public void touchform(){
ImageView bt=findViewById(R.id.imageView);
bt.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int x = motionEvent.getAction();
if (x == MotionEvent.ACTION_DOWN) {
data[3]='2'; //赋值为俯仰值的低八位形式
TextView td = findViewById(R.id.textView); //显示油门值
td.setText("正在向后移动");
}
if (x == MotionEvent.ACTION_MOVE) {
TextView tx = findViewById(R.id.textView);
tx.setText("正在移动");
}
if (x == MotionEvent.ACTION_UP) {
data[3]='0'; //赋值为俯仰值的低八位形式
TextView td = findViewById(R.id.textView); //显示油门值
td.setText("");
}
return true;
}
});
}
//向左
public void touchleft(){
ImageView bt=findViewById(R.id.imageView4);
bt.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int x = motionEvent.getAction();
if (x == MotionEvent.ACTION_DOWN) {
data[3]='3'; //赋值为俯仰值的低八位形式
TextView td = findViewById(R.id.textView); //显示油门值
td.setText("正在向左移动");
}
if (x == MotionEvent.ACTION_MOVE) {
TextView tx = findViewById(R.id.textView);
tx.setText("正在移动");
}
if (x == MotionEvent.ACTION_UP) {
data[3]='0'; //赋值为俯仰值的低八位形式
TextView td = findViewById(R.id.textView); //显示油门值
td.setText("");
}
return true;
}
});
}
//向右
public void touchfight(){
ImageView bt=findViewById(R.id.imageView2);
bt.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int x = motionEvent.getAction();
if (x == MotionEvent.ACTION_DOWN) {
data[3]='4'; //赋值为俯仰值的低八位形式
TextView td = findViewById(R.id.textView);
td.setText("正在向右移动");
}
if (x == MotionEvent.ACTION_MOVE) {
TextView tx = findViewById(R.id.textView);
tx.setText("正在移动");
}
if (x == MotionEvent.ACTION_UP) {
data[3]='0'; //赋值为俯仰值的低八位形式
TextView td = findViewById(R.id.textView); //显示油门值
td.setText("");
}
return true;
}
});
}
软件已经搭建好了那么我们就可以利用串口来设置ESP8266功能
AT+CWMODE=2
AT+RST
AT+CWSAP="ESP8266","12345678",1,2
AT+CIPMUX=1
AT+CIPSERVER=1
把上面的命令一个一个复制发到串口识别ok就可以了,但是波特率要一样,默认为115200
然后设置好用手机连接wifi 名称和密码上面已经设置好了是这个AT+CWSAP="ESP8266","12345678",1,2
然后连接之后就可以打开我们的手机软件了,软件生成是点这里生成apk文件就可以之间发送到手机下载了。
然后打开软件就可以安照流程点击连接,启动然后,点击其它组件就可以看到我们刚才设置好的字符发过来了。
连接:
启动:
前进:
后退:
后面的格式都是一样的,这个字符就是刚才我们上面代码事件发送的数据流就是这些字符,然后我们在硬件方面判断接收的字符就可以得到我们想要的动作,例如控制开关灯,开洗衣机,开电视,等等需要电器。
附带一个软件控制无人机的视频
无人机控制
本次的话题就到这里了,虽然讲的比较潦草没有很仔细,等有时间再发一个比较完整的流程,但是能有一个大概的概念也是不错的收获。
CSDN话题挑战赛第1期
示例:脚注的内容,使用[^x]
↩︎