安卓-PC-Arduino3方通信实现

2019-04-15 18:54发布

请仔细理解相关参数,如端口设置、IP设置、COM口设置......等等.....不要盲目COPY.....这涉及手机、电脑和一个单片机,其中一台电脑作为服务器并与单片机相连,负责通过网络与客户端通信(socket)和通过数据线与单片机通过COM口通信(我实验时用的是COM9,其他电脑可能不同需要调整:具体在设备管理器中查看)。 1、Arduino端搭建实现:(这里默认大家都会该系列单片机的代码烧写) ////////////////////////////////////////////////////////// //Arduino 1.0.x-----Arduino Uno----COM9 //使用3-10号引脚连接8个LED ////////////////////////////////////////////////////////// int incomingByte = 0; //输入的数据存储变量 int count=1; void setup() { Serial.begin(9600);// opens serial port, sets data rate to 9600 bps for(int i=3;i<=10;i++)//打开3-10号引脚 pinMode(i,OUTPUT); } void loop() { while(count){ Serial.println("please input 0 1 2 3 4 5 6 7 8 9 a"); count=0; }//第一次操作说明,count为了第一次限制 if (Serial.available() > 0){ incomingByte = Serial.read();//读取 Serial.println(incomingByte, DEC);//写入 }//从COM口读取数据 switch (incomingByte)//数据处理并对引脚进行调控 { case 48://输入0时将3-10号引脚设为高电位,使所有的灯灭 for(int i=3;i<=10;i++){ digitalWrite(i,HIGH); }break; case 49://输入1从3-10号引脚电位依次设低电位维持0.5s,然后设为高电位,实现流水灯效果 for(int i=3;i<=10;i++){ digitalWrite(i,LOW); delay(500); digitalWrite(i,HIGH); }break; case 50://输入2流水灯,和输入1时方向相反 for(int i=10;i>=3;i--){ digitalWrite(i,LOW); delay(500); digitalWrite(i,HIGH); }break; case 51: digitalWrite(3,LOW);break;//输入3,将3号电位调低,只让3号引脚的灯亮 case 52: digitalWrite(4,LOW);break; //..... case 53: digitalWrite(5,LOW);break; //..... case 54: digitalWrite(6,LOW);break; //..... case 55: digitalWrite(7,LOW);break; //..... case 56: digitalWrite(8,LOW);break; //..... case 57: digitalWrite(9,LOW);break; //..... case 97: digitalWrite(10,LOW);break;//..... default: for(int i=3;i<=10;i++){ digitalWrite(i,HIGH); }break;//将所电位调高关闭所有灯 } } 硬件烧入代码 2、服务器代码: package serial; public class SerialBuffer{ private String Content = ""; private String CurrentMsg, TempContent; private boolean available = false; private int LengthNeeded = 1; public synchronized String GetMsg(int Length){ LengthNeeded = Length; notifyAll(); if (LengthNeeded > Content.length()){ available = false; while (available == false){ try{ wait(); } catch (InterruptedException e) {} } } CurrentMsg = Content.substring(0, LengthNeeded); TempContent = Content.substring(LengthNeeded); Content = TempContent; LengthNeeded = 1; notifyAll(); return CurrentMsg; }//本函数从串口(缓冲区)中读取指定长度的一个字符串。 //参数Length指定所返回字符串的长度。 public synchronized void PutChar(int c){ Character d = new Character((char) c); Content = Content.concat(d.toString()); if (LengthNeeded < Content.length()){ available = true; } notifyAll(); } } //SerialBuffer.java (用来保存从串口所接收数据的缓冲区) //在往缓冲区写入数据或者是从缓冲区读取数据的时候,必须保证数据的同步, //因此GetMsg和PutChar函数均被声明为synchronized并在具体实现中采取措施实现的数据的同步。 ASerialBuffer A package serial; import java.io.*; public class ReadSerial extends Thread { private SerialBuffer ComBuffer; private InputStream ComPort; public ReadSerial(SerialBuffer SB, InputStream Port){ ComBuffer = SB; ComPort = Port; }//本函数构造一个ReadSerial进程, //参数SB指定存放传入数据的缓冲区, //参数Port指定从串口所接收的数据流 public void run(){ int c; try{ while (true){ c = ComPort.read(); ComBuffer.PutChar(c); } } catch (IOException e) {} } } //ReadSerial.java (从串口读取数据的程序) //ReadSerial是一个进程,它不断的从指定的串口读取 //数据并将其存放到缓冲区中 BReadSerial B package serial; import java.io.*; import java.util.*; import gnu.io.*; public class SerialBean { static String PortName; CommPortIdentifier portId; SerialPort serialPort; static OutputStream out; static InputStream in; SerialBuffer SB; ReadSerial RT; public SerialBean(int PortID){ PortName = "COM" + PortID; }// 本函数构造一个指向特定串口的SerialBean //该串口由参数PortID所指定。PortID = 1 表示COM1 public int Initialize(){ int InitSuccess = 1; int InitFail = -1; try{ portId = CommPortIdentifier.getPortIdentifier(PortName); try{ serialPort = (SerialPort)portId.open("Serial_Communication", 2000); } catch (PortInUseException e){ return InitFail; }//打开一个串口 try{ in = serialPort.getInputStream(); out = serialPort.getOutputStream(); } catch (IOException e){ return InitFail; }//读写流实例化 try{ serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e){ return InitFail; }//设置串行端口通讯参数 } catch (NoSuchPortException e){ return InitFail; } SB = new SerialBuffer(); RT = new ReadSerial(SB, in); RT.start(); // return success information return InitSuccess; }//本函数初始化所指定的串口并返回初始化结果。如果初始化成功返回1,否则返回-1。 //初始化的结果是该串口被SerialBean独占性使用,其参数被设置为9600, N, 8, 1。 //如果串口被成功初始化,则打开一个进程读取从串口传入的数据并将其保存在缓冲区中。 public String ReadPort(int Length){ String Msg; Msg = SB.GetMsg(Length); if(Msg==null)Msg="ssdfsdf"; return Msg; }//本函数从串口(缓冲区)中读取指定长度的一个字符串。参数Length指定所返回字符串的长度 public void WritePort(String Msg){ int c; try{ for (int i = 0; i < Msg.length(); i++) out.write(Msg.charAt(i)); } catch (IOException e) {} }//本函数向串口发送一个字符串。参数Msg是需要发送的字符串 public void ClosePort(){ RT.stop(); serialPort.close(); }//本函数停止串口检测进程并关闭串口 } //SerialBean是本类库与其他应用程序的接口。 //该类库中定义了SerialBean的构造方法以及初始化串口 //从串口读取数据,往串口写入数据以及关闭串口的函数 C SerialBean C 分别把这3个文件放在D盘中然后分别编译:如下(一定要注意-d后面有一个空格+一个点+一个空格). 三个java文件编译好之后,你将在D盘看到一个serial文件夹,里面有相应的3个class文件。然后把原来的java文件删除或者移到别的地方(非常重要,不然会在编译服务器和客户端时报错)。然后把服务器代码放到D:盘编译如下: import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import serial.*; import serial.ReadSerial; public class MyServer implements Runnable{ public int num=0; //服务器连接 public static ServerSocket serverSocket; //连接 public static Socket socket; //端口 public static final int PORT = 8888; public void run() { SerialBean SB = new SerialBean(9);//硬件通信部分,构造一个COM9通信口 SB.Initialize();//初始化该通信端 DataInputStream dis = null; DataOutputStream dos = null; try { serverSocket = new ServerSocket(PORT); System.out.println("正在等待客户端连接..."); //这里处于等待状态,如果没有客户端连接,程序不会向下执行 while(true){ socket = serverSocket.accept(); dis = new DataInputStream(socket.getInputStream()); dos = new DataOutputStream(socket.getOutputStream()); if((num++)==0){ System.out.println("----客户端已成功连接!----"); //得到客户端的IP System.out.println("客户端的IP =" + socket.getInetAddress()); //得到客户端的端口号 System.out.println("客户端的端口号 =" + socket.getPort()); //得到本地端口号 System.out.println("本地服务器端口号=" + socket.getLocalPort()); }else{ //读取数据 String clientStr = dis.readUTF(); if(clientStr.equals("close"))break; //写出数据 dos.writeUTF(clientStr); System.out.println("客户端:" + clientStr); SB.WritePort(clientStr);//将从客户端独到的信息读到COM端口中 } } SB.ClosePort();//关闭通信端口 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally {//我们把流的关闭写在finally里,即使读写出现问题,我们也能正常的关闭流! try { if (dis != null) dis.close(); if (dos != null) dos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args){ Thread desktopServerThread = new Thread(new MyServer()); desktopServerThread.start(); } } 服务器代码   (我这里采用port = 8888 ,COM是COM9   你在实验时,要注意COM是否要修改,这取决于你的电脑(属性-资源管理器-端口) 3、客户端(安卓APP)代码: package="com.himi" android:versionCode="1" android:versionName="1.0"> 1、AndroidManifest.xml(主xml文件) 这里输入文字发给服务器 SocketConnect 发送 这里显示服务器发来的信息! 2、res/values/strings.xml(资源文件) android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/BTN" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:text="链接" /> <EditText android:id="@+id/ET1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/ET2" android:layout_alignParentTop="true" android:layout_marginTop="20dp" android:ems="10" android:hint="IP" /> <EditText android:id="@+id/ET2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/ET1" android:layout_centerHorizontal="true" android:layout_marginTop="25dp" android:ems="10" android:hint="PORT" /> 3、res/layout/mains.xml(界面文件1) android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_height="wrap_content" android:text="@string/hello" /> android:layout_height="wrap_content" />