android 串口 android-serialport-api
最近在做Android串口的开发,找到一个开源的串口类android-serialport-api。其主页在这里http://code.google.com/p/android-serialport-api/ ,这里可以下到APK及对源码。
但是下载源码之后发现源码不能直接使用,而且源码结构较为复杂。关于串口的操作不外乎几步:
1.打开串口(及配置串口);
2.读串口;
3.写串口;
4.关闭串口。
android-serialport-api的代码使用了继承等复杂的行为,不容易使初学者很快掌握关于串口的上述4步,所以我特别自己写了一个demo,只有一个activity,其中包含了打开串口,写串口,读串口的操作,对于关闭串口,大家一开就会不明白怎么写了。
http://www.cnblogs.com/CZM-/p/7943572.html
参考此贴,利用NDK编译jni c文件为库并运行
这里是工程结构
首先新建jni包,添加SerialPort.c即可,
/*
* Copyright 2009-2011 Cedric Priscal
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ #include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h> #include "SerialPort.h" #include "android/log.h"
static const char *TAG="serial_port";
//#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
//#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
//#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) static speed_t getBaudrate(jint baudrate)
{
switch(baudrate) {
case : return B0;
case : return B50;
case : return B75;
case : return B110;
case : return B134;
case : return B150;
case : return B200;
case : return B300;
case : return B600;
case : return B1200;
case : return B1800;
case : return B2400;
case : return B4800;
case : return B9600;
case : return B19200;
case : return B38400;
case : return B57600;
case : return B115200;
case : return B230400;
case : return B460800;
case : return B500000;
case : return B576000;
case : return B921600;
case : return B1000000;
case : return B1152000;
case : return B1500000;
case : return B2000000;
case : return B2500000;
case : return B3000000;
case : return B3500000;
case : return B4000000;
default: return -;
}
} /*
* Class: android_serialport_SerialPort
* Method: open
* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open
(JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags)
{
int fd;
speed_t speed;
jobject mFileDescriptor; /* Check arguments */
{
speed = getBaudrate(baudrate);
if (speed == -) {
/* TODO: throw an exception */
// LOGE("Invalid baudrate");
return NULL;
}
} /* Opening device */
{
jboolean iscopy;
const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
// LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
fd = open(path_utf, O_RDWR | flags);
// LOGD("open() fd = %d", fd);
(*env)->ReleaseStringUTFChars(env, path, path_utf);
if (fd == -)
{
/* Throw an exception */
// LOGE("Cannot open port");
/* TODO: throw an exception */
return NULL;
}
} /* Configure device */
{
struct termios cfg;
// LOGD("Configuring serial port");
if (tcgetattr(fd, &cfg))
{
// LOGE("tcgetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
} cfmakeraw(&cfg);
cfsetispeed(&cfg, speed);
cfsetospeed(&cfg, speed); if (tcsetattr(fd, TCSANOW, &cfg))
{
// LOGE("tcsetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
}
} /* Create a corresponding file descriptor */
{
jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
(*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);
} return mFileDescriptor;
} /*
* Class: cedric_serial_SerialPort
* Method: close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close
(JNIEnv *env, jobject thiz)
{
jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); // LOGD("close(fd = %d)", descriptor);
close(descriptor);
}
接下来在工程的local.properties文件中添加NDK路径(上面下载好的那个NDK),类似其中的SDK路径一样,我的添加后如下:
ndk.dir=/home/cam/Android/Sdk/ndk-bundle
sdk.dir=/home/cam/Android/Sdk
接下来在app module目录下的build.gradle中设置库文件名(生成的so文件名)。找到gradle文件的defaultConfig这项,在里面添加如下内容:
defaultConfig { ndk {
moduleName "testhello"
ldLibs "log", "z", "m" //添加依赖库文件,因为有log打印等
}
}
新建android_serialport_api包,(包名字必须一模一样,不然需要根据你的包名重新编译产生头文件,并修改c文件)并在此包下新建SerialPort.java
/*
* Copyright 2009 Cedric Priscal
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package android_serialport_api; import android.util.Log; import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.Iterator;
import java.util.Vector; public class SerialPortFinder { public class Driver {
private String mDriverName;
private String mDeviceRoot;
Vector<File> mDevices = null;
public Driver(String name, String root) {
mDriverName = name;
mDeviceRoot = root;
}
public Vector<File> getDevices() {
if (mDevices == null) {
mDevices = new Vector<File>();
File dev = new File("/dev");
File[] files = dev.listFiles();
if(null == files || files.length ==0){
return mDevices;
}
int i;
for (i=0; i<files.length; i++) {
if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {
Log.d(TAG, "查找的设备: " + files[i]);
mDevices.add(files[i]);
}
}
}
return mDevices;
}
public String getName() {
return mDriverName;
}
} private static final String TAG = "SerialPort"; private Vector<Driver> mDrivers = null; Vector<Driver> getDrivers() throws IOException {
if (mDrivers == null) {
mDrivers = new Vector<Driver>();
LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
String l;
while((l = r.readLine()) != null) {
String drivername = l.substring(0, 0x15).trim();
String[] w = l.split(" +");
if ((w.length >= 5) && (w[w.length-1].equals("serial"))) {
Log.d(TAG, "---串口设备=" + drivername + " on " + w[w.length-4]);
mDrivers.add(new Driver(drivername, w[w.length-4]));
}
}
r.close();
}
return mDrivers;
} public String[] getAllDevices() {
Vector<String> devices = new Vector<String>();
// Parse each driver
Iterator<Driver> itdriv;
try {
itdriv = getDrivers().iterator();
while(itdriv.hasNext()) {
Driver driver = itdriv.next();
Iterator<File> itdev = driver.getDevices().iterator();
while(itdev.hasNext()) {
String device = itdev.next().getName();
String value = String.format("%s (%s)", device, driver.getName());
devices.add(value);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return devices.toArray(new String[devices.size()]);
} public String[] getAllDevicesPath() {
Vector<String> devices = new Vector<String>();
Iterator<Driver> itdriv;
try {
itdriv = getDrivers().iterator();
while(itdriv.hasNext()) {
Driver driver = itdriv.next();
Iterator<File> itdev = driver.getDevices().iterator();
while(itdev.hasNext()) {
String device = itdev.next().getAbsolutePath();
devices.add(device);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return devices.toArray(new String[devices.size()]);
}
}
创建主活动MainActivity.java
package com.otherway.myapplication; import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Toast; import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import android_serialport_api.SerialPort; public class MainActivity extends Activity implements View.OnClickListener {
private static final String TAG = "MainActivity"; protected SerialPort mSerialPort;
protected InputStream mInputStream;
protected OutputStream mOutputStream; private String prot = "/dev/ttySAC2";
private int baudrate = 9600;
private static long i = 0; private Toast mToast; Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == 1) { }
}
};
private Thread receiveThread;
private Thread sendThread; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); initLayout(); mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
} /**
* 初始化Layout。
*/
private void initLayout() {
findViewById(R.id.btn_open).setOnClickListener(MainActivity.this);
findViewById(R.id.btn_send).setOnClickListener(MainActivity.this);
findViewById(R.id.btn_close).setOnClickListener(MainActivity.this);
} @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_open:
showTip("btn_open"); // 打开
try {
mSerialPort = new SerialPort(new File(prot), baudrate, 0);
mInputStream = mSerialPort.getInputStream();
mOutputStream = mSerialPort.getOutputStream();
receiveThread();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
Log.e(TAG, "打开失败");
e.printStackTrace();
} break;
case R.id.btn_send:
showTip("btn_send"); // 发送
sendThread = new Thread() {
@Override
public void run() {
while (true) {
try {
i++;
mOutputStream.write((String.valueOf(i)).getBytes());
Log.i("test", "发送成功:1" + i);
Thread.sleep(1);
} catch (Exception e) {
Log.i("test", "发送失败");
e.printStackTrace();
}
}
}
};
sendThread.start(); break;
case R.id.btn_close:
showTip("btn_close"); closeSerialPort(); break;
default:
break;
}
} private void receiveThread() {
// 接收
receiveThread = new Thread() {
@Override
public void run() {
while (true) {
int size;
try {
byte[] buffer = new byte[1024];
if (mInputStream == null)
return;
size = mInputStream.read(buffer);
if (size > 0) {
String recinfo = new String(buffer, 0,
size);
Log.i("test", "接收到串口信息:" + recinfo);
// sb = recinfo;
// handler.sendEmptyMessage(1);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
receiveThread.start();
} /**
* 关闭串口
*/
public void closeSerialPort() { if (mSerialPort != null) {
mSerialPort.close();
}
if (mInputStream != null) {
try {
mInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (mOutputStream != null) {
try {
mOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
} } private void showTip(final String str) {
mToast.setText(str);
mToast.show();
}
}
主界面布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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: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.otherway.myapplication.MainActivity"> <Button
android:id="@+id/btn_open"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:text="打开" /> <Button
android:id="@+id/btn_send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/btn_open"
android:text="发送" /> <Button
android:id="@+id/btn_close"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/btn_send"
android:text="关闭" /> </RelativeLayout>
改为你需要的串口端口号及波特率;
测试时将串口rx,tx短接,打开串口后,再点击发送程序会一直循环发送,在调试信息上会打印出串口接受数据;
android 串口 android-serialport-api的更多相关文章
- Android 串口设置校验位、速率、停止位等参数
Android 串口通讯设置校验位.速率.停止位等参数 最近业余时间有个android项目需要和硬件进行通信,通讯方式都是通过串口,android串口通讯google有个开源的demo 和很多人一样我 ...
- android 串口开发第二篇:利用jni实现android和串口通信
一:串口通信简介 由于串口开发涉及到jni,所以开发环境需要支持ndk开发,如果未配置ndk配置的朋友,或者对jni不熟悉的朋友,请查看上一篇文章,android 串口开发第一篇:搭建ndk开发环境以 ...
- Android串口开发
参考资料: https://www.jianshu.com/p/9249ed03e745 GitHUb地址: https://github.com/AIlll/AndroidSerialPort An ...
- Android串口操作,简化android-serialport-api的demo(转载)
原帖地址:点击打开 最近在做android串口的开发,找到一个开源的串口类android-serialport-api.其主页在这里http://code.google.com/p/android-s ...
- 最新Android系统版本与API等级对应关系表
最新Android系统版本与API等级对应关系表 从Android官网拷过来的,方便查阅... 官网地址:https://developer.android.com/guide/topics/mani ...
- Android端百度地图API使用详解
百度地图API简介 百度地图移动版API(Android)是一套基于Android设备的应用程序接口,通过该接口,可以轻松的访问百度服务和数据,构建功能丰富.交互性强的地图应用程序. 百度地图移动版A ...
- android 基于百度地图api开发定位以及获取详细地址
一:百度地图开发必须要到百度开发平台android开发api下载相应的库,已经申请百度地图开发key. 二:新建项目baidumaplocation.设计main.xml文件这里注意的是MapView ...
- Android M Developer Preview - API Preview(一)
API Overview The M Developer Preview gives you an advance look at the upcoming release for the Andro ...
- Android 系统版本和API level的关系表
Android 系统版本和API level的关系表 wiki: https://zh.wikipedia.org/wiki/Android%E6%AD%B7%E5%8F%B2%E7%89%88%E6 ...
随机推荐
- 关于数位dp的一些思考
大致看完了claris的数位dp的pdf,感觉题目很厚实啊QAQ. 然后回过头再总结一下(感觉也不算总结啊,就是日常吐槽....) 首先数位dp这个东西是有格式的....所以明天早上再找道题来把模板联 ...
- 用html标签+css写出旋转的正方体
有一段时间没写代码了,刚写有点手生,无从下手,为了能快速进入状态,就写了这一个小东西,纯用标签和样式表写.下面看一下我写的. 这一段是样式表: <style> *{ margin: 0; ...
- docker 安装Filebeat
1.查询镜像 docker search filebeat 2.拉取镜像 我此处选择的是prima/filebeat docker pull prima/filebeat 3.创建配置文件 fileb ...
- Spring 2.5配置文件详解(转)
http://book.51cto.com/art/201004/193743.htm 6.2.3 Spring 2.5配置文件详解 Spring配置文件是用于指导Spring工厂进行Bean生产. ...
- SGU438 The Glorious Karlutka River =)
传送门 sgu原来搬到cf了呀点了好几个链接才找到233 传说中的动态流(?) 反正很暴力就对了QwQ 有容量限制->拆点 对于每个点拆成入点和出点 时间限制->分层 对于每个时刻的每个石 ...
- mysql添加中文数据失败
日志信息: INFO 2015-01-13 10:44:36,078 org.springframework.beans.factory.xml.XmlBeanDefinitionReader: Lo ...
- linux基础(六)
今天我们来看一下Samba服务和nginx服务. Samba服务 1.samba的功能 samba是一个网络服务器,用于Linux和Windows之间共享文件. 2.samba服务的启动.停止.重启 ...
- [CSP-S模拟测试]:世界线(DFS+bitset)
题目描述 时间并不是一条单一的线,而是有许多世界线构成的流. 在一些时刻,世界线会发生分裂:同样的,它们也有可能在一些时刻收束在一起.如果将这些时刻抽象成点,那么这些世界线构成的网络,实际上是一张有向 ...
- Android_开发片段(Part 1)
1.maven环境配置时也跟java类似,进行我的电脑环境的设置,cmd查询:mvn -version 2.在新建AVD时,要注意AVD的版本(API),版本太低或者太高,经常不能运行项目或者在运行项 ...
- Weblogic console控制台密码更改后导致重启服务失败
weblogic版本10.3.3.0 更改控制台密码后,服务重启失败,报错如下: ----------------------------------------------------------- ...