串口配置流程
(1)保存原先串口配置使用tcgetattr(fd,&oldtio)函数
struct termios newtio,oldtio;tcgetattr(fd,&oldtio);
(2)激活选项有CLOCAL和CREAD,用于本地连接和接收使能。newtio.c_cflag|=CLOCAL|CREAD;
(3)设置波特率,使用函数cfsetispeed、cfsetospeed
cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);
(4)设置数据位,需使用掩码设置。
newtio.c_cflag&=~CSIZE;
newtio.c_cflag|=CS8;
(5)设置奇偶校验位,使用c_cflag和c_iflag。
设置奇校验:
newtio.c_cflag|=PARENB;
newtio.c_cflag|=PARODD;
newtio.c_iflag|=(INPCK | ISTRIP);
设置偶校验:
newtio.c_iflag|=(INPCK|ISTRIP);
newtio.c_cflag|=PARENB;
newtio.c_cflag&=~PARODD;
(5)设置停止位,通过激活c_cflag中的CSTOPB实现,若停止位为1,则清除CSTOPB,若停止位为2,则激活CSTOPB。
newtio.c_cflag&=~CSTOPB;
(6)设置最少字符和等待时间,对于接收字符和等时间没有特别要求时,可设为0。
newtio.c_cc[VTIME]=0;
newtio.c_cc[VMIN]=0;
(7)处理要写入的引用对象tcflush函数刷清(抛弃)输入缓存(终端驱动程序已接收到,但用户程序尚未读)或输出缓存(用户程序已经写,但尚未发送)。
int tcflush(int filedes,int queue)
queue数应当是下列三个常数之一:
TCIFLUSH 刷清输入队列
TCOFLUSH 刷清输出队列。
TCIOFLUSH 刷清输入、输出队列。
如:tcflush(fd,TCIFLUSH);
(8)激活配置。在完成配置后,需激活配置使其生效。使用
tsettattr()函数。原型:
int tcgetattr(int filedes,struct termios *termptr);
int tcsetattr(int filedes, int opt, const struct termios
*termptr);
tcsetattr的参数opt使我们可以指定在什么时候新的终端属性才起作用。opt可以指定为下列常数中的一个:
TCSANOW更改立即发生。
TCSADRAIN发送了所有输出后更改才发生。若更改输出参数则应使用此选择项。
TCSAFLUSH发送了所有输出后更改才发生。更进一步,在列改发生时未读的所有输入数据都被删除(刷清)使用如:tcsetattr(fd,TCSANOW,&newtio)
打开串口
fd=open("/dev/ttyS0",O_RDWR|O_NOCTTY|O_NDELAY);
Open函数中除普通参数外,另有两个参数O_NOCTTY和O_NDELAY。
O_NOCTTY:通知linux系统,这个程序不会成为这个端口的控制终端。
O_NDELAY:通知linux系统不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。
在标准模式下,除非设置了O_NONBLOCK选项,否则只有当遇到文件结束符或各行的字符都已经编辑完毕后才返回,即默认的读操作是阻塞的。
例子:
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define RS485_NAME "/dev/ttyS2"
#define IOC_SET_SEND _IOW(RTS_MAJOR, 1, unsigned long)
#define IOC_SET_RECEIVE _IOW(RTS_MAJOR, 2, unsigned long)
#define BAUDRATE 19200
int speed_arr[] = { B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300,};
int name_arr[] = {115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300,};
/*******************************************************************
@brief 设置串口通信速率
fd 类型 int 打开串口的文件句柄
speed 类型 int 串口速度
void
********************************************************************/
int 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);
}
return 0;
}
/***************************************************************************
设置串口数据位,停止位和效验位
fd 类型 int 打开的串口文件句柄
databits 类型 int 数据位 取值 为 7 或者8
stopbits 类型 int 停止位 取值为 1 或者2
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(-1);
}
options.c_cflag &= ~CSIZE;
switch (databits) /*设置数据位数*/
{
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf(stderr,"Unsupported data size\n"); return (-1);
}
switch (parity)
{
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Clear parity checking */
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
options.c_iflag |= INPCK; /* enable parity checking */
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* 转换为偶效验*/
options.c_iflag |= INPCK; /* enable 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 (-1);
}
/* 设置停止位*/
switch (stopbits)
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr,"Unsupported stop bits\n");
return (-1);
}
/* Set input parity option */ /*have set it befor*/
//if (parity != 'n')
// options.c_iflag |= INPCK;
// options.c_iflag=0;/*直接设置为0最方便;否则以前的设置会影响接收*/
// options.c_cflag |= (CLOCAL | CREAD);
// options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// options.c_oflag &= ~OPOST; /*Output*/
tcflush(fd,TCIFLUSH);
//设置最少字符和等待时间,对于接收字符和等时间没有特别要求时,可设为0
options.c_cc[VTIME] = 50; /* 设置超时15 seconds*/
options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
if (tcsetattr(fd,TCSANOW,&options) != 0)
{
perror("SetupSerial 3");
return (-1);
}
return (0);
}
/*==========================================================================*
int uart_test(void)
{
int iRtn,iRS485,status;
char rxbuf[100]={0};
int iRes=0;
iRS485= open(RS485_NAME, O_RDWR);
if (iRS485 < 0)
{
printf("Can't open device %s.\n", RS485_NAME);
goto err;
}
set_speed(iRS485,BAUDRATE);
set_Parity(iRS485,8,1,'o');
ioctl(iRS485, TIOCSERGETLSR, &iRtn);
//printf("\nThe 1 MODEM status bit is 0x%x\n",iRtn);
ioctl(iRS485,TIOCMGET,&status);
// status |=TIOCM_DTR;
status |=TIOCM_RTS;
ioctl(iRS485,TIOCMSET,&status); //set RTS in write mode
write(iRS485, "RS485 test data!!", 10);
iRtn = 0;
while(!iRtn)
{
ioctl(iRS485, TIOCSERGETLSR, &iRtn);
// printf("%d",iRtn);
}
ioctl(iRS485,TIOCMGET,&status);
status &=~ TIOCM_RTS;
ioctl(iRS485,TIOCMSET,&status); //set RTS in receive mode
// getchar();
iRtn = read(iRS485, rxbuf, sizeof(rxbuf));
if(iRtn > 0) printf("RS485 receive data is :%s\n",rxbuf);
err:
close(iRS485);
return iRS485;
}