精华内容
下载资源
问答
  • 串口开发

    2017-05-07 21:39:04
    串口编程理论

    最近为了实习,老师找个C#串口开发高级工程师过来授课!(其实是师兄),8年工作经验。


    串口编程。首先来了解什么是串口,串口有什么用?串口的规则是由谁定义好的?带着一连串疑问来了解串口。


    1、串口通讯:
    串口通讯(Serial Communication),是指外设和计算机间,通过数据信号线、地线等,按位进行传输数据的一种通讯方式。
    串口是一种接口标准,它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。

    2 、串口通讯的数据格式
    这里写图片描述
    一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以“起始位”开始,以“停止位”结束,字符之间没有固定的时间间隔要求。
    每一个字符的前面都有一位起始位(低电平),字符本身由7位数据位组成,接着字符后面是一位校验位(检验位可以是奇校验、偶校验或无校验位),最后是一位或一位半或二位停止位,停止位后面是不定长的空闲位,停止位和空闲位都规定为高电平。实际传输时每一位的信号宽度与波特率有关,波特率越高,宽度越小,在进行传输之前,双方一定要使用同一个波特率设置。

    3 通讯方式
    ①单工模式(Simplex Communication)的数据传输是单向的。通信双方中,一方固定为发送端,一方则固定为接收端。信息只能沿一个方向传输,使用一根传输线。
    ②半双工模式(Half Duplex)通信使用同一根传输线,既可以发送数据又可以接收数据,但不能同时进行发送和接收。数据传输允许数据在两个方向上传输,但是,在任何时刻只能由其中的一方发送数据,另一方接收数据。因此半双工模式既可以使用一条数据线,也可以使用两条数据线。半双工通信中每端需有一个收发切换电子开关,通过切换来决定数据向哪个方向传输。因为有切换,所以会产生时间延迟,信息传输效率低些。
    ③全双工模式(Full Duplex)通信允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。在全双工模式中,每一端都有发送器和接收器,有两条传输线,信息传输效率高。
    显然,在其它参数都一样的情况下,全双工比半双工传输速度要快,效率要高。

    4 偶校验与奇校验
    在标准ASCII码中,其最高位(b7)用作奇偶校验位。所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1;偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。

    5 停止位
    停止位是按长度来算的。串行异步通信从计时开始,以单位时间为间隔(一个单位时间就是波特率的倒数),依次接受所规定的数据位和奇偶校验位,并拼装成一个字符的并行字节;此后应接收到规定长度的停止位“1”。所以说,停止位都是“1”,1.5是它的长度,即停止位的高电平保持1.5个单位时间长度。一般来讲,停止位有1,1.5,2个单位时间三种长度。

    6 波特率
    波特率就是每秒钟传输的数据位数。
    波特率的单位是每秒比特数(bps),常用的单位还有:每秒千比特数Kbps,每秒兆比特数Mbps。串口典型的传输波特率600bps,1200bps,2400bps,4800bps,9600bps,19200bps,38400bps。
    PLC/PC与称重仪表通讯时,最常用的波特率是9600bps,19200bps。PLC/PC或仪表与大屏幕通讯时,最常用的波特率是600bps。

    7 典型的串口通讯标准
    EIA RS232(通常简称“RS232”): 1962年由美国电子工业协会(EIA)制定。
    EIA RS485(通常简称“RS485”): 1983年由美国电子工业协会(EIA)制定。

    8 RS232串口
    RS232是计算机与通信工业应用中最广泛一种串行接口。它以全双工方式工作,需要地线、发送线和接收线三条线。RS232只能实现点对点的通信方式。

    8.1 RS232串口缺点
    ●接口信号电平值较高,接口电路芯片容易损坏。
    ●传输速率低,最高波特率19200bps。
    ●抗干扰能力较差。
    ●传输距离有限,一般在15m以内。
    ●只能实现点对点的通讯方式。

    8.2 RS232串口接口定义
    RXD:接收数据,TXD:发送数据,GND/SG:信号地。

    8.3 电脑DB9针接口定义
    电脑DB9针接口是常见的RS232串口,其引脚定义如下:
    2号脚:RXD(接收数据)
    3号脚:TXD(发送数据)
    5号脚:SG或GND(信号地)
    其它脚:我们不用
    这里写图片描述
    电脑RS232串口与仪表串口连接图:
    这里写图片描述

    9 串口通讯硬件常见的注意事项
    ●通讯电缆端子一定接牢,不可有任何松动,否则,可能会烧坏仪表或上位机的通讯板。
    ●不可带电拔插通讯端子,否则,可能会烧坏仪表或上位机的通讯板,一定要关闭仪表电源后才能去拔插通讯端子或接通讯线。
    ●通讯用的屏蔽电缆最好选用双层隔离型屏蔽电缆,其次选用单层屏蔽电缆,最好不要选用无屏蔽层的电缆,且电缆屏蔽层一定要能完全屏蔽,有些质量差的电缆,屏蔽层很松散,根本起不到屏蔽的作用。单层屏蔽的电缆屏蔽层应一端接地,双层屏蔽的电缆屏蔽层其外层(含铠装)应两端接地,内层屏蔽则应一端接地。
    ●仪表使用RS232通讯时,通讯电缆长度不得超过15米。
    ●一般RS485协议的接头没有固定的标准,可能根据厂家的不同引脚顺序和管脚功能可能不尽相同,用户可以查阅相关产品RS485的引脚图。
    ●RS485通讯电缆最好选用阻阬匹配、低衰减的RS485专用通讯电缆(双绞线),不要使用普通的双绞电缆或质量较差的通讯电缆。因为普通电缆或质量差的通讯电缆,可能阻抗不匹配、衰减大、绞合度不够、屏蔽层太松散,这样会导致干扰将非常大,会造成通讯不畅,甚至通讯不上。
    ●仪表使用RS485通讯时,每台仪表必须手牵手地串下去,不可以有星型连接或者分叉,如果有星型连接或者分叉,干扰将非常大,会造成通讯不畅,甚至通讯不上。
    这里写图片描述

    ●485总线结构理论上传输距离达到1200米,一般是指通讯线材优质达标,波特率9600,只有一台485设备才能使得通讯距离达到1200米,而且能通讯并不代表每次通讯都正常,所以通常485总线实际的稳定通讯距离远远达不到1200米。负载485设备多,线材阻抗不同时,通讯距离更短。
    ●仪表使用RS485通讯时,必要时,请接入终端电阻,以增强系统的抗干扰性,典型的终端电阻阻值是120欧。

    10 串口通讯软件设置要点
    10.1 有关通讯的一些基本概念
    ●主机与从机:在通讯系统中起主要作用、发布主要命令的称为主机,接受命令的称为从机。
    ●连续方式:指主机不需要发布命令,从机就能自动地向主机发送数据。
    ●指令方式:指主机向从机发布命令,从机根据指令执行动作,并将结果“应答”给主机的模式。
    ●输出数据类型:指在连续方式通讯时,从机输出给主机的数据类型。
    ●通讯协议:指主机与从机通讯时,按哪一种编码规则来通讯。
    ●波特率:主从机之间通讯的速度。
    ●数据位:每次传输数据时,数据由几位组成。
    ●校验位:数据传输错误检测,可以是奇校验、偶校验或无校验。
    ●地址:每一台从机的编号。

    11.2 主从机之间通讯设置要点
    ●要点一:主/从RS232/485硬件有无设置正确,通讯线有无接对。有些通讯板卡是RS422与RS485共用的,依靠板上跳线来实现的,有些仪表RS232/485也需要通讯跳线来实现。
    ●要点二:主机上的通讯端口有无设置正确;超时(一般设置为2s)、通讯延时(一般设置为5~20ms)、ACK信号延时(一般设置为0ms)有无设置正确。
    ●要点三:主/从机通讯协议有无选择正确。
    ●要点四:主/从机波特率有无选择正确。
    ●要点五:主/从机数据位有无选择正确。数据位可以选择7位,8位。
    ●要点六:主/从机校验位有无选择正确。校验位一般可选择偶校验、奇校验、无校验。
    ●要点七:主/从机停止位有无选择正确。停止位可以选择1位、1.5位还是2位。
    ●要点八:从机地址有无选择正确。
    ●要点九:主/从机的通讯方式有无选择正确。

    进行通讯测试的时候经常会进行线路测试,测试所用的串口线是否可用,方法有二如下:

    1 把串口线接到不同的串口,用串口调试工具从一个串口发数据,另一个能正常收到说明串口线是OK的。
    2 把串口线的一端短接(用金属把2,3号脚连通),用万用表测另一端的2,3号如果正常的话会有嘀嘀的短接报警声。

    这里写图片描述

    展开全文
  • Java使用开源Rxtx实现串口通讯 串口开发

    千次下载 热门讨论 2014-04-13 15:48:48
    Java使用开源Rxtx实现串口通讯 串口开发,里面包含实例,下载后按自己的要求进行修改即可(仅限对java有基础的人员)。
  • 在做串口开发的时候通常需要破解串口协议,需要知道串口发过来的消息
  • Android蓝牙串口开发指南
  • c#com串口开发 可用串口读取 串口数据接收 串口数据发送
  • 前段时间因为工作需要研究了一下android的串口通信,网上有很多讲串口通信的文章,我在做的时候也参考了很多文章,现在就将我学习过程中的一些心得分享给大家,由于串口开发涉及到jni,所以开发环境需要支持ndk开发...
  • 物联网硬件设备(COM)串口通讯配置器,适合串口开发串口调试,包括COM端口设备自动识别,自动接收输出硬件设备数据,可下发参数指令到硬件设备中,部分指令可自动保存,方便调试等日常工作。
  • java 串口开发jar包

    2018-05-25 13:58:08
    comm-2.0.jar java串口开发主要jar包。。。。。。。。
  • Android USB串口开发

    千次阅读 2018-06-21 14:04:53
    因为第一次接触Android下的串口开发,在网上找了很多例子都不能满足自己的需要以及不能正常使用,于是结合网上的资源以及查阅资料,终于完成了关于这个串口的开发,在此记录下usb转串口通信开发的过程。 Android...

    因为第一次接触Android下的串口开发,在网上找了很多例子都不能满足自己的需要以及不能正常使用,于是结合网上的资源以及查阅资料,终于完成了关于这个串口的开发,在此记录下usb转串口通信开发的过程。

    Android串口开发步骤总共分为四大类,如下
    1. 权限获取
    2. 发现打开串口
    3. 串口操作(发送与读取)
    4. 关闭串口

    一、权限获取

    首先我们需要在AndroidMainfest.xml文件中配置USB使用权限

    <uses-feature android:name="android.hardware.usb.host" />

    并在我们的Activity标签中配置intent-filter

    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
    </intent-filter>
    
    <meta-data
        android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
        android:resource="@xml/device_filter" />

    resource资源为res资源文件夹下的xml文件下的device_filter.xml文件。device_filter.xml文件是我们需要知道我们USB设备硬件的vendor-id和product-id。文件内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <usb-device
            vendor-id="xxxx"
            product-id="xxxx"/>
    </resources>

    其中vendor-id以及product-id我们可以通过计算机管理 -> 电脑电脑设备管理器,Android Phone 查看详细信息,属性选择硬件ID。
    这里写图片描述

    二、发现打开串口
    首先我们需要获取到UsbManager管理类,通过此类的getDeviceList()方法得到包含所有已连接的USB设备的列表。最后,通过设备名称来得到给设备对象。

    UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
    HashMap<String, UsbDevice> deviceMap = usbManager.getDeviceList();
    UsbDevice device = deviceMap.get("deviceName");

    上面是获取指定的串口设备,如果你想获取到所有的可以通过usbManager.getDeviceList().values();获取在foreach循环迭代拿到每一个设备。

    当我们获取到一个设备之后,我们首先要判断是否有该权限,通过usbManager.hasPermission(device)判断是否有该权限。当有权限我们就可以打开串口设备以及对他设置波特率、检验位等参数信息。

     private void permissionAllow(UsbDevice device) {
    
            List<UsbSerialPort> result = new ArrayList<>();
    
            for (final UsbSerialDriver driver : drivers) {
                final List<UsbSerialPort> ports = driver.getPorts();
                result.addAll(ports);
            }
    
            UsbDeviceConnection usbDeviceConnection = usbManager.openDevice(device);
    
            try {
                serialPort = result.get(0);
                serialPort.open(usbDeviceConnection);
                // 第一个参数为波特率 第二个为停止位 第三个为奇偶校验,具体的应该根据自己的协议来配置
                serialPort.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            UsbInterface anInterface = device.getInterface(0);
    
            if (anInterface == null) {
                Toast.makeText(this, "初始化失败", Toast.LENGTH_SHORT).show();
                return;
            }
    
            // 判断端口号
            for (int i = 0; i < anInterface.getEndpointCount(); i++) {
                UsbEndpoint endpoint = anInterface.getEndpoint(i);
                if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                        // 输入端口
                        usbEndpointIn = endpoint;
                    } else if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                        // 输出端口
                        usbEndpointOut = endpoint;
                    }
                }
            }
        }

    当没有权限的使用,需要注册本地广播去申请权限

    //  private static final String ACTION_USB_PERMISSION = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
    UsbPermissionActionReceiver mUsbPermissionActionReceiver = new UsbPermissionActionReceiver();
    Intent intent = new Intent(ACTION_USB_PERMISSION);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
    IntentFilter intentFilter = new IntentFilter(ACTION_USB_PERMISSION);
    registerReceiver(mUsbPermissionActionReceiver, intentFilter);
    usbManager.requestPermission(device, pendingIntent);
    
    
    private class UsbPermissionActionReceiver extends BroadcastReceiver {
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (ACTION_USB_PERMISSION.equals(action)) {
                    synchronized (this) {
                        UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                            // user choose YES for your previously popup window asking for grant perssion for this usb device
                            if (null != usbDevice) {
                                permissionAllow(usbDevice);
                            }
                        } else {
                            //user choose NO for your previously popup window asking for grant perssion for this usb device
                            Toast.makeText(context, String.valueOf("Permission denied for device" + usbDevice), Toast.LENGTH_LONG).show();
                        }
                    }
                }
            }
        }

    三、串口操作

    通过以上我们已经对串口的获取以及配对都已经完成了,接下来只需要发送数据给串口就OK了。

    private void sendToUsb(String[] hexString) throws Exception {
    // 在这里需要转换byte数组,因为串口按位(bit)发送和接收字节
         byte[] bytes = new byte[hexString.length];
         for (int i = 0; i < hexString.length; i++) {
             bytes[i] = (byte) Integer.parseInt(hexString[i].substring(2), 16);
         }
         serialPort.write(bytes, bytes.length);
     }

    已某一个指令为例

    private void studyCode() {
         try {
          // 该数据为协议规定的十六进制的数据值
             String[] studyCodeStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0A 0X00 0XEF".replace("X", "x").split(" ");
             sendToUsb(studyCodeStrArr);
         } catch (Exception e) {
             Toast.makeText(this, "学码失败", Toast.LENGTH_SHORT).show();
             e.printStackTrace();
         }
     }
    

    四、关闭串口

    当你完成数据的传输或者你的设备已拔出时,通过调用releaseInterface()和 close()来关闭接口和连接。

    支持已完成了串口的开发,下面附上完整代码。

    package com.huruwo.serialporthelper;
    
    import android.app.PendingIntent;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.hardware.usb.UsbConstants;
    import android.hardware.usb.UsbDevice;
    import android.hardware.usb.UsbDeviceConnection;
    import android.hardware.usb.UsbEndpoint;
    import android.hardware.usb.UsbInterface;
    import android.hardware.usb.UsbManager;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.SeekBar;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.hoho.android.usbserial.driver.UsbSerialDriver;
    import com.hoho.android.usbserial.driver.UsbSerialPort;
    import com.hoho.android.usbserial.driver.UsbSerialProber;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Locale;
    
    /**
     * author: YJZ
     * date:  2018/6/15
     * des: USB串口开发
     */
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener, IAudioListen, SeekBar.OnSeekBarChangeListener {
    
        private UsbEndpoint usbEndpointIn;
        private UsbEndpoint usbEndpointOut;
    
        private UsbManager usbManager;
        private UsbSerialPort serialPort;
        private TextView textView;
        private TextView seekBarValue;
        private List<UsbSerialDriver> drivers;
    
        public MainActivity() {
        }
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_test);
    
            initView();
    
            initUsbSerial();
        }
    
        private void initUsbSerial() {
    
            // 1.查找设备
            usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
    
            drivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager);
    
            if (drivers.size() <= 0) {
                Toast.makeText(this, "无串口设备", Toast.LENGTH_SHORT).show();
                return;
            }
    
            UsbDevice device = drivers.get(0).getDevice();
    
            if (usbManager.hasPermission(device)) {
                permissionAllow(device);
            } else {
                Log.e("TAG", "没有权限");
                UsbPermissionActionReceiver mUsbPermissionActionReceiver = new UsbPermissionActionReceiver();
                Intent intent = new Intent(ACTION_USB_PERMISSION);
                PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
                IntentFilter intentFilter = new IntentFilter(ACTION_USB_PERMISSION);
                registerReceiver(mUsbPermissionActionReceiver, intentFilter);
                usbManager.requestPermission(device, pendingIntent);
            }
    
        }
    
        private void permissionAllow(UsbDevice device) {
    
            List<UsbSerialPort> result = new ArrayList<>();
    
            for (final UsbSerialDriver driver : drivers) {
                final List<UsbSerialPort> ports = driver.getPorts();
                result.addAll(ports);
            }
    
            UsbDeviceConnection usbDeviceConnection = usbManager.openDevice(device);
    
            try {
                serialPort = result.get(0);
                serialPort.open(usbDeviceConnection);
                serialPort.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            UsbInterface anInterface = device.getInterface(0);
    
            if (anInterface == null) {
                Toast.makeText(this, "初始化失败", Toast.LENGTH_SHORT).show();
                return;
            }
    
            // 判断端口号
            for (int i = 0; i < anInterface.getEndpointCount(); i++) {
                UsbEndpoint endpoint = anInterface.getEndpoint(i);
                if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                        // 输入端口
                        usbEndpointIn = endpoint;
                    } else if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                        // 输出端口
                        usbEndpointOut = endpoint;
                    }
                }
            }
        }
    
        private static final String ACTION_USB_PERMISSION = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
    
        @Override
        public void top() {
            topTurn();
        }
    
        @Override
        public void pause() {
            pauseTurn();
        }
    
        @Override
        public void update(final double volume) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    textView.setText("分贝:" + String.valueOf(volume));
                }
            });
    
            Log.e("TAG", "volume = " + volume);
        }
    
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            AudioRecordDemo.MAX_VOLUME = progress;
            seekBarValue.setText(String.format(Locale.CHINA, "阀值:%s", progress));
        }
    
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
    
        }
    
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
    
        }
    
        private class UsbPermissionActionReceiver extends BroadcastReceiver {
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (ACTION_USB_PERMISSION.equals(action)) {
                    synchronized (this) {
                        UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                            // user choose YES for your previously popup window asking for grant perssion for this usb device
                            if (null != usbDevice) {
                                permissionAllow(usbDevice);
                            }
                        } else {
                            //user choose NO for your previously popup window asking for grant perssion for this usb device
                            Toast.makeText(context, String.valueOf("Permission denied for device" + usbDevice), Toast.LENGTH_LONG).show();
                        }
                    }
                }
            }
        }
    
        private void initView() {
            findViewById(R.id.study_code).setOnClickListener(this);
            findViewById(R.id.top).setOnClickListener(this);
            findViewById(R.id.pause).setOnClickListener(this);
            findViewById(R.id.bottom).setOnClickListener(this);
            findViewById(R.id.start_audio).setOnClickListener(this);
            findViewById(R.id.stop_audio).setOnClickListener(this);
            SeekBar seekBar = findViewById(R.id.seek_bar);
            seekBarValue = findViewById(R.id.seek_bar_value);
            seekBar.setOnSeekBarChangeListener(this);
            textView = findViewById(R.id.value);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.study_code:
                    studyCode();
                    break;
    
                case R.id.top:
                    topTurn();
                    break;
    
                case R.id.pause:
                    pauseTurn();
                    break;
    
                case R.id.bottom:
                    bottomTurn();
                    break;
    
                case R.id.start_audio:
                    AudioRecordDemo demo = new AudioRecordDemo();
                    demo.setAudioRecordListener(this);
                    demo.getNoiseLevel();
                    break;
    
                case R.id.stop_audio:
                    AudioRecordDemo.isGetVoiceRun = false;
                    break;
            }
        }
    
    
        private void bottomTurn() {
            try {
                String[] bottomStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0C 0X00 0XF1".replace("X", "x").split(" ");
                sendToUsb(bottomStrArr);
            } catch (Exception e) {
                Toast.makeText(this, "失败", Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }
        }
    
        private void pauseTurn() {
            try {
                String[] pauseStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0D 0X00 0XF2".replace("X", "x").split(" ");
                sendToUsb(pauseStrArr);
            } catch (Exception e) {
                Toast.makeText(this, "失败", Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }
        }
    
        private void topTurn() {
            try {
                String[] topStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0E 0X00 0XF3".replace("X", "x").split(" ");
                sendToUsb(topStrArr);
            } catch (Exception e) {
                Toast.makeText(this, "失败", Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }
        }
    
        private void studyCode() {
            try {
                String[] studyCodeStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0A 0X00 0XEF".replace("X", "x").split(" ");
                sendToUsb(studyCodeStrArr);
            } catch (Exception e) {
                Toast.makeText(this, "学码失败", Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }
        }
    
        private void sendToUsb(String[] hexString) throws Exception {
            byte[] bytes = new byte[hexString.length];
            for (int i = 0; i < hexString.length; i++) {
                bytes[i] = (byte) Integer.parseInt(hexString[i].substring(2), 16);
            }
            serialPort.write(bytes, bytes.length);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            AudioRecordDemo.isGetVoiceRun = false;
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            AudioRecordDemo.isGetVoiceRun = false;
        }
    }
    
    展开全文
  • ZylSerialPort.NET_v1.51 最好的.net 串口开发
  • Android串口开发(android-serialport-api开发)工程实例。SerialPortUtil里面有我常用的转换工具(16进制字符串转二进制字符串并补位、二进制字符串转16进制字符串并补位)
  • Android JNI串口开发

    2018-08-03 15:06:00
    最近公司要做一个展示牌形式的打卡器,Android系统且展示牌底部有个串口来接收...项目创建时如图,这样会包含native-lib.cpp文件,此文件是主要串口开发的C++函数,包含打开串口/串口设置/关闭串口等的设置  nativ...

    最近公司要做一个展示牌形式的打卡器,Android系统且展示牌底部有个串口来接收大家手环打卡出勤的信息,这就需要读取每个手环或者工牌的id信息,因此用到了Android studio自带的jni功能在这里做一下总结笔记,方便以后直接拉下来使用.


    • 项目创建时如图,这样会包含native-lib.cpp文件,此文件是主要串口开发的C++函数,包含打开串口/串口设置/关闭串口等的设置

    •  native-lib.cpp文件
    #include <jni.h>
    #include <string>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <string.h>
    #include <stdint.h>
    #include <termios.h>
    #include <sys/ioctl.h>
    #include <android/log.h>
    
    static const char *TAG="serial_port";
    #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
    #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)
    #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
    
    extern "C" JNIEXPORT jstring
    
    JNICALL
    Java_com_jetsen_joy_carddemo_MainActivity_stringFromJNI(
            JNIEnv *env,
            jobject /* this */) {
        std::string hello = "Hello from C++";
        return env->NewStringUTF(hello.c_str());
    }
    
    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_jetsen_joy_carddemo_SerialPort_open(JNIEnv *env, jclass thiz, jstring path,
                                                 jint baudrate) {
    
        int fd;
        speed_t speed;
        jobject mFileDescriptor;
    
        /* 这里获取设置的波特率 */
        {
            speed = getBaudrate(baudrate);
            if (speed == -1) {
                /* TODO: throw an exception */
                LOGE("Invalid baudrate");
                return NULL;
            }
        }
    
        /* 打开串口 */
        {
            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);
            fd = open(path_utf, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
            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;
            }
        }
    
        /*配置串口 */
        {
            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);// 结构中存储的输入波特率为 speed。如果输入波特率被设为0,实际输入波特率将等于输出波特率
            cfsetospeed(&cfg, speed);//设置 termios_p 指向的 termios 结构中存储的输出波特率为 speed
    
            if (tcsetattr(fd, TCSANOW, &cfg))//设置串口的配置,TCSANOW立即生效的意思
            {
                LOGE("tcsetattr() failed");
                close(fd);
                /* TODO: throw an exception */
                return NULL;
            }
        }
    
        /* 生成一个文件描述符FileDescriptor*/
        {
            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);
        }
    
        return mFileDescriptor;
    }
    
    
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_jetsen_joy_carddemo_SerialPort_close(JNIEnv *env, jobject thiz) {
    
        jclass SerialPortClass = env->GetObjectClass( thiz);
        jclass FileDescriptorClass = env->FindClass( "java/io/FileDescriptor");
    
        jfieldID mFdID = env->GetFieldID( SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
        jfieldID descriptorID = env->GetFieldID(FileDescriptorClass, "descriptor", "I");
    
        jobject mFd = env->GetObjectField(thiz, mFdID);
        jint descriptor = env->GetIntField(mFd, descriptorID);
    
        LOGD("close(fd = %d)", descriptor);
        close(descriptor);
    
    }
    
    •  新建一个SerialPort类,此类中主要是open close串口方法,创建此两个本地方法,运行时Android会自动调用jni中对应的方法,从而实现对指定串口的打开及关闭;
    public class SerialPort {
    
        private final String TAG=SerialPort.class.getName();
    
        private FileDescriptor mFd;
        private FileInputStream mFileInputStream;
        private FileOutputStream mFileOutputStream;
    
        public SerialPort(File device, int baudrate) throws SecurityException, IOException {
            /* 这里是判断有串口的读写权限 */
            if (!device.canRead() || !device.canWrite()) {
                try {
                    /*没有就需要申请权限,这个地方需要将Android设备root提供权限 */
                    Process su;
                    su = Runtime.getRuntime().exec("/system/bin/su");
                    String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
                            + "exit\n";
                    su.getOutputStream().write(cmd.getBytes());
                    if ((su.waitFor() != 0) || !device.canRead()
                            || !device.canWrite()) {
                        throw new SecurityException();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new SecurityException();
                }
            }
            //调用jni,打开串口
            this.mFd = open(device.getAbsolutePath(), baudrate);
            if(this.mFd == null) {
                Log.e(TAG, "native open returns null");
                throw new IOException();
            } else {
                //获取与串口通信的输入输出流
                this.mFileInputStream = new FileInputStream(this.mFd);
                this.mFileOutputStream = new FileOutputStream(this.mFd);
            }
        }
    
        // Getters and setters
        public InputStream getInputStream() {
            return mFileInputStream;
        }
    
        public OutputStream getOutputStream() {
            return mFileOutputStream;
        }
    
        static {
            //这个静态库的名字必须与之前我们在CMakeLists.txt中的命名相同
            System.loadLibrary("native-lib");
        }
        // JNI
        private native static FileDescriptor open(String path, int baudrate);
        public native void close();
    
    
    }
     
    • SerialPortUtil串口工具类 ,对串口的打开,关闭,接收数据进行处理
    public class SerialPortUtil {
    
        private String TAG = SerialPortUtil.class.getSimpleName();
        private SerialPort mSerialPort;
        private OutputStream mOutputStream;
        private InputStream mInputStream;
        private ReadThread mReadThread;
        private String path = "/dev/ttyS3";//不固定,我这里硬件设备读取手环信息的串口是ttyS3
        private int baudrate = 9600;//不固定,波特率 串口需要同设备提供商要到信息
        private static SerialPortUtil portUtil;
        private OnDataReceiveListener onDataReceiveListener = null;//声明接口变量
        private boolean isStop = false;
    
    
    
        //定义接口
        public interface OnDataReceiveListener {
            public void onDataReceive(byte[] buffer, int size);
        }
    
        public void setOnDataReceiveListener(OnDataReceiveListener dataReceiveListener) {
            onDataReceiveListener = dataReceiveListener;
        }
    
        public static SerialPortUtil getInstance() {
            if (null == portUtil) {
                portUtil = new SerialPortUtil();
                portUtil.onCreate();
            }
            return portUtil;
        }
    
        /**
         * 初始化串口通信
         */
        private void onCreate() {
            try {
                mSerialPort = new SerialPort(new File(path), baudrate);
                mOutputStream = mSerialPort.getOutputStream();
                mInputStream = mSerialPort.getInputStream();
    
                mReadThread = new ReadThread();
                isStop = false;
                mReadThread.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 循环读取手环信息
         */
        private class ReadThread extends Thread {
    
            @Override
            public void run() {
                super.run();
                while (!isStop && !isInterrupted()) {
                    int size;
                    try {
                        if (mInputStream == null)
                            return;
    
                        if (mInputStream.available() > 0){
                            byte[] buffer = new byte[mInputStream.available()];
                            size = mInputStream.read(buffer);
                            if (size > 0) {
    
                                if (null != onDataReceiveListener) {
                                    onDataReceiveListener.onDataReceive(buffer, size);
                                }
                            }
    
                        }
    
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                    } catch (Exception e) {
                        e.printStackTrace();
                        return;
                    }
                }
            }
        }
    
        /**
         * 关闭串口
         */
        public void closeSerialPort() {
            isStop = true;
            if (mReadThread != null) {
                mReadThread.interrupt();
            }
            if (mSerialPort != null) {
                mSerialPort.close();
            }
        }
    
    
    }
    •  MainActivty类中做读取到数据的处理
    public class MainActivity extends AppCompatActivity {
    
        // Used to load the 'native-lib' library on application startup.
        static {
            System.loadLibrary("native-lib");
        }
    
        TextView tv;
        SerialPortUtil mSerialPortUtil;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Example of a call to a native method
            tv = (TextView) findViewById(R.id.sample_text);
            tv.setText(stringFromJNI());
    
    
    
            mSerialPortUtil = SerialPortUtil.getInstance();
            
            mSerialPortUtil.setOnDataReceiveListener(new SerialPortUtil.OnDataReceiveListener() {
                @Override
                public void onDataReceive(final byte[] buffer, final int size) {
    
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //将读取到的数据进行处理
                            tv.setText("读到了size:" + size + "--" + new String(buffer) + "end");
                            Toast.makeText(MainActivity.this,
                                    "收到了size:" + size + "--" + new String(buffer) + "end",
                                    Toast.LENGTH_LONG).show();
    
                        }
                    });
    
                }
            });
    
        }
    
    
        /**
         * A native method that is implemented by the 'native-lib' native library,
         * which is packaged with this application.
         */
        public native String stringFromJNI();
    }
    • 添加权限
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />

     

    展开全文
  • 安卓基于谷歌串口api进行串口开发准备材料前情提要开始骚操作首先解压谷歌api demo放一边备用;新建AS项目,一路next,拿到一个空空的自带界面的项目;打开项目目录app下的build.gradle,在buildTypes同级设置so文件...

    安卓基于谷歌串口api进行串口开发

    准备材料

    AndroidStudio
    谷歌android-serialport-api

    前情提要

    网上提供很多基于c语言对安卓串口开发,有jni、cmake等等,不过都太高深,谷歌提供的api已经可以满足基本读写(对数据位、停止位、校验位无要求,默认N81),这也是最简单的串口开发。

    Java并不是直接调用c中的函数去和串口交互,而是用cmake或jni编译c得到的so库文件实现的,所以使用谷歌api不用再去把他的c文件之类的拿来,只用把他的so库文件拿来用即可,也不用知道so文件怎么用,谷歌demo中写好了直接调用so文件的java类,所以最终我们只需要导入需要的东西然后在谷歌串口类之上编写就行了。

    开始操作

    • 首先解压谷歌api demo放一边备用;
    • 新建AS项目,一路next,拿到一个空空的自带界面的项目;
    • 打开项目目录app下的build.gradle,在buildTypes同级设置so文件的lib位置,这里用的自己生成的libs文件夹
    android {
    	compileSdkVersion 28
    	defaultConfig {
    		applicationId "com.example.hp.demo"
    		minSdkVersion 19
    		targetSdkVersion 28
    		versionCode 1
    		versionName "1.0"
    		testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    	}
    	buildTypes {
    		release {
    			minifyEnabled false
    			proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    		}
    	}
    	// there!!!!!!
    	sourceSets.main{
    		jniLibs.srcDirs = ['libs']
    	}
    }
    
    • 打开谷歌api对应的lib文件夹android-serialport-api\android-serialport-api\project\libs,将里面的三种CPU架构用的so文件夹全复制过去
    • 打开谷歌api的源代码目录android-serialport-api\android-serialport-api\project\src,内含谷歌api串口开发地基,将该文件夹android_serialport_api直接复制到自己项目java文件夹内(和com同级)
    • android_serialport_api这个文件夹包含三件物品:
      1. sample:谷歌api DEMO所用演示代码,移植到自己项目后直接删除,不然会和xml接不上报错
      2. SerialPort.java:我们直接接触的对串口开发操作的类,串口读写都基于此,由该文件和so文件对接,我们的操作和该文件对接
      3. SerialPortFinder.java:一般用不到(我没用到),可以找到并输出所有可用串口名和路径,可能是用于对串口批量操作的,一两个串口的用不到
    • 在此再次说一下:正常大神流程是,先写c文件和h文件,然后jni或cmake编译得出so文件,然后写调用so文件的java类,然后再调用该java类进行各种操作;
      我们的流程是上述操作的最后一步,直接用谷歌大佬写好的c编译好的so写好的java类,在这之上写我们自己的代码
    • 这时就已经可以准备自己的代码了,在此之前检查几个地方:
      1. 第3点是否写好
      2. SerialPort.java中的末尾有这么一段代码:
    static {
    	System.loadLibrary("serial_port");
    }
    

    这就是传说中调用so库的地方,第三点没写好是找不到这个库的,此外(“”)中的库名也要和so文件对应,即so文件的libserial_port.so去掉开头lib就是库名

    • 开始编写自己的代码:
    1. 写一个基于SerialPort.java封装好的串口类,虽然已经可以直接用SerialPort.java,但是SerialPort.java中的方法还是稍微有点基层,当项目里有对多个串口进行不同的操作时这一步是必要的,不然代码太重复繁琐,封装的串口类应该有这几个功能:
    • 从外部设置串口号、波特率
    • 向外部传递串口返回报文
    • 打开串口,获取输入输出流
    • 关闭串口,关闭输入输出流
    • 向串口写入字节*
    • 向串口写入字节数组*
    • 向串口写入字符串*
    • 实时监听串口,获取完整的报文
    • 具体代码见Demo
    1. 使用串口类,new一个你做的串口类,注册好串口类的数据接收器,在需要串口发送数据的地方调用串口类的发送方法,在接收器中做好对报文的校验等处理

    踩坑预警

    • 串口返回报文残缺,中间少那么一两个字节
      因为你注册了两个对同一个串口的监听器,他俩在互抢
    • 串口返回报文从中间断开
      串口另一头发送的时候可能是一个字节一个字节发送的,或者一段一段发送的,不过都会在很短的时间全给你发过来,这时候最保险的做法就是收到数据时,睡上10~100ms,再读一次(接收数据实际上是你从对串口的输入流缓冲区中取出数据),然后拼上返回给外部
    • New一个串口太吃资源
      接收数据的地方其实是一个循环读取的线程,读取一次让它睡10~100ms再循环
    • 关闭串口之后该串口读取线程还在执行
      把读取线程run()里的内容拿while(){ }括起来,while条件里扔一个布尔型,默认符合条件,关闭串口时改了变量让while不符合条件,线程就自然销毁了
    • SerialPort.java类new的时候除了串口文件和波特率之外,还要一个int型flags参数
      这个我也没搞明白,学长用的时候都是写死了0传过去,没发现出问题
    • 读取数据时inputStream.read() 方法
      该方法返回值是个int,表示读到的字节数组长度,所以读的时候拿个int接着,当读完缓冲区的数据后会返回-1,所以读了之后有无数据都有返回值,所以对返回数据进一步操作前用个if括起来,int大于0再执行;
      该方法传递参数有几种不同形式:
    1. 传入一个byte[]容器,读到的数据存入该容器,注意不要空指针,不要超出容器容量
    2. 传入一个byte[]容器,一个int型起始位置off,一个int型数据长度len,off表示读到的数据从容器的byte[off]位置开始存,len表示读len个字节存进容器,这种传参在第二次读取拼接第一次报文的地方会用到

    附上Demo

    https://gitee.com/zhao983021488/Android-GoogleApi-Demo

    展开全文
  • Android串口开发简单教程

    万次阅读 2018-01-09 14:52:20
    串口开发四部曲:打开串口,串口输入,串口输出,关闭串口 以下是基于开源项目https://github.com/cepr/android-serialport-api下开发的,作简要记录。 一、项目配置 1.创建了jni和jniLibs两...
  • PLC,工控串口开发

    2018-07-28 10:17:46
    对PLC,工控串口开发 开发有兴趣可加了解。
  • Android串口开发

    千次阅读 2015-04-22 16:00:50
    最近公司有个新项目,android设备(android手机)连接RFID设备,通过android应用来操作RFID设备来实现一些功能。Android设备和RFID设备通过GPIO接口连接,实现这样的android... android串口开发有个开源的项目:andro
  • QT for Android串口开发

    千次阅读 2019-12-28 10:35:41
    最近在搞QT for Android开发,在网上搜了下解决方案发现都是需要java库的支持,QT原生接口QSerialPort不支持Android系统的串口开发,因为QT的接口掉的都是标准的接口,而Android都是非标准的,所以用不了,只能自己...
  • 软硬件交互串口开发

    2019-11-10 23:13:11
    https://blog.csdn.net/l13020227067/article/details/80693087 案例为串口开发,连接硬件和电脑软件。
  • 原创:物联网硬件设备(COM)串口通讯配置器,适合串口开发串口调试 物联网硬件设备(COM)串口通讯配置器,适合串口开发串口调试,包括COM端口设备自动识别,自动接收输出硬件设备数据,可下发参数指令到硬件设备中,...
  • C# 串口开发填坑记

    2020-12-30 13:23:46
    C# 串口开发填坑记 串口虽然简单,但是想要做得“耐用”,还是要花些心思!本文把开发中遇到的问题总结,希望能帮到各位小伙伴。 1. 界面数据更新报错 因为,串口接收和界面显示更新不属于同一线程,如果在接收到...
  • Android利用Android串口开发与硬件利用1K Xmodem协议远程升级,Android串口232开发,硬件利用1K Xmodem协议进行远程升级
  • MAC串口开发环境搭建

    千次阅读 2016-07-22 16:58:54
    MAC串口开发环境搭建MAC串口开发环境搭建 什么是串口 安装USB转串口驱动 安装终端仿真程序 配置SecureCRT参数 串行通信参数 SecureCRT开发配置 什么是串口串行接口 (Serial Interface) 是指数据一位一位地顺序传送,...
  • 【android 串口开发

    千次阅读 2017-04-07 16:50:06
    说到串口开发,不得不先明确一下以下概念。接口的定义: 接口泛指实体把自己提供给外界的一种抽象化物(可以为另一实体),用以由内部操作分离出外部沟通方法,使其能被修改内部而不影响外界其他实体与其交互的方式...
  • 开发串口程序首先要求你的设备需要支持串口通信,可以在设备上装一个App端的串口工具来检测一下 链接:https://pan.baidu.com/s/11L4aZI9orBhbnztka6H1Og 提取码:bvot 或者在电脑端下载一个友善串口助手检测一下...
  • Android开发板之串口开发

    万次阅读 多人点赞 2016-05-30 11:22:36
    Android开发板之串口开发简介 首先描述一下我的应用项目,它是一个简单的智能盒子,主要内容:是通过Android开发板上的串口进行数据的读取操作,一块android开发板外接一个Arduino,再接一个传感器,当传感器上返回...
  • # 安卓能使用C++进行串口开发吗? 使用USBDevice.getName拿到路径后,(/dev/bus/usb/001/019),使用C++的open函数调用失败
  • JAVA进行串口开发,简单直接

    万次阅读 2018-06-14 15:19:26
    Java要进行串口开发,不多bb直接开始把。先要有思路1,我们现在很多笔记本或者电脑是没有串口的,所以你要先确定你的电脑上是不是又串口2,没有串口也不用着急,又usb接口就可以读写串口,因为有个东西叫做usb转串口...
  • android 串口开发

    2018-07-21 11:49:39
    物联网开发开发是时下热门的行业。Android系统自然也能进行物联网开发。除开Android本身自带的模块还有一类通过外部链接的设备需要通过串口来进行通信。 关于串口 串口通信指串口按位(bit)发送和接收字节。尽管...
  • Android 串口开发

    千次阅读 2019-07-05 15:40:18
    1. 主板型号:AIO-3399J 2. 芯片型号:RK3399 3. 操作系统版本:Android 7.1 ...本文根据驱动来修改非标准波特率,然后通过APP读写雷达设备串口数据,修改串口读写、串口安全权限的问题。 5. ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,793
精华内容 5,117
关键字:

串口开发