串口回环实验

写在前边

本文是B站up主韦东山4_10-6_Linux串口应用编程_回环_哔哩哔哩_bilibili视频的笔记,其中有些部分博主也没有理解,希望各位辩证的看。

面向有连接型

在串口应用实验中,根据视频信息,需要将串口6的发送和接收引脚连起来,在整个原理图中并未找到串口6,而且这里也没有购买扩展口,所以一直未找到串口6的位置,最后在百问网的问答贴中才找到了J5的复用接口:

串口应用编程 1MX6ULL J5原理图

串口应用编程 2MX6ULL J5复用原理图

串口应用编程 3实物连接图

连接完成后进行软件编程,这里软件编程主要就是完成串口的基本设置,最后在while循环中一直循环发送后读取数据。

这里的主要是实现串口的初始化和设置函数,接下来一个一个分析。

初始化函数:

/* com参数的格式为"/dev/ttySAC1" (串口文件描述符)*/

int open_port(char* com)

{

       int fd;

       //fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY);

       // 打开串口,获得文件描述符,O_NOCTTY:如果路径名指向终端设备,不要把这个设备用作控制终端。

       fd = open(com, O_RDWR | O_NOCTTY);

       if (-1 == fd) {

              return(-1);

       }

       if (fcntl(fd, F_SETFL, 0) < 0) /* 设置串口为阻塞状态*/

       {

              printf("fcntl failed!\n");

              return -1;

       }

       return fd;

}

这个函数主要就是打开串口设备节点,然后获得串口的文件描述符fd。

设置串口参数函数:

/* set_opt(fd,115200,8,'N',1)

* 设置串口参数

*/

int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop)

{

       struct termios newtio, oldtio;

       /*

       * tcgetattr函数用于获取与终端相关的参数。参数fd为终端的文件描述符,返回的结果保存在termios结构体中

       * tcflag_t c_iflag;     

       * tcflag_t c_oflag;     

       * tcflag_t c_cflag;     

       * tcflag_t c_lflag;    

       * cc_t     c_cc[NCCS];

       * 在配置终端之前,通常需要先保存当前的终端属性,

       * 以便在配置完成后可以恢复到原来的状态。这样可以

       * 避免对终端的其他部分产生不必要的影响

       */

       if (tcgetattr(fd, &oldtio) != 0) {

              perror("SetupSerial 1");

              return -1;

       }



       bzero(&newtio, sizeof(newtio));

       newtio.c_cflag |= CLOCAL | CREAD;

       newtio.c_cflag &= ~CSIZE;



       newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/

       newtio.c_oflag &= ~OPOST;   /*Output*/

       // 设置数据位

       switch (nBits)

       {

       case 7:

              newtio.c_cflag |= CS7;

              break;

       case 8:

              newtio.c_cflag |= CS8;

              break;

       }

       // 设置校验位

       switch (nEvent)

       {

       case 'O':

              newtio.c_cflag |= PARENB;

              newtio.c_cflag |= PARODD;

              newtio.c_iflag |= (INPCK | ISTRIP);

              break;

       case 'E':

              newtio.c_iflag |= (INPCK | ISTRIP);

              newtio.c_cflag |= PARENB;

              newtio.c_cflag &= ~PARODD;

              break;

       case 'N':

              newtio.c_cflag &= ~PARENB;

              break;

       }

       // 设置通信波特率

       switch (nSpeed)

       {

       case 2400:

              cfsetispeed(&newtio, B2400);

              cfsetospeed(&newtio, B2400);

              break;

       case 4800:

              cfsetispeed(&newtio, B4800);

              cfsetospeed(&newtio, B4800);

              break;

       case 9600:

              cfsetispeed(&newtio, B9600);

              cfsetospeed(&newtio, B9600);

              break;

       case 115200:

              cfsetispeed(&newtio, B115200);

              cfsetospeed(&newtio, B115200);

              break;

       default:

              cfsetispeed(&newtio, B9600);

              cfsetospeed(&newtio, B9600);

              break;

       }

       // 设置停止位

       if (nStop == 1)

              newtio.c_cflag &= ~CSTOPB;

       else if (nStop == 2)

              newtio.c_cflag |= CSTOPB;



       newtio.c_cc[VMIN] = 1;  /* 读数据时的最小字节数: 没读到这些数据我就不返回! */

       newtio.c_cc[VTIME] = 0; /* 等待第1个数据的时间:

                                                  * 比如VMIN设为10表示至少读到10个数据才返回,

                                                  * 但是没有数据总不能一直等吧? 可以设置VTIME(单位是10秒)

                                                  * 假设VTIME=1,表示:

                                                  *    10秒内一个数据都没有的话就返回

                                                  *    如果10秒内至少读到了1个字节,那就继续等待,完全读到VMIN个数据再返回

                                                  */



       tcflush(fd, TCIFLUSH);

       // 设置新终端属性

       if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)

       {

              perror("com set error");

              return -1;

       }

       //printf("set done!\n");

       return 0;

}

这个函数中主要实现了对串口的基本参数的设置:波特率、停止位、校验位等,其中,这里还保存了之前串口的设置,可以后期自己在使用完成后恢复之前的串口设置:

串口应用编程 4保存串口之前设置

串口之前的设置保存在oldtio结构体中。

串口应用编程 5设置最少接收到数据返回

这里设置最小接收到1个字节数据才返回,一直等待。

这两个函数实现完成后,在主函数中调用即可,而且后续再次使用时,一般不需要更改这两个函数内部,只需要在外部调用即可。

主函数:

int main(int argc, char** argv)

{

       int fd;

       int iRet;

       char c;



       /* 1. open */



       /* 2. setup

        * 115200,8N1

        * RAW mode

        * return data immediately

        */



        /* 3. write and read */



       if (argc != 2)

       {

              printf("Usage: \n");

              printf("%s </dev/ttySAC1 or other>\n", argv[0]);

              return -1;

       }



       fd = open_port(argv[1]);

       if (fd < 0)

       {

              printf("open %s err!\n", argv[1]);

              return -1;

       }



       iRet = set_opt(fd, 115200, 8, 'N', 1);

       if (iRet)

       {

              printf("set port err!\n");

              return -1;

       }



       printf("Enter a char: ");

       while (1)

       {

              scanf("%c", &c);

              if (c == 'Q')

              {

                     break;

              }

              iRet = write(fd, &c, 1);

              iRet = read(fd, &c, 1);

              if (iRet == 1)

                     printf("get: %02x %c\n", c, c);

              else

                     printf("can not get data\n");

       }



       return 0;

}

实现结果是完成串口回环,即向控制台发送数据,串口接受到数据之后,将这个数据返回到控制台处,具体运行结果如下图。

串口应用编程 6运行程序结果

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值