android 串口通信丢失数据原因
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android 串口通信丢失数据原因相关的知识,希望对你有一定的参考价值。
在平板上发出来数据没有问题,当平板接收由
pc上的串口调试助手发送的数据就有问题了。总是丢失数据。还会出现这种现象。这是pc上的串口调试助手窗口显示的问题。我想知道是驱动的问题。还是java源码的问题。要是修改。需要修改哪一部分。
要详细说明。说的太简单了根本就解决不了问题。
解决方案:
mscomm的inputlen设置为0吧(读取整个缓冲区),读完一次,清空一次缓冲区试试;
参考如下:
窗体初始化事件中建议将mscomm的这几个属性做如下设置:
mscomm.inbuffersize=8 '接收缓冲区大小
mscomm.rthreshold=4 '促发oncomm事件的字符数
mscomm.inputlen=0 '默认读取整个缓冲区
mscomm.inputmode=cominputmodetext '以文本方式接收
mscomm.inbuffercount=0 '清空缓冲区
oncomm事件中,建议处理完接收数据后用mscomm.inbuffercount=0清空缓冲区 参考技术A 我现在测试也遇到这个问题,我是根据android_serialport_api里面的代码做的,就是在android端接收串口发过来的数据不完整,几乎每次都只是接收一部分的数据,另外一部分就不知道跑到哪里去,请问你这个问题你解决了吗 参考技术B 这个还真不知道,不过如果你想恢复丢失的那部分数据的话,我倒是有办法,现在有手机数据恢复软件进行恢复,你有需要的话,可以试试赤兔Android数据恢复软件!
Android串口通信
1. 解析SerialPort API 串口通信例子
首先分析一下例子中的类结构 :
通过类结构可知,最主要的还是在SerialPortJNI.java 类 ,该类写了一些Native 方法处理打开与关闭 串口 接收 发送的
SerialPort.Java 代码如下 :
package com.dwin.navy.serialportapi;
import java.io.FileDescriptor;
import android.util.Log;
/**
* 串口JNI
*
* @author dwin
*
*/
public class SerialPortJNI {
static {
Log.i("NativeClass", "before load library");
System.loadLibrary("serialport");
Log.i("NativeClass", "after load library");
}
public FileDescriptor mFd;
public String mDevNum;
public int mSpeed;
public int mDataBits;
public int mStopBits;
public int mParity;
public int RS485ModFp = -1;
public static int RS485Read = 0;
public static int RS485Write = 1;
public native int setSpeed(FileDescriptor fd, int speed);
public native int setParity(FileDescriptor fd, int dataBits, int stopBits,
int parity);
public native FileDescriptor openDev(String devNum);
public native FileDescriptor open485Dev(String devNum);
public native int closeDev(FileDescriptor fd);
public native int close485Dev(FileDescriptor fd);
public native int readBytes(FileDescriptor fd, byte[] buffer, int length);
public native boolean writeBytes(FileDescriptor fd, byte[] buffer,
int length);
public native int set485mod(int mode);
}
红色区域 先申明一个static 静态域 加载.so 动态库文件 .so通过JNI方式生成 保存在libs目录下 ,由于本例子使用的cpu为 mips(默认为arm) 所以 .so库文件 将存入mips文件夹下
还有打开串口,关闭串口,485模式下开关方式 ,接收 与发送 byte
1> SerialPort API 处理了接收与发送 文本与十六进制 两种模式下接收与发送数据
UI布局如下 :
2>在电脑中插入usb转串口工具 ,然后在app中打开串口
SerialPortOpt.java 继承了 SerialPortJNI.Java 类 调用相应的JNI接口
SerialPortOpt.java 类大致如下 :
package com.dwin.navy.serialportapi;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import android.util.Log;
/**
* 调用JNI的串口
*
* @author dwin
*
*/
public class SerailPortOpt extends SerialPortJNI {
private static final String TAG = "SerialPort";
private FileInputStream mFileInputStream;
private FileOutputStream mFileOutputStream;
public FileDescriptor openDev(String devNum) {
super.mFd = super.openDev(devNum);
if (super.mFd == null) {
Log.e(TAG, "native open returns null");
return null;
}
mFileInputStream = new FileInputStream(super.mFd);
mFileOutputStream = new FileOutputStream(super.mFd);
return super.mFd;
}
public FileDescriptor open485Dev(String devNum) {
super.mFd = super.open485Dev(devNum);
if (super.mFd == null) {
Log.e(TAG, "native open returns null");
return null;
}
mFileInputStream = new FileInputStream(super.mFd);
mFileOutputStream = new FileOutputStream(super.mFd);
return super.mFd;
}
public InputStream getInputStream() {
return mFileInputStream;
}
public OutputStream getOutputStream() {
return mFileOutputStream;
}
public int setSpeed(FileDescriptor optFd, int speed) {
return super.setSpeed(optFd, speed);
}
public int setParity(FileDescriptor optFd, int databits, int stopbits,
int parity) {
return super.setParity(optFd, databits, stopbits, parity);
}
public int closeDev(FileDescriptor optFd) {
int retStatus;
retStatus = super.closeDev(optFd);
super.mFd = null;
return retStatus;
}
public int close485Dev(FileDescriptor optFd) {
int retStatus;
retStatus = super.close485Dev(optFd);
super.mFd = null;
return retStatus;
}
public int readBytes(FileDescriptor fd, byte[] buffer, int length) {
return super.readBytes(fd, buffer, length);
}
public boolean writeBytes(FileDescriptor fd, byte[] buffer, int length) {
return super.writeBytes(fd, buffer, length);
}
public int readBytes(FileDescriptor fd, byte[] buffer) {
return super.readBytes(fd, buffer, buffer.length);
}
public boolean writeBytes(FileDescriptor fd, byte[] buffer) {
return super.writeBytes(fd, buffer, buffer.length);
}
public int readBytes(byte[] buffer) {
return super.readBytes(mFd, buffer, buffer.length);
}
public boolean writeBytes(byte[] buffer) {
return super.writeBytes(mFd, buffer, buffer.length);
}
public int read485Bytes(FileDescriptor fd, byte[] buffer, int length) {
return super.readBytes(fd, buffer, length);
}
public boolean write485Bytes(FileDescriptor fd, byte[] buffer, int length) {
boolean ret;
super.set485mod(RS485Write);
ret = super.writeBytes(fd, buffer, length);
super.set485mod(RS485Read);
return ret;
}
public int read485Bytes(FileDescriptor fd, byte[] buffer) {
return super.readBytes(fd, buffer, buffer.length);
}
public boolean write485Bytes(FileDescriptor fd, byte[] buffer) {
boolean ret;
super.set485mod(RS485Write);
ret = super.writeBytes(fd, buffer, buffer.length);
super.set485mod(RS485Read);
return ret;
}
public int read485Bytes(byte[] buffer) {
return super.readBytes(mFd, buffer, buffer.length);
}
public boolean write485Bytes(byte[] buffer) {
boolean ret;
super.set485mod(RS485Write);
ret = super.writeBytes(mFd, buffer, buffer.length);
super.set485mod(RS485Read);
return ret;
}
}
在openDev(String str)方法中调用父类的方法 ,将返回一个文件描述对象FileDescriptor ,然后初始化 FileInputStream,FileOutputStream 输入输出IO流对象 ,
还有读写byte字节数组的方法
3>申明或者实例化一个类用来调用和实现 这些方法 前两个类只是申明 相应的方法并没有实现相应的方法体
定义一个SerialPort 类
SerialPort.Java :
package com.dwin.dwinapi;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import com.dwin.navy.serialportapi.SerailPortOpt;
import android.content.Context;
import android.util.Log;
/**
* 自定义串口对象
*
* @author F
*
*/
public class SerialPort {
Context context;
/**
* 自定义串口对象
*/
private static SerialPort serialPort;
/**
* 调用JNI的串口
*/
private SerailPortOpt serialportopt;
/**
* 读取数据线程
*/
/**
* 串口接收到的流
*/
private InputStream mInputStream;
/**
* 用来判断串口是否已打开
*/
public boolean isOpen = false;
/*
* 接收到的数据
*/
String data;
/**
* 实例化并打开串口对象
*
* @param devNum
* 串口号 S0,S1,S2,S3,S4
* @param dataBits
* 数据位
* @param speed
* 波特率
* @param stopBits
* 停止位
* @param parity
* 校验位
*/
public SerialPort(String devNum, int speed, int dataBits, int stopBits,
int parity) {
serialportopt = new SerailPortOpt();
openSerial(devNum, speed, dataBits, stopBits, parity);
}
/**
* 打开串口时传入参数,可以指定打开某个串口,并设置相应的参数
*
* @param devNum
* 串口号 COM0,COM1,COM2,COM3,COM4
* @param dataBits
* 数据位
* @param speed
* 波特率
* @param stopBits
* 停止位
* @param parity
* 校验位
* @return
*/
private boolean openSerial(String devNum, int speed, int dataBits,
int stopBits, int parity) {
serialportopt.mDevNum = devNum;
serialportopt.mDataBits = dataBits;
serialportopt.mSpeed = speed;
serialportopt.mStopBits = stopBits;
serialportopt.mParity = parity;
// 打开串口
FileDescriptor fd = serialportopt.openDev(serialportopt.mDevNum);
if (fd == null) {
return false;// 串口打开失败
} else {
// 设置串口参数
serialportopt.setSpeed(fd, speed);
serialportopt.setParity(fd, dataBits, stopBits, parity);
mInputStream = serialportopt.getInputStream();
isOpen = true;
return true;
}
}
/**
* 关闭串口
*/
public void closeSerial() {
if (serialportopt.mFd != null) {
serialportopt.closeDev(serialportopt.mFd);
isOpen = false;
}
}
/**
* 发送数据
*
* @param data
* 数据内容
*/
public void sendData(String data, String type) {
try {
serialportopt.writeBytes(type.equals("HEX") ? HexString2Bytes(data
.length() % 2 == 1 ? data += "0" : data.replace(" ", ""))
: HexString2Bytes(toHexString(data)));
} catch (Exception e) {
}
}
/**
* 接收数据
*
* @param 收发数据类型
* @return 接收到的字符串
*/
public String receiveData(String type) {
byte[] buf = new byte[1024];
int size;
if (mInputStream == null) {
return null;
}
size = serialportopt.readBytes(buf);
if (size > 0) {
try {
data = type.equals("HEX") ? bytesToHexString(buf, size)
: new String(buf, 0, size, "gb2312").trim().toString();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return data;
} else {
return null;
}
}
/**
* 转化字符串为十六进制编码
*
* @param s
* @return
*/
private String toHexString(String s) {
String str = "";
for (int i = 0; i < s.length(); i++) {
int ch = (int) s.charAt(i);
String s4 = Integer.toHexString(ch);
str = str + s4;
}
return str;
}
/**
* 将指定字符串src,以每两个字符分割转换为16进制形式 如:"2B44EFD9" --> byte[]{0x2B, 0x44, 0xEF,
* 0xD9}
*
* @param src
* String
* @return byte[]
*/
private static byte[] HexString2Bytes(String src) {
byte[] ret = new byte[src.length() / 2];
byte[] tmp = src.getBytes();
for (int i = 0; i < tmp.length / 2; i++) {
ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
}
return ret;
}
/**
* 将Hex数组转换为Hex字符串
*
* @param src
* @param size
* @return
*/
public static String bytesToHexString(byte[] src, int size) {
String ret = "";
if (src == null || size <= 0) {
return null;
}
for (int i = 0; i < size; i++) {
String hex = Integer.toHexString(src[i] & 0xFF);
if (hex.length() < 2) {
hex = "0" + hex;
}
hex += " ";
ret += hex;
}
return ret.toUpperCase();
}
/**
* 将两个ASCII字符合成一个字节; 如:"EF"--> 0xEF
*
* @param src0
* byte
* @param src1
* byte
* @return byte
*/
private static byte uniteBytes(byte src0, byte src1) {
byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 }))
.byteValue();
_b0 = (byte) (_b0 << 4);
byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 }))
.byteValue();
byte ret = (byte) (_b0 ^ _b1);
return ret;
}
}
剩下的就是MainActivty中 ,打开串口 创建两个线程,ReceiverThread,SendThread 先 ,Handler 异步更新UI
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
Date date = new Date();
eTextShowMsg.append("[" + date.getMinutes() + ":"
+ date.getSeconds() + "] " + (CharSequence) msg.obj);
break;
default:
break;
}
};
};
/**
* 接收数据线程
*/
class ReceiveThread extends Thread {
public void run() {
while (serialPort.isOpen) {
if (isReceive) {
String type = togBtnShowDataType.getText().toString()
.trim();
String data = serialPort.receiveData(type);
if (data != null) {
Message msg = new Message();
msg.what = 1;
msg.obj = data;
System.out.println(data + "<<<<<<<<==========data");
mHandler.sendMessage(msg);
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
当串口接收到数据 每一秒更新一次UI,根据需求可转换为十六进制与字符
本文出自 “Android学习笔记” 博客,请务必保留此出处http://846499695.blog.51cto.com/6937060/1748440
以上是关于android 串口通信丢失数据原因的主要内容,如果未能解决你的问题,请参考以下文章