<linux+qt>使用thread监控串口通信(一)
2013-11-11 21:13
579 查看
最近做的项目需要使用到串口通信方面的知识,就这方面的内容加以总结和分享:
(1)首先是串口的读写操作,都是在Linux下进行的操作
1.1 串口的打开
//打开串口
用以上两个函数,打开串口,并设置串口的各项属性,主要的有波特率等信息,设置错误即使打开串口也无法通信。
调用例子:
1.2 数据的写入
写操作较为简单,因为不需要一直监视串口,直接写到串口就可以,不完备的写操作大致如下:
/*
将ACK通过三号端口写出
*/
主要使用的函数为write函数
ssize_t write(int fd, const void *buf, size_t count);
返回值为写入串口的数据长度,buf为写入的数据,count为数据长度
以上例子是一个不完备的写入情况,没有对写入不完全的情况进行处理,也没有考虑资源的保护和互斥的使用。
1.3 数据的读出
数据的读出较写入麻烦,原因在于对读取数据时机的判断,为在数据到达时立即得到通知,并把数据读出,需要时时对端口进行监控,同时主程序保持运行,此时就需要用到多线程,一个主线程,一个守护线程。此处先给出读数据的示例代码,多线程串口通信在下一节给出。
/*
子线程一直监视串口,在有数据时,将其读出
*/
read函数原型
#include<unistd.h>
ssize_t read(intfd, void *buf,
size_t count);
read返回为读取字符串的长度,fd为端口的文件描述符,buf为读取的数据,count为长度。
(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为长度。
相关文章推荐
- <linux+qt>使用thread监控串口通信(二)
- <Linux+qt>设置使用键盘控制事件响应
- <Linux+Qt>将中文写入串口
- <Linux+Qt>使用Qt绘制2D 图形 <五 图片变换>
- <Linux+Qt>Qt4编程控制mplayer嵌入自定义界面监控或视频显示
- <Linux+Qt>使用Qt实现单例模式
- <Linux+Qt>在Widget中使用qlabel显示图片与动画
- <Linux+Qt>Linux+Qt学习(二)qt编程相关网站
- 使用muduo编译链接错误 undefined reference to `muduo::ThreadPool::run(boost::function<void ()()>&&)'
- <Linux+Qt>QDialog
- <Linux+Qt>一种移植qt可执行代码的方式
- <Boost> boost::thread 多线程的使用
- <Linux+Qt>QDialog的模态与非模态的对话框
- <Linux+Qt>调用mplayer
- Linux:使用ulimit设置文件最大打开数<转>
- <Linux+Qt>时间控制事件触发
- <linux>adb fastboot 和VNC工具的安装使用
- <Qt+Linux>事件过滤
- linux 下使用man查看命令帮助时 [] <>什么含义
- <Linux+Qt>char*,QString,String类型的相互转换