精华内容
下载资源
问答
  • 在rk3288android5.1平台上,一个USB固定一个ttyUSB节点,例如有4个USB口,则USB0/1/2/3分别固定ttyUSB6/7/8/9. 实现思路: 根据USB的设备名去识别USB串口插入的是哪个U口,再不同的U口给他分配一个不同的节点,...

    该技术点实现的功能:

        在rk3288 android5.1平台上,一个USB固定一个ttyUSB节点,例如有4个USB口,则USB0/1/2/3分别固定ttyUSB6/7/8/9.

    实现思路:

    根据USB的设备名去识别USB串口插入的是哪个U口,再不同的U口给他分配一个不同的节点,具体内容如下

    当USB转串设备插入U口,驱动会识别到设备插入到的是哪个口,并把对应口的字符串保存到dev结构体里,对应保存的字符串的内容,可以在插拔USB串口的打印信息中看到:

    USB转串设备插入第一个USB口,dev名字为2-1,插入第二个USB口名字为4-1.1 ,第三个为4-1.2,第四个为4-1.3 (第一个USB口为原生口,后三个为HUB扩出的口)

     

    在usb-serial.c文件中的get_free_serial函数下,传入dev的name,根据这个name,给串口分配固定的节点:

    diff --git a/kernel/drivers/usb/serial/usb-serial.c b/kernel/drivers/usb/serial/usb-serial.c
    index 80d689f0fd..0b17b3e7cd 100644
    --- a/kernel/drivers/usb/serial/usb-serial.c
    +++ b/kernel/drivers/usb/serial/usb-serial.c
    @@ -79,7 +79,7 @@ struct usb_serial *usb_serial_get_by_index(unsigned index)
     }
      
     static struct usb_serial *get_free_serial(struct usb_serial *serial,
    -                                       int num_ports, unsigned int *minor)
    +                                       int num_ports, unsigned int *minor, char * dev_name)
     {
            unsigned int i, j;
            int good_spot;
    @@ -101,7 +101,23 @@ static struct usb_serial *get_free_serial(struct usb_serial *serial,
                            }
                    if (good_spot == 0)
                            continue;
    -
    +              
    +               if(!strcmp(dev_name,"2-1")) //USB0
    +               {
    +                       i = 6;
    +               }
    +               else if(!strcmp(dev_name,"4-1.1"))
    +               {
    +                       i = 7; 
    +               }
    +               else if(!strcmp(dev_name,"4-1.2"))
    +                {
    +                        i = 8;
    +                }
    +               else if(!strcmp(dev_name,"4-1.3"))
    +                {
    +                        i = 9;
    +                }
                    *minor = i;
                    j = 0;
                    dev_dbg(&serial->interface->dev, "%s - minor base = %d\n", __func__, *minor);
    @@ -1055,8 +1071,9 @@ static int usb_serial_probe(struct usb_interface *interface,
             * registered.
             */
            serial->disconnected = 1;
    +      
      
    -       if (get_free_serial(serial, num_ports, &minor) == NULL) {
    +       if (get_free_serial(serial, num_ports, &minor,dev_name(&port->serial->dev->dev)) == NULL) {
                    dev_err(ddev, "No more free serial devices\n");
                    goto probe_error;
            }

     

    展开全文
  • ttyUSB 串口编程 Linux下 USB转串口

    万次阅读 2017-04-06 16:43:18
    在Linux下对设备的操作方法与对文件的操作方法是一样的,因此对串口的读写就可以使用简单的read()、write()函数来完成,所不同的是只是需要对串口的其他参数进行其他配置,本文实现的是宿主机实现写功能,目标机实现...

    
    
    转:http://www.360doc.com/content/12/0222/15/1317564_188649565.shtml


    在Linux下对设备的操作方法与对文件的操作方法是一样的,因此对串口的读写就可以使用简单的read()、write()函数来完成,所不同的是只是需要对串口的其他参数进行其他配置,本文实现的是宿主机实现写功能,目标机实现读功能,采用单工方式的串口通信,下面针对我个人的mini2440开发板简单介绍下串口应用开发的步骤。

      笔者的操作系统 Ubuntu 10.10; 使用USB转串口:/dev/ttyUSB0; 开发板mini2440,开发板串口:/dev/ttySAC0  (电脑中串口名称不一定一样)

      1.打开串口,这里使用函数open_port.c实现。

      2.设置串口参数,这里使用函数set_com_config.c实现。

      3.读写串口,宿主机上是com_writer.c;目标机上是com_reader_arm9.c

      以下再分别展开介绍上面步骤的详细子步骤:

      1.打开串口函数open_port.c实现步骤:

    (1)利用open()函数打开:

    1)针对宿主机的串口打开方法:
    fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NDELAY);

    2)针对目标机的串口打开方法:

    fd = open("/dev/ttySAC0",O_RDWR | O_NOCTTY | O_NDELAY);

     

    (2)利用fcntl()函数恢复串口的为阻塞状态,用于等待串口数据的读入:

    fcntl(fd, F_SETFL, 0)

     

    (3)利用isatty()函数测试打开的文件描述符是否链接到一个终端设备,以进一步确认串口是否正确打开:

    isatty(STDIN_FILENO);

     

    (4)打开宿主机的串口程序open_port.c如下所示:

     
    [cpp]  view plain copy
    1. /*打开宿主机串口函数*/  
    2. #define MAX_COM_NUM 3  
    3. int open_port(int com_port)  
    4. {  
    5.         int fd;  
    6. //#if (COM_TYPE == GNR_COM)    /*use general Serial port*/  
    7. //      char *dev[] = {"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};  
    8. //#else /*use USB turn Serial port*/  
    9.         char *dev[] = {"/dev/ttyUSB0","/dev/ttyUSB1","/dev/ttyUSB2"};               //使用USB转串口。ps:用预处理没能成功选择,望指教??  
    10. //#endif  
    11.         if((com_port < 0) || (com_port > MAX_COM_NUM))  
    12.                return -1;  
    13.    
    14.         /*打开串口*/  
    15.         fd = open(dev[com_port - 1], O_RDWR | O_NOCTTY | O_NDELAY);  
    16.         if(fd < 0)  
    17.         {  
    18.                perror("open serial port");  
    19.                return -1;  
    20.         }  
    21.    
    22.         /*恢复串口为阻塞状态*/  
    23.         if(fcntl(fd, F_SETFL, 0) < 0)  
    24.         {  
    25.                perror("fcntl F_SETFL\n");  
    26.                return -1;  
    27.         }  
    28.    
    29.         /*测试是否为终端设备*/  
    30.         if(isatty(STDIN_FILENO) == 0)  
    31.         {  
    32.                perror("standard input is not a terminal device");  
    33.                return -1;  
    34.         }  
    35.         return fd;  
    36. }  

     

    (5)打开目标机(mini2440开发板)串口程序open_port_arm9.c(不同的就只是在char *dev[]那里):

     
    [cpp]  view plain copy
    1. /*打开开发板串口程序open_port_arm9.c (不同的就只是在char *dev[]那里)*/  
    2. #define MAX_COM_NUM 3  
    3. int open_port(int com_port)  
    4. {  
    5.         int fd;  
    6. //#if (COM_TYPE == GNR_COM)    /*use general Serial port*/  
    7. //      char *dev[] = {"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};  
    8. //#else /*use USB turn Serial port*/  
    9. //      char *dev[] = {"/dev/ttyUSB0","/dev/ttyUSB1","/dev/ttyUSB2"};  
    10.         char *dev[] = {"/dev/ttySAC0","/dev/SAC1","/dev/SAC2"};  
    11. //#endif  
    12.         if((com_port < 0) || (com_port > MAX_COM_NUM))  
    13.                return -1;  
    14.    
    15.         /*打开串口*/  
    16.         fd = open(dev[com_port - 1], O_RDWR | O_NOCTTY | O_NDELAY);  
    17.         if(fd < 0)  
    18.         {  
    19.                perror("open serial port");  
    20.                return -1;  
    21.         }  
    22.    
    23.         /*恢复串口为阻塞状态*/  
    24.         if(fcntl(fd, F_SETFL, 0) < 0)  
    25.         {  
    26.                perror("fcntl F_SETFL\n");  
    27.                return -1;  
    28.         }  
    29.    
    30.         /*测试是否为终端设备*/  
    31.         if(isatty(STDIN_FILENO) == 0)  
    32.         {  
    33.                perror("standard input is not a terminal device");  
    34.                return -1;  
    35.         }  
    36.         return fd;  
    37. }  

      2.设置串口参数,这里使用函数set_com_config.c实现。

    (1)串口的设置主要是设置struct termios结构体的各成员值,如下所示:

     
    [cpp]  view plain copy
    1. #include<termios.h>  
    2. struct termios  
    3. {  
    4.     unsigned short c_iflag;           /*输入模式标志*/  
    5.     unsigned short c_oflag;           /*输出模式标志*/  
    6.     unsigned short c_cflag;           /*控制模式标志*/  
    7.     unsigned short c_lflag;           /*本地模式标志*/  
    8.     unsigned char c_line;             /*线路规程*/  
    9.     unsigned char c_cc[NCC];   /*控制特性*/  
    10.     speed_t c_ispeed;          /*输入速度*/  
    11.     speed_t c_ospeed;          /*输出速度*/  
    12. };  


    (2)set_com_config.c程序如下:

     
    [cpp]  view plain copy
    1. int set_com_config(int fd, int baud_rate, \  
    2.                int data_bits, char parity, int stop_bits)  
    3. {  
    4.         struct termios new_cfg,old_cfg;  
    5.         int speed;  
    6.    
    7.         /*步骤一:保存原先串口配置*/  
    8.         if(tcgetattr(fd, &old_cfg) != 0)  
    9.         {  
    10.                perror("tcgetattr");  
    11.                return -1;  
    12.         }  
    13.         new_cfg = old_cfg;  
    14.         /*步骤二:激活选项*/  
    15.         cfmakeraw(&new_cfg);   //config to raw mode  
    16.         /*步骤三:设置字符大小*/  
    17.         new_cfg.c_cflag &= ~CSIZE;     //set mask  
    18.    
    19.         /*步骤四:设置波特率*/  
    20.         switch(baud_rate)  
    21.         {  
    22.                case 2400:  
    23.                        speed = B2400;  
    24.                        break;  
    25.                case 4800:  
    26.                        speed = B4800;  
    27.                        break;  
    28.                case 9600:  
    29.                        speed = B9600;  
    30.                        break;  
    31.                case 19200:  
    32.                        speed = B19200;  
    33.                        break;  
    34.                case 38400:  
    35.                        speed = B38400;  
    36.                        break;  
    37.                default:  
    38.                case 115200:  
    39.                        speed = B115200;  
    40.                        break;  
    41.         }  
    42.         cfsetispeed(&new_cfg, speed);  
    43.         cfsetospeed(&new_cfg, speed);  
    44.    
    45.         /*步骤五:设置数据位*/  
    46.         switch(data_bits)  
    47.         {  
    48.                case 7:  
    49.                        new_cfg.c_cflag |= CS7;  
    50.                        break;  
    51.                default:  
    52.                case 8:  
    53.                        new_cfg.c_cflag |= CS8;  
    54.                        break;  
    55.         }  
    56.    
    57.         /*步骤六:设置奇偶校验位*/  
    58.         switch(parity)  
    59.         {  
    60.                default:  
    61.                case 'n':  
    62.                case 'N':  
    63.                        new_cfg.c_cflag &= ~PARENB;  
    64.                        new_cfg.c_cflag &= ~INPCK;  
    65.                        break;  
    66.           
    67.                case 'o':  
    68.                case 'O':  
    69.                        new_cfg.c_cflag |= (PARODD | PARENB);  
    70.                        new_cfg.c_cflag |= INPCK;  
    71.                        break;  
    72.                          
    73.                case 'e':  
    74.                case 'E':  
    75.                        new_cfg.c_cflag |= PARENB;  
    76.                        new_cfg.c_cflag &= ~PARODD;  
    77.                        new_cfg.c_cflag |= INPCK;  
    78.                        break;  
    79.                case 's':      //as no parity  
    80.                case 'S':  
    81.                        new_cfg.c_cflag &= ~PARENB;  
    82.                        new_cfg.c_cflag &= ~CSTOPB;  
    83.                        break;  
    84.         }//end of 'switch parity'  
    85.    
    86.         /*步骤七:设置停止位*/  
    87.         switch (stop_bits)  
    88.         {  
    89.                default:  
    90.                case 1:  
    91.                        new_cfg.c_cflag &= ~CSTOPB;  
    92.                        break;  
    93.                case 2:  
    94.                        new_cfg.c_cflag |= CSTOPB;  
    95.                        break;  
    96.         }//end of 'switch stop_bits'  
    97.    
    98.         /*步骤八:设置最少字符和等待时间*/  
    99.         new_cfg.c_cc[VTIME] = 0;  
    100.         new_cfg.c_cc[VMIN] = 1;  
    101.    
    102.         /*步骤九:处理未接收的字符*/  
    103.         tcflush(fd,TCIFLUSH);  
    104.    
    105.         /*步骤十:激活新配置*/  
    106.         if((tcsetattr(fd, TCSANOW, &new_cfg)) != 0)  
    107.         {  
    108.                perror("tcsetattr");  
    109.                return -1;  
    110.         }  
    111.         return 0;  
    112. }  


      3.读写串口,宿主机上是com_writer.c;目标机上是com_reader_arm9.c

    (1)宿主机的写程序com_writer.c程序如下:

     
    [cpp]  view plain copy
    1. /*com_writer.c*/  
    2. #include<stdio.h>  
    3. #include<stdlib.h>  
    4. #include<string.h>  
    5. #include<sys/types.h>  
    6. #include<sys/stat.h>  
    7. #include<fcntl.h>  
    8. #include<unistd.h>  
    9. #include<errno.h>  
    10. #include<termios.h>  
    11.    
    12. #include"open_port.c"  
    13. #include"set_com_config.c"  
    14.    
    15. #define HOST_COM_PORT 1        /*使用1表示PC机的串口1*/  
    16. #define BUFFER_SIZE 30 /*最大缓存大小*/  
    17.    
    18. int main(void)  
    19. {  
    20.         int fd;  
    21.         char buff[BUFFER_SIZE];  
    22.         if((fd = open_port(HOST_COM_PORT)) < 0)       /*打开串口*/  
    23.         {  
    24.                perror("open_port");  
    25.                return 1;  
    26.         }  
    27.    
    28.         if(set_com_config(fd, 115200, 8, 'N', 1) < 0)  
    29.         {  
    30.                perror("set_com_config");  
    31.                return 1;  
    32.         }  
    33.           
    34.         do  
    35.         {  
    36.                printf("Input some words(enter 'quit' to exit):");  
    37.                memset(buff, 0, BUFFER_SIZE);  
    38.                if(fgets(buff, BUFFER_SIZE, stdin) == NULL)  
    39.                {  
    40.                        perror("fgets");  
    41.                        break;  
    42.                }  
    43.                write(fd,buff,strlen(buff));  
    44.         } while(strncmp(buff,"quit",4));  
    45.         close(fd);  
    46.         return 0;  
    47. }  


    (2)目标机读串口程序com_reader_arm9.c:

     
    [cpp]  view plain copy
    1. /*com_reader.c*/  
    2. #include<stdio.h>  
    3. #include<stdlib.h>  
    4. #include<string.h>  
    5. #include<sys/types.h>  
    6. #include<sys/stat.h>  
    7. #include<errno.h>  
    8.    
    9. #include<unistd.h>  
    10. #include<termios.h>  
    11. #include<fcntl.h>  
    12.    
    13. #include"open_port_arm9.c"  
    14. #include"set_com_config.c"  
    15.    
    16. #define BUFFER_SIZE 30 /*最大缓存区*/  
    17. #define TARGET_COM_PORT 1      /*用1来表示目标机上的串口1*/  
    18.    
    19. int main(void)  
    20. {  
    21.         int fd;  
    22.         char buff[BUFFER_SIZE];  
    23.    
    24.         if((fd = open_port(TARGET_COM_PORT)) < 0)     /*打开串口*/  
    25.         {  
    26.                perror("open_port");  
    27.                return 1;  
    28.         }  
    29.    
    30.         if(set_com_config(fd, 115200, 8, 'N', 1) < 0) /*配置串口*/  
    31.         {  
    32.                perror("set_com_config");  
    33.                return 1;  
    34.         }  
    35.    
    36.         do  
    37.         {  
    38.                memset(buff, 0, BUFFER_SIZE);  
    39.                if(read(fd, buff, BUFFER_SIZE) > 0)  
    40.                        printf("The received words are : %s", buff);  
    41.         } while(strncmp(buff, "quit", 4));  
    42.         close(fd);  
    43.         return 0;  
    44. }  


      最后,进行将com_writer.c用gcc编译: gcc -g com_writer.c -o com_writer            

    将com_reader_arm9.c用arm-linux-gcc交叉编译:arm-linux-gcc -g com_reader_arm9.c -o com_reader_arm9     并且将其NFS或者其他方法放在开发板上,然后打开。

     

    将串口线直连,这里我是通过终端用telnet登陆到开发板,然后用nfs挂载文件到开发板,留下串口用来通信(之前用kermit利用串口相连通信收到数据的时候会有异常,且不能正常退出,可能是互相占用的问题),再打开com_reader_arm9程序。接着在宿主机上运行com_writer,再里面输入字符,开发板上面就会收到。如下图所示:

     宿主机打开com_writer

    目标机打开com_reader_arm9

     

      最后,我想总结下我弄这个程序所遇到的一些问题,希望在我以后知识提高的时候可以解决掉或者各位现在提供些参考意见。

    问题1:能不能只用一个open_port.c函数就直接选择USB转串口、普通PC串口、开发板串口的选择?之前按照书中的条件编译#if  #else  #endif没能实现,默认选择普通PC串口,所以源程序中我注释掉了。

    问题2:以上两图中,对于com_writer写入的第一条语句时候com_reader_arm9并不能读出,只能从第二条开始。之后我试着把new_cfg.c_cc[VMIN] = 1改成"=0”后再进行编译连接,反倒在目标板上用com_reader_arm9不能读出任何来自宿主机的写信息了。

    问题3:在第一次成功实现串口单工通信后,用quit退出后,想要再次实现串口通信确不行了,得要开发板重启后才能再次进行串口通信。

     

    如果是自己写的驱动,先检查驱动是否支持波特率的修改。
      如果支持: stty -F /dev/ttyS0 speed 115200 cs8 -parenb -cstopb -echo 修改 波特率115200 8 N 1 下位机采用相同的配置,并在linux终端输入echo "hello" > /dev/ttyS0 看看是否能通信。
    stty -F /dev/ttyUSB0 speed 115200 cs8 -parenb -cstopb -echo 


    我自己的代码(输出):

    #include <stdio.h>
    #include <fcntl.h> 
    #include <unistd.h>
    #include <termios.h> 
    #include <sys/types.h>
    #include <sys/select.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <netdb.h>
    #include <string.h>
    #include <pthread.h>
    #include <errno.h>
    #include <time.h>
    
    struct timeval timeout;
    
    /*设置串口参数*/
    int init_tty(int fd)
    {
    	struct termios termios_rfid;
    	
    	bzero(&termios_rfid, sizeof(termios_rfid));//清空结构体
    	
    	cfmakeraw(&termios_rfid);//设置终端属性,激活选项
    	
    	cfsetispeed(&termios_rfid, B9600);//输入波特率
    	cfsetospeed(&termios_rfid, B9600);//输出波特率
    	
    	termios_rfid.c_cflag |= CLOCAL | CREAD;//本地连接和接收使能
    	
    	termios_rfid.c_cflag &= ~CSIZE;//清空数据位
    	termios_rfid.c_cflag |= CS8;//数据位为8位
    	
    	termios_rfid.c_cflag &= ~PARENB;//无奇偶校验
    	
    	termios_rfid.c_cflag &= ~CSTOPB;//一位停止位
    	
    	tcflush(fd,TCIFLUSH);
    	
    	termios_rfid.c_cc[VTIME] = 10;//设置等待时间
    	termios_rfid.c_cc[VMIN] = 1;
    	
    	tcflush(fd, TCIFLUSH);//清空输入缓冲区
    	
    	if(tcsetattr(fd, TCSANOW, &termios_rfid))//激活串口设置
    		return 0;
    	
    	return 1;
    }
    
    int main(void)
    {
    	int fd;
    	char ch[]="good job!";
    	while(1)
    	{
    		fd = open("/dev/ttyUSB0", O_RDWR);
    		if(fd < 0)
    		{
    			printf("open s3c2410_serial1 failed!\n");
    		}	
    
    		if(init_tty(fd) == -1)//初始化串口
    		{
    			printf("init_tty in failed!\n");
    		}
    		
    		timeout.tv_sec = 1;//设置超时时间为1秒
    		timeout.tv_usec = 0;
    		
    		write(fd, ch, sizeof(ch));
    		
    		tcflush(fd, TCIFLUSH);//清空输入缓冲区
    		tcflush(fd, TCOFLUSH);//清空输入缓冲区
    		close(fd);
    		sleep(3);
    	}
    
    
    	return 0;
    }

    本文中的程序参考了书籍《嵌入式Linux应用程序开发标准教程(第2版)》

    原创文章,欢迎转载,转载请注明:blog.csdn.net/jjzhoujun2010


    展开全文
  • Linux串口ttyUSB设置

    万次阅读 多人点赞 2019-07-18 19:56:35
    Linux串口ttyUSB设置1 简介2 /dev/tty、/dev/ttyS/、/dev/ttyUSB区别3 USB和串口(COM)的区别,以及相互转换4 波特率等参数设置5 确定有效端口5.1 通过收发数据确定5.2 命令查看6 生成固定USB转串口设备节点7 linux...

    1 简介

    控制板改版,之前电路中直接从工控机主板引脚中连出com口(ttyS),现在在FT4232H(配置TTL)之后又连接了ADM3232EARUZ(TTL转RS232)需要使用USB转串口(ttyUSB)
    在这里插入图片描述

    2 /dev/tty、/dev/ttyS/、/dev/ttyUSB区别

    • /dev/tty 当前控制终端Terminal
    • /dev/ttyn和/dev/console (虚拟)控制台终端
    • /dev/ttySn 一般为/dev/ttyS0 串行端口终端,接串口线使用的端口设备
    • /dev/ttyUSBn 一般为/dev/ttyUSB0 USB转串口终端,接USB转串口线可用此端口设备

    3 USB和串口(COM)的区别,以及相互转换

    • 串口、COM口是指的物理接口形式(硬件)。
    • 而TTL、RS-232、RS-485指的是串口的电平标准(电信号)
    • 接线的时候,一般只接GND、RX(接收)、TX(发送)。不会接入Vcc等电源线,避免与目标设备上的供电冲突

    3.1 接线法则

    • 交叉连接
    • 主机的 TX 接目标设备的 RX ,主机的 RX 接目标设备的 TX
    • 很多设计人员为了接线更为直观而故意颠倒标记 RX、TX
    • 如果有问题可以尝试交换RX、TX,不会烧坏设备

    3.2 拓展芯片

    • PL2303、CP2102、FT232R芯片是用USB来扩展串口(TTL电平输出)的芯片,需要对应的驱动
    • 知名的Z-TEK就用的是FT232芯片
    • MAX232芯片是TTL电平与RS232电平的专用双向转换芯片,不同引脚实现TTL转RS-232或RS-232转TTL的功能
    • ADM3232EARUZ 也是TTL电平与RS232电平转换芯片

    3.3 电气特性

    • TTL电平标准是:低电平为0,高电平为1(对地,标准数字电路逻辑)。
    • RS-232电平标准是:正电平为0,负电平为1(对地高低,电压具体数值不敏感,甚至可以用高阻态)。
    • RS-485、RS-422 与RS-232类似,但是采用差分信号逻辑,更适合长距离、高速传输
    • 台式电脑后边带的D型9针插头(板载串口,公口),是RS-232电平标准的。可以通过MAX232转换为TTL电平。

    3.4 串口(COM)

    COM口 即 串行通讯端口,简称 串口。这里区别于 USB的“通用串行总线”和“SATA”串行硬盘

    3.4.1 物理形式

    一般我们见到的是两种物理形式。D型9针插头(DB9)和 4针杜邦头 两种,早年的25针串口已被淘汰

    • 下图是常见的4针串口,在电路板上常见,经常上边还带有杜邦插针
      在这里插入图片描述

    四针分别为:GND、TX、RX、VCC。其中GND可以通过焊盘接地判断出来,而VCC一般走线稍粗些。由于是预留在电路板上的,协议可以有很多种,要看具体设备。

    经验是:不管单片机也好、ARM也罢,这些芯片都是数字逻辑的,电平只有高和低,输出肯定是TTL电平的。
    如果你看到串口线从核心芯片直接连出来,未经其他芯片,那99%是TTL的,STC下载和中九升级都属此范畴。

    • 下图就是D型9针串口(通俗说法,DB9)
      在这里插入图片描述

    DB9接口的协议常用的只有三种:RS-232、RS-485和RS-422。绝不会是TTL电平,80%的可能性是RS-232
    DB9 公头母头引脚定义及连接

    3.4.2 USB 转 TTL

    • 下图是个USB转TTL串口的小板(TTL电平),可以用USB扩展出一个串口。芯片为PL2303HX。
      在这里插入图片描述
    • CP2102芯片的,也是USB转串口(TTL电平)
      在这里插入图片描述

    3.4.2 USB转RS-232串口

    • 转接口
      USB经过PL2303转成了TTL串口(中间那四个窟窿可以引出),再经由MAX232转换为RS-232电平,9针串口引出.
      MAX232只能转换两个T和两个R,无法实现完整的9针全串口电平转换,所以此类串口转接板只有TX、RX和GND三针有效,对于涉及到串口中其他控制线的目标设备不适用。(PL2303等芯片都转出了TTL电平的全部引脚,只不过MAX232只用到了TX和RX。若要全串口电平转换,MAX3232可以实现。)
      在这里插入图片描述
    • 转接线
      D型9针串口,不会是TTL电平的,没特殊说明就默认是RS-232。所以这根线,不管里边构造怎样的,是 USB转RS-232串口 的线,内置了电平转换芯片。
      在这里插入图片描述

    4 波特率等参数设置

    4.1 查看串口波特率信息

    stty -F /dev/ttyS0 -a  #ttyS0为要查看的串口
    

    4.2 用stty设置串口参数

    stty -F /dev/ttyS0 ispeed 115200 ospeed 115200 cs8
    

    该命令将串口1(/dev/ttyS0)设置成115200波特率,8位数据模式。一般情况下设置这两个参数就可以了,如果显示数据乱码,可能还需要设置其它参数,使用man查看stty其它设置选项。

    5 确定有效端口

    5.1 短接串口Rx和Tx

    • 短接串口的收发引脚
    • 输入如下命令
    # cat /dev/ttyS0 &
    # echo testSerialCharString > /dev/ttyS0
    

    5.2 通过收发数据确定

    • linux的shell中输入
    echo "worthsen" > /dev/ttyUSB1
    
    • XCOM V2.0 接收

    5.3 命令查看

    使用 dmsg 命令查看

    6 生成固定USB转串口设备节点

    每个USB端口都有唯一的端口号

    6.1 硬件上电顺序的变化会导致ttyUSB0或者ttyUSB1无法每次固定的对应的USB口

    • ls -l /sys/class/tty/ttyUSB* 确定端口号,假设端口号是3-1.1
    • 通过bash + 正则表达式确定3-1.1端口号对应的设备挂载的文件名(ttyUSBx)
    • 并建立一个软链接将当时获取到的ttyUSBx生成一个软链接,假设名字固定为ttydata,那么以后每次打开/dev/ttydata就能找到正确3-1.1这个端口,并获取数据了

    7 通信

    7.1 处理器与外部设备通信的两种方式

    在这里插入图片描述

    7.2 串行通信:

    (1)按照数据传输方式分为单工、半双工、全双工
    (2)串行通信的通信方式:

    • 同步通信:速度由时钟同步信号决定,每个时钟信号(如上升沿)发生时传输一个bit,如SPI、IIC通信接口;
    • 异步通信:不带时钟同步信号,但有传输约定。如UART(通用异步收发器),单总线。UART(通用异步收发器)通信,发送/接收端使用统一波特率(确定每个bit所使用的时间),起始位/校验位/停止位;单总线通信,没有约定波特率,在标准时间内高低电平的占比来确定是1还是0。

    7.3 常见通信

    在这里插入图片描述

    7.4 UART异步通信方式引脚连接方法

    在这里插入图片描述

    7.5 UART在不同电气规范下的接口

    对于不同平台或者使用环境,信号管脚的电气特性依次可以分为TTL/CMOS、RS232、RS422、RS485

    • TTL/CMOS
      TTL电平,逻辑“0”等于0V电压,逻辑“1”等于+5V电压。
      CMOS电平,逻辑“0”接近0V电压,逻辑“1”接近电源电压(3.3V或其他)。
    • RS-232
      RS232对电气特性、逻辑电平和各种信号线功能都作了规定。
      在TxD和RxD信号管脚上:
      逻辑“1”电压范围-3V~-15V
      逻辑“0”电压范围+3~+15V
      在RTS、CTS、DSR、DTR和DCD等控制线上:
      信号有效(接通,ON状态,正电压)电压范围+3V~+15V
      信号无效(断开,OFF状态,负电压)电压范围-3V~-15V
    • RS-422
      RS-422的信号线采用的是差分传输方式,即原来的TxD、RxD信号线,此时分别改用两根线来完成,即TxD+和TxD-、RxD+和RxD-两组,并且利用两根线之间的电压差值来表示数据的逻辑“1”和逻辑“0”。
      逻辑“1”的差分信号电压差范围:+2~+6V
      逻辑“0”的差分信号电压差范围:-6~-2V
      最大通信距离:1500米
      通信速率范围:100 kbit / s - 10 Mbit / s
    • RS-485
      EIA于1983年在RS-422基础上制定了RS-485标准,由之前的4线改为2线传输,即全双工改为半双工,增加了多点、双向通信能力。2线制的半双工,仅由2差分线A、B来连接,其中A线的“高”表示逻辑“0”而低表示逻辑“1”;B线的“高”表示逻辑“1”,“低”表示逻辑“0”。
      看一张图就可以明白了,如下图引用的是维基百科RS485介绍的时序图片:
      在这里插入图片描述

    8 linux设备和驱动加载的先后顺序

    1 动态加载
    动态加载是将驱动模块加载到内 核中,而不能放入/lib/modules/下。
    在2.4内核中,加载驱动命令为:insmod ,删除模块为:rmmod;
    在2.6以上内核中,除了insmod与rmmod外,加载命令还有modprobe;
    insmod与modprobe不同之处:
    insmod 绝对路径/××.o,而modprobe ××即可,不用加.ko或.o后缀,也不用加路径;最重要的一点是:modprobe同时会加载当前模块所依赖的其它模块;
    lsmod查看当前加载到内核中的所有驱动模块,同时提供其它一些信息,比如其它模块是否在使用另一个模块。
    2 静态加载
    2.1 概念
    在执行make menuconfig命令进行内核配置裁剪时,在窗口中可以选择是否编译入内核,还是放入/lib/modules/下相应内核版本目录中,还是不选。
    2.2 操作步骤
    linux设备一般分为:字符设备、块设备和网络设备,每种设备在内核源代码目录树drivers/下都有对应的目录,其加载方法类似,以下以字符设备静 态加载为例,假设驱动程序源代码名为ledc.c,具体操作步骤如下:
    第一步:将ledc.c源程序放入内核源码drivers/char/下;
    第二步:修改drivers/char/Config.in文件,具体修改如下:
    按照打开文件中的格式添加即可;
    在文件的适当位置(这个位置随便都可以,但这个位置决定其在make menuconfig窗口中所在位置)加入以下任一段代码:

    tristate 'LedDriver' CONFIG_LEDC
             if [ "$CONFIG_LEDC" = "y" ];then
             bool '   Support for led on h9200 board' CONFIG_LEDC_CONSOLE
             fi
             说明:以上代码使用tristate来定义一个宏,表示此驱动可以直接编译至内核(用*选择),
             也可以编制至/lib/modules/下(用M选择), 或者不编译(不选)。
    
             bool 'LedDriver' CONFIG_LEDC
             if [ "$CONFIG_LEDC" = "y" ];then
             bool '   Support for led on h9200 board' CONFIG_LEDC_CONSOLE
             fi
    

    说明:以上代码使用tristate来定义一个宏,表示此驱动只能直接编译至内核(用*选择)或者不编译(不选),不能编制至/lib/modules/ 下(用M选择)。
    第三步:修改drivers/char/Makefile文件
    在适当位置加入下面一行代码:
    obj-$(CONFIG_LEDC) += ledc.o
    或者在obj-y一行中加入ledc.o,如:
    obj-y += ledc.o mem.o 后面不变;
    OK,经过以上的设置就可以在执行make menuconfig命令后的窗口中的character devices—> 中进行选择配置了。选择后重新编译就ok了。

    参考

    1、/dev/tty、/dev/ttyS/、/dev/ttyUSB区别
    2、USB和串口(COM)的区别,以及相互转换
    3、DB9 公头母头引脚定义及连接
    4、FT4232H
    5、TTL和RS232之间的详细对比
    6、linux下/dev/tty, /dev/tty0, /dev/console区别
    7、linux设备和驱动加载的先后顺序
    8、从需求的角度去理解Linux系列:总线、设备和驱动
    9、解决Linux下USB设备节点ttyUSB名不固定的问题,生成固定USB转串口设备节点
    10、linux查看某串口(或串口终端)的波特率等属性
    11、linux 串口/dev/ttyS0测试(UART0)
    12、STM32F407–串行通信的原理
    13、嵌入式硬件通信接口协议-UART(二)不同电气规范下的标准

    展开全文
  • ttyUSB串口设备节点生成过程

    千次阅读 2017-03-19 21:37:47
    在USB虚拟总线匹配USB接口,如果有USB接口匹配到,会调用 option_driver 的probe函数 下面是设备插入后的匹配过程: 如果一个 USB 设备插入,最终 USB 接口接口设备匹配,那么就会匹配到 option_driver ...

    usbserial和option模块加载过程:

    struct bus_type usb_serial_bus_type  虚拟的 usb_serial 总线
    struct usb_driver usb_serial_driver
    
    usbserial模块初始化函数:
    usb_serial_init
        struct tty_driver *usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
    
        bus_register(&usb_serial_bus_type);             注册虚拟总线
    
        usb_serial_tty_driver       设置tty_driver, 操作函数 serial_ops
    
        tty_register_driver(usb_serial_tty_driver);     注册 tty_driver
    
        usb_register(&usb_serial_driver);               注册一个USB接口驱动 usb_serial_driver
    
    
    
    struct usb_driver option_driver
    struct usb_serial_driver * const serial_drivers
    struct usb_serial_driver option_1port_device
    
    option模块初始化函数
    module_usb_serial_driver(option_driver, serial_drivers);
        usb_serial_register_drivers(option_driver, serial_drivers)
            saved_id_table = option_driver->id_table;
            option_driver->id_table = NULL;                   这里把id_table临时保存一下,下面注册的时候,即使有设备,也不会匹配到
            usb_register(option_driver);                      注册一个USB接口驱动 option_driver 这里会将 option_driver->drvwrap.for_devices = 0; 表示这是个接口驱动
    
            usb_serial_register(option_1port_device);                   注册一个 struct usb_serial_driver
                list_add(&driver->driver_list, &usb_serial_driver_list);        这里会将 option_1port_device 添加到 usb_serial_driver_list 链表
    
            option_driver->id_table = saved_id_table;           再把id_table取回来
            driver_attach(&option_driver->drvwrap.driver);      在USB虚拟总线匹配USB接口,如果有USB接口匹配到,会调用 option_driver 的probe函数

    下面是设备插入后的匹配过程:

    如果一个USB设备插入,最终USB接口和接口设备匹配,那么就会匹配到 option_driver 驱动,然后执行它的probe函数:
    usb_serial_probe
        struct usb_serial_driver *type = search_serial_device(interface);           这里在链表里找驱动,找到的是 option_1port_device
        struct usb_serial *serial = create_serial(dev, interface, type);            创建一个 usb_serial serial 的type指针就指向了 option_1port_device
        type->probe(serial, id);                                                    执行 option_1port_device 的probe函数 option_probe
            这里注册了一个 struct usb_wwan_intf_private 结构体
    
        读取接口的信息,设置 usb_serial
        port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);                 分配对应的 usb_serial_port 结构体
        serial->port[i] = port;                                                     usb_serial_port 放入 usb_serial 中
        port->dev.bus = &usb_serial_bus_type;                                       port 设备注册的虚拟总线
        device_add(&port->dev);                                                     向系统中加入中port,这个设备会挂在 usb_serial_bus_type 虚拟总线的设备列表,并执行匹配函数 usb_serial_device_match
            usb_serial_device_match
                driver = to_usb_serial_driver(drv);             这是取得drv嵌入的 struct usb_serial_driver 结构
                if (driver == port->serial->type)               如果这个驱动和serial的type是一个驱动,那么匹配成功,前面看到了驱动的设置,
                                                                所以这里匹配成功的是 option_1port_device 驱动,
                                                                匹配成功后优先执行 usb_serial_bus_type 的probe函数 usb_serial_device_probe
    
            usb_serial_device_probe
                port = to_usb_serial_port(dev);                 从dev找到 usb_serial_port
                driver = port->serial->type;                    取得serial对应的驱动,也就是 option_1port_device
                driver->port_probe(port);                       如果有 port_probe 函数,就执行,这里没有就不执行
                minor = port->number;
                tty_register_device(usb_serial_tty_driver, minor, dev);     注册tty设备

    设备插入后会注册tty设备,那么对应的tty驱动注册过程:

    再来看tty驱动的注册和设备注册
    usb_serial_init
        struct tty_driver *usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
        tty_set_operations(usb_serial_tty_driver, &serial_ops);
        tty_register_driver(usb_serial_tty_driver);
            cdev_init(&driver->cdev, &tty_fops);
            cdev_add(&driver->cdev, dev, driver->num);          注册一个字符型设备
            list_add(&driver->tty_drivers, &tty_drivers);       将 usb_serial_tty_driver 驱动加入到 tty_drivers 链表

    设备插入后创建tty设备过程:

    再看设备插入后 usb_serial_probe -> device_add -> usb_serial_device_probe -> tty_register_device(usb_serial_tty_driver, minor, dev) 添加设备
    tty_register_device(usb_serial_tty_driver, minor, dev)      这里的参数 dev 代表的是 struct usb_serial_port
        dev = MKDEV(driver->major, driver->minor_start) + index;        取得设备的设备号,这里的主设备号就是 usb_serial_tty_driver 驱动的主设备号
        tty_line_name(driver, index, name);        
        device_create(tty_class, device, dev, NULL, name);      创建设备节点

    打开一个设备的过程:

    如果 open 一个设备节点,首先会调用到 tty_fops 中的open函数
    tty_open(struct inode *inode, struct file *filp)
        struct tty_driver *driver = tty_lookup_driver(device, filp, &noctty, &index);
            struct tty_driver *driver = get_tty_driver(device, index);
    
        struct tty_struct *tty = tty_init_dev(driver, index);
            tty = alloc_tty_struct();
            initialize_tty_struct(tty, driver, idx);
                tty->driver = driver;
                tty->ops = driver->ops;                         这里就得到了 usb_serial_tty_driver 驱动中的ops,也就是 tty_fops
    
            tty_ldisc_setup(tty, tty->link);
    
    
        retval = tty->ops->open(tty, filp);                     这里就执行了 tty_fops 中的open函数
    展开全文
  • 在linux下用串口助手cutecom,打开/dev/ttyUSB0串口时,报错 /dev/ttyUSB0 permission denied. 原因是没有权限,查阅发现两种解决方案 //使用root权限启动cutecom sudo cutecom //终端打开指定串口权限 sudo chmod...
  • 在linux环境下的串口收发两端测试程序 c语言实现
  • <p>I am using Go for a project and am transmitting data to an embedded device via the serial port (ttyusb). During fast and "large" transfers I've noticed that the transmitted data did not match the ...
  • !!   1. Linux下USB设备节点名不...以USB转串口设备为例,通常设备节点名为ttyUSBx(x为0~n),Linux内核会根据设备插入的先后顺序进行编号的分配,比如第一个插入的设备编号为ttyUSB0,然后依此加1,变为tty...
  • 基于NUC123的usb虚拟串口,在Linux下显示ttyacm,如何使得Linux识别为ttyusb,应该修改NUC123开发板程序设计还是Linux的驱动程序?
  • Linux串口ttyUSB

    2020-07-22 14:23:42
    Linux串口ttyUSB设置 1 简介 参考: 控制板改版,之前电路中直接从工控机主板引脚中连出com口(ttyS),现在在FT4232H(配置TTL)之后又连接了ADM3232EARUZ(TTL转RS232)需要使用USB转串口(ttyUSB) ...
  • #设置通信的目标串口,由于我的笔记本没有串口,使用了USB转串口,所以设备为/dev/ttyUSB0 set line /dev/ttyUSB0#设置波特率 set speed 115200#关闭通信监视 set carrier-watch off#设置没有握手协议 set ...
  • Linux下ttyUSB0等串口权限设置1.问题描述2. 解决方法(一)3. 解决方法(二) 1.问题描述 最近在Linux/ubuntu使用串口设备,发现无法通过串口给Tof相机启动程序,权限不足的问题。 假设串口设备是 /dev/ttyUSB0,...
  • 需求:在Linux系统(Ubuntu)下,需要查找ttyUSB口,以便串口通讯工具如Putty连接,显示FPGA板通过UART输出的结果。 Putty界面: 如何获取usb口的参数: 下面展示一些 内联代码片。 // ctrl+shift+t open terminal ...
  • 执行 ls /dev/tty “Tab按键”目标串口 ttyUSB0 ttyUSB1 这个需要配置一下,如下 step2:sudo minicom -s >A 编辑/dev/modem --> /dev/ttyUSB0 or /dev/ttyUSB1 连接到的USB串口有差异,需要试一下0或者...
  • 如果只需要将外部的串口设备(如: 底盘控制的单片机、雷达、 IMU) 临时接入工控机,请参考方法 1,这 一设置断电重启后会失效; 每次插拔和重启都会影响串口的编号,所以如果这个设备是长期接入工控机的,就可以...
  • bytes.fromhex('77 68 06 00 02 0C 01 04') comma_trail = bytes.fromhex('0A') portx = "/dev/ttyUSB0" bps = 115200 send_data_01_motor = comma_head_01_motor + left_front.to_bytes(1, byteorder='big', signed...
  • ubuntu安装串口驱动(找不到ttyUSB*)

    千次阅读 2020-04-06 23:54:32
    https://elixir.bootlin.com/linux/v4.15/source/drivers/usb/serial/ch341.c http://www.wch.cn/download/CH341SER_LINUX_ZIP.html 由于内核升级或者其他什么找不到ttyUSB*,不得已安装对应的驱动~ 1 查看电脑的...
  • 可问题是我明明确认了端口号确实是/dev/ttyUSB0呀 cdw@cdw-MS-7B89:~$ ls -l /dev/ttyUSB* crw-rw---- 1 root dialout 188, 0 12月 1 16:43 /dev/ttyUSB0 然后我就看了一下相关的代码: fd_ = open(port_name_.c_...
  • ttyUSB0,ttyUSB1,顺序变化问题解决 一 输入命令 查看usb 串口 mesg | grep ttyS* 二 进入root模式。 1.系统左下角单击,单击终端。 2.输入命令:【sudo su】,输入密码。 三 编辑串口名 1. 输入 cd /etc/udev/...
  • Device /dev/ttyUSB0 is locked.解决办法

    万次阅读 2016-12-14 20:09:43
    cd /var/lock 删除目录下的LOCK
  • 在工控机ubuntu操作系统上发现每次连接USB设备串口号不固定,ttyUSB0和ttyUSB1经常变来变去的,为了固定端口号,网上搜了下,整理出以下可行步骤: 1.首先命令行输入lsusb查看设备: 找到对应USB的设备ID,我这里...
  • 一般使用USB口,无论USB转什么口,串口之类的,启动时容易出现:/dev/ttyUSB0 permission denied. 因为一般情况下不是root用户,对端口没有权限. 遇到这种情况,我一般这样做:  sudo chmod 777 /dev/ttyUSB0 ...
  • 上篇链接: Android usb串口通信(ttyusb)+handler+databinding 实现总结 前面的操作都完成之后现在我们就已经可以使用别人的APP进行通信了,下面具体说一下我们自己如何去写一个实现串口通信的Android应用。 ——...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,054
精华内容 2,421
关键字:

ttyusb串口