Linux下串口编程

时间:2021-12-08 16:12:06
 Linux系统下,诸如串口、触摸屏、GPIO、ADC等等各种设备的操作,都是通过访问其对应的设备节点进行控制。相应地,串口通过访问/dev/ttyS0、/dev/ttyS1、/dev/ttyS2...对其进行配置与控制。
串口配置的参数包括:波特率,数据位,校验位,停止位与流控。
串口的配置主要是通过配置struct termios结构体,其原型如下:
#include<termios.h>
struct termio
{
unsigned short c_iflag; /*输入模式标志*/
unsigned short c_oflag; /*输出模式标志*/
unsigned short c_cflag; /*控制模式标志*/
unsigned short c_lfag; /*本地模式标志*/
unsigned short c_line; /*line discipline*/
unsigned short c_cc[NCC]; /*control characters*/
};
其中,通过对 c_cflag与c_iflag的赋值,可以设置波特率、数据位、奇偶校验位、停止位、流控。
1、波特率配置
串口通过函数cfsetispeed和cfsetospeed设置端口的输入/输出波特率:
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
其中termios_p为串口接头体termios指针变量;speed为需要设置的串口传输速率,取值与波特率对应关系见表: 

   

波特率(单位:bit/s

   

波特率(单位:bit/s

B0

0

B1800

1800

B50

50

B2400

2400

B75

75

B4800

4800

B110

110

B9600

9600

B134

134

B19200

19200

B150

150

B38400

38400

B200

200

B57600

57600

B300

300

B115200

115200

B600

600

B230400

230400

B1200

1200

 

 

2、数据位配置
串口数据位的配置通过修改termios结构体成员c_cflag实现,CS5、CS6、CS7和CS8分别表示数据位为5、6、7和8。在设置数据位前,先使用CSIZE做位屏蔽:
termios_p.c_cflag &= ~CSIZE;
termios_p.c_cflag  |=  CS5;  /*配置为5数据位*/
3、校验位配置
校验位包括:无校验、奇校验、偶校验、空格等:
无校验:
termios_p.c_cflag &= ~PARENB;
termios_p.c_iflag &= ~INPCK;
奇校验:
termios_p.c_cflag &= (PARODD | PARENB);
termios_p.c_iflag &= INPCK;
偶校验:
termios_p.c_cflag |= PARENB;
termios_p.c_cflag ~PARODD;
termios_p.c_iflag & |= INPCK;
空格:
termios_p.c_cflag &= ~PARENB;
termios_p.c_cflag &= ~CSTOPB;
termios_p.c_iflag |= INPCK;
4、停止位配置
串口停止位通过激活c_cflag的CSTOPB控制,具体方法如下:
1个停止位:
termios_p.c_cflag &= ~CSTOPB;
2个停止位:
termios_p.c_cflag |= CSTOPB;
5、流控配置
流控用于标识数据的开始与结束,流控的种类包括硬件流、软件流与不使用流控。
不使用流控:
termios_p.c_cflag &= ~CRTSCTS;
硬件流:
termios_p.c_cflag |= CRTSCTS;
软件流:
termios_p.c_cfalg |= IXON | IXOFF | IXANY;
 

例子程序:
程序实现了配置串口0参数与向串口0输出数据

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

void Set_uart(int fd, int databits, int stopbit, char parity, char datastream)
{
int ret;
struct termios termios_opt;

if(tcgetattr(fd, &termios_opt))
{
perror("tcgetattr error\n");
return;
}

/*flush memory*/
tcflush(fd,TCIOFLUSH);

/*Set i/o speed*/
cfsetispeed(&termios_opt, B115200);
cfsetospeed(&termios_opt, B115200);

/*active options*/
termios_opt.c_cflag |= CLOCAL | CREAD;

/*set databits,default is 8 databits*/
termios_opt.c_cflag &= ~CSIZE;
switch (databits)
{
case 5:
termios_opt.c_cflag |= CS5;
break;
case 6:
termios_opt.c_cflag |= CS6;
break;
case 7:
termios_opt.c_cflag |= CS7;
break;
case 8:
termios_opt.c_cflag |= CS8;
break;
default:
termios_opt.c_cflag |= CS8;
break;
}

/*Set Parity, default is no vertify*/
switch (parity)
{
case 'N': /*no vertify*/
termios_opt.c_cflag &= ~PARENB;
termios_opt.c_iflag &= ~INPCK;
break;
case 'O': /*odd vertify*/
termios_opt.c_cflag |= (PARODD | PARENB);
termios_opt.c_iflag |= INPCK;
break;
case 'E': /*even vertify*/
termios_opt.c_cflag |= PARENB;
termios_opt.c_cflag &= ~PARODD;
termios_opt.c_iflag |= INPCK;
break;
case 'S': /*space vertify*/
termios_opt.c_cflag &= ~PARENB;
termios_opt.c_cflag &= ~CSTOPB;
termios_opt.c_iflag |= INPCK;
break;
default:
termios_opt.c_cflag &= ~PARENB;
termios_opt.c_iflag &= ~INPCK;
break;
}

/*Set stop bits, default is 1 stopbit*/
switch (stopbit)
{
case 1:
termios_opt.c_cflag &= ~CSTOPB;
break;
case 2:
termios_opt.c_cflag |= CSTOPB;
break;
default:
termios_opt.c_cflag &= ~CSTOPB;
break;
}

/*set data stream,default is no data stream control*/
switch (datastream)
{
case 'N': /*no data stream control*/
termios_opt.c_cflag &= ~CRTSCTS;
break;
case 'H': /*hardware data stream control*/
termios_opt.c_cflag |= CRTSCTS;
break;
case 'S': /*software data stream control*/
termios_opt.c_cflag |= IXON | IXOFF | IXANY;
break;
default:
termios_opt.c_cflag &= ~CRTSCTS;
break;
}

/*oput modle,initial data output*/
termios_opt.c_oflag &= ~OPOST;

/*set waiting time and recv min character*/
termios_opt.c_cc[VTIME] = 0;
termios_opt.c_cc[VMIN] = 0;

/*flush memory*/
tcflush(fd,TCIFLUSH);

/*start using new options*/
if((tcsetattr(fd,TCSANOW,&termios_opt)) != 0)
{
perror("serial setup error\n");
return;
}

printf("set serial done!\n");
return ;
}

int main(void)
{
int serial_fd;
unsigned char data[14] = {0};

memset(data,'a',sizeof(data));
printf("open UART..\n");

serial_fd = open("/dev/ttyS0",O_RDWR | O_NOCTTY | O_NONBLOCK);
if (serial_fd == -1)
{
perror("Serial open error!\n");
return -1;
}

/*Set uart*/
Set_uart(serial_fd, 8, 1, 'N', 'N'); //8 databits, 1 stopbit, No vertify, No data stream control

while(1)
{
write(serial_fd, data, sizeof(data));
tcdrain(serial_fd);
sleep(2);
}
close(serial_fd);
return 0;
}