select问题!多任务系统下,ARM与单片机串口通讯任务,为什么用select阻塞串口通讯任务后,任务就不能恢复了?
该串口初始化如下
ioctl(comm2Fd,FIOBAUDRATE,9600)
ioctl(comm2Fd,FIOSETOPTIONS,OPT_RAW)
使用如下
FD_ZERO (&readFds);
FD_SET (comm2Fd, &readFds);
width = comm2Fd + 1;
FD_ISSET (comm2Fd, &readFds);
FOREVER
{
if(timeoutvalue==0)
{
printf("\nselect start!\n");
selectnum = select (width, &readFds, NULL, NULL, NULL);
printf("\nselect over!\n");
}
...........
}
现在的状况是程序跑一段时间后会死机或这个串口通讯任务死掉,每次死机都是“select start!”打印出来,而“select over!”打印不出来,在仅这个串口通讯任务死掉的情况下,用comm1Fd超级终端登陆,查询任务状态,会发现tExcTask任务居然处于挂起状态???
哪位大哥帮忙分析一下或给予一点提示,小弟不胜感激!!
专业提供SDK二次开发包的短信平台接口等,企业短信群发平台,可群发短信、彩信、语音、传真、邮件等。发送接受速度快,成功率高,5万家用户保证质量!附注:软件界面简洁化,操作简便化,不需要任何硬件配备(除了电脑及上网)可以几个部门同时使用,并可以由一个总帐号管理,可以随时查看子帐号的使用情报况,余额分配等有如意通客户端,网络版,SDK短信平台接口等多版本供您选择
联系人:刘斌 手机号码:13163799460 QQ:178493093 MSN:liubinkyt@hotmail.com
select函数在设备读(或写)操作未就绪时应该处于阻塞状态,也就是说你的进程在串口没有收到数据时会处于挂起状态,一旦select监测到有数据可读(或可写如),进程就会转为运行态,继续执行。
从你描述的现象上看,进程本身因该没有当掉,而是底层驱动没有收到数据供应用层读取。不知道你用的是CPU自带串口还是扩展串口。建议你查查串口驱动,有可能的话把中断信号牵出来看看,是不是每次中断都能正确响应。
avbsp您好,我还有一个问题,我上面给出的代码是不是有些问题?
FD_ZERO (&readFds);
FD_SET (comm2Fd, &readFds); 这两句是不是应该写在FOREVER 循环中?
请问,如果不清除,按照我当前的代码来写,会有什么问题吗?能解释一下吗?谢谢
详细函数如下:
static STATUS RecvDataWithTimeOut(UINT16 datacount,UINT16 timeoutvalue)
{
....
....
timeout.tv_sec = timeoutvalue;
timeout.tv_usec = 0;
FD_ZERO (&readFds);
FD_SET (comm2Fd, &readFds);
width = comm2Fd + 1;
FD_ISSET (comm2Fd, &readFds);
FOREVER
{
if(timeoutvalue==0)
selectnum = select (width, &readFds, NULL, NULL, NULL);
else
selectnum = select (width, &readFds, NULL, NULL, &timeout);
if (selectnum == ERROR)
{
#ifdef DEBUG_PRINT
printErr("ERROR:An select error has occurred in received data from COM2!\n");
#endif
return ERROR;
}
else if(selectnum == 0)
{
#ifdef DEBUG_PRINT
printErr("ERROR:An timeout error has occurred in received data from COM2!\n");
#endif
return ERROR;
}
if (FD_ISSET (comm2Fd, &readFds))
{
bytesRead = fioRead(comm2Fd,szBuf,datacount);
return bytesRead;
}
}
}
我的问题是,因为我用的是fioRead,所以还用不用将
FD_ZERO (&readFds);
FD_SET (comm2Fd,&readFds);这两句写在FOREVER循环中?
如果需要写入,为什么?
如果不写入按照我当前的代码写,会出现什么问题?
还有这里用fioRead代替read会出现什么问题吗?
我使用read函数来读数据,select的使用方式和你差不多,不过作了一下保护:
void UartRX(void)
{
struct fd_set ltv_readFds;
struct fd_set ltv_saveFds;
int liv_width;
int liv_numFds;
liv_width = 0;
FD_ZERO(<v_saveFds); /* initialize the set - all bits off */
/*
* The liv_width argument is the maximum file descriptor to
* be tested, plus one. The descriptors 0,1, up through
* and including liv_width -1 are tested.
*/
FD_SET(UartInfo.fd, <v_saveFds); /* Turn on bit for panel uart fd */
liv_width = UartInfo.fd;
liv_width++;
FOREVER
{
ltv_readFds = ltv_saveFds;
/*
* Pend on multiple file descriptors indefinitely using select
* until one or more file descriptors become ready for reading.
*/
if ((liv_numFds = select(liv_width, <v_readFds, NULL, NULL, NULL)) == ERROR)
{
logMsg("ERROR in select.\n");
continue;
}
if (FD_ISSET(UartInfo.fd, <v_readFds))
{
// read data from uart
}
}
return;
}
问个问题:如果你的函数在select错误或超时后退出,该函数还会重新创建吗?
不会了!我的函数比较弱!select错误或超时后退出就丢弃这次通讯,这样除了丢失信息还会有其他问题吗?
为什么我在我的代码里把fioRead换成read就不行,是不是要对收的字节数进行判断循环接收,read不是读取制定的字节数吗?
通常情况下,如果你需要一直监测串口,最好让串口接收进程始终处于运行状态,在select错误或超时后给出提示信息并让循环重新执行;要么在接收串口数据前发起进程,前提是你知道数据什么时候来。
对于read函数,你指定的dataCount是要读取的最大长度。假设缓冲区中有10个字节,你指定的dataCount为5,那么
read(fd, buf, dataCount)的返回值为5;如果缓冲区中只有3个字节,dataCount仍为5,那么read(fd, buf, dataCount)将返回实际读取的字节数——3。
你可以根据需要定义一套通信协议,按照一定的格式进行通信,如
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| 起始标志(1字节) | 长度(1字节) | 数据........(n字节) | 结束表示(1字节) |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
根据指定的数据帧结构就可以判断数据是否接收完毕。
这个任务在运行的一段后会打印(前后调用select均正常)
select start!
Undefined instruction
Exception address: 0x0005c1e0
Current Processor Status Register: 0x20000013
Task: 0xff45c8 "tTffsPTask"
select over!
请问是怎么回事?我仔细看了一下这个文件没有include库文件selectLib.h,是这个原因吗?这个原因会造成死机吗?
FD_ZERO (&readFds);
FD_SET (comm2Fd,&readFds);这两句要写在FOREVER循环中。
你可以自己监测一下,每次select完,readFds都被改动了,所以必须重新设置。不设置,会导致select不按照你预想的对comm2Fd进行IO检查,这样即使你comm2有数据,也无法激活select
那个"tTffsPTask"任务是调用你那个select程序的任务吗?
确认一下comm2Fd是不是打开的串口2对应的fd。
其实如果对select函数不熟悉的话,看看示例代码,或者如果赶时间的话直接别用select了。某个地方自己没有搞清楚,觉得有也许可能没有问题的时候,往往就会出问题。
可以专门启动一个任务直接对串口read好了,将获取的数据往一个消息队列里放,然后其他任务从消息队列里读就好了(或者将这个过程封装成读函数就更好了),消息队列反正是有timeout功能的了。这样就能实现想要的功能而不用select了。