PC-PC-单片机(Arduino)通信实例
请仔细理解相关参数,如端口设置、IP设置、COM口设置......等等.....不要盲目COPY.....这涉及2台电脑和一个单片机,其中一台电脑作为服务器并与单片机相连,负责通过网络与客户端通信(socket)和通过数据线与单片机通过COM口通信(我实验时用的是COM9,其他电脑可能不同需要调整:具体在设备管理器中查看)。
1、Arduino板待烧入代码:(这里硬件的代码没啥好说的,只要你会写个简单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并在具体实现中采取措施实现的数据的同步。
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是一个进程,它不断的从指定的串口读取 //数据并将其存放到缓冲区中
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的构造方法以及初始化串口 //从串口读取数据,往串口写入数据以及关闭串口的函数
分别把这3个文件放在D盘中然后分别编译:如下(一定要注意-d后面有一个空格+一个点+一个空格).
三个java文件编译好之后,你将在D盘看到一个serial文件夹,里面有相应的3个class文件。然后把原来的java文件删除或者移到别的地方(非常重要,不然会在编译服务器和客户端时报错)。然后把服务器代码放到刚才的D盘编译 && 客户端代码放到另一台电脑编译(如下图)
import java.util.Scanner; import java.io.*; import java.net.*; import serial.*; import serial.ReadSerial; public class EchoServer{ private int port = 8000; private ServerSocket serverSocket; public EchoServer()throws IOException{ serverSocket = new ServerSocket(port); System.out.println("服务器启动"); }//构造函数 private PrintWriter getWriter(Socket socket)throws IOException{ OutputStream socketOut=socket.getOutputStream(); return new PrintWriter(socketOut,true); }//write函数 private BufferedReader getReader(Socket socket)throws IOException{ InputStream socketIn=socket.getInputStream(); return new BufferedReader(new InputStreamReader(socketIn)); }//read函数 public void service(){ Scanner scanner=new Scanner(System.in); SerialBean SB = new SerialBean(9); SB.Initialize(); while(true){ Socket socket=null; try{ socket=serverSocket.accept(); System.out.println("New connection accepted"+ socket.getInetAddress()+":"+socket.getPort()); BufferedReader br=getReader(socket); PrintWriter pw=getWriter(socket); String clientMsg=null,portMsg=null; while((clientMsg=br.readLine())!=null){ System.out.println(clientMsg); pw.println("~!:"+clientMsg); if(clientMsg.equals("bye"))break; portMsg = SB.ReadPort(9); System.out.println(portMsg); SB.WritePort(clientMsg); } SB.ClosePort(); }catch(IOException e){ e.printStackTrace(); }finally{ try{ if(socket!=null)socket.close(); }catch(IOException e){ e.printStackTrace(); } } } }//服务函数 public static void main(String args[])throws IOException{ new EchoServer().service(); } }
//网络通信客户端实现 import java.net.*; import java.io.*; import java.util.*; public class EchoClient{ private String host="localhost"; private int port=8000; private Socket socket; public EchoClient()throws IOException{ InetAddress addr=InetAddress.getByName("192.168.16.101");socket =new Socket(addr,port);//采用网络 //socket = new Socket(host,port);//本地通信,就是服务器和客户端在同一个电脑(一台电脑测试时用) }//构造函数 public static void main(String args[])throws IOException{ new EchoClient().talk(); }//main函数 private PrintWriter getWriter(Socket socket)throws IOException{ OutputStream socketOut=socket.getOutputStream(); return new PrintWriter(socketOut,true); }//重写write函数 private BufferedReader getReader(Socket socket)throws IOException{ InputStream socketIn=socket.getInputStream(); return new BufferedReader(new InputStreamReader(socketIn)); }//重写read函数 public void talk()throws IOException{ try{ BufferedReader br=getReader(socket); PrintWriter pw=getWriter(socket); BufferedReader localReader=new BufferedReader( new InputStreamReader(System.in)); String msg=null; while((msg=localReader.readLine())!=null){ pw.println(msg); System.out.println(br.readLine()); if(msg.equals("bye"))break; } }catch(IOException e){ e.printStackTrace(); }finally{ try{ socket.close(); }catch(IOException e){ e.printStackTrace(); } } }//对话函数 }
接着分别启动主机和服务器就可以实现PC通过网络远程控制单片机啦!