linux串口拼接,Linux下串口操作之數據拼接

串口操作中,特別以非阻塞的方式讀取和發送數據,做好進程之間的同步很重要。有時我們會發現這樣一個問題,在進行read操作時,一次read不能獲得一個完整的數據幀,這就好比你買了一個電腦,送貨的先把顯示器送到你家,再把機箱送到,你會發現還少鍵盤鼠標什么的,又要過幾天才送,這會讓你急死。很不幸,在串口操作的時候,接受數據很可能就是這樣分批收貨的,但是幸運的是,接受數據的動作很快,別忘了計算機就是靠速度這一點,拋開這個,啥都不是。

很自然的,我們就會進行數據的拼接,將一堆零散的數據拼接成一個個有用的數據幀,哈哈,變廢為寶。說多了讓人很煩,舉個例子吧。

假如我們定義的數據幀是以'$'開頭,以‘#’結尾的。

首先定義了兩個字符數組:

//一個緩沖數組,用來存放每一次讀到的數據

char read_data[256]={0};

//存放一個完整的數據幀,以便處理

char read_buf[256]={0};

再看看憑借數據的函數是怎么樣實現的:

//得到了一個完整的數據幀

void get_complete_frame()

{

char read_tmp[256]={0};

int return_flag=0;

int i;

//存放讀取到的字節數

while(1)

{

memset(read_tmp,0,sizeof(read_tmp));

if(read(fd, read_tmp, sizeof(read_tmp))>0)

{

//數據幀的拼接

printf("read_tmp: %s\n",read_tmp);

for( i=0;i

{

if(read_tmp[i]=='$')

{

memset(read_data,0,sizeof(read_data));

char tmp[5]={0};

tmp[0]=read_tmp[i];

strcat(read_data,tmp);

}

else if(read_tmp[i]=='#')

{

char tmp[5]={0};

tmp[0]=read_tmp[i];

strcat(read_data,tmp);

return_flag=1;

memset(read_buf,0,sizeof(read_buf));

//遇到幀尾,將read_data幀拷貝到read_buf中,以便處理

memcpy(read_buf,read_data,sizeof(read_data));

}

else

{

char tmp[5]={0};

tmp[0]=read_tmp[i];

strcat(read_data,tmp);

}

}

//有了一個完整的數據幀就返回處理

if(return_flag==1)

return;

}

else//讀不到數據就返回,以便檢查對方是否斷線

return;

usleep(100000);

}

}

從上面的代碼中,我們可以看到,每一次從串口讀取數據,將讀到的數據放在read_tmp中。對這個數組進行逐個地字符分析,遇到幀頭標志就清空緩沖數組read_data中,保證了緩沖數組中的數組都是以‘$’開頭的;如果遇到了幀尾,哈,我們現在遇到有了一個完整的幀啦,可以去處理幀咯,將數據幀拷貝到read_buf中,程序直接對read_buf進行處理,處理之前別忘了幀尾后面的字符是新的一楨的開頭部分,要把它們也保存下來。在程序中我們看到讀不到數據就返回,如果不返回,這個函數就會一直運行,那么這樣做的效果不就等價於阻塞操作了么,非阻塞就失去了其意義。

大概就這樣吧。

在 Android 中,可以通过使用 `SerialPort` 类来进行串口通信,其中可以使用 `InputStream` 来读取串口数据。在读取串口数据时,需要注意数据的拆包和拼接。 一般情况下,串口通信中的数据都是按照固定长度的数据包进行传输的。因此,在读取串口数据时,可以先读取数据包的包头,然后根据包头中的信息来确定数据包的长度,最后读取完整数据包。 以下是一个简单的示例代码,演示了如何在 Android 中进行串口数据的拆包和拼接: ```java public class SerialPortActivity extends AppCompatActivity { private SerialPort mSerialPort; private InputStream mInputStream; private final int PACKET_HEADER = 0xAA; // 数据包包头 private int mPacketLength = 0; // 数据包长度 private byte[] mPacketData = new byte[1024]; // 数据数据 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_serial_port); try { // 打开串口 mSerialPort = new SerialPort(new File("/dev/ttyS1"), 115200, 0); mInputStream = mSerialPort.getInputStream(); } catch (IOException e) { e.printStackTrace(); } // 开启一个线程来读取串口数据 new Thread(new Runnable() { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { try { // 读取一个字节的数据 int data = mInputStream.read(); // 判断是否为包头 if (data == PACKET_HEADER) { // 读取数据包长度 mPacketLength = mInputStream.read(); // 读取数据数据 for (int i = 0; i < mPacketLength; i++) { mPacketData[i] = (byte) mInputStream.read(); } // 拼接完整数据包 byte[] packet = new byte[mPacketLength + 2]; packet[0] = (byte) PACKET_HEADER; packet[1] = (byte) mPacketLength; System.arraycopy(mPacketData, 0, packet, 2, mPacketLength); // 处理数据包 handlePacket(packet); } } catch (IOException e) { e.printStackTrace(); } } } }).start(); } private void handlePacket(byte[] packet) { // 在这里处理完整数据包 // ... } @Override protected void onDestroy() { super.onDestroy(); // 关闭串口 if (mSerialPort != null) { mSerialPort.close(); } } } ``` 在上面的示例代码中,当读取到包头后,先读取数据包的长度,然后再读取数据包的数据。最后,使用 `System.arraycopy()` 方法将包头和数据拼接成一个完整数据包,然后再将其传递给 `handlePacket()` 方法进行处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值