0

データを有効にするためにシリアルポートとgpioを使用して、アーム開発ボードにRS485を実装しています。

送信前にデータ イネーブルを High に設定していますが、送信が完了したら Low に設定したいと考えています。

次のように書くだけで簡単に実行できます。

//fd = open("/dev/ttyO2", ...);
DataEnable.Set(true);
write(fd, data, datalen);
tcdrain(fd); //Wait until all data is sent
DataEnable.Set(false);

ブロッキング モードからノンブロッキング モードに変更し、fd で poll を使用したいと考えていました。しかし、「送信完了」に対応するポーリング イベントが表示されません。

すべてのデータが送信されたときに通知を受け取るにはどうすればよいですか?

システム: Linux 言語: c++ ボード: BeagleBone Black

4

2 に答える 2

1

ありえないと思います。別のスレッドで実行tcdrainしてメイン スレッドに通知させるか、timeout onpollを使用してポーリングし、出力が排出されたかどうかを確認する必要があります。

ioctl を使用してTIOCOUTQ、出力バッファー内のバイト数を取得し、ボーレートに従ってタイムアウトを調整できます。これにより、必要なポーリングの量が 1 回か 2 回に減るはずです。何かのようなもの:

 enum { writing, draining, idle } write_state;
 while(1) {
     int write_event, timeout = -1;
     ...
     if (write_state == writing) {
         poll_fds[poll_len].fd = write_fd;
         poll_fds[poll_len].event = POLLOUT;
         write_event = poll_len++
     } else if (write == draining) {
         int outq;
         ioctl(write_fd, TIOCOUTQ, &outq);
         if (outq == 0) {
             DataEnable.Set(false);
             write_state = idle;
         } else {
             // 10 bits per byte, 1000 millisecond in a second
             timeout = outq * 10 * 1000 / baud_rate; 
             if (timeout < 1) {
                 timeout = 1;
             }
         }
     }
     int r = poll(poll_fds, poll_len, timeout);
     ...
     if (write_state == writing && r > 0 && (poll_fds[write_event].revent & POLLOUT)) {
         DataEnable.Set(true); // Gets set even if already set. 
         int n = write(write_fd, write_data, write_datalen);
         write_data += n;
         write_datalen -= n;
         if (write_datalen == 0) {
             state = draining;
         }
     }
 }
于 2014-08-27T05:47:42.367 に答える
0

古いスレッドですが、Linux で 16550 互換の UART を使用して RS-485 に取り組んでおり、

  • tcdrain は機能しますが、10 ~ 20 ミリ秒の遅延が追加されます。投票されているようです
  • TIOCOUTQ によって返される値は、OS バッファー内のバイトをカウントしているように見えますが、UART FIFO 内のバイトをカウントしていないようです。そのため、送信が既に開始されている場合、必要な遅延を過小評価する可能性があります。

私は現在 CLOCK_MONOTONIC を使用して各送信にタイムスタンプを付け、送信がいつ完了するかを計算し、その時間を次の送信と比較してチェックし、必要に応じて遅延します。悪いが、うまくいくようだ

于 2016-05-04T17:45:24.077 に答える