您的位置:首页 > 编程语言 > Qt开发

<linux+qt>使用thread监控串口通信(一)

2013-11-11 21:13 579 查看
最近做的项目需要使用到串口通信方面的知识,就这方面的内容加以总结和分享:

(1)首先是串口的读写操作,都是在Linux下进行的操作

1.1 串口的打开

//打开串口

/******************************************************************************

* 函数名称:OpenSerialPort()

* 功能描述:打开串口

* 输入参数: intiComNum// 串口号(COM0,COM1,COM2等)

* 输出参数:

* 返回值:打开的串口的文件描述符

* 其它说明:

* 修改历史:

******************************************************************************/



static intOpenSerialPort(intiComNum)// 串口号(COM1,COM2等)

{

/* 各变量的定义 */

intfd = -1;// 串口的文件描述符


if ( 1 == iComNum )// 串口1

{

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

if ( -1 == fd )

{

perror("Can't Open Serial Port 1");

return(-1);

}

}

else if ( 2 == iComNum )// 串口2

{

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

if ( -1 == fd )

{

perror("Can't Open Serial Port 2");

return(-1);

}

}

else if ( 3 == iComNum )// 串口3

{

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

if ( -1 == fd )

{

perror("Can't Open Serial Port 3");

return(-1);

}

}

//change by hss delete 0 add 4 serial port

else if ( 4 == iComNum )// 串口4

{

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

if ( -1 == fd )

{

perror("Can't Open Serial Port 4");

return(-1);

}

}

else

{

printf("system don't have Serial Port %d\n",iComNum);

return -1;

}


fcntl(fd, F_SETFL, O_NONBLOCK);//非阻塞


/* 测试是否为一个终端设备,以进一步确认串口是否正确打开 */

if( 0 == isatty(STDIN_FILENO) )

{

printf("standard input is not a terminal device.\n");

}

else

{

;//printf("is a tty success!\n");

}


//printf("fd-open = %d\n", fd);


returnfd;

}






使用到的函数fcntl(fd, F_SETFL, 0);//此为阻塞方式


/******************************************************************************

* 函数名称:SetSerialPort()

* 功能描述:配置串口参数

* 输入参数: intfd,// 串口的文件描述符

*intiSerialPortSpeed,// 串口速率(读写速率一致)

*intiBits,// 数据位 或 字符大小 ???

*charcParityCheck,// 奇偶校验位

*intiStop// 停止位

* 输出参数:无

* 返回值:int

* 其它说明:

******************************************************************************/

intSetSerialPort(

intfd,// 串口的文件描述符

intiSerialPortSpeed,// 串口速率(读写速率一致)

intiBits,// 数据位 或 字符大小 ???

intiParityCheck,// 奇偶校验位

intiStop,// 停止位

intiFlowControl// 流控标志位

)

{

/* 各变量的定义 */

struct termiosTNewSerialPortParam;// 新串口配置参数

struct termiosTOldSerialPortParam;// 老串口配置参数


/* 各变量值的赋值和初始化 */


/* 函数任务开始 */

// 保存测试现有串口的参数设置,如果串口号等出错,则有相关出错信息

if ( 0 != tcgetattr( fd, &TOldSerialPortParam ) )

{

perror("SetupSerial 1");

return(-1);

}


// 新串口配置参数清零

bzero( &TNewSerialPortParam, sizeof(TNewSerialPortParam) );


// 激活本地连接和接收使能

TNewSerialPortParam.c_cflag |= CLOCAL | CREAD;


// 设置数据位

TNewSerialPortParam.c_cflag &= ~CSIZE;

switch ( iBits )

{

case 7:

TNewSerialPortParam.c_cflag |= CS7;

break;

case 8:

TNewSerialPortParam.c_cflag |= CS8;

break;

default:// 默认数据位为8

TNewSerialPortParam.c_cflag |= CS8;

break;

}// end of switch ( iBits )


// 设置波特率

switch ( iSerialPortSpeed )

{

case 2400:

同下

case 4800:

同下

case 9600:

cfsetispeed( &TNewSerialPortParam, B9600);

cfsetospeed( &TNewSerialPortParam, B9600);

break;

case 19200:

同上

case 38400:

同上

case 57600:

同上

case 115200:

cfsetispeed( &TNewSerialPortParam, B115200 );

cfsetospeed( &TNewSerialPortParam, B115200);

break;

case 460800:

同上

default:

cfsetispeed( &TNewSerialPortParam, B9600 );

cfsetospeed( &TNewSerialPortParam, B9600);

break;

}// end of switch ( iSerialPortSpeed )


// 设置奇偶校验位

switch ( iParityCheck )

{

case ODD_CHECK:// 奇校验

TNewSerialPortParam.c_cflag |= PARENB;

TNewSerialPortParam.c_cflag |= PARODD;

TNewSerialPortParam.c_iflag |= (INPCK | ISTRIP);

break;

case EVEN_CHECK:// 偶校验

TNewSerialPortParam.c_iflag |= (INPCK | ISTRIP);

TNewSerialPortParam.c_cflag |= PARENB;

TNewSerialPortParam.c_cflag &= ~PARODD;

break;

case NO_CHECK:// 无奇偶校验位

TNewSerialPortParam.c_cflag &= ~PARENB;

break;

default:// 默认无奇偶校验位

TNewSerialPortParam.c_cflag &= ~PARENB;

break;

}// end of switch ( cParityCheck )


// 设置停止位

switch ( iStop )

{

case 2:// 停止位为2,激活CSTOPB

TNewSerialPortParam.c_cflag |= CSTOPB;

break;

case 1:// 停止位为1,清除CSTOPB

TNewSerialPortParam.c_cflag &= ~CSTOPB;

break;

default:// 默认停止位为1

TNewSerialPortParam.c_cflag &= ~CSTOPB;

break;

}// end of switch ( iStop )


// 设置流控

switch ( iFlowControl )

{

case NO_FLOW_CTRL:    // 无流控

TNewSerialPortParam.c_cflag &= ~CRTSCTS;// 关闭硬件流控

TNewSerialPortParam.c_iflag &= ~( IXON | IXOFF | IXANY );// 关闭软件流控

break;


case HARD_FLOW_CTRL:// 硬流控

TNewSerialPortParam.c_cflag |= CRTSCTS;// 开启硬件流控

TNewSerialPortParam.c_iflag &= ~( IXON | IXOFF | IXANY );// 关闭软件流控

break;


case SOFT_FLOW_CTRL:// 软流控

TNewSerialPortParam.c_cflag &= ~CRTSCTS;// 关闭硬件流控

TNewSerialPortParam.c_iflag |= ( IXON | IXOFF | IXANY );// 开启软件流控

break;

default:// 默认无流控

TNewSerialPortParam.c_cflag &= ~CRTSCTS;// 关闭硬件流控

TNewSerialPortParam.c_iflag &= ~( IXON | IXOFF | IXANY );// 关闭软件流控

break;

}// end of switch ( iFlowControl )


// 设置等待时间和最小接收字符

TNewSerialPortParam.c_cc[VTIME] = 0;

TNewSerialPortParam.c_cc[VMIN] = 0;


// 处理未接受字符

tcflush( fd, TCIFLUSH );


// 激活新配置

if ( 0 != tcsetattr(fd, TCSANOW, &TNewSerialPortParam) )

{

perror("com set error");

return(-1);

}



//printf("set done!\n");

/* 函数任务结束 */

return0;

}


用以上两个函数,打开串口,并设置串口的各项属性,主要的有波特率等信息,设置错误即使打开串口也无法通信。

调用例子:

int di_s4b_comfd = OpenSerialPort();

SetSerialPort(di_s4b_comfd, //文件描述符

115200,//波特率

8,//数据位

0,//奇偶校验位

1,//停止位

0);//流控标志位

1.2 数据的写入

写操作较为简单,因为不需要一直监视串口,直接写到串口就可以,不完备的写操作大致如下:

/*

将ACK通过三号端口写出

*/

void writeMessage()

{

int comfd = sthread->retComfd();//由外部获得端口的文件描述符

const char array[]={'A','C','K'};

write(comfd,array,3);

qDebug("writeMessage done!");

}

主要使用的函数为write函数

ssize_t write(int fd, const void *buf, size_t count);

返回值为写入串口的数据长度,buf为写入的数据,count为数据长度

以上例子是一个不完备的写入情况,没有对写入不完全的情况进行处理,也没有考虑资源的保护和互斥的使用。

1.3 数据的读出

数据的读出较写入麻烦,原因在于对读取数据时机的判断,为在数据到达时立即得到通知,并把数据读出,需要时时对端口进行监控,同时主程序保持运行,此时就需要用到多线程,一个主线程,一个守护线程。此处先给出读数据的示例代码,多线程串口通信在下一节给出。

/*

子线程一直监视串口,在有数据时,将其读出

*/

void SThread::run()

{

while (1)

{

res = read(di_s4b_comfd, tosendstr, 4);

if (res >=4)

 {

qDebug("abcd\n");

emit get(1);

}

}

qDebug("Serial done\n");

}


read函数原型

#include<unistd.h>

ssize_t read(intfd, void *buf,
size_t
count);

read返回为读取字符串的长度,fd为端口的文件描述符,buf为读取的数据,count为长度。


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: