主题 : jni串口每次只能读16个字节 复制链接 | 浏览器收藏 | 打印
~
级别: 新手上路
UID: 72783
精华: 0
发帖: 43
金钱: 215 两
威望: 43 点
综合积分: 86 分
注册时间: 2012-06-28
最后登录: 2012-10-28
楼主  发表于: 2012-09-05 09:42

 jni串口每次只能读16个字节

使用jni读串口时候,如果发送的数据超过16个字节,它会每16个字节发送一次。比如35个字节数据,我要read3次,前两次都是16个字节,第三次3个字节。我能一次接收吗?
级别: 骑士
UID: 29604
精华: 9
发帖: 171
金钱: 1830 两
威望: 366 点
综合积分: 522 分
注册时间: 2010-10-01
最后登录: 2016-04-13
1楼  发表于: 2012-09-05 11:18
可以使用循环,并判断是否已经读取35个字节,如果你是使用协议接收且不定长度的话,则要自己编写接收过程。
下面的android代码没有经过验证,仅供参考
ByteArrayBuffer buffer;//最终读取到的数据缓冲区
int readCount = 0; // 已经成功读取的字节的个数
while (readCount < 35) {
    if (isTimeOut()){return;}//接收超时,这部分代码省略,如果不需要,则这行就不要了。
  byte[] btemp;//每次读取用临时缓冲区
    int iCount = read(fd,btemp, 35 - readCount);
    readCount +=iCount ;
    buffer.append(btemp, 0,iCount );
}
byte[] bresult=buffer.toByteArray();
~
级别: 新手上路
UID: 72783
精华: 0
发帖: 43
金钱: 215 两
威望: 43 点
综合积分: 86 分
注册时间: 2012-06-28
最后登录: 2012-10-28
2楼  发表于: 2012-09-05 12:05

 回 1楼(benjaminwan) 的帖子

我可以这样实现,但是能不能把缓冲改大呢。比如改成16改成32或64.
级别: 骑士
UID: 29604
精华: 9
发帖: 171
金钱: 1830 两
威望: 366 点
综合积分: 522 分
注册时间: 2010-10-01
最后登录: 2016-04-13
3楼  发表于: 2012-09-05 12:32
串口真正的缓冲区是比较大的,一般可以容纳512或以上。
友善的串口jni没有开放缓冲区内有效数据长度的查询功能,只有开放是否有数据的判断功能,所以不能够判断串口缓冲区里有多少数据。
我不知道你的读取是如何写的,但可以猜测得到,因每次循环读取的时间间隔很小(确切说来是16个字节读取所花的时间,10ms吧大概),所以会让人觉得每次只能读取16个字节。
如果你在的接收循环里加上Thread.sleep(50);,就会不同了(假设一直有数据接收,串口缓冲接收50ms的数据,如果是9600的波特率,大概60字节吧,然后被你的接收方法读出来),但这不是个好办法。
级别: 骑士
UID: 29604
精华: 9
发帖: 171
金钱: 1830 两
威望: 366 点
综合积分: 522 分
注册时间: 2010-10-01
最后登录: 2016-04-13
4楼  发表于: 2012-09-05 12:33
还是通过判断已接收的字节数来读取比较好。
~
级别: 新手上路
UID: 72783
精华: 0
发帖: 43
金钱: 215 两
威望: 43 点
综合积分: 86 分
注册时间: 2012-06-28
最后登录: 2012-10-28
5楼  发表于: 2012-09-05 12:47
关键是我这里可以判断数据是否结束,然后把数据拼接。但是我发,对方接受好像也有这个问题,不是一次发出去的。而对方是成品,不能随便改。所以如果能设置缓冲区最好了。。。。
级别: 骑士
UID: 29604
精华: 9
发帖: 171
金钱: 1830 两
威望: 366 点
综合积分: 522 分
注册时间: 2010-10-01
最后登录: 2016-04-13
6楼  发表于: 2012-09-05 14:54
代码的运行是毫秒以下级别的,而串口接收是毫秒以上级别的,代码读取(这个过程很快),等待串口接收下一字节数据(这个过程较慢),以计算机的角度来看的话,总是代码在等待串口接收。
串口的发送和接收一般不在同一线程,发送也是由代码把数据写到串口缓冲区(这个过程很快),然后由串口慢慢发送。
印象中,唯一有例外的是VB6的串口控件,VB6程序发送串口数据不管长度多少,实际接收方收到时,都是1字节1字节地收到的。
另外,只有Windows桌面中使用的串口控件,如C#/VB.Net/VB6/C++bulde/delphi等,才有查询串口接收缓冲区中有多少未读数据的功能。
例如VB.net可以如此
Do
                System.Windows.Forms.Application.DoEvents()
                If isTimeOut() Then Exit Sub  '超时判断
Loop Until SerialPort1.BytesToRead > 35  '循环等待直到串口缓冲区内可读取的字节数大于35字节
------------------------------------------------------------------------------------------------------------------------------------
例如C#是这样
while (serialPort1.BytesToRead < 35) //当串口缓冲区内可读取字节小于35时循环等待
{
   if (isTimeOut()){return;}
   Application.DoEvents();
}
这个扯得有点远了。
总之,一般串口通讯不会以长度来判断,还是必须有一个通讯协议的,至少有个校验位以防止误码。
级别: 骑士
UID: 29604
精华: 9
发帖: 171
金钱: 1830 两
威望: 366 点
综合积分: 522 分
注册时间: 2010-10-01
最后登录: 2016-04-13
7楼  发表于: 2012-09-05 15:00
c++builder/delphi有些串口控件还能实现更高级的功能,确实能够实现你所说的功能。
这种串口控件除了串口缓冲区,接收还有一个控件的缓冲区,可以通过设置控件属性,自动判断起始字节或结束字节或到达某个长度,从而自动产生事件通知,确实非常方便。
级别: 新手上路
UID: 77175
精华: 0
发帖: 21
金钱: 105 两
威望: 21 点
综合积分: 42 分
注册时间: 2012-09-04
最后登录: 2018-12-25
8楼  发表于: 2014-04-11 15:34
今天也发现了这个问题,折腾了半天,恍然醒悟,这是因为一发现缓存有数据,就立马读回来,这样串口才来得及传输16字节数据,只要在发现有数据,但read之间加上一定的延时(根据自己的数据帧长度),这样就能读取完整的一帧数据了。err = HardwareControler.select(serial_fd, 2, 0);
            if (err == 1)
            {
                try
                {
                    Thread.sleep(200);
                } catch (InterruptedException e)
                {

                    e.printStackTrace();
                }
                int len = HardwareControler.read(serial_fd, buf, buf.length);
           }
级别: 新手上路
UID: 102780
精华: 0
发帖: 1
金钱: 5 两
威望: 1 点
综合积分: 2 分
注册时间: 2014-04-10
最后登录: 2014-04-12
9楼  发表于: 2014-04-12 13:00
请问一下我也是用的友谊之臂提供的read方法 但是只能从设配向PC写数据,不能读取到PC发过来的信息  请指点一下 邮箱haizhenweb@163.com