android之WIFI小车编程详述
有了前几篇wifi模块eps8266的使用,单片机设置eps8266程序,android TCP客户端,现在就做一个wifi小车
先上图
小车是四个轮子的,每个轮子上都有电机驱动,前进后退的时候四个轮子同时前进和后退,转弯的时候,小车两边的轮子按反方向转。
为了达到更好的操作效果(一直按下前进,小车前进,按下左右转小车左右转,松开左右转,小车继续前进。松开前进,小车停止。后退同理),在单片机程序里加入了前进或后退的标志位。先说明一下,,,,,,
按下前进向单片机发送‘0’,按下后退向单片机发送‘1’,按下左转向单片机发送‘2’,按下右转向单片机发送‘3’,松开前进或后退向单片机发送‘5’,松开左转或右转向单片机发送‘6’,这样子发数据也是为了获得更好的操作体验
前进 后退 左转 右转按钮是使用的setOnTouchListener方法,以便在按钮按下或松开时发送数据,
就看一下前进代码
我在前面声明了一下
//前进,关于OnTouchListener的使用,,找度娘,我也是找的度娘,不要偷懒呦
//前进 private OnTouchListener forwordButtonTouch = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub switch (event.getAction()) { case MotionEvent.ACTION_DOWN://如果按下 try { //获取输出流 outputStream = socket.getOutputStream(); //发送数据 //outputStream.write(msgEditText.getText().toString().getBytes()); outputStream.write("0".getBytes());//发送0 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } break; case MotionEvent.ACTION_UP://如果松开 try { //获取输出流 outputStream = socket.getOutputStream(); //发送数据 //outputStream.write(msgEditText.getText().toString().getBytes()); outputStream.write("5".getBytes());//发送‘5’ } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } default: break; } return false; } };
//源码 package com.wifi_Contrl; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; @SuppressLint("ClickableViewAccessibility") public class MainActivity extends Activity { boolean isConnect=true;//连接还是断开 Button connectButton;//定义连接按钮 Button forwordButton;//定义前进按钮 Button backButton;//定义后退按钮 Button leftButton;//定义左转按钮 Button righButton;//定义右转按钮 EditText ipEditText;//定义ip输入框 EditText portText;//定义端口输入框 Socket socket = null;//定义socket private InputStream inputStream=null;//定义输入流 private OutputStream outputStream=null;//定义输出流 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); connectButton = (Button) findViewById(R.id.btConnect); forwordButton = (Button) findViewById(R.id.btqianjin); backButton = (Button) findViewById(R.id.bthoutui); leftButton = (Button) findViewById(R.id.btzuozhuan); righButton = (Button) findViewById(R.id.btyuozhuan); ipEditText = (EditText) findViewById(R.id.etIP); portText = (EditText) findViewById(R.id.etPort); connectButton.setOnClickListener(connectButtonListener); forwordButton.setOnTouchListener(forwordButtonTouch); backButton.setOnTouchListener(backButtonTouch); leftButton.setOnTouchListener(leftButtonTouch); righButton.setOnTouchListener(righButtonTouch); } //连接 private OnClickListener connectButtonListener = new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if (isConnect == true) //标志位 = true表示连接 { isConnect = false;//置为false connectButton.setText("断开");//按钮上显示--断开 //打开连接线程 Connect_Thread connect_Thread = new Connect_Thread(); connect_Thread.start(); } else //标志位 = false表示退出连接 { isConnect = true;//置为true connectButton.setText("连接");//按钮上显示连接 Toast.makeText(MainActivity.this,"已退出连接!", Toast.LENGTH_SHORT).show(); try { socket.close();//关闭连接 socket=null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; //前进 private OnTouchListener forwordButtonTouch = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub switch (event.getAction()) { case MotionEvent.ACTION_DOWN: try { //获取输出流 outputStream = socket.getOutputStream(); //发送数据 //outputStream.write(msgEditText.getText().toString().getBytes()); outputStream.write("0".getBytes()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } break; case MotionEvent.ACTION_UP: try { //获取输出流 outputStream = socket.getOutputStream(); //发送数据 //outputStream.write(msgEditText.getText().toString().getBytes()); outputStream.write("5".getBytes()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } default: break; } return false; } }; //后退 private OnTouchListener backButtonTouch = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub switch (event.getAction()) { case MotionEvent.ACTION_DOWN: try { //获取输出流 outputStream = socket.getOutputStream(); //发送数据 //outputStream.write(msgEditText.getText().toString().getBytes()); outputStream.write("1".getBytes()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } break; case MotionEvent.ACTION_UP: try { //获取输出流 outputStream = socket.getOutputStream(); //发送数据 //outputStream.write(msgEditText.getText().toString().getBytes()); outputStream.write("5".getBytes()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } default: break; } return false; } }; //左转 private OnTouchListener leftButtonTouch = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub switch (event.getAction()) { case MotionEvent.ACTION_DOWN: try { //获取输出流 outputStream = socket.getOutputStream(); //发送数据 //outputStream.write(msgEditText.getText().toString().getBytes()); outputStream.write("2".getBytes()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } break; case MotionEvent.ACTION_UP: try { //获取输出流 outputStream = socket.getOutputStream(); //发送数据 //outputStream.write(msgEditText.getText().toString().getBytes()); outputStream.write("6".getBytes()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } default: break; } return false; } }; //右转 private OnTouchListener righButtonTouch = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub switch (event.getAction()) { case MotionEvent.ACTION_DOWN: try { //获取输出流 outputStream = socket.getOutputStream(); //发送数据 //outputStream.write(msgEditText.getText().toString().getBytes()); outputStream.write("3".getBytes()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } break; case MotionEvent.ACTION_UP: try { //获取输出流 outputStream = socket.getOutputStream(); //发送数据 //outputStream.write(msgEditText.getText().toString().getBytes()); outputStream.write("6".getBytes()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } default: break; } return false; } }; //连接线程 class Connect_Thread extends Thread//继承Thread { public void run()//重写run方法 { try { if (socket == null) { //用InetAddress方法获取ip地址 InetAddress ipAddress = InetAddress.getByName(ipEditText.getText().toString()); int port =Integer.valueOf(portText.getText().toString());//获取端口号 socket = new Socket(ipAddress, port);//创建连接地址和端口 if (socket !=null) { runOnUiThread(new Runnable() { public void run() { // TODO Auto-generated method stub Toast.makeText(MainActivity.this,"已成功连接!", Toast.LENGTH_SHORT).show(); } }); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
//布局源码,大神勿喷,小弟才入门android,所以关于布局还,,,,, <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_purple" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.wifi_Contrl.MainActivity" > <!-- IP地址 : --> <TextView android:id="@+id/tvIP" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="IP地址 :" android:textSize="23dp" android:layout_x="0dp" android:layout_y="0dp" /> <!-- 左转 --> <Button android:id="@+id/btzuozhuan" android:layout_width="wrap_content" android:layout_height="80dp" android:layout_x="400dp" android:layout_y="118dp" android:text="左转" /> <!-- 右转 --> <Button android:id="@+id/btyuozhuan" android:layout_width="wrap_content" android:layout_height="80dp" android:layout_x="520dp" android:layout_y="118dp" android:text="右转" /> <!-- 后退 --> <Button android:id="@+id/bthoutui" android:layout_width="wrap_content" android:layout_height="90dp" android:layout_x="105dp" android:layout_y="200dp" android:text="后退" /> <!-- 前进 --> <Button android:id="@+id/btqianjin" android:layout_width="wrap_content" android:layout_height="90dp" android:layout_marginBottom="21dp" android:layout_x="105dp" android:layout_y="65dp" android:text="前进" /> <!-- 连接 --> <Button android:id="@+id/btConnect" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_marginBottom="21dp" android:layout_x="500dp" android:text="连接" /> <!-- 端口号 : --> <TextView android:id="@+id/tvPort" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_x="280dp" android:layout_y="0dp" android:text="端口号 :" android:textSize="23dp" /> <!-- 输入端口地址的文本控件 --> <EditText android:id="@+id/etPort" android:layout_width="70dp" android:layout_height="30dp" android:layout_x="380dp" android:layout_y="0dp" android:background="@android:color/white" android:ems="10" android:text="8080" /> <!-- 输入ip地址的文本控件 --> <EditText android:id="@+id/etIP" android:layout_width="150dp" android:layout_height="30dp" android:layout_x="100dp" android:layout_y="0dp" android:background="@android:color/white" android:ems="10" android:text="192.168.4.1" > <requestFocus /> </EditText> </AbsoluteLayout>
再看单片机,因为学实时操作系统UCOSII的时候,写程序就养成了这样写程序习惯,如果对于这样
#ifndef _USART_C_//如果没有定义_USART_C_
#define _USART_ex_ extern
#else
#define _USART_ex_
#endif
_USART_ex_ unsigned char Usart_Receive[20];
_USART_ex_ unsigned char Usart_Cnt;
_USART_ex_ bit Usart_AT_flage;
_USART_ex_ bit Command_Flag;
_USART_ex_ unsigned char UsartData;
_USART_ex_ void InitUART(void);//串口初始化
_USART_ex_ void SendOneByte(unsigned char c);//发送字节型数据
_USART_ex_ void UartSends(unsigned char *str);//串行口连续发送char型数组,遇到终止号/0将停止
其实这样写,有助于各个c文件之间调用变量。说一下
#ifndef _USART_C_//如果没有定义_USART_C_
#define _USART_ex_ extern//就定义_USART_ex_ 为extern
#else//否则
#define _USART_ex_就定义_USART_ex_为空
#endif
如果是自身文件编译由于我在USART.C文件的开头加上了#define _USART_C_所以,就定义_USART_C_为空
即 unsigned char Usart_Receive[20];
如果别的文件编译那么因为别的文件没有定义#define _USART_C_ 所以就定义_USART_ex_ 为extern
即extern unsigned char Usart_Receive[20];
对于extern 这应该不陌生吧,好了接着往下看,
不好意思再啰嗦下,我把所有的.h文件全放在了一个.h文件中,这样在每个c文件的开头只需加上#include "include.h"就方便多了
#define _MAIN_C_ #include "include.h" sbit a1 = P1^0;//前左轮前进 sbit a2 = P1^1;//前左轮后退 sbit a3 = P1^2;//前右轮前进 sbit a4 = P1^3;//前右轮后进 sbit a5 = P1^4;//后左轮前进 sbit a6 = P1^5;//后左轮后退 sbit a7 = P1^6;//后右轮前进 sbit a8 = P1^7;//后右轮后进 bit forword_flag=0; bit back_flag=0; unsigned char CWMODE[]="AT+CWMODE=2\r\n"; //设置模块的工作的模式为AP模式 unsigned char RST[]="AT+RST\r\n"; //重启模块使AT+CWMODE=2模式生效 unsigned char CIPMUX[]="AT+CIPMUX=1\r\n"; //启动多连接 unsigned char CIPSERVER[]="AT+CIPSERVER=1,8080\r\n";//开启服务器模式,端口号8080 void delay1s(void) //误差 -0.00000000024us { unsigned char a,b,c; for(c=95;c>0;c--) for(b=26;b>0;b--) for(a=185;a>0;a--); } //多连接AP模式 void ManyConnect_AP() { P0=0x00; while(1) { UartSends(CWMODE);//返回ok delay1s(); if(Usart_AT_flage ==1) { if(strstr(Usart_Receive, "OK") ) { Usart_AT_flage = 0; P0 = 0x01; break; } } } UartSends(RST);//返回一大溜,不用判断返回 delay1s(); delay1s(); while(1) { UartSends(CIPMUX);//返回ok delay1s(); if(Usart_AT_flage ==1) { if(strstr(Usart_Receive, "OK") ) { Usart_AT_flage = 0; P0 = 0x03; break; } } } while(1) { UartSends(CIPSERVER);//返回ok,多了也返回ok delay1s(); if(Usart_AT_flage ==1) { if(strstr(Usart_Receive, "OK") ) { Usart_AT_flage = 0; P0 = 0x07; break; } } } } void main() { InitUART(); while(1) { ManyConnect_AP();//多连接AP模式 while(1) { //由于消息的开头是+IP 故做此判断 if((Usart_Receive[0]=='+')&&(Usart_Receive[1]=='I')&&(Usart_Receive[2]=='P')) { if((Usart_Receive[3]=='D')&&(Usart_Receive[6]==',')) { if(Usart_Receive[9]=='0')//前进 { forword_flag = 1;//前进标志位置一 back_flag = 0; //后退标志位置零 a1 = 1;//前左轮前进 a2 = 0;//前左轮后退 a3 = 1;//前右轮前进 a4 = 0;//前右轮后进 a5 = 1;//后左轮前进 a6 = 0;//后左轮后退 a7 = 1;//后右轮前进 a8 = 0;//后右轮后进 /*sbit a1 = P1^0;//前左轮前进 sbit a2 = P1^0;//前左轮后退 sbit a3 = P1^1;//前右轮前进 sbit a4 = P1^2;//前右轮后进 sbit a5 = P1^3;//后左轮前进 sbit a6 = P1^0;//后左轮后退 sbit a7 = P1^0;//后右轮前进 sbit a8 = P1^1;//后右轮后进*/ } if(Usart_Receive[9]=='1')//后退 { forword_flag = 0;//前进标志位置一 back_flag = 1; //后退标志位置零 a1 = 0;//前左轮前进 a2 = 1;//前左轮后退 a3 = 0;//前右轮前进 a4 = 1;//前右轮后进 a5 = 0;//后左轮前进 a6 = 1;//后左轮后退 a7 = 0;//后右轮前进 a8 = 1;//后右轮后进 } if(Usart_Receive[9]=='6')//左右转停止 { if(forword_flag == 1 && back_flag == 0)//上一次按下的是前进,没松开 { //前进 a1 = 1;//前左轮前进 a2 = 0;//前左轮后退 a3 = 1;//前右轮前进 a4 = 0;//前右轮后进 a5 = 1;//后左轮前进 a6 = 0;//后左轮后退 a7 = 1;//后右轮前进 a8 = 0;//后右轮后进 } if(forword_flag == 0 && back_flag == 1)//上一次按下的是后退,没松开 { //后退 a1 = 0;//前左轮前进 a2 = 1;//前左轮后退 a3 = 0;//前右轮前进 a4 = 1;//前右轮后进 a5 = 0;//后左轮前进 a6 = 1;//后左轮后退 a7 = 0;//后右轮前进 a8 = 1;//后右轮后进 } if(forword_flag == 0 && back_flag == 0)//上一次松开了前进或后退 { //停止 a1 = 0;//前左轮前进 a2 = 0;//前左轮后退 a3 = 0;//前右轮前进 a4 = 0;//前右轮后进 a5 = 0;//后左轮前进 a6 = 0;//后左轮后退 a7 = 0;//后右轮前进 a8 = 0;//后右轮后进 } } if(Usart_Receive[9]=='2')//左转 { a1 = 0;//前左轮前进 a2 = 1;//前左轮后退 a3 = 1;//前右轮前进 a4 = 0;//前右轮后进 a5 = 0;//后左轮前进 a6 = 1;//后左轮后退 a7 = 1;//后右轮前进 a8 = 0;//后右轮后退 } if(Usart_Receive[9]=='3')//右转 { a1 = 1;//前左轮前进 a2 = 0;//前左轮后退 a3 = 0;//前右轮前进 a4 = 1;//前右轮后进 a5 = 1;//后左轮前进 a6 = 0;//后左轮后退 a7 = 0;//后右轮前进 a8 = 1;//后右轮后退 } if(Usart_Receive[9]=='5')//停止 { forword_flag = 0;//前进标志位置零 back_flag = 0; //后退标志位置零 a1 = 0;//前左轮前进 a2 = 0;//前左轮后退 a3 = 0;//前右轮前进 a4 = 0;//前右轮后进 a5 = 0;//后左轮前进 a6 = 0;//后左轮后退 a7 = 0;//后右轮前进 a8 = 0;//后右轮后进 } } } } } }
#define _USART_C_ #include "include.h" unsigned char Usart_Receive[20]={0}; unsigned char Usart_Cnt=0; bit Usart_AT_flage; bit flage; bit Command_Flag; void InitUART(void) { TMOD = 0x20; SCON = 0x50; TH1 = 0xFD; TL1 = TH1; PCON = 0x00; EA = 1; ES = 1; TR1 = 1; } void SendOneByte(unsigned char c) { SBUF = c; while(!TI); TI = 0; } //串行口连续发送char型数组,遇到终止号/0(空格)将停止 void UartSends(unsigned char *str) { while(*str!='\0') { SBUF=*str; while(!TI);//等待发送完成信号(TI=1)出现 TI=0; str++; } } void UARTInterrupt(void) interrupt 4 { RI=0; Usart_Receive[Usart_Cnt]=SBUF;//接收串口数据 Usart_Cnt++;// //返回数据以回车结尾,有回车,而且数据个数大于2,说明接收到了数据 if(Usart_Receive[Usart_Cnt-2]=='\r' && Usart_Receive[Usart_Cnt-1]=='\n' && Usart_Cnt >= 2) { Usart_Cnt = 0;//接收数据计数清零 Usart_AT_flage = 1;//数据接收成功标志位 } else if(Usart_Cnt > 20)// { Usart_Cnt = 0; } }
#ifndef __USART_H_ #define __USART_H_ #ifndef _USART_C_ #define _USART_ex_ extern #else #define _USART_ex_ #endif _USART_ex_ unsigned char Usart_Receive[20]; _USART_ex_ unsigned char Usart_Cnt; _USART_ex_ bit Usart_AT_flage; _USART_ex_ bit Command_Flag; _USART_ex_ unsigned char UsartData; _USART_ex_ void InitUART(void);//串口初始化 _USART_ex_ void SendOneByte(unsigned char c);//发送字节型数据 _USART_ex_ void UartSends(unsigned char *str);//串行口连续发送char型数组,遇到终止号/0将停止 #endif
#include <REGX52.H> #include "USART.h" #include <string.h>
下载好程序,接好线,等一会用手机连接就好了,连接成功会显示连接成功
eps8266说是3.3v供电因为我手头没有降压模块也没有二极管所以就直接接的5v供电,不过没有烧,正常工作,就是摸上去有点热。其实程序还有点不够可靠,以后再改进