Android开发笔记——串口通讯
来源:互联网 发布:空心软件测试平台 编辑:程序博客网 时间:2024/05/20 17:07
这是参考谷歌官网的开源项目和网上的串口通讯写的一个简单的demo。刚刚接触NDK编程以及串口通讯,可能很多写的不是很好,不喜勿喷。
大多数的的代码都在这个Google串口开源项目:https://code.google.com/p/android-serialport-api/
先新建一个带有c的项目。
勾选C++然后一路Next新建。
在编写代码前或者安装该项目前先将该项目使用的NDk换为NDK14版本,不然可能会出现串口打不开问题(本人现在不知道为什么,可能是环境配置问题),没有NDK14的先下载(在https://developer.android.google.cn/ndk/downloads/older_releases.html下载),然后在Android视图下,app——OPen Module Settings——SDK Location中重新选择NDK的路径。
将MainActivity中
static { System.loadLibrary("native-lib");}
的删除,在创建SerialPort类中添加
//在应用程序启动时,用于加载serial_port库static { System.loadLibrary("serial_port");//serial_port根据后面的CMakeLists.txt内容写 。}
将创建项目时的Cpp文件删除,再新建一个jni文件夹,然后在该文件夹中新建serial_port的.c文件 调用串口的读写主要就是open和close方法,类似于文件读写。
按照下面代码中的注释修改后,左边的绿红箭头表示java中的open方法和c中的open方法建立了联系。
#include <jni.h>#include <termios.h>#include <unistd.h>#include <fcntl.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 1200: return B1200; case 1800: return B1800; case 2400: return B2400; case 4800: return B4800; case 9600: return B9600; case 19200: return B19200; case 38400: return B38400; case 57600: return B57600; case 115200: return B115200; case 230400: return B230400; case 460800: return B460800; case 500000: return B500000; case 576000: return B576000; case 921600: return B921600; case 1000000: return B1000000; case 1152000: return B1152000; default: return -1; }}/* * Java_com_smartlab_blue_serialdemo_SerialPort_open中的com_smartlab_blue_serialdemo是包名 * SerialPort_open是SerialPort类中的private native static FileDescriptor open(...)方法,需要用"_"连接不能用"." * 有的可能直接在SerialPort类中进行Alt+Enter就可以在这个文件里面创建一个open方法,只需把这个类中我写的方法名换一下就行了, * 有的就需要按照我上面说的方法改方法名字。 下面的close方法配置一样 * */JNIEXPORT jobject JNICALLJava_com_smartlab_blue_serialdemo_SerialPort_open(JNIEnv *env, jclass type, jstring path, jint baudrate, jint flags) { int fd; speed_t speed; //引用#include <termios.h> jobject mFileDescriptor; /* Check arguments */ { speed=getBaudrate(baudrate); if (speed==-1){ LOGE("Invalid baudrate"); return NULL; } } /* 开启 设备 */ { jboolean iscapy; const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscapy); LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); fd=open(path_utf,O_RDWR | flags | O_NDELAY);//O_RDWR 引入 #include <fcntl.h> LOGD("open() fd = %d", fd); (*env)->ReleaseStringUTFChars(env, path, path_utf ); if (fd==-1){ /* 引发异常 */ LOGE("Cannot open port"); /* TODO: throw an exception */ return NULL; } } /* 配置 设备 */ { 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; } } /* 创建一个相应的文件描述符 */ { 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;}JNIEXPORT void JNICALLJava_com_smartlab_blue_serialdemo_SerialPort_close(JNIEnv *env, jobject instance) { jclass SerialPortClass = (*env)->GetObjectClass(env, instance); 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, instance, mFdID); jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); LOGD("close(fd = %d)", descriptor); close(descriptor);}
先将app 的build,gradle中的 以下内容 注释
//externalNativeBuild { // cmake { // path "CMakeLists.txt" // }//}
在创建该项目时生成的的CMakeLists.txt中进行以下修改
add_library( # Sets the name of the library.
serial_port //双引号中写的是这里的名字,在应用程序启动时,用于加载serial_port库
# Provides a relative path to your source file(s). src/main/jni/serial_port.c //你新建的.c文件的路径和名字。
target_link_libraries( # Specifies the target library.
serial_port //双引号中写的是这里的名字
app 的build,gradle中添加一下内容
defaultConfig {
applicationId “com.smartlab.blue.serialdemo”
minSdkVersion 14
targetSdkVersion 26
versionCode 1
versionName “1.0”
testInstrumentationRunner “android.support.test.runner.AndroidJUnitRunner”
//添加
ndk { moduleName "serial_port" ldLibs "log", "z", "m" }
}
切换成Android视图在app上右键,然后选择Link C++ Project with Gradle
第一个选择CMake,路径选择刚刚修改的CMakeLists.txt,然后OK。
注意:有时候可能无法开启Android板上串口读写权限,需要自己去手动的添加权限
在调试中如果大家没有串口硬件的话可以使用PC机+模拟器完成调试实验。具体操作方法:
1、打开cmd进入到android开发的sdk目录下的tools文件夹下;
2、执行命令emulator @(你自己的模拟器的名字) -qemu -serial COM3(COM3是你的PC的一个串口通过命令挂载到你的模拟器上,当然你也可以是COM1跟你电脑对应);例:我的模拟器叫123,我给模拟器挂载的电脑上的串口是COM3,则执行:emulator @123 -qemu -serial COM3
这样你会看到模拟器已经启动,这时候你将程序部署上运行即可。
如果用程序打开串口,提示没有读写权限。应该在命令提示符下用linux命令赋予读写的权限: 进入shell:adb shell 进入设备目录:#cd dev 修改权限:#chmod 777 ttyS2即可。(这个我已经写入程序内,无需在添加,如果LOG日志打印显示无权限,那就只能你手动在执行一边,再解说以下这个进入shell,这个是adb shell,你的命令执行的目录下必须有adb shell.exe多的不解释了)
修改的地方基本上就上面那些,推荐一遍博客http://blog.csdn.net/qq_35071078/article/details/73065046,不知道串口的可以看下 。
下面是主要的代码
public class SerialPort { private static final String TAG = "SerialPort"; private FileDescriptor mFd; private FileInputStream mFileInputStream; private FileOutputStream mFileOutputStream; public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { /* 检查是否又读写的权限 */ if (!device.canRead() || !device.canWrite()) { /* 如果没有读写的权限, 尝试使用chmod来给文件权限 */ Process su = null; try { su = Runtime.getRuntime().exec("/system/xbin/su"); //su = Runtime.getRuntime().exec("su"); String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" + "exit\n"; su.getOutputStream().write(cmd.getBytes()); if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) { Log.e(TAG, "su.waitFor == " + su.waitFor() + " device.canRead = " + device.canRead() + " device.canWrite = " + device.canWrite()); throw new SecurityException(); } } catch (Exception e) { Log.e(TAG, "Exception == " + e.toString()); e.printStackTrace(); throw new SecurityException(); } finally { if (su != null) { su.destroy(); } } } mFd = open(device.getAbsolutePath(), baudrate, flags); if (mFd == null) { Log.e(TAG, "串 口 打 开 失 败 >>>>>>>> native open returns null"); throw new IOException(); } mFileInputStream = new FileInputStream(mFd); mFileOutputStream = new FileOutputStream(mFd); Log.e(TAG, "****************** 串 口 打 开 成 功 !**********************"); } // Getters and setters public InputStream getInputStream() { return mFileInputStream; } public OutputStream getOutputStream() { return mFileOutputStream; } /** * jni方法 打开串口 * * @param path 串口文件的路径 * @param baudrate 波特率 * @param flags 端口 * @return 文件描述符 */ private native static FileDescriptor open(String path, int baudrate, int flags); /** * jni方法 关闭串口 */ public native void close(); //在应用程序启动时,用于加载serial_port库 static { System.loadLibrary("serial_port"); }}public abstract class SerialPortActivity extends Activity { protected Application mApplication; protected SerialPort mSerialPort; protected OutputStream mOutputStream; private InputStream mInputStream; private ReadThread mReadThread; private class ReadThread extends Thread { @Override public void run() { super.run(); while(!isInterrupted()) { int size; try { byte[] buffer = new byte[64]; if (mInputStream == null) return; Log.e("读取数据的线程","233333"); size = mInputStream.read(buffer); if (size > 0) { onDataReceived(buffer, size); } } catch (IOException e) { e.printStackTrace(); return; } } } } private void DisplayError(int resourceId) { AlertDialog.Builder b = new AlertDialog.Builder(this); b.setTitle("Error"); b.setMessage(resourceId); b.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { SerialPortActivity.this.finish(); } }); b.show(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mApplication = (Application) getApplication(); try { mSerialPort = mApplication.getSerialPort(); mOutputStream = mSerialPort.getOutputStream(); mInputStream = mSerialPort.getInputStream(); /* Create a receiving thread */ mReadThread = new ReadThread(); mReadThread.start(); } catch (SecurityException e) { DisplayError(R.string.error_security); } catch (IOException e) { DisplayError(R.string.error_unknown); } catch (InvalidParameterException e) { DisplayError(R.string.error_configuration); } } protected abstract void onDataReceived(final byte[] buffer, final int size); @Override protected void onDestroy() { if (mReadThread != null) mReadThread.interrupt(); mApplication.closeSerialPort(); mSerialPort = null; super.onDestroy(); }}public class SerialPortFinder { private static final String TAG = "SerialPort"; private Vector<Driver> mDrivers = null; private class Driver { private Driver(String name, String root) { mDriverName = name; mDeviceRoot = root; } private String mDriverName; private String mDeviceRoot; Vector<File> mDevices = null; private Vector<File> getDevices() { if (mDevices == null) { mDevices = new Vector<File>(); File dev = new File("/dev"); File[] files = dev.listFiles(); int i; for (i = 0; i < files.length; i++) { if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) { Log.d(TAG, "Found new device: " + files[i]); mDevices.add(files[i]); } } } return mDevices; } public String getName() { return mDriverName; } } private 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) { // Issue 3: // Since driver name may contain spaces, we do not extract // driver name with split() String drivername = l.substring(0, 0x15).trim(); String[] w = l.split(" +"); if ((w.length >= 5) && (w[w.length - 1].equals("serial"))) { Log.d(TAG, "Found new driver " + 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>(); // 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().getAbsolutePath(); devices.add(device); } } } catch (IOException e) { e.printStackTrace(); } return devices.toArray(new String[devices.size()]); }}
源代码:http://download.csdn.net/download/qq_36462112/10161978
- Android开发笔记——串口通讯
- Android串口通讯开发
- 串口通讯—通信协议
- 串口通讯—通信协议
- 串口通讯—通信协议
- 串口通讯—通信协议
- 串口通讯—通信协议
- 串口通讯—通信协议
- 串口通讯—通信协议
- 串口通讯—通信协议
- 串口通讯—通信协议
- 串口通讯—通信协议
- 串口通讯学习笔记
- [转]串口通讯笔记
- 串口通讯笔记
- bundle开发----串口通讯
- LabVIEW串口通讯—通信协议
- Android——串口开发
- shiro(二)
- springboot(十六):使用Jenkins部署Spring Boot
- 面向对象:谁家女朋友走丢了,快来认领!
- 趣图:工作一整天,你就写了 6 行代码?
- 漫画:什么是HashMap?
- Android开发笔记——串口通讯
- codeforces 116A Tram
- shiro(三)
- [操作系统] I/O硬件原理
- setPreferredSize和的setSize和setbounds的用法
- How To Install Java with Apt-Get on Ubuntu 16.04
- bzoj3926 [Zjoi2015]诸神眷顾的幻想乡(广义后缀自动机)
- shiro(四)
- Java中用正则表达式截取字符串