IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]ubuntu下串口编程备忘

    mao0514发表于 2017-02-15 10:22:12
    love 0
    弄了一下串口,一个小问题多折腾了下,备忘。
    软件环境:
    zl@zhanglong:~$ cat /etc/lsb-release 
    DISTRIB_ID=Ubuntu
    DISTRIB_RELEASE=12.04
    DISTRIB_CODENAME=precise
    DISTRIB_DESCRIPTION="Ubuntu 12.04.4 LTS"
    zl@zhanglong:~$uname -a
    Linux zhanglong 3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 17:37:58 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
    硬件环境:
        另有一台win7,有串口及读写串口的工具软件。两机通过交叉串口线相连

    代码如下:

    点击(此处)折叠或打开

    1. #include <stdio.h>
    2. #include <string.h>
    3. #include <unistd.h>
    4. #include <fcntl.h> 
    5. #include <errno.h>
    6. #include <termios.h>

    7. /**
    8.  * 写/读数据
    9.  **/

    10. int main(int argc, char* argv[])
    11. {
    12.     int i;
    13.     int fd; /* File descriptor for the port */
    14.     int iRet;
    15.     char buf[1024];

    16.     fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    17.     if (fd < 0) { /** error **/
    18.         printf("[%s-%d] open error!!!\n", __FILE__, __LINE__);
    19.         goto err1;
    20.     } 
    21.     //fcntl(fd, F_SETFL, FNDELAY);
    22.     fcntl(fd, F_SETFL, 0);

    23.     iRet = write(fd, "a1b2c3\r", 7);
    24.     if (iRet < 0) {
    25.         printf("[%s-%d] write error!!!\n", __FILE__, __LINE__);
    26.     }

    27.     iRet = read(fd, buf, 1024);
    28.     for(i = 0; i < iRet; i++) {
    29.         if((i & 0xf) == 0) {
    30.             printf("\n");
    31.         }
    32.         printf("0x%02x ", buf[i]);
    33.         fflush( fflush(stdout));
    34.     }
    35.     printf("\n");

    36.     close(fd);
    37. err1:
    38.     return 0;
    39. }
    编译运行此代码后发现:
          win7能够收到ubuntu发出的数据,但win7发出的数据,自己意外收到了,而ubuntu却收不到。或有时能收到数据(如win7以十六进制发4567890a时,ubuntu能收到数据0x45 0x67 0xffffff89 0x0a)。
      将char buf[1024]数组改成unsigned char buf[1024]后,0xffffff89变成了0x89。
      win7机器上单独发以十六进制,先发"7890a",ubuntu无打印输出,再发"457890a",ubuntu无打印输出,然后发"4567890a"时,ubuntu上的程序打印收到的数据,并且前面几次发出的都收到了。
      网上发现一说法,如果不是终端,使用Raw Mode方式来通讯。偿试将串口设置成Raw Mode,再读数据。

        修改后的代码如下:

    点击(此处)折叠或打开

    1. #include <stdio.h>
    2. #include <string.h>
    3. #include <unistd.h>
    4. #include <fcntl.h> 
    5. #include <errno.h>
    6. #include <termios.h>

    7. /**
    8.  * 读数据
    9.  **/

    10. int main(int argc, char* argv[])
    11. {
    12.     int i;
    13.     int fd; /* File descriptor for the port */
    14.     int iRet;
    15.     struct termios options_old, options;
    16.     unsigned char buf[1024];

    17.     fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    18.     if (fd < 0) { /** error **/
    19.         printf("[%s-%d] open error!!!\n", __FILE__, __LINE__);
    20.         goto err1;
    21.     } 
    22.     //fcntl(fd, F_SETFL, FNDELAY);
    23.     fcntl(fd, F_SETFL, 0);

    24.     /*********************************************************/
    25.     /** * Get the current options for the port... **/
    26.     tcgetattr(fd, &options);
    27.     options_old = options;
    28.     /*** Set the baud rates to 9600... **/
    29. // cfsetispeed(&options, B9600);
    30. // cfsetospeed(&options, B9600);

    31.     options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
    32.     //options.c_oflag |= OPOST; /** 加工过的输出 **/
    33.     options.c_oflag &= ~OPOST; /** 选择原始输出 **/

    34.     /*** Enable the receiver and set local mode... **/
    35. // options.c_cflag |= (CLOCAL | CREAD);

    36.     /*** Set the new options for the port... **/
    37.     tcsetattr(fd, TCSANOW, &options);
    38.     /*********************************************************/

    39.     iRet = write(fd, "a1b2c3\r", 7);
    40.     if (iRet < 0) {
    41.         printf("[%s-%d] write error!!!\n", __FILE__, __LINE__);
    42.     }

    43.     iRet = read(fd, buf, 1024);
    44.     for(i = 0; i < iRet; i++) {
    45.         if((i & 0xf) == 0) {
    46.             printf("\n");
    47.         }
    48.         printf("0x%02x ", buf[i]);
    49.         fflush(stdout);
    50.     }
    51.     printf("\n");

    52.     tcsetattr(fd, TCSANOW, &options_old);
    53.     close(fd);
    54. err1:
    55.     return 0;
    56. }
    简单测试,发现win7每次发出数据,ubuntu一端都可以收到。并且win7一端没有再收到自己发出的数据。
         但win7一次发出很长一段数据(如456789abcdef)时,ubuntu只收到前面的数据(0x34 0x35 0x36 0x37 0x38 0x39 0x61 0x62)。估计是串口速度慢,read()系统调用等不了那么长时间,接收到一部分数据后就返回了。
                   测试循环执行read()系统调用,并打印收到的数据,确实可以收到更多数据。

    至此,问题已经清晰:ubuntu下的/dev/ttyS0设备打开时,默认设置了终端相关的特性,会根据收到不同的数据做出不同的反应。如果用作纯粹的数据传输通道,需要进行设置,去除终端相关特性设定。


沪ICP备19023445号-2号
友情链接