加载中…
个人资料
HALO_O_WANG
HALO_O_WANG
  • 博客等级:
  • 博客积分:0
  • 博客访问:26,023
  • 关注人气:3
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
正文 字体大小:

VC++串口通信编程示例

(2016-07-06 22:41:49)
标签:

编程

1.       介绍

我们在进行硬件嵌入式系统开发的时候,通常会涉及到串口通信。上位机进行串口数据收发的时候,可以使用现有的“串口调试助手”等软件,但有时候需要我们自己来编写串口通信的程序。

使用VC++编写基于win32平台上的串口通信程序有很多种方法。其中比较常见的是调用API函数的方法和使用ActiveX控件的方法。由于我目前还未掌握使用ActiveX控件的方法,我只是简单介绍调用API函数的方法来编写基于win32平台上的串口通信程序,并给出我自己写的简易的示例程序。

示例程序链接:http://pan.baidu.com/s/1mijLu1E

(注:开发环境VS2010,里面有三个程序,分别是通过设备管理器检测串口,同步读写串口和异步读写串口)

2.       检测串口是否被使用

如果我们从网上下载一个串口调试助手,点开“串口选择”通常会出现一个下拉菜单,菜单中列出了所有存在的串口号,而不存在的串口则没有出现在下拉菜单中。那么这是怎么做到的呢?我认为有两种方法。一种方法是把COM1COM20都打开一遍,如果打开成功,就说明这个串口是存在的,否则该串口是不存在的。第二种方法是读取设备管理器,从设备管理器中获取串口信息。经测试发现,前一种方法是有一定缺陷的。如果电脑开启了内置蓝牙功能,使用第一种方法通常不能正确检测出蓝牙串口,而后一种方法则通常不会出现这些问题。

读取设备管理器的程序编写可以参照http://www.fenlog.com/post/110.html。设备管理器所列出的设备中类型为Ports的设备就是串口。将这些设备对应的串口号提取出来即可。

3.       串口通信编程步骤

使用Win 32 API进行串口通信编程通常分为四个步骤,分别是打开串口、配置串口、读写串口和关闭串口。这个过程会涉及到很多的类和函数,详细的使用方法可以参见http://www.jizhuomi.com/software/309.html,这篇文章总结的是比较好的。

串口读写方法有同步读写和异步读写(重叠执行)两种。在用ReadFileWriteFile读写串口时,既可以同步执行,也可以重叠执行。在同步执行时,函数直到操作完成后才返回。这意味着同步执行时线程会被阻塞,从而导致效率下降。在重叠执行时,即使操作还未完成,这两个函数也会立即返回,费时的I/O操作在后台进行。

对一个串口的操作是同步执行还是重叠执行是通过CreateFile函数指定的。如果CreateFile函数的第六个参数为FILE_FLAG_OVERLAPPED,则该串口操作为重叠执行,如果为0则串口操作是同步执行。此外,同步执行与重叠执行方式的读写代码有一定差别。使用异步方式读写串口时,需要建立并初始化重叠结构OVERLAPPED,而以同步方式执行时不需要此步骤。

4.       通过设备管理器检测串口的示例代码

 

  1. #include "stdafx.h"
  2. #include "stdlib.h"
  3. #include "windows.h"
  4. #include
  5.  
  6. #pragma comment(lib,"setupapi.lib")
  7.  
  8. wchar_t** GetSerialNumber(int& len){//通过读取设备管理器,得到可用的串口号
  9.     //先通过读取设备管理器,得到类型为“Ports”的设备,并把这些设备的友好类型记录下来
  10.     HDEVINFO hDevInfo;
  11.     SP_DEVINFO_DATA DeviceInfoData;
  12.     DWORD t;
  13.     int n=0;
  14.     wchar_t szClassBuf[MAX_PATH]={0};
  15.     wchar_t** szNameBuf=newwchar_t*[20];
  16.     for(int t=0;t<=19;t++) szNameBuf[t]=new wchar_t[MAX_PATH];
  17.     hDevInfo=SetupDiGetClassDevs(NULL,0,0,DIGCF_PRESENT|DIGCF_ALLCLASSES);
  18.     if(hDevInfo==INVALID_HANDLE_VALUE) return NULL;
  19.     DeviceInfoData.cbSize=sizeof(SP_DEVINFO_DATA);
  20.     for(t=0;SetupDiEnumDeviceInfo(hDevInfo,t,&DeviceInfoData);t++){
  21.      if(!SetupDiGetDeviceRegistryProperty(hDevInfo,&DeviceInfoData,SPDRP_CLASS,NULL,(PBYTE)szClassBuf,MAX_PATH-1,NULL)) continue;//先找到设备的类
  22.      if(szClassBuf[0]=='P'&&szClassBuf[1]=='o'&&szClassBuf[2]=='r'&&szClassBuf[3]=='t'&&szClassBuf[4]=='s'){//如果类型为'Ports'
  23.             if(!SetupDiGetDeviceRegistryProperty(hDevInfo,&DeviceInfoData,SPDRP_FRIENDLYNAME,NULL,(PBYTE)szNameBuf[n++],MAX_PATH-1,NULL)) continue;//找到设备的友好名称
  24.         }
  25.     }
  26.     //通过Ports设备的友好类型,找到可用的COM
  27.     //也就是提取到“COMx”这样的字符串
  28.     wchar_t** serialnumber=newwchar_t*[n];
  29.     SetupDiDestroyDeviceInfoList(hDevInfo);
  30.     for(int m=0;m<=n-1;m++){
  31.         int atleft=0;
  32.         int atright=0;
  33.         for(int t1=0;t1<=MAX_PATH-1;t1++){
  34.             if(szNameBuf[m][t1]=='(') atleft=t1;
  35.             if(szNameBuf[m][t1]==')') atright=t1;
  36.         }
  37.         if(atleft==0||atright==0) continue;
  38.         serialnumber[m]=new wchar_t[6];
  39.         for(int t2=0;t2<=5;t2++) serialnumber[m][t2]=0;
  40.         for(int t3=0;t3
  41.             serialnumber[m][t3]=szNameBuf[m][t3+atleft+1];
  42.         }
  43.     }
  44.     len=n;
  45.     return serialnumber;
  46. }
  47. void PrintSerialNumber(wchar_t** serialnumber,int len){//把可用的串口编号显示出来
  48.     for(int t=0;t<=len-1;t++){
  49.         wprintf(L"%s\n",serialnumber[t]);
  50.     }
  51.     printf("\r\n");
  52. }
  53. int _tmain(int argc, _TCHAR* argv[])
  54. {
  55.     int len;
  56.     wchar_t** serialnumber=GetSerialNumber(len);//找到当前存在的串口编号
  57.     PrintSerialNumber(serialnumber,len);//把串口编号显示出来
  58.     system("pause");
  59.     return 0;
  60. }

 

5.       同步读写串口的示例代码

 

  1.  #include "stdafx.h"
  2. #include "stdlib.h"
  3. #include "windows.h"
  4.  
  5. int serial_connect(HANDLE& hCom,wchar_t* serialport,int baudrate){
  6.     hCom=CreateFile(serialport,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);//打开串口,读写方式,同步方式
  7.     if(hCom==(HANDLE)-1) return-1;  
  8.     SetupComm(hCom,1024,1024); //输入缓冲区和输出缓冲区的大小都是1024
  9.     COMMTIMEOUTS TimeOuts; //设定读超时
  10.     TimeOuts.ReadIntervalTimeout=1000;
  11.     TimeOuts.ReadTotalTimeoutMultiplier=500;
  12.     TimeOuts.ReadTotalTimeoutConstant=5000; //设定写超时
  13.     TimeOuts.WriteTotalTimeoutMultiplier=500;
  14.     TimeOuts.WriteTotalTimeoutConstant=2000;
  15.     SetCommTimeouts(hCom,&TimeOuts); //设置超时
  16.     DCB dcb;//通过dcb结构配置串口
  17.     GetCommState(hCom,&dcb);
  18.     dcb.BaudRate=baudrate;//设置波特率
  19.     dcb.fParity=0; // 指定奇偶校验使能。若此成员为1,允许奇偶校验检查 …
  20.     dcb.ByteSize=8;
  21.     dcb.Parity=NOPARITY; //指定奇偶校验方法。此成员可以有下列值: EVENPARITY 偶校验 NOPARITY 无校验 MARKPARITY 标记校验 ODDPARITY 奇校验
  22.     dcb.StopBits=ONESTOPBIT; //指定停止位的位数。此成员可以有下列值: ONESTOPBIT 1位停止位 TWOSTOPBITS 2位停止位
  23.     SetCommState(hCom,&dcb);
  24.     PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
  25.     return 0;
  26. }
  27. int Write(HANDLE hCom,char* lpOutBuffer,int length){//串口发送,同步写串口
  28.     DWORD dwBytesWrite=length;
  29.     COMSTAT ComStat;
  30.     DWORD dwErrorFlags;
  31.     BOOL bWriteStat;
  32.     ClearCommError(hCom,&dwErrorFlags,&ComStat);
  33.     bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);
  34.     if(!bWriteStat){
  35.         return -1;
  36.     }
  37.     PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
  38.     return 0;
  39. }
  40. int Read(HANDLE hCom){//同步读串口
  41.     char str[1000];
  42.     for(int t=0;t<=999;t++) str[t]=0;
  43.     DWORD dwBytesRead=1000;
  44.     BOOL bReadStatus;
  45.     bReadStatus=ReadFile(hCom,str, dwBytesRead,&dwBytesRead,NULL);//接收数据
  46.     if(!bReadStatus) return-1;
  47.     printf("串口接收到的内容是%s\n",str);//把接收到的显示出来
  48.     return 0;
  49. }
  50. int _tmain(int argc, _TCHAR* argv[])
  51. {
  52.     HANDLE hCom;//串口句柄
  53.     int connectstate=serial_connect(hCom,L"COM4",CBR_115200);//连接到COM4,波特率115200
  54.     if(connectstate!=-1){
  55.         Write(hCom,"ABCDE\r\n",8);//发送“ABCDE
  56.         Read(hCom);//读串口,并将读到的内容显示出来
  57.         CloseHandle(hCom);//关闭串口
  58.     }else{
  59.         printf("串口连接失败!\n");
  60.     }
  61.  
  62.     system("pause");
  63.     return 0;
  64. }

6.       异步读写串口的示例代码

 

  1. #include "stdafx.h"
  2. #include "windows.h"
  3. #include "stdlib.h"
  4.  
  5. int serial_connect(HANDLE& hCom,wchar_t* serialport,int baudrate){
  6. hCom=CreateFile(serialport,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);//打开串口,允许读和写,异步方式
  7.     if(hCom==(HANDLE)-1) return-1;  
  8.     SetupComm(hCom,1024,1024); //输入缓冲区和输出缓冲区的大小都是1024
  9.     COMMTIMEOUTS TimeOuts; //设定读超时
  10.     TimeOuts.ReadIntervalTimeout=1000;
  11.     TimeOuts.ReadTotalTimeoutMultiplier=500;
  12.     TimeOuts.ReadTotalTimeoutConstant=5000; //设定写超时
  13.     TimeOuts.WriteTotalTimeoutMultiplier=500;
  14.     TimeOuts.WriteTotalTimeoutConstant=2000;
  15.     SetCommTimeouts(hCom,&TimeOuts); //设置超时
  16.     DCB dcb;
  17.     GetCommState(hCom,&dcb);
  18.     dcb.BaudRate=baudrate;//设置波特率
  19.     dcb.fParity=0; // 指定奇偶校验使能。若此成员为1,允许奇偶校验检查 …
  20.     dcb.ByteSize=8;
  21.     dcb.Parity=NOPARITY; //指定奇偶校验方法。此成员可以有下列值: EVENPARITY 偶校验 NOPARITY 无校验 MARKPARITY 标记校验 ODDPARITY 奇校验
  22.     dcb.StopBits=ONESTOPBIT; //指定停止位的位数。此成员可以有下列值: ONESTOPBIT 1位停止位 TWOSTOPBITS 2位停止位
  23.     SetCommState(hCom,&dcb);
  24.     PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
  25.     return 0;
  26. }
  27. int Write(HANDLE hCom,char* lpOutBuffer,int length){//串口发送
  28.     DWORD dwBytesWrite=(DWORD)length;
  29.     COMSTAT ComStat;
  30.     DWORD dwErrorFlags;
  31.     BOOL bWriteStat;
  32.     OVERLAPPED m_osWrite;//建立Overlapped结构
  33.     m_osWrite.InternalHigh = 0;
  34.     m_osWrite.Offset = 0;
  35.     m_osWrite.OffsetHigh = 0;
  36.     m_osWrite.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);//初始化Overlapped结构
  37.     ClearCommError(hCom,&dwErrorFlags,&ComStat);
  38.     bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,&dwBytesWrite,&m_osWrite);//异步写串口
  39.     if(!bWriteStat){
  40.         return -1;
  41.     }
  42.     PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
  43.     return 0;
  44. }
  45. int Read(HANDLE hCom){//串口接收
  46.     DWORD dwBytesRead=1000;
  47.     char* str=new char[(int)dwBytesRead];
  48.     for(int t=0;t<=(int)dwBytesRead-1;t++) str[t]=0;
  49.     COMSTAT ComStat;
  50.     DWORD dwErrorFlags;
  51.     OVERLAPPED m_osRead; //建立Overlapped结构
  52.     memset(&m_osRead,0,sizeof(OVERLAPPED));
  53.     m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
  54.     ClearCommError(hCom,&dwErrorFlags,&ComStat);
  55.     dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
  56.     if(!dwBytesRead){//如果缓冲区为空,那么这里就会返回
  57.         return -1;
  58.     }
  59.     BOOL bReadStatus;
  60.     bReadStatus=ReadFile(hCom,str, dwBytesRead,&dwBytesRead,&m_osRead);//异步读串口,读取缓冲区的内容
  61.     if(!bReadStatus) {
  62.         return -1;
  63.     }
  64.     if(dwBytesRead) printf("串口接受到的内容为:%d\r\n%s\r\n",(int)dwBytesRead,str);//如果读取出来的缓冲区的内容不为空,那么把读取出来的内容发送出来
  65.     return 0;
  66. }
  67. int _tmain(int argc, _TCHAR* argv[])
  68. {
  69.     HANDLE hCom;//串口句柄
  70.     int connectstate=serial_connect(hCom,L"COM4",CBR_115200);//连接到COM4,波特率115200
  71.     if(connectstate!=-1){
  72.         while(1){
  73.             Write(hCom,"ABCDE\r\n",20);//发送“ABCDE
  74.             Sleep(500);//延时0.5s
  75.             Read(hCom);//读串口,并将读到的内容显示出来
  76.             system("pause");
  77.         }
  78.         CloseHandle(hCom);//关闭串口
  79.     }else{
  80.         printf("串口连接失败!\n");
  81.     }
  82.     system("pause");
  83.     return 0;
  84. }

 


0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有