Armadilloフォーラム

シリアル通信で0x00の送信

morimori

2015年10月3日 20時06分

お世話になっております、森下と申します。

シリアル通信で0x00が含まれるデータを送信すると0x00以降が送信されません。
3Byteの数値データを送ろうとしています。
どのようにしたら0x00も送ることができますでしょうか。

下記に「FAQ : シリアル通信をおこなうプログラムを作成するには?」
http://armadillo.atmark-techno.com/faq/serial-programming
をベースにしたソースを添付します。

下記のプログラムを実行するとシリアル通信のデバッグツールで受信すると
02 04 までしか受信できません。

どうかご教授のほどよろしくお願いいたします。

#include
#include
#include
#include
#include
#include

#define SERIAL_PORT "/dev/ttymxc1" /* シリアルインターフェースに対応するデバイスファイル */
#define BAUDRATE B19200

int main(int argc, char *argv[])
{
char buf[5]; /* バッファ */
int fd; /* ファイルディスクリプタ */
struct termios oldtio, newtio; /* シリアル通信設定 */

fd = open(SERIAL_PORT, O_RDWR); /* デバイスをオープンする */

ioctl(fd, TCGETS, &oldtio); /* 現在のシリアルポートの設定を待避させる */
newtio = oldtio; /* ポートの設定をコピー */
newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
ioctl(fd, TCSETS, &newtio); /* ポートの設定を有効にする */

buf[0] = 0x02;
buf[1] = 0x04;
buf[2] = 0x00;
buf[3] = 0x06;
buf[4] = 0x03;

write(fd, buf, sizeof(buf)); /* デバイスへ5バイト書き込み */

ioctl(fd, TCSETS, &oldtio); /* ポートの設定を元に戻す */
close(fd); /* デバイスのクローズ */

return 0;
}

コメント

中村です。

> ioctl(fd, TCGETS, &oldtio); /* 現在のシリアルポートの設定を待避させる */
> newtio = oldtio; /* ポートの設定をコピー */
> newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
> ioctl(fd, TCSETS, &newtio); /* ポートの設定を有効にする */

この部分を次のように変更してみてください。
(エラーチェックを省略していますが、チェックをするようにしてくださいね)

    tcgetattr(fd, &oldtio);
    newtio = oldtio;
    cfmakeraw(&newtio);
    cfsetispeed(&newtio, BAUDRATE);
    cfsetospeed(&newtio, BAUDRATE);
    tcsetattr(fd, TCSAFLUSH, &newtio);

最後のtcsetattrの第2引数TCSAFLUSHは
TCSANOWでもいいかもしれません。

一応、これ(↓)も書いておきます。
man tty_ioctlから引用
ioctl を 使 用 す る と 移 植性のないプログラムになる。可能な場合は、
termios(3) に記述されている POSIX インタフェースを使うこと。

ここで言っている「termios(3) に記述されている POSIX インタフェース」とは、
次のような関数です。
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
int tcsendbreak(int fd, int duration);
int tcdrain(int fd);
int tcflush(int fd, int queue_selector);
int tcflow(int fd, int action);
void cfmakeraw(struct termios *termios_p);
speed_t cfgetispeed(const struct termios *termios_p);
speed_t cfgetospeed(const struct termios *termios_p);
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
int cfsetspeed(struct termios *termios_p, speed_t speed);

--
なかむら

中村です。

訂正です。すみません。

> ここで言っている「termios(3) に記述されている POSIX インタフェース」とは、
> 次のような関数です。
> int tcgetattr(int fd, struct termios *termios_p);
> int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
> int tcsendbreak(int fd, int duration);
> int tcdrain(int fd);
> int tcflush(int fd, int queue_selector);
> int tcflow(int fd, int action);
> void cfmakeraw(struct termios *termios_p);
> speed_t cfgetispeed(const struct termios *termios_p);
> speed_t cfgetospeed(const struct termios *termios_p);
> int cfsetispeed(struct termios *termios_p, speed_t speed);
> int cfsetospeed(struct termios *termios_p, speed_t speed);
> int cfsetspeed(struct termios *termios_p, speed_t speed);

termiosのmanをよく読まずにmanページからコピペしてしまいました。
次の2つはPOSIXでは規定されてないそうです。
void cfmakeraw(struct termios *termios_p);
int cfsetspeed(struct termios *termios_p, speed_t speed);

POSIX標準ではないですが、Linuxで使えます。

--
なかむら

なかむら 様

早速のご回答ありがとうございます。

うまく動作することができました。

ご丁寧な回答をいただきありがとうございました。

森下