USB Gadget serial应用实例(下)

描述

3. 编程

PC: open/read/write  /dev/ttyACM0

板子: open/read/write  /dev/ttyGS0

源码:

#include < stdio.h >
#include < string.h >
#include < sys/types.h >
#include < errno.h >
#include < sys/stat.h >
#include < fcntl.h >
#include < unistd.h >
#include < termios.h >
#include < stdlib.h >
#include < pthread.h >

static struct termios old, current;

/* Initialize new terminal i/o settings */
void initTermios(int echo) 
{
  tcgetattr(0, &old); /* grab old terminal i/o settings */
  current = old; /* make new settings same as old settings */
  current.c_lflag &= ~ICANON; /* disable buffered i/o */
  if (echo) {
      current.c_lflag |= ECHO; /* set echo mode */
  } else {
      current.c_lflag &= ~ECHO; /* set no echo mode */
  }
  tcsetattr(0, TCSANOW, ¤t); /* use these new terminal i/o settings now */
}

/* Restore old terminal i/o settings */
void resetTermios(void) 
{
  tcsetattr(0, TCSANOW, &old);
}

/* set_opt(fd,115200,8,'N',1) */
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
 struct termios newtio,oldtio;
 
 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;
}

int open_port(char *com)
{
 int fd;
 //fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY);
 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;
}

static void *my_read_thread_func(void *data)
{
    int fd = (int)data;
    int iRet;
    char c;
    
 while (1)
 {
  iRet = read(fd, &c, 1);
        printf("%c", c);
        fflush(stdout);
 }
}

/*
 * ./serial_send_recv < dev >
 */
int main(int argc, char **argv)
{
 int fd;
 int iRet;
 char c;
 pthread_t tid;

 /* 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;
 }

 /* 创建一个读线程 */
 iRet = pthread_create(&tid, NULL, my_read_thread_func, (void *)fd);
 if (iRet)
 {
  printf("pthread_create err!n");
  return -1;
 }

 printf("Enter a char: ");
  initTermios(1);
    
  // 写线程
 while (1)
 {  
        c = getchar();
  iRet = write(fd, &c, 1);
  if (iRet != 1)
   printf("can not write datan");
 }
    resetTermios();

 return 0;
}

4. 上机实验

编译 2 个版本,有两条命令:PC、ARM

gcc -o serial_send_recv_pc serial_send_recv.c -lpthread

arm-buildroot-linux-gnueabihf-gcc -o serial_send_recv_arm serial_send_recv.c -lpthread

使用 USB 线连接板子的 OTG 口、PC 的 USB 口,PC 上监测到 USB 串口后把它连接到 VMWare,确定:

  • 开发板上有设备节点:/dev/ttyGS0
  • Ubuntu上有设备节点:/dev/ttyACM0

测试:

  • 在 Ubuntu 上执行:sudo ./serial_send_recv_pc /dev/ttyACM0
  • 在板子上执行:sudo ./serial_send_recv_arm /dev/ttyGS0
  • 双方即可互发数据
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分