串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488定义并行通行状态时,规定设备线总长不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。典型地,串口用于ASCII码字符的传输。通信使用3根线完成,分别是地线、发送、接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。

波特率

这是一个衡量符号传输速率的参数。指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。一般调制速率大于波特率,比如曼彻斯特编码)。通常电话线的波特率为14400,28800和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。 [1]

数据位

这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。

停止位

用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

奇偶校验位

在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位为1,这样就有3个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。

RS-485和RS-232区别:

传输方式不同、传输距离不同、RS-232 只允许一对一通信。

1、传输方式不同。 RS-232采取不平衡传输方式,即所谓单端通讯. 而RS485则采用平衡传输,即差分传输方式。

2、传输距离不同。RS-232适合本地设备之间的通信,传输距离一般不超过20m。而RS-485的传输距离为几十米到上千米。

3、RS-232 只允许一对一通信,而RS-485 接口在总线上是允许连接多达128个收发器。

这些区别其实不是特别重要,因为一般移动开发一般遇到软件APP对接外部硬件设备,需要用的外部第三方设备的通讯协议,USB,232或而485协议进行交互通讯。

关于RS-485项目

首先我遇到的是安卓主板和外接的现金纸币机的交互,是这样一个需求:软件通过后台发来的socket指令,要求用户使用现金纸币支付订单(火车站,地铁,投入现金买票等场景),通过现金纸币机的验钞,计算现金额度,传输给软件进行找零计算,通过接口反馈到云端后台进行确认,开启其他权限操作。因为没有485串口线,所以采购量一根usb转串口,线里需要额外的芯片

usb转串口,通讯485模式

com.github.mik3y:usb-serial-for-android:3.3.0(具体可以详细查看)

首先是获取设备的属性权限

broadcastReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if (intent.getAction().equals(INTENT_ACTION_GRANT_USB)) {usbPermission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)? UsbPermission.Granted : UsbPermission.Denied;connect();}}
};
mainLooper = new Handler(Looper.getMainLooper());
private void connect() {//连接UsbDevice device = null;UsbManager usbManager = (UsbManager) getActivity().getSystemService(Context.USB_SERVICE);for (UsbDevice v : usbManager.getDeviceList().values())if (item != null) {if (v.getDeviceId() == item.getDevice().getDeviceId()) {device = v;}}if (device == null) {status("连接失败:未找到设备");return;}UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(device);if (driver == null) {driver = CustomProber.getCustomProber().probeDevice(device);}if (driver == null) {status("连接失败:设备没有驱动程序");return;}if (driver.getPorts().size() < item.getPort()) {status("连接失败:设备上没有足够的端口");return;}usbSerialPort = driver.getPorts().get(item.getPort());UsbDeviceConnection usbConnection = usbManager.openDevice(driver.getDevice());if (usbConnection == null && usbPermission == UsbPermission.Unknown && !usbManager.hasPermission(driver.getDevice())) {usbPermission = UsbPermission.Requested;PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(getActivity(), 0, new Intent(INTENT_ACTION_GRANT_USB), 0);usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);return;}if (usbConnection == null) {if (!usbManager.hasPermission(driver.getDevice()))status("连接失败:权限被拒绝");elsestatus("连接失败:打开失败");return;}try {usbSerialPort.open(usbConnection);usbSerialPort.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);if (withIoManager) {usbIoManager = new SerialInputOutputManager(usbSerialPort, this);Executors.newSingleThreadExecutor().submit(usbIoManager);}status("连接");connected = true;} catch (Exception e) {status("连接失败: " + e.getMessage());disconnect();}
}
*/
@Override
public void onNewData(byte[] data) {//类似心跳操作+接收字节流接收操作runOnUiThread(() -> {receive(data);});
}
@Override
public void onRunError(Exception e) {//类似关流mainLooper.post(() -> {disconnect();});
}
private void send(String str) {//发送指令,485 以16进制转btye[]发送Log.e("tag", "------------请求指令-----:" + str);if (!connected) {Toast.makeText(getActivity(), "未连接", Toast.LENGTH_SHORT).show();return;}try {byte[] data = hexToByteArray(str);usbSerialPort.write(data, WRITE_WAIT_MILLIS);} catch (Exception e) {onRunError(e);}
}
private void disconnect() {connected = false;//  controlLines.stop();if (usbIoManager != null)usbIoManager.stop();usbIoManager = null;try {if (usbSerialPort != null) {usbSerialPort.close();}} catch (IOException ignored) {}usbSerialPort = null;
}
public static byte[] hexToByteArray(String inHex) {int hexlen = inHex.length();byte[] result;if (hexlen % 2 == 1) {//奇数hexlen++;result = new byte[(hexlen / 2)];inHex = "0" + inHex;} else {//偶数result = new byte[(hexlen / 2)];}int j = 0;for (int i = 0; i < hexlen; i += 2) {result[j] = hexToByte(inHex.substring(i, i + 2));j++;}return result;
}
private void send(String str) {Log.e("tag", "------------请求指令-----:" + str);if (!connected) {Toast.makeText(getActivity(), "未连接", Toast.LENGTH_SHORT).show();return;}try {byte[] data = hexToByteArray(str);usbSerialPort.write(data, WRITE_WAIT_MILLIS);} catch (Exception e) {onRunError(e);}
}

另一个项目需要使用ETC天线进行扣费处理,232协议,一大堆国标接口协议。。。

提供一个Serial.cpp文件

#include <jni.h>
#include <termios.h>#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.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 0:return B0;case 50:return B50;case 75:return B75;case 110:return B110;case 134:return B134;case 150:return B150;case 200:return B200;case 300:return B300;case 600:return B600;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;case 1500000:return B1500000;case 2000000:return B2000000;case 2500000:return B2500000;case 3000000:return B3000000;case 3500000:return B3500000;case 4000000:return B4000000;default:return -1;}
}extern "C" {JNIEXPORT jobject JNICALL
Java_com_sky_besthardtool_category_serialport_api_SerialPort_open(JNIEnv *env, jclass type,jstring path_, jint baudrate,jint flags) {const char *path = env->GetStringUTFChars(path_, 0);// TODOint fd;speed_t speed;jobject mFileDescriptor;/* Check arguments */{speed = getBaudrate(baudrate);if (speed == -1) {/* TODO: throw an exception */LOGE("Invalid baudrate");return NULL;}}/* Opening device */{jboolean iscopy;const char *path_utf = env->GetStringUTFChars(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(path_, path_utf);if (fd == -1) {/* 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("java/io/FileDescriptor");jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor, "<init>", "()V");jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");mFileDescriptor = env->NewObject(cFileDescriptor, iFileDescriptor);env->SetIntField(mFileDescriptor, descriptorID, (jint) fd);}LOGD("Uart open succeed!!!");env->ReleaseStringUTFChars(path_, path);return mFileDescriptor;}JNIEXPORT void JNICALL
Java_com_sky_besthardtool_category_serialport_api_SerialPort_close(JNIEnv *env, jobject instance) {// TODOjclass SerialPortClass = env->GetObjectClass(instance);jclass FileDescriptorClass = env->FindClass("java/io/FileDescriptor");if (FileDescriptorClass == NULL) {LOGD("java/lang/ClassNotFoundException::java.io.FileDescriptor");}jfieldID mFdID = env->GetFieldID(SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");if (mFdID == NULL) {LOGD("java/lang/NoSuchFieldException::FileDescriptor.readOnly(Z)");}jfieldID descriptorID = env->GetFieldID(FileDescriptorClass, "descriptor", "I");jobject mFd = env->GetObjectField(instance, mFdID);jint descriptor = env->GetIntField(mFd, descriptorID);LOGD("close(fd = %d)", descriptor);close(descriptor);
}
}

CmakeList.txt文件配置

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html# Sets the minimum version of CMake required to build the native library.cmake_minimum_required(VERSION 3.4.1)# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.add_library( # Sets the name of the library.serial_port# Sets the library as a shared library.SHARED# Provides a relative path to your source file(s).src/main/cpp/Serial.cpp )# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.find_library( # Sets the name of the path variable.log-lib# Specifies the name of the NDK library that# you want CMake to locate.log )# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.target_link_libraries( # Specifies the target library.serial_port# Links the target library to the log library# included in the NDK.${log-lib} )
public class TransferManager {private static TransferManager instance;private SerialPort serialPort;private FileInputStream inputStream;public FileOutputStream outputStream;private ReadThread mReadThread;private OnIOTransferListener listener;private TransferManager() {}public static TransferManager getInstance() {if (instance == null) {synchronized (TransferManager.class) {if (instance == null) {instance = new TransferManager();}}}return instance;}public void connect(Context context) {String com = SpUtil.getCom(context);int baudRate = SpUtil.getBaudrate(context);try {serialPort = new SerialPort(com, baudRate);inputStream = (FileInputStream) serialPort.getInputStream();outputStream = (FileOutputStream) serialPort.getOutputStream();mReadThread = new ReadThread();mReadThread.start();} catch (Exception e) {listener.onSerialConnect(false);e.printStackTrace();}}public void disConnect() {if (mReadThread != null) {mReadThread.interrupt();mReadThread = null;}try {if (inputStream != null) {inputStream.close();inputStream = null;}if (outputStream != null) {outputStream.close();outputStream = null;}} catch (IOException e) {e.printStackTrace();}if (serialPort != null) {serialPort.close();}}private class ReadThread extends Thread {public void run() {int nMaxBufLength = 64;byte[] buffer = new byte[nMaxBufLength];while (!isInterrupted()) {try {int byteRead;Thread.sleep(50);if (inputStream != null) {byteRead = inputStream.read(buffer);if (byteRead >= 0) {if (listener != null) {byte[] sendBytes = new byte[byteRead];System.arraycopy(buffer, 0, sendBytes, 0, byteRead);listener.onReceive(sendBytes, byteRead);}}} else {
//                        P("mInputStream==null");break;}} catch (IOException e) {
//                    P("IOException");if (listener != null) {listener.onSerialConnect(false);}break;} catch (InterruptedException e) {
//                    P("InterruptedException");e.printStackTrace();}}//while(!isInterrupted())}}public void setOnIOTransferListener(OnIOTransferListener listener) {this.listener = listener;}}

完整的demo已经上传制github了

Android基于串口通讯笔记(USB,485协议,232协议)相关推荐

  1. Android终端硬件通讯总结(串口通讯、Usb Com、Usb、蓝牙、Wifi)

    前言 如果你开发的App需要与硬件做通讯,获取相应数据进行业务处理,这个库肯定对你有帮助.常见的硬件通讯连接方式有:串口通讯.Usb Com.Usb.蓝牙.Wifi等,实际硬件支持哪种连接方式,要看硬 ...

  2. android设备rs232数据格式,如何通过rs232 android进行串口通讯?(How to do serial communication via rs232 android?)...

    如何通过rs232 android进行串口通讯?(How to do serial communication via rs232 android?) 我有一个Android设备'Micronet A ...

  3. Android蓝牙串口通讯【转】

    本文转载自:http://blog.sina.com.cn/s/blog_631e3f2601012ixi.html Android蓝牙串口通讯 闲着无聊玩起了Android蓝牙模块与单片机蓝牙模块的 ...

  4. STM32串口通讯实现——USB转串口

    一.RS232,TTL简介 RS232是个人计算机的通讯接口之一,一般会有两组RS323接口,分别为COM1和COM2,电平标准为+12V为逻辑负,-12为逻辑正. TTL电平为5V为逻辑正,0为逻辑 ...

  5. android蓝牙串口通讯

    2019独角兽企业重金招聘Python工程师标准>>> 最近做的项目用到了蓝牙串口通讯功能.毕竟是接触到底层的一些东西,让吾等局限于java编程思想的小菜遇到了一些意想不到的问题. ...

  6. 基于html5+的nativejs实现android蓝牙串口通讯

    ##开发工具 基于hbuilder打包的webapp. ##所需知识 了解基本的html,css,js,vue.js 了解原生android的开发 了解android蓝牙的开发 了解hbuilder的 ...

  7. android 连接蓝牙电子秤_Android实现串口通讯—连接有线电子秤

    前言 在之前的有讲过Andrpid中USB通讯的文章,大家感兴趣的话,可以参看以下文章: Android实现USB连接 今天就来讲讲Android利用串口实现有线电子秤的连接. 今天涉及以下内容: 电 ...

  8. 嵌入式linux作为hid设备,基于嵌入式系统的USB(HID)设备

    基于嵌入式系统的USB(HID)设备 目前嵌入式系统在数字化电子产品领域应用越来越广泛.随着其成本的降低,大有取代单片机的趋势. USB设备以其小巧.便携.即插即用.成本低廉等优势在当前的桌面应用中有 ...

  9. STM32_USART 串口通讯详解

    对51单片机有了解的都知道51单片机的串口通讯工作原理,我们单片机使用的电平TTL电平,为了使我们的的单片机与PC进行通信,就需要一个电平转换芯片,把TTL电平转换为USB电平(使用的USB接口,如果 ...

  10. 核电仿真卡项目技术回顾 -- 串口通讯、以太网通讯的对比

    - 串口通讯 - 了解串口通讯 常见的串口通信一般是指异步串行通信.这里就要说一下同步和异步的区别了.算了,还是先讲一下串行通信的概念.那么,与串行通信相对的是什么呢. 与串行通信相对的是并行通信.数 ...

最新文章

  1. how to improve your ielts score on the exam?
  2. 章节六、2-异常---运行时异常
  3. mysql order 关键字_PHP数据库MySQL Order By 关键词 - PHP教程
  4. MapReduce中源码分析(map端的过程)
  5. jq绑定的事件不生效
  6. jsp显示服务器路径下的图片,jsp 从服务器获取图片路径
  7. oracle监听的动态注册和静态注册
  8. ios侧滑返回:完美解决 interactivePopGestureRecognizer 卡住的问题
  9. 韩国被申遗 (转自果壳)
  10. 快速开发框架V0.001(免费、100%开源)
  11. H264 视频文件 帧格式
  12. sigmoid 激励函数
  13. 关于解决“无法定位程序输入点于动态链接库”问题的思路
  14. Android 实现自定义宽高比的ImageView
  15. addon@Node.js之新手上路
  16. 9.10 安卓常用工具类之一 对话 ---- DialogUtil
  17. 30岁以后最大的勇敢,是敢于走出舒适圈还是留在舒适圈?
  18. iNFTnews | iPhone14已来,苹果的元宇宙还有多远?
  19. 使用idea批量反编译class
  20. 入职体检乙肝携带者被新单位拒绝入职怎么办?

热门文章

  1. 三坐标检测之报告查看T值
  2. Spring5--@Indexed注解
  3. 道岔及转辙机结构详解
  4. 使用phpQuery轻松采集网页内容
  5. 贵州大学计算机网络试题,贵州大学计算机基础考试题库.doc
  6. 推荐几款大家常使用的 SSH 客户端工具
  7. null object java_java1.8--Null Object模式
  8. 51单片机之TMOD寄存器
  9. Java拦截器和过滤器的作用和区别
  10. 使用vue开发的网易云音乐播放器