0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

安卓端的串口通信实践讲解2

jf_78858299 来源:Android技术之家 作者:Android技术之家 2023-04-23 17:59 次阅读

和原生 API 不同的是,因为我们此时已经知道了我们的 ESP32 主板的设备信息,以及使用的驱动(CDC),所以我们就不使用原生的查找可用设备的方法了,我们这里直接指定我们已知的这个设备(当然,你也可以继续使用原生API的查找和连接方法):

private fun scanDevice(context: Context) {
    val manager = context.getSystemService(Context.USB_SERVICE) as UsbManager


    val customTable = ProbeTable()
    // 添加我们的设备信息,三个参数分别为 vendroId、productId、驱动程序
    customTable.addProduct(0x1a86, 0x55d3, CdcAcmSerialDriver::class.java)


    val prober = UsbSerialProber(customTable)
    // 查找指定的设备是否存在
    val drivers: List

连接到设备后,下一步就是和数据交互,这里封装的十分方便,只需要获取到 UsbSerialPort 后,直接调用它的 read()write() 即可读写数据:

port = driver.ports[0] // 大多数设备都只有一个 port,所以大多数情况下直接取第一个就行


port.open(connection)
// 设置连接参数,波特率9600,以及 “8N1”
port.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE)


// 读取数据
val responseBuffer = ByteArray(1024)
port.read(responseBuffer, 0)


// 写入数据
val sendData = byteArrayOf(0x6F)
port.write(sendData, 0)

此时,一个完整的,用于测试我们上述 ESP32 程序的代码如下:

@Composable
fun SerialScreen() {
    val context = LocalContext.current




    Column(
        Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(onClick = { scanDevice(context) }) {
            Text(text = "查找并连接设备")
        }


        Button(onClick = { switchLight(true) }) {
            Text(text = "开灯")
        }
        Button(onClick = { switchLight(false) }) {
            Text(text = "关灯")
        }


    }
}


private fun scanDevice(context: Context) {
    val manager = context.getSystemService(Context.USB_SERVICE) as UsbManager


    val customTable = ProbeTable()
    customTable.addProduct(0x1a86, 0x55d3, CdcAcmSerialDriver::class.java)


    val prober = UsbSerialProber(customTable)
    val drivers: List

运行这个程序,并且连接设备。

可以看到输出的是 byte 的 101,转换为 ASCII 即为 “e”。

然后我们点击 “开灯”、“关灯” 效果如下:

图片

对了,这里发送的数据 “0x6F” 即 ASCII “o” 的十六进制,同理,“0x63” 即 “c”。

可以看到,可以完美的和我们的 ESP32 开发版进行通信

实例

无论使用什么方式与串口通信,我们在安卓APP的代码层面能够拿到的数据已经是处理好了的数据。

即,在上一篇文章中我们说过串口通信的一帧数据包括起始位、数据位、校验位、停止位。但是我们在安卓中使用时一般拿到的都只有 数据位 的数据,其他数据已经在底层被解析好了,无需我们去关心怎么解析,或者使用。

我们可以直接拿到的就是可用数据。

这里举一个我之前用过的某型号驱动版的例子。

这块驱动版关于通信的信息如图:

图片

可以看到,它采用了 RS485 的通信方式,波特率支持 9600 或 38400,8位数据位,无校验,1位停止位。

并且,它还规定了一个数据协议。

在它定义的协议中,第一位为地址;第二位为指令;第三位到第N位为数据内容;最后两位为CRC校验。

需要注意的是,这里定义的协议是基于串口通信的,不要把这个协议和串口通信搞混了,简单来说就是在串口通信协议的数据位中又定义了一个自己的协议。

而且可以看到,虽然定义串口参数时没有指定校验,但是在它自己的协议中指定了使用 CRC 校验。

另外,弱弱的吐槽一句,这个驱动版的协议真的不好使。

在实际使用过程中,主机与驱动版的通信数据无法保证一定会在同一个数据帧中发送完成,所以可能会造成“粘包”、“分包”现象,也就是说,数据可能会分几次发过来,而且你不好判断这数据是上次没发送完的数据还是新的数据。

我使用过的另外一款驱动版就方便的多,因为它会在帧头加上开始符号和数据长度,帧尾加上结束符号。

这样一来,即使出现“粘包”、“分包”我们也能很好的给它解析出来。

当然,它这样设计协议肯定是有它的道理的,无非就是减少通信代价之类的。

我还遇到过一款十分简洁的驱动版,直接发送一个整数过去表示执行对应的指令。

驱动版回传的数据同样非常简单,就是一个数字,然后事先约定各个数字表示什么意思……

说归说,我们还是继续来看这款驱动版的通信协议:

图片

这是它的其中一个指令内容,我们发送指令 “1” 过去后,它会返回当前驱动版的型号和版本信息给我们。

因为我们的主板是定制工控主板,所以使用的通信方式是直接用 android-serialport-api。

最终发送与接收回复也很简单:

/**
 * 将十六进制字符串转成 ByteArray
 * */
private fun hexStrToBytes(hexString: String): ByteArray {
    check(hexString.length % 2 == 0) { return ByteArray(0) }


    return hexString.chunked(2)
        .map { it.toInt(16).toByte() }
        .toByteArray()
}


private fun isReceivedLegalData(receiveBuffer: ByteArray): Boolean {


    val rcvData = receiveBuffer.copyOf()  //重新拷贝一个使用,避免原数据被清零


    if (cmd.cmdId.checkDataFormat(rcvData)) {  //检查回复数据格式
        isPkgLost = false
        if (cmd.cmdId.isResponseBelong(rcvData)) {  //检查回复命令来源
            if (!AdhShareData.instance.getIsUsingCrc()) {  //如果不开启CRC检验则直接返回 true
                resolveRcvData(cmdRcvDataCallback, rcvData, cmd.cmdId)
                coroutineScope.launch(Dispatchers.Main) {
                    cmdResponseCallback?.onCmdResponse(ResponseStatus.Success, rcvData, 0, rcvData.size, cmd.cmdId)
                }
                return true
            }


            if (cmd.cmdId.checkCrc(rcvData)) {  //检验CRC
                 resolveRcvData(cmdRcvDataCallback, rcvData, cmd.cmdId)
                coroutineScope.launch(Dispatchers.Main) {
                    cmdResponseCallback?.onCmdResponse(ResponseStatus.Success, rcvData, 0, rcvData.size, cmd.cmdId)
                }


                return true
            }
            else {
                coroutineScope.launch(Dispatchers.Main) {
                    cmdResponseCallback?.onCmdResponse(ResponseStatus.FailCauseCrcError, ByteArray(0), -1, -1, cmd.cmdId)
                }


                return false
            }
        }
        else {
            coroutineScope.launch(Dispatchers.Main) {
                cmdResponseCallback?.onCmdResponse(ResponseStatus.FailCauseNotFromThisCmd, ByteArray(0), -1, -1, cmd.cmdId)
            }


            return false
        }
    }
    else {  //数据不符合,可能是遇到了分包,继续等待下一个数据,然后合并
        isPkgLost = true
        return isReceivedLegalData(cmd)
        /*coroutineScope.launch(Dispatchers.Main) {
            cmdResponseCallback?.onCmdResponse(ResponseStatus.FailCauseWrongFormat, ByteArray(0), -1, -1, cmd.cmdId)
        }


        return false  */
    }
}


// ……省略初始化和连接代码


// 发送数据
val bytes = hexStrToBytes("0201C110")
outputStream.write(bytes, 0, bytes.size)


// 解析数据
val recvBuffer = ByteArray(0)
inputStream.read(recvBuffer)


while (receiveBuffer.isEmpty()) {
   delay(10)
}


isReceivedLegalData()

本来打算直接发我封装好的这个驱动版的协议库的,想了想,好像不太合适,所以就大概抽出了这些不完整的代码,懂这个意思就行了,哈哈。

总结

从上面介绍的两种方式可以看出,两种方式使用各有优缺点。

使用 android-serialport-api 可以直接读取串口数据内容,不需要转USB接口,不需要驱动支持,但是需要 ROOT,适合于定制安卓主板上已经预留了 RS232 或 RS485 接口且设备已 ROOT 的情况下使用。

而使用 USB host ,可以直接读取USB接口转接的串口数据,不需要ROOT,但是只支持有驱动的串口转USB芯片,且只支持使用USB接口,不支持直接连接串口设备。

各位可以根据自己的实际情况灵活选择使用什么方式来实现串口通信。

当然,除了现在介绍的这些串口通信,其实还有一个通信协议在实际使用中用的非常多,那就是 MODBUS 协议。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • plc
    plc
    +关注

    关注

    5010

    文章

    13267

    浏览量

    462973
  • 串口通信
    +关注

    关注

    34

    文章

    1624

    浏览量

    55505
  • 安卓
    +关注

    关注

    5

    文章

    2126

    浏览量

    57143
  • ESP32
    +关注

    关注

    18

    文章

    969

    浏览量

    17195
收藏 人收藏

    评论

    相关推荐

    LabVIEW串口通信实例:PC机与PC机串口通信实

    08、LabVIEW串口通信实例:PC机与PC机串口通信实
    发表于 06-28 20:07

    LabVIEW串口通信实例:PC机与51单片机串口通信实

    LabVIEW串口通信实例:PC机与51单片机串口通信实
    发表于 12-18 10:16

    STM32的USART串口通信实践

    STM32的USART串口通信实践
    发表于 08-16 07:20

    Matlab的串口通信实

    第9章 Matlab的串口通信实现本章节主要为大家讲解Matlab的串口方式波形数据传输和后期数据分析功能,非常实用。目录第9章 Matlab的串口
    发表于 08-17 06:48

    与ESP8266串口WIFI模块的通信实现相关资料推荐

    Button分别对应相应的功能键。通信实现原理使用基于tcp协议的socket通信串口WiFi模块配置成tcp Service模式,然后
    发表于 01-18 08:34

    STM32 USART串口通信实践

    STM32串口通讯USART串口通信实践USART串口通信实践1、实验环境参考资料 野火官方的 《零死角玩转STM32—F103指南者》①
    发表于 02-10 07:06

    基于串口的LABVIEW与PLC的通信实

    基于串口的LABVIEW与PLC的通信实现:介绍使用ADAM5000的通信协议实现LABVIEW与ADAM5510通信
    发表于 09-19 07:55 62次下载

    串口通信实例教程

    串口通信实例教程,感兴趣的可以看看。
    发表于 06-23 17:56 0次下载

    STM32 串口通信实

    USB转RS485线在F103环境下进行UART通信实验和RS232通信实验在F407环境下进行RS485实验(1.我的103板子没有485口,2.正好看下开发板环境不同的差异)UART
    发表于 12-20 19:26 15次下载
    STM32 <b class='flag-5'>串口</b><b class='flag-5'>通信实</b>验

    STM32下的USART串口通信程序

    STM32的USART串口通信实践
    发表于 12-24 18:42 13次下载
    STM32下的USART<b class='flag-5'>串口</b><b class='flag-5'>通信</b>程序

    串口通信实

    串口通信实串口通信实验代码图像串口通信实验晶振12MHz,波特率1200, 程序启动后单片机主
    发表于 01-14 10:12 6次下载
    <b class='flag-5'>串口</b><b class='flag-5'>通信实</b>验

    串口通信入门之modbus(上)

    在之前的两篇文章中,我们讲解串口的基础知识和在中使用串口通信的方法,如果还没看过之前文章的
    的头像 发表于 04-23 17:40 1921次阅读
    <b class='flag-5'>安</b><b class='flag-5'>卓</b>与<b class='flag-5'>串口</b><b class='flag-5'>通信</b>入门之modbus(上)

    串口通信入门之modbus(下)

    在之前的两篇文章中,我们讲解串口的基础知识和在中使用串口通信的方法,如果还没看过之前文章的
    的头像 发表于 04-23 17:40 4960次阅读
    <b class='flag-5'>安</b><b class='flag-5'>卓</b>与<b class='flag-5'>串口</b><b class='flag-5'>通信</b>入门之modbus(下)

    串口通信实践讲解1

    这篇文章我们将讲解串口通信实践,即如何使用串口
    的头像 发表于 04-23 17:59 2959次阅读
    <b class='flag-5'>安</b><b class='flag-5'>卓</b><b class='flag-5'>端</b>的<b class='flag-5'>串口</b><b class='flag-5'>通信实践</b><b class='flag-5'>讲解</b>1

    串口通信实验资料分享

    串口通信实验资料分享
    发表于 06-29 15:03 5次下载