RS-232-C端口实时监控软件的设计实现

原创 2004年08月04日 11:23:00
文章标题:RS-232-C端口实时监控软件的设计实现
原 作 者:郎锐
原 出 处:天极网
发 布 者:loose_went
发布类型:转载



  摘要:

  本文介绍了在Microsoft Visual C++ 6.0环境下对RS-232-C串行端口进行编程,以及对后台监控程序所普遍涉及到的无阻塞后台运行、数据的实时接收和处理等问题的解决方法。

  一、 引言

  在实验室和工业应用中,受信道成本限制,串口常常作为计算机与外部串行设备之间的首选数据传输通道,而且由于串行通信方便易行,许多设备和计算机都可以通过串口对外设进行控制、检测,串口通讯日益成为计算机和外设进行通讯、获取由外设采集到的监测数据的一个非常重要的手段。本文所描述的程序实例运行于Windows 9x操作系统下,可后台运行、实时接收、处理从端口传来的数据,并能通过向串口发送命令来控制外设的动作。为了避免在实时监控数据时引发程序阻塞,在本程序中引入了线程和端口中断响应等技术。

  二、 程序设计思路

  由于本程序要对串行端口进行实时监控,这就要求它是一个后台程序,在监控的同时可以在前台进行其他一些于之无关的操作。因而在实现时即要避免无时无刻都在反复读端口的效率低下的轮询方式,又不能因为来不及处理而将突然到达的监测数据丢失。只有采取端口中断的异步方式才能实现高效、安全的监控过程,只要一有数据到达端口,马上抛出中断请求,中断处理函数便会及时启动以处理到来的数据,从而避免了轮询间隙丢时数据的可能。而在大部分无数据到达的时间内不会有中断抛出,中断处理函数也不会执行,即仅仅在有数据到达的一瞬间进行工作,此效率不可谓不高。

  综上所述,要实现上述要求,就要用到下列技术来解决所遇到的关键性问题:一是采用多线程来避免在进行文件操作等耗时操作时会引发阻塞现象的发生。同时为了防止多个线程同时对同一个变量进行操作引起时序上的差错,为了保持线程的同步,还采取了临界区加解锁的技术;二是对端口的数据读取方式采取中断响应模式,具体原因前面以讲的很清楚,在此不再赘述;三是使用了定时器,以满足实时监控类程序的实时显示功能,以便及时的将所接收到的动态数据及时的反映到屏
幕上。

三、 RS-232-C串行端口监控软件的程序实现

  (一) 界面风格

  由于是实时监控软件,那就既要监测从外设传来的实时数据,又要通过串口向外设发送一些具体的指令以控制外设完成预先设定的动作。为了方便向串口发送命令可以在工具条上再加一个类似于"Internet Explorer 浏览器"风格的对话条,可以在初建工程时指定"Internet Explorer ReBars"风格,也可以通过添加Microsoft Visual C++ 6.0自带的"Dialog Bar"组件来实现。而要及时将从外部读取的数据显示给管理人员,并且留有相当记录以备查阅,可以选择列表视图来实现。

  (二) 串口的参数设置及打开

  对RS-232-C串行端口进行参数配置是使用串口进行通讯的必要条件。而且由于场合不同、用途、功能的不同对串口也采取不同的配置方式,为了使本程序更灵活,适应面更广,采取将所有的可能参数都预先设置在几个组合框中,可以在程序运行后随时更改设置。自定义一个设置串口参数的数据结构:

typedef struct tagCOM_CONFIG
{
int nPort; file://端口号,从COM1到COM4
int nBaud; file://波特率,从1200bps到57600bps(对应的宏为CBR_1200到CBR_57600)
int nData; file://数据位个数,7位或是8位
int nStop; file://停止位个数,可以是1位、1.5位、2位。
int nParity;//采取的校验方式,有无校验(NOPARITY)、
file://奇校验(ODDPARITY)和偶校验(EVENPARITY)等。
}COM_CONFIG;

  当选择好适当的参数后就可以根据设置好的端口配置情况打开通讯端口了。与以往DOS下串行通信程序不同的是,Windows操作平台下不提倡应用程序直接控制硬件(包括端口),也不让使用中断(除非打入到Ring0系统级),而是通过Windows操作系统提供的设备驱动程序来进行数据传递。在Windows操作系统下串行口和其他通讯端口一样是作为文件来进行处理的,而不是直接对端口进行操作,对于串行通信,Win 32 提供了相应的文件I/O函数与通信函数,通过了解这些函数的使用,可以编制出符合不同需要的通信程序。与通信设备相关的结构有COMMCONFIG ,COMMPROP,COMMTIMEOUTS,COMSTAT,DCB,MODEMDEVCAPS,MODEMSETTINGS共7个,与通信有关的Windows API函数共有26个,具体说明可参考MSDN帮助文件。下面是打开串口的部分关键代码:

//以创建文件的形式打开文件,并将返回的端口句柄保存于句柄idComDev之中。
idComDev =CreateFile( g_szCom_Port[g_com_config.nPort],
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
……
file://cfg为COMMCONFIG结构的实例对象,获取当前通讯口的状态。
cfg.dcb.DCBlength = sizeof( DCB ) ;
GetCommState( idComDev, &(cfg.dcb) ) ;
file://设置发送、接收缓存大小
SetupComm( idComDev, 4096, 4096 ) ;
// PurgeComm()是一个清除函数,它可以用来中止任何未决的后台读或写,并且可以冲掉I/O
file://缓冲区.其中:PURGE_TXABORT 用于中止后台写操作;PRUGE_RXABORT用于中止后台
file://读操作 ;PRUGE_TXCLEAR用于清除发送缓冲区;PRUGE_RXCLEAR用于清除接收缓冲区
PurgeComm(idComDev,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
file://根据设置的参数填充DCB结构对象dcb的各个数据成员变量
dcb.DCBlength = sizeof( DCB ) ;
GetCommState( idComDev, &dcb ) ;
file://设置端口通讯参数
dcb.BaudRate =g_Com_Baud[g_com_config.nBaud];
dcb.ByteSize =g_Com_ByteSize[g_com_config.nData];
dcb.Parity =g_Com_Parity[g_com_config.nParity] ;
dcb.StopBits =g_Com_StopBits[g_com_config.nStop];
file://硬件流控制
dcb.fDtrControl = DTR_CONTROL_DISABLE ;
dcb.fOutxCtsFlow = FALSE ;
dcb.fRtsControl = RTS_CONTROL_DISABLE ;
file://软件流控制
dcb.fInX = dcb.fOutX = FALSE ;
dcb.XonChar = (char)0xFF ;
dcb.XoffChar = (char)0XFF ;
dcb.XonLim = 100 ;
dcb.XoffLim = 100 ;
dcb.EvtChar=0x0d;
dcb.fBinary = TRUE ;
dcb.fParity = TRUE ;

file://超时控制的设置。超时有两种:区间超时:(仅对从端口中读取数据有用)它指定在读取两个字符之间要经历的时间;总超时: 当读或写特定的字节数需要的总时间超过某一阈值时,超时触发。计算超时可以根据公式:
file://ReadTotalTimeout = (ReadTotalTimeoutMultiplier * bytes_to_read)+
// ReadToTaltimeoutConstant
file://WriteTotalTimeout = (WriteTotalTimeoutMuliplier * bytes_to_write)+
// WritetoTotalTimeoutConstant
file://如果在设置超时时参数为0则为无限等待,即无超时。
CommTimeOuts.ReadIntervalTimeout =MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier =0;
CommTimeOuts.ReadTotalTimeoutConstant = 0 ;
CommTimeOuts.WriteTotalTimeoutMultiplier =2*9600/dcb.BaudRate ;
CommTimeOuts.WriteTotalTimeoutConstant = 25 ;
SetCommTimeouts(idComDev , &CommTimeOuts ) ;
file://根据设置好的dcb结构设置好通讯口的状态,并开启用于侦听端口,监视从外设传来的数
file://据的线程COMReadThreadProc。
if (SetCommState( idComDev, &dcb ))
{
m_bComPortOpen=TRUE;
g_hCom=idComDev;
AfxBeginThread(COMReadThreadProc,NULL,THREAD_PRIORITY_NORMAL);
return;
}
BOOL CCOMReadBuf::GetOneByte(BYTE *cb)
{
m_Lock.Lock();
if(m_nHead==m_nTail)
{
m_Lock.Unlock();
return FALSE;//空
}
*cb=m_readbuf[m_nTail];
if(m_nTail < m_nBufSize-1)
m_nTail++;
else
m_nTail=0;
m_Lock.Unlock();
return TRUE;//空
}

void CCOMReadBuf::Add(BYTE buf[],int nBytes)
{
int nt,i;
m_Lock.Lock();
for(i=0;iBR> {
nt=(m_nHead-m_nTail);
if(nt<0)
nt+=m_nBufSize;
if(nt+1==m_nBufSize)
break;//缓冲区满
m_readbuf[m_nHead]=buf[i];
if(m_nHead < m_nBufSize-1)
m_nHead++;
else
m_nHead=0;
}
m_Lock.Unlock();
}

  (四) 控制命令的发送

  控制命令可以从对话条上的编辑框获取,然后就可以通过写文件形式从端口发送出去,这部分实现起来较简单,也牵扯不到线程等技术。主要的代码主要有:

……
file://从对话条获取命令行
nRead=m_wndDlgBar.GetDlgItemText(IDC_EDIT_SEND,buf,500);
file://向端口发送命令
if(nRead>0)
{
buf[nRead]=0x0d;
buf[nRead+1]=0x00;
::WriteFile(g_hCom,buf,nRead+1,&dwActWrite,NULL);
}
……

  (五) 监测信息的显示

  本程序选择了列表视图作为数据的显示途径。为了能及时的将接收到的数据反馈给监控者,在视类中通过定时器完成定时刷新的功能,可以在视类的OnCreate() 函数里用SetTimer(……)函数在程序开始执行时打开定时器,在OnDestroy()里用KillTimer(……)函数在程序退出前先关闭定时器。在定时器消息 WM_TIMER的响应函数里完成向列表控件添加最新接收到的信息。主要语句有:

……
file://获取列表视相关的列表空间的句柄
CListCtrl &ListCtrl=GetListCtrl();
file://列表有两列:收到字符的时间和对应的信息
CTime t = CTime::GetCurrentTime();
CString szTemp;
szTemp.Format("%02d:%02d:%02d",t.GetHour(),t.GetMinute(),t.GetSecond());
file://向列表添加信息
int nIndex=ListCtrl.InsertItem(0, szTemp);
if(-1!=nIndex)
{
m_Buf[m_nCurPoint]=0;
ListCtrl.SetItemText(nIndex,1,LPTSTR(m_Buf));
}
……

  四、 调试与检测

  现在程序已经写完,可以编译运行。我们最好先检验一下机器串口是否能正常工作,可用DOS下的Comdebug程序检查。在确认串口工作正常后,如果条件允许最好同另一台计算机或外设相连,进行检测,如笔者用的是一台高频段数传电台。如果只有一台计算机也可以进行简单的测试:将计算机串口的第2脚和第3脚短接,即自己发送、接收数据。如果接有外设,当有采集到的数据送到端口时就会在列表中将时间和信息内容记录下来,也可以在对话条中输入命令来控制外设的工作状态,完全具备实时监控软件所需的功能。

  小结:

  串行通讯在通讯领域被广泛应用,标准的RS-232-C接口已成为计算机、外设、交换机和许多通讯设备的标准接口。计算机与计算机、计算机与外设等都可以通过RS-232-C接口进行方便的连接,以实现监视、控制外设和传输数据等目的。对于其他类型的串口通讯程序本文所介绍的方法也是值得借鉴的。本程序由
Microsoft Visual C++ 6.0编译、在Windows 98下运行通过。

关于实时监控软件需要注意的几个编程要点

1.背景 第一次做实时监控程序的时候,可能都会和博主一样,遇到界面刷新速度很慢,或者说界面响应速度很慢的情况,而且很难一下子断定问题的关节。刚遇到这个问题的时候,按照学过的算法优化基础,做了一些简单...
  • BuquTianya
  • BuquTianya
  • 2014年03月23日 22:03
  • 2422

基于HyperPacer的websocket实时监控

一、准备测试脚本 使用eclipse+java_webSocket+tpm.hyperpacer.dependence_1.0.0开发websocket客服端脚本 1、在eclipse安装插件开发...
  • w306695293
  • w306695293
  • 2017年03月01日 14:09
  • 370

一个c#即时监控小程序

关键词:委托  线程  异步操作  大数据存储过程分页  实时刷新界面数据  声音报警 任务栏提示   动态任务栏图标切换    需求:启动监控程序后,每隔10秒(可配置多少秒)从后台数据库查询...
  • u011981242
  • u011981242
  • 2015年09月24日 00:00
  • 3085

定时监控服务端口是否正常 发送邮件

定时监控服务端口是否正常 发送邮件1.搭建简单maven web项目 2.写一个监听类 实现 接口ServletContextListener,实现其方法 如图: 3.具体的监控任务类Liste...
  • Java_HuiLong
  • Java_HuiLong
  • 2016年11月21日 17:37
  • 400

web项目的实时监控-思路

今天,做了一个用户登陆后,实时监控后台数据的任务,整整搞了一天,(环境是 mybatis、spring、springmvc)。上午想搞一个定时线程,在用户的登陆后就执行,然后从后台执行该线程,如果发现...
  • goodluck_mh
  • goodluck_mh
  • 2017年04月19日 19:39
  • 1141

现在的SQLSERVER数据库监控软件有哪些?

现在的SQLSERVER数据库监控软件有哪些? 收集了一下当前SQLSERVER数据库监控软件,发现开源免费的真的是“没有” Questsoftware  Quest's spotligh...
  • notbaron
  • notbaron
  • 2016年08月13日 23:41
  • 30601

Android手机实时视频监控

最近手机安装了一个“千里眼”和千里眼家居远程监控的应用,对里面的实时监控交通路口的状态有点好奇。以是使用相应的方法反编译看看她的原理。 对于软件“千里眼”,经过代码的翻看,发现采用的是VideoVi...
  • xdwyyan
  • xdwyyan
  • 2015年05月20日 09:25
  • 6929

将Qt截图的软件改为本地屏幕监控软件

Client端 :不断的截图,并复制到系统的粘贴区 Server端 :得到系统粘贴区的一张张图片,实现观看截到的屏幕,类似gif图片的原理说明 :如果加上TCP通信不就可以成为一个远程监控了么~~哈...
  • sinat_29173167
  • sinat_29173167
  • 2017年01月18日 16:02
  • 370

超级 Ping 监测工具——为您的网络状态保驾护航

Ping 是一个网络命令,主要是用于确定本地主机是否能与另一台主机交换(发送与接收)数据。根据返回的信息,就可以推断 TCP/IP 参数是否设置得正确以及运行是否正常。正常情况下,Ping 将返回若干...
  • wangpeng198688
  • wangpeng198688
  • 2015年12月29日 19:09
  • 2624

局域网实时通信系统的设计与实现(1)

本文要解决的问题: 整理之前在大连东软实习做的一个局域网内部实时通信系统,进行一个系统的回顾。 基本窗体的设计 一、前言 局域网实时通信系统相当于一个“简易版飞鸽传书”,该程序可实现在局域...
  • sbq63683210
  • sbq63683210
  • 2016年07月15日 22:54
  • 1686
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:RS-232-C端口实时监控软件的设计实现
举报原因:
原因补充:

(最多只允许输入30个字)