设为首页 收藏本站
查看: 1635|回复: 0

[经验分享] VS2010 Windows API 串口编程 (二)

[复制链接]

尚未签到

发表于 2015-12-16 08:35:41 | 显示全部楼层 |阅读模式
转载请注明出自:blog.csdn.net/mingojiang

目录
一串口通信基础      
1.1串口通信原理与特点     
1.2串口通信的传输方式     
1.3串口通信的同步技术     
1.4串行接口标准     
API函数实现串口通信   
2.1打开串口
2.1.1串口是否有驱动   
2.1.2连接串口   
2.1.3串口逻辑端口号大于10无法打开问题
2.2串口配置
2.2.1设置缓冲区大小   
2.2.2设置串口状态  
2.2.3设置需通知的事件      
2.2.4清空缓冲区      
2.3异步接收数据     
三示例代码
3.1连接串口并设置参数     
3.2发送与接收数据
3.3关闭串口



串口通信基础
        提到串口让人想起并口,它们是计算机中两个比较重要的通信方式.
也叫COM,把字节的二进制位按位列队进行传输,每个字节占一个固定的时间长,速度慢,但是传输距离远,9针和25针两种,是阳插座(插座中有针凸起),目前25针较少使用;Modem\鼠标\USB\老式摄像头等都是用串口.
把字节的二进制位用多条线同时传输,速度快串口8倍左右,传输距离有限,一般计算机内部数据传输用此方式,平常使用的有打印机,扫描仪等;25,阴插座(插座有25个针孔).
  
1.1串口通信原理与特点
        串行端口是CPU与串行设备间的编码转换器,CPU经过串行端口发数据时,字节数据列队成串行位,串行端口接收数据时,串行位转换成字节数据.所以必须安装相应的驱动程序.
        串行通信有成本低的特点,而且可以在现有的电话网络上进行传输,家庭通过电话线上网即是这种方式.只要配置一个相应的通信接口,:Modem.
1.2串口通信的传输方式
        只能从一头传输到另一头,如只能从AB传或者BA,如看电视,只允许电视台向电视发数据,不允许电视向电视台发数据.在单工传输方式上一般采用两个通信,一个通道传输数据,一个通道传输控制信号.
        允许互传信息,但是不能同时进行,如对讲机,A说话时,B不能说话,B说话时A不能说话.
        允许双同时通信,如讲电话.
1.3串口通信的同步技术
        物理连接建立后,需要使用一种机制使对方正确解释发送的数据,发送方安位发出数据后,接收方如何识别这些数据,并如何正确组装成正确的字节.这就需要同步技术.数据同步技术一般解决如下问题:
?确定发送数据起始时间
?发送数据的传输速率
?发送数据所需的时间
?发送时间间隔
3.1异步传输
        按字节为单位传输,异步传输方式也叫起止方式,在被传输的字节前后加起止位,起止位无信号时处于高电平,接收方检测到低电平信号表示开始接收,收到停止信号表示传输完成.
3.2同步传输
        以数据块为单位传输,在块的前后加一个特殊字节表示起止,传输效率高,线路利用率高,设备负担也大.
1.4串行接口标准
        常用标准有RS-232C,RS-485,RS-422,其中RS-232C被广泛用于计算机串口通信.RS-232C标准要求一般线路不要超过15.
  
API函数实现串口通信
        API函数串口编程,可采用简单的查询方式或定时方式,也可采用复杂的事件驱动方式,所谓事件驱动方式是当输入缓冲区中有数据时,将自动调用某个方法执行相应的操作.定时方式是在一定的时间间隔内判断缓冲区内有数据被写入,此方法效率不高,查询方式就更落后的一种方式.所以设计的好的串口通信程序一般用事件驱动,有实时,高效,灵活等特点.
一般编制串行通信程序分以下几个部分:
?打开串行端口:打开通信资源,设置通信参数、设置通信事件、创建读、写事件、进入等待串口消息循环。
?读取串行端口信息:当串口发生EV_RXCHAR(接收到字符并放入了输入缓冲区)消息后读取串口、数据传输错误处理、字符串处理如回车符、空格并相应转化成数据,如果模拟量还要进行数据检验等功能。
?写串行端口信息:将要发送的信息写入串口,相应进行错误处理。
?断开串行端口连接:关闭事件,清除通信事件,丢弃通信资源并关闭。
  
2.1打开串口
2.1.1串口是否有驱动
        如何判断PC机中串口是否正常,驱动是否安装,串口名(逻辑端口名)是多少.如果PC机有串口同时驱动正常,那么在注册表的HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP目录下,包含字符"Serial""VCom"项下面的值就是,可以有多项,如下图:
DSC0000.jpg

SERIALCOMM下有一个值----COM11,表明有一个可用串口,如果目录下包含字符SerialVCom的项下没有任何值,表明没有串口或者驱动不正常.以下是获取串口逻辑名的代码:
#define MAX_KEY_LENGTH   255

#define MAX_VALUE_NAME  16383

HKEY hTestKey;

if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_READ, &hTestKey) ){

        TCHAR   achClass[MAX_PATH] = TEXT(""); // buffer for class name

        DWORD   cchClassName = MAX_PATH; // size of class string

        DWORD   cSubKeys=0;                  // number of subkeys

        DWORD   cbMaxSubKey;             // longest subkey size

        DWORD   cchMaxClass;             // longest class string

        DWORD   cValues;             // number of values for key

        DWORD   cchMaxValue;         // longest value name

        DWORD   cbMaxValueData;      // longest value data

        DWORD   cbSecurityDescriptor; // size of security descriptor

        FILETIME ftLastWriteTime;     // last write time


        DWORD i, retCode;

        TCHAR achValue[MAX_VALUE_NAME];

        DWORD cchValue = MAX_VALUE_NAME;


        // Get the class name and the value count.

        retCode = RegQueryInfoKey(

                  hKey,                   // key handle

                  achClass,               // buffer for class name

                  &cchClassName,          // size of class string

                  NULL,                   // reserved

                  &cSubKeys,              // number of subkeys

                  &cbMaxSubKey,           // longest subkey size

                  &cchMaxClass,           // longest class string

                  &cValues,               // number of values for this key

                  &cchMaxValue,           // longest value name

                  &cbMaxValueData,        // longest value data

                  &cbSecurityDescriptor,  // security descriptor

                  &ftLastWriteTime);      // last write time


        if (cValues > 0) {

                  for (i=0, retCode=ERROR_SUCCESS; i 1000)

                                         g_OutPutList.RemoveAll();
                           WORD nLen = (WORD)m_nBuffLen + 2;
                           PBYTE pIn = new BYTE[nLen];
                           pIn[0] = HIBYTE(nLen);
                           pIn[1] = LOBYTE(nLen);
                           memcpy(pIn + 2, m_InPutBuff, m_nBuffLen);
                           g_InPutList.AddTail(pIn);
                           m_nBuffLen = 0;
             }
             else if(1 == nResutl){
                           PBYTE pOut = (PBYTE)g_OutPutList.RemoveHead();
                           int nLen = pOut[0] * 0x100 + pOut[1] - 2;
                           WriteCommBlock(pOut + 2, nLen);
                           delete[] pOut;
             }
             DWORD dwEvtMask = 0 ;
             WaitCommEvent( COMFile, &dwEvtMask, &ShareEvent);//?¨¨?y??¨???t
             if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR) {
                           ReadCommBlock( );
             }
}
  
示例代码
    关于本文的代码下载链接:http://download.csdn.net/detail/mingojiang/4425803 VS2010编写的,编译通过,是个串口调试工具. 如图:
DSC0001.jpg
3.1连接串口并设置参数
DCB dcb ;
BOOL fRetVal ;
COMMTIMEOUTS CommTimeOuts;
CString szCom;
szCom.Format(_T("\\\\.\\COM%d"), nPort);
COMFile = CreateFile(szCom.GetBuffer(50), GENERIC_READ | GENERIC_WRITE,//¨?¨?¨???
                                                                                   FILE_SHARE_READ | FILE_SHARE_WRITE,                                                                                
NULL,
                                                                                   OPEN_EXISTING,
                                                                                   FILE_FLAG_OVERLAPPED,
                                                                                   NULL);
if (INVALID_HANDLE_VALUE == COMFile){
             return ( FALSE ) ;
}

SetupComm(COMFile,6000,6000) ;
SetCommMask(/*COMFileTemp*/COMFile, EV_RXCHAR ) ;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;
CommTimeOuts.ReadTotalTimeoutConstant = 1000 ;
CommTimeOuts.WriteTotalTimeoutMultiplier = 2*CBR_9600/9600 ;
CommTimeOuts.WriteTotalTimeoutConstant = 0 ;
SetCommTimeouts(/*COMFileTemp*/COMFile, &CommTimeOuts ) ;

dcb.DCBlength = sizeof( DCB ) ;
GetCommState(COMFile, &dcb ) ;
dcb.BaudRate =CBR_9600;
dcb.StopBits =ONESTOPBIT;
dcb.Parity = NOPARITY;
dcb.ByteSize=8;
dcb.fBinary=TRUE;
dcb.fOutxDsrFlow = 0 ;
dcb.fDtrControl = DTR_CONTROL_ENABLE ;
dcb.fOutxCtsFlow = 0 ;
dcb.fRtsControl = RTS_CONTROL_ENABLE ;
dcb.fInX = dcb.fOutX = 1 ;
dcb.XonChar = 0X11 ;
dcb.XoffChar = 0X13 ;
dcb.XonLim = 100 ;
dcb.XoffLim = 100 ;
dcb.fParity = TRUE ;

fRetVal = SetCommState(/*COMFileTemp*/COMFile, &dcb ) ;

if(!fRetVal) return FALSE;

PurgeComm( /*COMFileTemp*/COMFile, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ;

EscapeCommFunction( /*COMFileTemp*/COMFile, SETDTR ) ;
  
3.2发送与接收数据
HANDLE hEventArr[2];
hEventArr[0] = osRead.hEvent;
hEventArr[1] = *g_OutPutList.GetEvent();

while(1){
             DWORD nResutl = WaitForMultipleObjectsEx(2, hEventArr, FALSE, 200, TRUE/*INFINITE*/);
             if(0 == nResutl){
                           if (g_OutPutList.GetCount() > 1000)
                                         g_OutPutList.RemoveAll();
                           WORD nLen = (WORD)m_nBuffLen + 2;
                           PBYTE pIn = new BYTE[nLen];
                           pIn[0] = HIBYTE(nLen);
                           pIn[1] = LOBYTE(nLen);
                           memcpy(pIn + 2, m_InPutBuff, m_nBuffLen);
                           g_InPutList.AddTail(pIn);
                           m_nBuffLen = 0;
             }
             else if(1 == nResutl){
                           PBYTE pOut = (PBYTE)g_OutPutList.RemoveHead();
                           int nLen = pOut[0] * 0x100 + pOut[1] - 2;
                           WriteCommBlock(pOut + 2, nLen);
                           delete[] pOut;
             }

DWORD dwEvtMask = 0 ;
WaitCommEvent( COMFile, &dwEvtMask, &ShareEvent);//?¨¨?y??¨???t
if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR) {
             ReadCommBlock( );
             }
}

3.3关闭串口
//禁止串行端口所有事件
SetCommMask(COMFile, 0) ;
//清除数据终端就绪信号
EscapeCommFunction( COMFile, CLRDTR ) ;
//丢弃通信资源的输出或输入缓冲区字符并终止在通信资源上挂起的读、写操操作
PurgeComm( COMFile, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
CloseHandle( COMFile );
COMFile = NULL;

转载请注明出自:blog.csdn.net/mingojiang

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-151753-1-1.html 上篇帖子: 旗舰版系统中玩CF警告配色方案已更改为windows Basic的更正方案 下篇帖子: Windows驱动开发技术详解__IRP的同步
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表