热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

安卓-PC-Arduino3方通信实现

请仔细理解相关参数,如端口设置、IP设置、COM口设置等等..不要盲目COPY..这涉及手机、电脑和一个单片机,其中一台电脑作为服务器并与单片机相连,负责通过网络与客户端通信(

请仔细理解相关参数,如端口设置、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并在具体实现中采取措施实现的数据的同步。

A\SerialBuffer
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是一个进程,它不断的从指定的串口读取
//数据并将其存放到缓冲区中

B\ReadSerial
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 )
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_
android:layout_height
="fill_parent">

android:layout_height="wrap_content" android:text="@string/hello" />

android:layout_height="wrap_content" />
4、res/layout/main.xml(界面文件2)
package com.himi;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {
private Button btn_ok, btn;
private EditText edit, et1, et2;
private TextView tv;
// Socket用于连接服务器获取输入输出流
private Socket socket;
// 服务器server/IP地址
private String ADDRESS = "10.203.8.167";
// 服务器端口
private int PORT = 8888;

DataInputStream dis
= null;
DataOutputStream dos
= null;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.mains);
// 加载登陆窗口

et1
= (EditText) findViewById(R.id.ET1);// 登陆窗口元素
et2 = (EditText) findViewById(R.id.ET2);
btn
= (Button) findViewById(R.id.BTN);
btn.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v1) {
Log.e(
"Himi", "btn-begin");
if(true){
// TODO Auto-generated method stub

if(et1.getText().toString()!=null)ADDRESS = et1.getText().toString();
if(et2.getText().toString()!=null)PORT = Integer.parseInt(et2.getText().toString());
Log.e(
"Himi", "string right");
try {
// 阻塞函数,正常连接后才会向下继续执行
socket = new Socket(ADDRESS, PORT);
setContentView(R.layout.main);
// 加载控制窗口
socket.close();
tv
= (TextView) findViewById(R.id.tv);// 对话窗口元素
edit = (EditText) findViewById(R.id.edit);
btn_ok
= (Button) findViewById(R.id.Btn_commit);
btn_ok.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View arg0) {
Log.e(
"Himi", "btn-ok-begin");
try {
// 阻塞函数,正常连接后才会向下继续执行
Socket socket1 = new Socket(ADDRESS, PORT);
dis
= new DataInputStream(socket1
.getInputStream());
dos
= new DataOutputStream(socket1
.getOutputStream());
Log.e(
"Himi", "bdsffdsfsdfsin");
// 向服务器写数据
dos.writeUTF(edit.getText().toString());
String temp
= "I say:";
temp
+= edit.getText().toString();
temp
+= "\n";
temp
+= "Server say:";
// 读取服务器发来的数据
temp += dis.readUTF();
tv.setText(temp);
}
catch (IOException e) {
Log.e(
"Himi", "Stream error!");
e.printStackTrace();
}
finally {
try {
if (dis != null)
dis.close();
if (dos != null)
dos.close();
if(socket!=null)
socket.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.e(
"Himi", "btn-ok-end");
}
});
}
catch (IOException e) {
Log.e(
"Himi", "Stream error!");
//e.printStackTrace();
}
}
//if(v1==)end
}//onclieck()end
});
}
}
5、Activity文件,客户端端主程序
最后:生成apk文件导入到手机,运行服务器,手机把正确的端口号和IP(服务器IP)输入,点击连接就可以实现连接,界面跳转到对话区,在对话区输入0-9或a就能看到单片机上的灯被有规律的控制啦。
 
 

 


推荐阅读
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • 微信官方授权及获取OpenId的方法,服务器通过SpringBoot实现
    主要步骤:前端获取到code(wx.login),传入服务器服务器通过参数AppID和AppSecret访问官方接口,获取到OpenId ... [详细]
author-avatar
高山流水2602934240
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有