Linux串口编程

开发环境

开发板:A33-Vstar

开发板系统:Linux

Ubuntu版本:Ubuntu14.04

-------------------------------------------

串口2(Ubuntu)

串口1(A33)

Ubuntu和A33都运行uart_test程序(见附件)。

 

一、串口设置

最基本的串口设置包括波特率、校验位和停止位设置,且串口设置主要使用termios.h头文件中定义的termios结构,如下:

struct termios

{

tcflag_t c_iflag; //输入模式标志

tcflag_t c_oflag; //输出模式标志

tcflag_t c_cflag; //控制模式标志

tcflag_t c_lflag; //本地模式标志

cc_t c_line; //line discipline

cc_t c_cc[NCC]; //control characters

}

 

1. 重要配置函数

1)获取终端对应的termios结构:

int tcgetattr(int fd, struct termios *termios_p); 

2)重新配置串口

int tcsetattr(int fd , int actions , const struct termios *termios_h); 

参数actions控制修改方式,共有三种修改方式,如下所示。

TCSANOW:立刻对值进行修改

TCSADRAIN:等当前的输出完成后再对值进行修改。

TCSAFLUSH:等当前的输出完成之后,再对值进行修改,但丢弃还未从read调用返回的当前的可用的任何输入。

 

2. 控制符VTIME和VMIN

VTIME定义要求等待的时间(百毫秒,通常是unsigned char变量),而VMIN定义了要求等待的最小字节数(相比之下,read函数的第三个参数指定了要求读的最大字节数)。

1)如果VTIME=0,VMIN=要求等待读取的最小字节数,read必须在读取了VMIN个字节的数据或者收到一个信号才会返回。

2)如果VTIME=时间量,VMIN=0,不管能否读取到数据,read也要等待VTIME的时间量。

3)如果VTIME=时间量,VMIN=要求等待读取的最小字节数,那么将从read读取第一个字节的数据时开始计时,并会在读取到VMIN个字节或者VTIME时间后返回。

4)如果VTIME=0,VMIN=0,不管能否读取到数据,read都会立即返回

 

二、使用过程中遇到的一些问题

1. 串口2到串口1:在发送数据时没有键入回车,信息就发送不出去,键入回车发送后,前面没有发送出去的数据会和本次一起全部发送出去。这主要是因为我们在输入输出时是按照规范模式接收到回车或换行才发送,而更多情况下我们是不必键入回车或换行的。此时将对方串口(串口1)设置如下:

Opt.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG);

主要是:ICANON

注:当A33使用cat(开机后串口1未经过程序设置),Ubuntu使用uart_test会出现此问题即A33收不到,Ubuntu使用echo发送数据时可以收到(echo 应该是发送了回车),win7使用串口助手不加回车发送数据时A33收不到,加了回车可以收到。

 

2. 回显问题:在串口2往串口1发送数据时,串口2能接收到发送出去的数据。此时,关闭串口1的回显即可。设置如下:

Opt.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG);

主要是:ECHO | ECHOE

 

3. 未经测试(未遇到的问题,网上摘录)

1)还存在这样的情况:发送字符0X0d的时候,往往接收端得到的字符是0X0a,原因是因为在串口设置中c_iflag和c_oflag中存在从NL-CR和CR-NL的映射,即串口能把回车和换行当成同一个字符,可以进行如下设置屏蔽之:

Opt.c_iflag &= ~ (INLCR | ICRNL | IGNCR);

Opt.c_oflag &= ~(ONLCR | OCRNL);

 

2)c_cc数组的VSTART和VSTOP元素被设定成DC1和DC3,代表ASCII标准的XON和XOFF字符,如果在传输这两个字符的时候就传不过去,需要把软件流控制屏蔽,即:

Opt.c_iflag &= ~ (IXON | IXOFF | IXANY);

 

三、附录

1. c_cflag用于设置控制参数,除了波特率外还包含以下内容:

EXTA External rate clock

EXTB External rate clock

CSIZE Bit mask for data bits

CS5 5个数据位

CS6 6个数据位

CS7 7个数据位

CS8 8个数据位

CSTOPB 2个停止位(清除该标志表示1个停止位

PARENB 允许校验位

PARODD 使用奇校验(清除该标志表示使用偶校验)

CREAD Enable receiver

HUPCL Hangup (drop DTR) on last close

CLOCAL Local line – do not change “owner” of port

LOBLK Block job control outpu

c_cflag标志可以定义CLOCAL和CREAD,这将确保该程序不被其他端口控制和信号干扰,同时串口驱动将读取进入的数据。CLOCAL和CREAD通常总是被是能的。

 

2. c_lflag用于设置本地模式,决定串口驱动如何处理输入字符,设置内容如下:

ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals

ICANON Enable canonical input (else raw)

XCASE Map uppercase \lowercase (obsolete)

ECHO Enable echoing of input characters

ECHOE Echo erase character as BS-SP-BS

ECHOK Echo NL after kill character

ECHONL Echo NL

NOFLSH Disable flushing of input buffers after interrupt or quit characters

IEXTEN Enable extended functions

ECHOCTL Echo control characters as ^char and delete as ~?

ECHOPRT Echo erased character as character erased

ECHOKE BS-SP-BS entire line on line kill

FLUSHO Output being flushed

PENDIN Retype pending input at next read or input char

TOSTOP Send SIGTTOU for background output

 

3. c_iflag用于设置如何处理串口上接收到的数据,包含如下内容:

INPCK Enable parity check

IGNPAR Ignore parity errors

PARMRK Mark parity errors

ISTRIP Strip parity bits

IXON Enable software flow control (outgoing)

IXOFF Enable software flow control (incoming)

IXANY Allow any character to start flow again

IGNBRK Ignore break condition

BRKINT Send a SIGINT when a break condition is detected

INLCR Map NL to CR

IGNCR Ignore CR

ICRNL Map CR to NL

IUCLC Map uppercase to lowercase

IMAXBEL Echo BEL on input line too long

 

4. c_oflag用于设置如何处理输出数据,包含如下内容:

OPOST Postprocess output (not set = raw output)

OLCUC Map lowercase to uppercase

ONLCR Map NL to CR-NL

OCRNL Map CR to NL

NOCR No CR output at column 0

ONLRET NL performs CR function

OFILL Use fill characters for delay

OFDEL Fill character is DEL

NLDLY Mask for delay time needed between lines

NL0 No delay for NLs

NL1 Delay further output after newline for 100 milliseconds

CRDLY Mask for delay time needed to return carriage to left column

CR0 No delay for CRs

CR1 Delay after CRs depending on current column position

CR2 Delay 100 milliseconds after sending CRs

CR3 Delay 150 milliseconds after sending CRs

TABDLY Mask for delay time needed after TABs

TAB0 No delay for TABs

TAB1 Delay after TABs depending on current column position

TAB2 Delay 100 milliseconds after sending TABs

TAB3 Expand TAB characters to spaces

BSDLY Mask for delay time needed after BSs

BS0 No delay for BSs

BS1 Delay 50 milliseconds after sending BSs

VTDLY Mask for delay time needed after VTs

VT0 No delay for VTs

VT1 Delay 2 seconds after sending VTs

FFDLY Mask for delay time needed after FFs

FF0 No delay for FFs

FF1 Delay 2 seconds after sending FFs

 

5. c_cc定义了控制字符,包含以下内容:

VINTR Interrupt CTRL-C

VQUIT Quit CTRL-Z

VERASE Erase Backspace (BS)

VKILL Kill-line CTRL-U

VEOF End-of-file CTRL-D

VEOL End-of-line Carriage return (CR)

VEOL2 Second end-of-line Line feed (LF)

VMIN Minimum number of characters to read

VSTART Start flow CTRL-Q (XON)

VSTOP Stop flow CTRL-S (XOFF)

VTIME Time to wait for data (tenths of seconds)

 

测试源码:

#include <sys/types.h>   
#include <sys/stat.h>  
#include <fcntl.h>  
#include <termios.h>  
#include <stdio.h>  


#define BAUDRATE        9600  
char *uart_device = "/dev/ttyUSB1";
  
#define FALSE  -1  
#define TRUE   0  


char rec_buf[100];
int  fd;


////////////////////////////////////////////////////////////////////////////////  
/** 
*@brief  设置串口通信速率 
*@param  fd     类型 int  打开串口的文件句柄 
*@param  speed  类型 int  串口速度 
*@return  void 
*/  
int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300,  
                   B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300, };  
int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400, 1200,  300,   
                  115200, 38400, 19200, 9600, 4800, 2400, 1200,  300, }; 
				  
void set_speed(int fd, int speed){  
  int   i;   
  int   status;   
  struct termios   Opt;  
  tcgetattr(fd, &Opt);   
  for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) {   
    if  (speed == name_arr[i]) {       
      tcflush(fd, TCIOFLUSH);       
      cfsetispeed(&Opt, speed_arr[i]);    
      cfsetospeed(&Opt, speed_arr[i]);     
      status = tcsetattr(fd, TCSANOW, &Opt);    
      if  (status != 0) {          
        perror("tcsetattr fd1");    
        return;       
      }      
      tcflush(fd,TCIOFLUSH);     
    }    
  }  
} 
 
////////////////////////////////////////////////////////////////////////////////  
/** 
*@brief   设置串口数据位,停止位和效验位 
*@param  fd     类型  int  打开的串口文件句柄 
*@param  databits 类型  int 数据位   取值 为 7 或者8 
*@param  stopbits 类型  int 停止位   取值为 1 或者2 
*@param  parity  类型  int  效验类型 取值为N,E,O,S 
*/  
int set_Parity(int fd,int databits,int stopbits,int parity)  
{   
    struct termios options;   
    if  ( tcgetattr( fd,&options)  !=  0) {   
        perror("SetupSerial 1");       
        return(FALSE);    
    }  
	
    options.c_cflag &= ~CSIZE;  
    options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/  
    options.c_oflag  &= ~OPOST;   /*Output*/  
	
    switch (databits) /*设置数据位数*/  
    {     
    case 7:       
        options.c_cflag |= CS7;   
        break;  
    case 8:       
        options.c_cflag |= CS8;  
        break;     
    default:      
        fprintf(stderr,"Unsupported data size\n"); return (FALSE);    
    } 
	
    switch (parity)   
    {     
        case 'n':  
        case 'N':      
            options.c_cflag &= ~PARENB;   /* Clear parity enable */  
            options.c_iflag &= ~INPCK;     /* Enable parity checking */   
            break;    
        case 'o':     
        case 'O':       
            options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/    
            options.c_iflag |= INPCK;             /* Disnable parity checking */   
            break;    
        case 'e':    
        case 'E':     
            options.c_cflag |= PARENB;     /* Enable parity */      
            options.c_cflag &= ~PARODD;   /* 转换为偶效验*/       
            options.c_iflag |= INPCK;       /* Disnable parity checking */  
            break;  
        case 'S':   
        case 's':  /*as no parity*/     
            options.c_cflag &= ~PARENB;  
            options.c_cflag &= ~CSTOPB;break;    
        default:     
            fprintf(stderr,"Unsupported parity\n");      
            return (FALSE);    
    } 
		
    /* 设置停止位*/    
    switch (stopbits)  
    {     
        case 1:      
            options.c_cflag &= ~CSTOPB;    
            break;    
        case 2:      
            options.c_cflag |= CSTOPB;    
           break;  
        default:      
             fprintf(stderr,"Unsupported stop bits\n");    
             return (FALSE);   
    }   
    /* Set input parity option */   
    if (parity != 'n')     
        options.c_iflag |= INPCK;  
	
    tcflush(fd,TCIFLUSH);  
    options.c_cc[VTIME] = 0; /* 设置超时0 seconds*/     
    options.c_cc[VMIN] = 1; //至少接收了1个字节数据才可以返回
	
    if (tcsetattr(fd,TCSANOW,&options) != 0)     
    {   
        perror("SetupSerial 3");     
        return (FALSE);    
    }   

    return (TRUE);    
} 


void *read_thread(void *argv) 
{
	int res = 0;
	
	while(1){
        res = read(fd, rec_buf, 50);  
  
        if(res <= 0){
			printf("\nrev faild, try rev again.\n");
            continue; 
		}			
		
        rec_buf[res]=0;   
        printf("rev data:%s\n", rec_buf);           
	
	}
	
}



int main(int argc, char *argv[])  
{  
  
    int  res; 
	pthread_t a_thread;	  
    char  buf[256];  
	
	if(argc == 2){
		uart_device = argv[1];
	}
  
    printf("open %s\n", uart_device);  
    fd = open(uart_device, O_RDWR);  
  
    if (fd < 0) {  
        perror(uart_device);  
        exit(1);  
    }  
  
    printf("setting...\n");  
    set_speed(fd, BAUDRATE);  
    if (set_Parity(fd,8,1,'N') == FALSE)  {  
        printf("Set Parity Error\n");  
        exit (0);  
    }	

    res = pthread_create(&a_thread, NULL, read_thread, NULL); /*启动线程函数*/
    if (res != 0){
        perror("Thread creation failed");
        exit(0);
    }
	printf("read thread is created.\n");
	
    while(1) { 
		printf("input the data: ");
		gets(buf);
		res = write(fd, buf, strlen(buf));
		if(res > 0) printf("write sucess. length:%d.\n", res); 
    }  
  
    printf("Close...\n");  
    close(fd);  
  
    return 0;  
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hello-linux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值