Linux串口通信

串口通信总体步骤:
在这里插入图片描述

  1. 打开串口
  int	m_nPortFD = open(m_sPortName, O_RDWR | O_NOCTTY);

参数1:串口名称
参数2:打开方式(可选)
返回值:成功返回文件描述符,失败返回-1
参数2必选其一

  • O_RDONLY只读模式

  • O_WRONLY只写模式

  • O_RDWR读写模式
    参数2可选配置

  • O_APPEND 每次写操作都写入文件的末尾

  • O_CREAT 如果指定文件不存在,则创建这个文件

  • O_EXCL如 果要创建的文件已存在,则返回 -1,并且修改 errno 的值

  • O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容

  • O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。对于串口的打开操作,必须使用O_NOCTTY参数,它表示打开的是一个终端设备,程序不会成为该端口的控制终端。如果不使用此标志,任务的一个输入(比如键盘终止信号等)都会影响进程。

  • O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式(nonblocking mode)

  1. 初始化串口
    2.1 设置波特率
cfsetispeed(&m_PortOptions, nUtiBaudRate);  // set up input baudrate   
cfsetospeed(&m_PortOptions, nUtiBaudRate);   // set up output baudrate

参数1:struct termios m_PortOptions; 参数2: 波特率

    struct termios
    {
               tcflag_t c_iflag; 1.输入模式
               tcflag_t c_oflag; 2.输出模式
               tcflag_t c_cflag; 3.控制模式
               tcflag_t c_lflag; 4.本地模式
               cc_t     c_cc[NCCS]; 5.特殊控制模式
    };

你可以调用函数tcgetattr来初始化一个终端对应的termios结构,该函数的原型如下:

    #include<termios.h>
    int tcgetattr(int fd, struct termios *m_OldPortOptions);

这个函数调用把当前终端接口变量的值写入termios_p参数指向的结构。如果这些值其后被修改了,你可以通过调用函数tcsetattr来重新配置
终端接口。

    #include<termios.h>
    int tcsetattr(int fd , int actions , const struct termios *m_PortOptions);

参数actions控制修改方式,共有三种修改方式,如下所示。
1.TCSANOW: 立刻对值进行修改
2.TCSADRAIN:等当前的输出完成后再对值进行修改。
3.TCSAFLUSH:等当前的输出完成之后,再对值进行修改,但丢弃还未从read调用返回的当前的可用的任何输入。

bool CreatePort(const char *sPortName, int nBaudRate)
{
    int nUtiBaudRate = 0;

    switch(m_nBaudRate)
    {
        case 115200:
            nUtiBaudRate = B115200;
            break;
        case 38400:
            nUtiBaudRate = B38400;
            break;
        case 19200:
            nUtiBaudRate = B19200;
            break;
        case 9600:
            nUtiBaudRate = B9600;
            break;
        case 4800:
            nUtiBaudRate = B4800;
            break;
        case 2400:
            nUtiBaudRate = B2400;
            break;
        case 1200:
            nUtiBaudRate = B1200;
            break;
        case 600:
            nUtiBaudRate = B600;
            break;
        case 300:
            nUtiBaudRate = B300;
            break;
        default:
            printf("Unsupported baud rate\n");
            return false;
    }
    m_nPortFD = open(m_sPortName, O_RDWR | O_NOCTTY);

    if (-1 == m_nPortFD)
    {
        printf("Open failed\n");
        perror(m_sPortName);
        exit(-1);
    }

    // 保存以前的串口配置
    if(tcgetattr(m_nPortFD, &m_OldPortOptions) != 0)
    {
        printf("Failed to get old default configuration");
		perror("tcgetattr");
	}; 

    // 清空m_PortOptions
    memset(&m_PortOptions, 0, sizeof(m_PortOptions));

    // 配置前,清空输入输出缓冲区
    tcflush(m_nPortFD, TCIOFLUSH);

    // m_PortOptions = m_OldPortOptions;
    m_PortOptions.c_cflag = nUtiBaudRate | CLOCAL | CREAD;
    m_PortOptions.c_iflag = IGNPAR;
    m_PortOptions.c_oflag = 0;

    // 配置数据位
    switch(m_nDataBits)
    {
        case 7:
        	m_PortOptions.c_cflag |= CS7;
            break;
        case 8:
            m_PortOptions.c_cflag |= CS8;
            break;
        default:
            m_PortOptions.c_cflag |= CS8;
    }

    //设置奇偶校验
    switch(m_cParity)
    {
        case 'O'://odd
            m_PortOptions.c_cflag |= PARENB;
            m_PortOptions.c_cflag |= PARODD;
            m_PortOptions.c_iflag |= (INPCK | ISTRIP);
            break;
        case 'E': //even
            m_PortOptions.c_cflag |= PARENB;
            m_PortOptions.c_cflag &= ~PARODD;
            m_PortOptions.c_iflag |= (INPCK | ISTRIP);
            break;
        case 'N':  //no parity
            m_PortOptions.c_cflag &= ~PARENB;
            break;
        default:
            m_PortOptions.c_cflag &= ~PARENB;
    }
    
    // 设置输入速率
	cfsetispeed(&m_PortOptions, nUtiBaudRate);
    // 设置输出速率
	cfsetospeed(&m_PortOptions, nUtiBaudRate);

    // 设置停止位
    switch(m_nStopBits)
    {
        case 1:
            m_PortOptions.c_cflag &= ~CSTOPB;
            break;
        case 2:
            m_PortOptions.c_cflag |= CSTOPB;
            break;
        default:
            m_PortOptions.c_cflag &= ~CSTOPB;
    } 

    // additional configuration

    // set input mode (non-canonical, no echo,...)
    m_PortOptions.c_lflag = 0;
	
	// configure VTIME VMIN
	m_PortOptions.c_cc[VTIME] = 0; 
	m_PortOptions.c_cc[VMIN] = 1;
  //read一直等待,直到有MIN个字符可以读取,返回值是字符的数量.到达文件尾时返回0
	
	// /*处理未接收字符*/ 
    tcflush(m_nPortFD, TCIFLUSH);
    
/*激活新配置*/ 
	if(tcsetattr(m_nPortFD, TCSANOW, &m_PortOptions) != 0)  // 立即生效
    {  
	    printf("Failed to enable the configuration for serial port\n");
        perror("tcsetattr");
		
		return false;
	}  
	 // 配置使能后 也清空输入和输出缓冲区
	tcflush(m_nPortFD, TCIOFLUSH);

    return m_nPortFD>-1;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux系统中,串口通信是通过串口驱动程序来实现的。下面是一个简单的Linux串口通信的步骤: 1. 打开串口设备文件 在Linux系统中,每个串口设备都对应一个设备文件,例如/dev/ttyS0、/dev/ttyS1等。要使用串口,首先需要打开串口设备文件。可以使用open()函数来打开串口设备文件,例如: ``` int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); ``` 其中,/dev/ttyS0是串口设备文件的路径,O_RDWR表示以读写方式打开文件,O_NOCTTY表示该串口不作为控制终端,O_NDELAY表示在读取串口时不会阻塞。 2. 配置串口参数 打开串口设备文件之后,需要设置串口的通信参数,例如波特率、数据位、停止位、校验位等。可以使用termios结构体来设置串口参数,例如: ``` struct termios options; // 获取当前串口参数 tcgetattr(fd, &options); // 设置波特率为9600 cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); // 设置数据位为8 options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; // 设置停止位为1 options.c_cflag &= ~CSTOPB; // 设置校验位为无校验 options.c_cflag &= ~(PARENB | PARODD); // 应用设置 tcsetattr(fd, TCSANOW, &options); ``` 3. 读写串口数据 设置完串口参数之后,就可以进行数据的读写操作了。可以使用read()函数从串口读取数据,例如: ``` char buf[1024]; int nbytes = read(fd, buf, sizeof(buf)); ``` 其中,fd是串口设备文件的文件描述符,buf是用于存储读取数据的缓冲区,sizeof(buf)表示最多读取的字节数,nbytes是实际读取的字节数。 可以使用write()函数向串口写入数据,例如: ``` char buf[] = "hello, world!"; write(fd, buf, strlen(buf)); ``` 其中,fd是串口设备文件的文件描述符,buf是要写入的数据,strlen(buf)表示要写入的字节数。 4. 关闭串口设备文件 使用完串口之后,需要关闭串口设备文件,可以使用close()函数来关闭串口设备文件,例如: ``` close(fd); ``` 以上就是一个简单的Linux串口通信的步骤,需要注意的是,对于串口的读写操作,还需要根据实际情况进行阻塞或非阻塞操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值