`
isiqi
  • 浏览: 16045169 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论
阅读更多

在windows程序设计与开发过程中,特别是涉及到开发嵌入式软硬件系统时,往往会涉及到串口编程。网上以及一些书籍上讲解windows下的串口编程 知识也挺多的,但我个人觉得,看完书上的知识点有时依然不知道该如何下手开始自己的程序设计和代码编写,许多知识如果能结合着详细的例子往往能够帮助我们 学习得更快,所以,在此,我专门为串口编程初学者设计了一个详细的例子,供大家参考和学习。

下面我将自己用C++编写的串口通信的例子贴出来,其特点如下:

1. 本例子使用了比较规范的软件设计方法,类的设计具有比较好的可扩展性和移植性、代码的注释采用doxgen支持的javaDoc风格。
2. 为了能方便初学者更快地了解和入门,几乎每一行代码都加上了详细的注释,对于注释中如果依然有不清楚的概念,相信你通过百度和google一定能找到答案。
3. 本例子设计的串口操作类可以直接移植到其他的工程中去,大家也可以根据自己的需要添加其他的接口。
4. 本例子只实现了串口数据的基本收发功能,其实为了保证串口数据传输的正确性,往往需要设计一些串口通信协议,协议的设计有待你自己完成,如果以后有时间, 我也会尝试提供一种比较基本的串口通信协议设计案例给大家学习。
5. 关于本程序的验证方法,可以使用虚拟串口软件VSPM和串口调试助手进行程序的测试与验证,上述两个软件的使用方法请参考:http://ticktick.blog.51cto.com/823160/285610

下面即为例子工程的三个文件,SerialPort.h、SerialPort.cpp、maincpp
附件中是工程文件,需要使用vs2008打开
  1. //////////////////////////////////////////////////////////////////////////
  2. ///COPYRIGHTNOTICE
  3. ///Copyright(c)2009,华中科技大学tickTickGroup(版权声明)
  4. ///Allrightsreserved.
  5. ///
  6. ///@fileSerialPort.h
  7. ///@brief串口通信类头文件
  8. ///
  9. ///本文件完成串口通信类的声明
  10. ///
  11. ///@version1.0
  12. ///@author卢俊
  13. ///@E-mail:lujun.hust@gmail.com
  14. ///@date2010/03/19
  15. ///
  16. ///修订说明:
  17. //////////////////////////////////////////////////////////////////////////
  18. #ifndefSERIALPORT_H_
  19. #defineSERIALPORT_H_
  20. #include<Windows.h>
  21. /**串口通信类
  22. *
  23. *本类实现了对串口的基本操作
  24. *例如监听发到指定串口的数据、发送指定数据到串口
  25. */
  26. class CSerialPort
  27. {
  28. public :
  29. CSerialPort( void );
  30. ~CSerialPort( void );
  31. public :
  32. /**初始化串口函数
  33. *
  34. *@param:UINTportNo串口编号,默认值为1,即COM1,注意,尽量不要大于9
  35. *@param:UINTbaud波特率,默认为9600
  36. *@param:charparity是否进行奇偶校验,'Y'表示需要奇偶校验,'N'表示不需要奇偶校验
  37. *@param:UINTdatabits数据位的个数,默认值为8个数据位
  38. *@param:UINTstopsbits停止位使用格式,默认值为1
  39. *@param:DWORDdwCommEvents默认为EV_RXCHAR,即只要收发任意一个字符,则产生一个事件
  40. *@return:bool初始化是否成功
  41. *@note:在使用其他本类提供的函数前,请先调用本函数进行串口的初始化
  42. *      \n本函数提供了一些常用的串口参数设置,若需要自行设置详细的DCB参数,可使用重载函数
  43. *\n本串口类析构时会自动关闭串口,无需额外执行关闭串口
  44. *@see:
  45. */
  46. bool InitPort( UINT portNo=1, UINT baud=CBR_9600, char parity= 'N' , UINT databits=8, UINT stopsbits=1, DWORD dwCommEvents=EV_RXCHAR);
  47. /**串口初始化函数
  48. *
  49. *本函数提供直接根据DCB参数设置串口参数
  50. *@param:UINTportNo
  51. *@param:constLPDCB&plDCB
  52. *@return:bool初始化是否成功
  53. *@note:本函数提供用户自定义地串口初始化参数
  54. *@see:
  55. */
  56. bool InitPort( UINT portNo, const LPDCB&plDCB);
  57. /**开启监听线程
  58. *
  59. *本监听线程完成对串口数据的监听,并将接收到的数据打印到屏幕输出
  60. *@return:bool操作是否成功
  61. *@note:当线程已经处于开启状态时,返回flase
  62. *@see:
  63. */
  64. bool OpenListenThread();
  65. /**关闭监听线程
  66. *
  67. *
  68. *@return:bool操作是否成功
  69. *@note:调用本函数后,监听串口的线程将会被关闭
  70. *@see:
  71. */
  72. bool CloseListenTread();
  73. /**向串口写数据
  74. *
  75. *将缓冲区中的数据写入到串口
  76. *@param:unsignedchar*pData指向需要写入串口的数据缓冲区
  77. *@param:unsignedintlength需要写入的数据长度
  78. *@return:bool操作是否成功
  79. *@note:length不要大于pData所指向缓冲区的大小
  80. *@see:
  81. */
  82. bool WriteData(unsigned char *pData,unsigned int length);
  83. /**获取串口缓冲区中的字节数
  84. *
  85. *
  86. *@return:UINT操作是否成功
  87. *@note:当串口缓冲区中无数据时,返回0
  88. *@see:
  89. */
  90. UINT GetBytesInCOM();
  91. /**读取串口接收缓冲区中一个字节的数据
  92. *
  93. *
  94. *@param:char&cRecved存放读取数据的字符变量
  95. *@return:bool读取是否成功
  96. *@note:
  97. *@see:
  98. */
  99. bool ReadChar( char &cRecved);
  100. private :
  101. /**打开串口
  102. *
  103. *
  104. *@param:UINTportNo串口设备号
  105. *@return:bool打开是否成功
  106. *@note:
  107. *@see:
  108. */
  109. bool openPort( UINT portNo);
  110. /**关闭串口
  111. *
  112. *
  113. *@return:void操作是否成功
  114. *@note:
  115. *@see:
  116. */
  117. void ClosePort();
  118. /**串口监听线程
  119. *
  120. *监听来自串口的数据和信息
  121. *@param:void*pParam线程参数
  122. *@return:UINTWINAPI线程返回值
  123. *@note:
  124. *@see:
  125. */
  126. static UINT WINAPIListenThread( void *pParam);
  127. private :
  128. /**串口句柄*/
  129. HANDLE m_hComm;
  130. /**线程退出标志变量*/
  131. static bool s_bExit;
  132. /**线程句柄*/
  133. volatile HANDLE m_hListenThread;
  134. /**同步互斥,临界区保护*/
  135. CRITICAL_SECTIONm_csCommunicationSync; //!<互斥操作串口
  136. };
  137. #endif//SERIALPORT_H_
  1. //////////////////////////////////////////////////////////////////////////
  2. ///COPYRIGHTNOTICE
  3. ///Copyright(c)2009,华中科技大学tickTickGroup(版权声明)
  4. ///Allrightsreserved.
  5. ///
  6. ///@fileSerialPort.cpp
  7. ///@brief串口通信类的实现文件
  8. ///
  9. ///本文件为串口通信类的实现代码
  10. ///
  11. ///@version1.0
  12. ///@author卢俊
  13. ///@E-mail:lujun.hust@gmail.com
  14. ///@date2010/03/19
  15. ///
  16. ///
  17. ///修订说明:
  18. //////////////////////////////////////////////////////////////////////////
  19. #include"StdAfx.h"
  20. #include"SerialPort.h"
  21. #include<process.h>
  22. #include<iostream>
  23. /**线程退出标志*/
  24. bool CSerialPort::s_bExit= false ;
  25. /**当串口无数据时,sleep至下次查询间隔的时间,单位:秒*/
  26. const UINT SLEEP_TIME_INTERVAL=5;
  27. CSerialPort::CSerialPort( void )
  28. :m_hListenThread(INVALID_HANDLE_VALUE)
  29. {
  30. m_hComm=INVALID_HANDLE_VALUE;
  31. m_hListenThread=INVALID_HANDLE_VALUE;
  32. InitializeCriticalSection(&m_csCommunicationSync);
  33. }
  34. CSerialPort::~CSerialPort( void )
  35. {
  36. CloseListenTread();
  37. ClosePort();
  38. DeleteCriticalSection(&m_csCommunicationSync);
  39. }
  40. bool CSerialPort::InitPort( UINT portNo /*=1*/ , UINT baud /*=CBR_9600*/ , char parity /*='N'*/ ,
  41. UINT databits /*=8*/ , UINT stopsbits /*=1*/ , DWORD dwCommEvents /*=EV_RXCHAR*/ )
  42. {
  43. /**临时变量,将制定参数转化为字符串形式,以构造DCB结构*/
  44. char szDCBparam[50];
  45. sprintf_s(szDCBparam, "baud=%dparity=%cdata=%dstop=%d" ,baud,parity,databits,stopsbits);
  46. /**打开指定串口,该函数内部已经有临界区保护,上面请不要加保护*/
  47. if (!openPort(portNo))
  48. {
  49. return false ;
  50. }
  51. /**进入临界段*/
  52. EnterCriticalSection(&m_csCommunicationSync);
  53. /**是否有错误发生*/
  54. BOOL bIsSuccess=TRUE;
  55. /**在此可以设置输入输出的缓冲区大小,如果不设置,则系统会设置默认值.
  56. *自己设置缓冲区大小时,要注意设置稍大一些,避免缓冲区溢出
  57. */
  58. /*if(bIsSuccess)
  59. {
  60. bIsSuccess=SetupComm(m_hComm,10,10);
  61. }*/
  62. /**设置串口的超时时间,均设为0,表示不使用超时限制*/
  63. COMMTIMEOUTSCommTimeouts;
  64. CommTimeouts.ReadIntervalTimeout=0;
  65. CommTimeouts.ReadTotalTimeoutMultiplier=0;
  66. CommTimeouts.ReadTotalTimeoutConstant=0;
  67. CommTimeouts.WriteTotalTimeoutMultiplier=0;
  68. CommTimeouts.WriteTotalTimeoutConstant=0;
  69. if (bIsSuccess)
  70. {
  71. bIsSuccess=SetCommTimeouts(m_hComm,&CommTimeouts);
  72. }
  73. DCBdcb;
  74. if (bIsSuccess)
  75. {
  76. //将ANSI字符串转换为UNICODE字符串
  77. DWORD dwNum=MultiByteToWideChar(CP_ACP,0,szDCBparam,-1,NULL,0);
  78. wchar_t *pwText= new wchar_t [dwNum];
  79. if (!MultiByteToWideChar(CP_ACP,0,szDCBparam,-1,pwText,dwNum))
  80. {
  81. bIsSuccess=TRUE;
  82. }
  83. /**获取当前串口配置参数,并且构造串口DCB参数*/
  84. bIsSuccess=GetCommState(m_hComm,&dcb)&&BuildCommDCB(pwText,&dcb);
  85. /**开启RTSflow控制*/
  86. dcb.fRtsControl=RTS_CONTROL_ENABLE;
  87. /**释放内存空间*/
  88. delete []pwText;
  89. }
  90. if (bIsSuccess)
  91. {
  92. /**使用DCB参数配置串口状态*/
  93. bIsSuccess=SetCommState(m_hComm,&dcb);
  94. }
  95. /**清空串口缓冲区*/
  96. PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
  97. /**离开临界段*/
  98. LeaveCriticalSection(&m_csCommunicationSync);
  99. return bIsSuccess==TRUE;
  100. }
  101. bool CSerialPort::InitPort( UINT portNo, const LPDCB&plDCB)
  102. {
  103. /**打开指定串口,该函数内部已经有临界区保护,上面请不要加保护*/
  104. if (!openPort(portNo))
  105. {
  106. return false ;
  107. }
  108. /**进入临界段*/
  109. EnterCriticalSection(&m_csCommunicationSync);
  110. /**配置串口参数*/
  111. if (!SetCommState(m_hComm,plDCB))
  112. {
  113. return false ;
  114. }
  115. /**清空串口缓冲区*/
  116. PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
  117. /**离开临界段*/
  118. LeaveCriticalSection(&m_csCommunicationSync);
  119. return true ;
  120. }
  121. void CSerialPort::ClosePort()
  122. {
  123. /**如果有串口被打开,关闭它*/
  124. if (m_hComm!=INVALID_HANDLE_VALUE)
  125. {
  126. CloseHandle(m_hComm);
  127. m_hComm=INVALID_HANDLE_VALUE;
  128. }
  129. }
  130. bool CSerialPort::openPort( UINT portNo)
  131. {
  132. /**进入临界段*/
  133. EnterCriticalSection(&m_csCommunicationSync);
  134. /**把串口的编号转换为设备名*/
  135. char szPort[50];
  136. sprintf_s(szPort, "COM%d" ,portNo);
  137. /**打开指定的串口*/
  138. m_hComm=CreateFileA(szPort, /**设备名,COM1,COM2等*/
  139. GENERIC_READ|GENERIC_WRITE, /**访问模式,可同时读写*/
  140. 0, /**共享模式,0表示不共享*/
  141. NULL, /**安全性设置,一般使用NULL*/
  142. OPEN_EXISTING, /**该参数表示设备必须存在,否则创建失败*/
  143. 0,
  144. 0);
  145. /**如果打开失败,释放资源并返回*/
  146. if (m_hComm==INVALID_HANDLE_VALUE)
  147. {
  148. LeaveCriticalSection(&m_csCommunicationSync);
  149. return false ;
  150. }
  151. /**退出临界区*/
  152. LeaveCriticalSection(&m_csCommunicationSync);
  153. return true ;
  154. }
  155. bool CSerialPort::OpenListenThread()
  156. {
  157. /**检测线程是否已经开启了*/
  158. if (m_hListenThread!=INVALID_HANDLE_VALUE)
  159. {
  160. /**线程已经开启*/
  161. return false ;
  162. }
  163. s_bExit= false ;
  164. /**线程ID*/
  165. UINT threadId;
  166. /**开启串口数据监听线程*/
  167. m_hListenThread=( HANDLE )_beginthreadex(NULL,0,ListenThread, this ,0,&threadId);
  168. if (!m_hListenThread)
  169. {
  170. return false ;
  171. }
  172. /**设置线程的优先级,高于普通线程*/
  173. if (!SetThreadPriority(m_hListenThread,THREAD_PRIORITY_ABOVE_NORMAL))
  174. {
  175. return false ;
  176. }
  177. return true ;
  178. }
  179. bool CSerialPort::CloseListenTread()
  180. {
  181. if (m_hListenThread!=INVALID_HANDLE_VALUE)
  182. {
  183. /**通知线程退出*/
  184. s_bExit= true ;
  185. /**等待线程退出*/
  186. Sleep(10);
  187. /**置线程句柄无效*/
  188. CloseHandle(m_hListenThread);
  189. m_hListenThread=INVALID_HANDLE_VALUE;
  190. }
  191. return true ;
  192. }
  193. UINT CSerialPort::GetBytesInCOM()
  194. {
  195. DWORD dwError=0; /**错误码*/
  196. COMSTATcomstat; /**COMSTAT结构体,记录通信设备的状态信息*/
  197. memset(&comstat,0, sizeof (COMSTAT));
  198. UINT BytesInQue=0;
  199. /**在调用ReadFile和WriteFile之前,通过本函数清除以前遗留的错误标志*/
  200. if (ClearCommError(m_hComm,&dwError,&comstat))
  201. {
  202. BytesInQue=comstat.cbInQue; /**获取在输入缓冲区中的字节数*/
  203. }
  204. return BytesInQue;
  205. }
  206. UINT WINAPICSerialPort::ListenThread( void *pParam)
  207. {
  208. /**得到本类的指针*/
  209. CSerialPort*pSerialPort= reinterpret_cast <CSerialPort*>(pParam);
  210. //线程循环,轮询方式读取串口数据
  211. while (!pSerialPort->s_bExit)
  212. {
  213. UINT BytesInQue=pSerialPort->GetBytesInCOM();
  214. /**如果串口输入缓冲区中无数据,则休息一会再查询*/
  215. if (BytesInQue==0)
  216. {
  217. Sleep(SLEEP_TIME_INTERVAL);
  218. continue ;
  219. }
  220. /**读取输入缓冲区中的数据并输出显示*/
  221. char cRecved=0x00;
  222. do
  223. {
  224. cRecved=0x00;
  225. if (pSerialPort->ReadChar(cRecved)== true )
  226. {
  227. std::cout<<cRecved;
  228. continue ;
  229. }
  230. } while (--BytesInQue);
  231. }
  232. return 0;
  233. }
  234. bool CSerialPort::ReadChar( char &cRecved)
  235. {
  236. BOOL bResult=TRUE;
  237. DWORD BytesRead=0;
  238. if (m_hComm==INVALID_HANDLE_VALUE)
  239. {
  240. return false ;
  241. }
  242. /**临界区保护*/
  243. EnterCriticalSection(&m_csCommunicationSync);
  244. /**从缓冲区读取一个字节的数据*/
  245. bResult=ReadFile(m_hComm,&cRecved,1,&BytesRead,NULL);
  246. if ((!bResult))
  247. {
  248. /**获取错误码,可以根据该错误码查出错误原因*/
  249. DWORD dwError=GetLastError();
  250. /**清空串口缓冲区*/
  251. PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_RXABORT);
  252. LeaveCriticalSection(&m_csCommunicationSync);
  253. return false ;
  254. }
  255. /**离开临界区*/
  256. LeaveCriticalSection(&m_csCommunicationSync);
  257. return (BytesRead==1);
  258. }
  259. bool CSerialPort::WriteData(unsigned char *pData,unsigned int length)
  260. {
  261. BOOL bResult=TRUE;
  262. DWORD BytesToSend=0;
  263. if (m_hComm==INVALID_HANDLE_VALUE)
  264. {
  265. return false ;
  266. }
  267. /**临界区保护*/
  268. EnterCriticalSection(&m_csCommunicationSync);
  269. /**向缓冲区写入指定量的数据*/
  270. bResult=WriteFile(m_hComm,pData,length,&BytesToSend,NULL);
  271. if (!bResult)
  272. {
  273. DWORD dwError=GetLastError();
  274. /**清空串口缓冲区*/
  275. PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_RXABORT);
  276. LeaveCriticalSection(&m_csCommunicationSync);
  277. return false ;
  278. }
  279. /**离开临界区*/
  280. LeaveCriticalSection(&m_csCommunicationSync);
  281. return true ;
  282. }
  1. //main.cpp:Definestheentrypointfortheconsoleapplication.
  2. //
  3. #include"stdafx.h"
  4. #include"SerialPort.h"
  5. #include<iostream>
  6. int _tmain( int argc,_TCHAR*argv[])
  7. {
  8. CSerialPortmySerialPort;
  9. if (!mySerialPort.InitPort(2))
  10. {
  11. std::cout<< "initPortfail!" <<std::endl;
  12. }
  13. else
  14. {
  15. std::cout<< "initPortsuccess!" <<std::endl;
  16. }
  17. if (!mySerialPort.OpenListenThread())
  18. {
  19. std::cout<< "OpenListenThreadfail!" <<std::endl;
  20. }
  21. else
  22. {
  23. std::cout<< "OpenListenThreadsuccess!" <<std::endl;
  24. }
  25. int temp;
  26. std::cin>>temp;
  27. return 0;
  28. }
分享到:
评论

相关推荐

    Virtual Serial Port Driver Pro V9.0.270 专业破解版 虚拟串口

    Virtual Serial Port Driver Pro(虚拟串口工具)是一款功能非常专业的虚拟串口辅助软件。压缩包内有破解说明,旧版本的win10用着好像有些兼容问题,于是到官网看看,发现已经更新到9.0版本了,还分为专业版和标准版,...

    Virtual Serial Port Driver 7.2.308 + vspdctl.dll 激活

    Serial port emulator by Eltima Software allows creating a large number of virtual COM ports and gives you great possibility to emulate serial port behavior fully. Virtual Serial Port Driver is not ...

    Serial Port Server with sample code

    Serial Port/Debug : Shows serial port debug msg such as open/close etc. ;; Serial Port/Hex : Shows data in hex format ;; Serial Port/CR : Appens \r\n at end of the line ;; Serial Port/Send file : ...

    Virtual Serial Port Driver Pro(虚拟串口工具)

    Virtual Serial Port Driver Pro(虚拟串口工具)是一款功能非常专业的虚拟串口辅助软件。最近课设需要用到这款软件,旧版本的win10用着好像有些兼容问题,于是到官网看看,发现已经更新到9.0版本了,还分为专业版和...

    Virtual.Serial.Port.Driver(免安装版)

    Virtual.Serial.Port.Driver(免安装版)Virtual.Serial.Port.Driver(免安装版)Virtual.Serial.Port.Driver(免安装版)Virtual.Serial.Port.Driver(免安装版)Virtual.Serial.Port.Driver(免安装版)Virtual....

    Virtual Serial Port Driver 7.1.289 破解版

    Virtual Serial Port Driver 7.1.289 手工破解版。 原程序DLL库用Armadillo 7.0 加壳。 可以用ArmaG3ddon_v1.9脱壳机直接脱壳 也可以手工脱壳,手工脱壳参考【Armadillo 7.0 DLL 脱壳】 脱壳后OD载入,patch几个...

    HSM USB SERIAL DRIVER

    HSM USB SERIAL DRIVER HSM 系统驱动程序

    DS1306 Serial Alarm Real Time Clock (RTC)

    DS1306 Serial Alarm Real Time Clock (RTC),时钟芯片的说明文档资料 Real time clock counts seconds, minutes, hours, date of the month, month, day of the week, and year with leap year compensation valid ...

    Serial to Ethernet Connector 8.0.1203

    Serial to Ethernet Connector 8.0.1203 直接替换文件

    Serial Port Monitor 4.1.2.293 破解版

    Serial Port Monitor 4.1.2.293 破解版 主要用来SPSniff串口,可以监听其他程序与串口的通信内容。 官方网站 http://www.eltima.com/products/serial-port-monitor/ 请支持正版

    Serial Monitor V6.02 破解版

    一个很棒的串口调试工具,HHD出品,Serial Monitor 6.02,原来有个Free版的,容易使电脑死机,所以换了这个V6.02最新版,我将使用天数改成了固定的,永不过期了。 不求完美,但求能用~

    python serial模块.zip

    python serial模块,可以做为你的学习设计参考,开发python串口的模块,简洁方便。

    USB-Serial Controller的驱动程序

    USB-Serial Controller的驱动程序

    Lumion8.0 Pro Serial number reading tool

    Lumion8.0 Pro Serial number reading toolLumion8.0 Pro Serial number reading tool

    c++跨平台串口库serial

    基于https://github.com/wjwwood/serial/tree/boostless项目修改,删除不必要文件,无需catkin只要cmake即可使用

    得到USB设备serial number

    根据USB设备的VID 和PID得到他的serial number。一些开发环境对于多个USB设备(同时插入多个设备),通过serial number区别使用不同的USB设备。 得到USB设备VID和PID方法。插拔一次设备,执行如下命令。 $ sudo dmesg ...

    gadgetserial 驱动 win7可用

    gadgetserial 驱动 实测win7可用,设备id为: USB\VID_0525&PID_A4A7,如果你的设备不是这个id,勿下载。

    USB serial Driver usb串口驱动

    USB-serial controller驱动程序,支持多种操作系统,连接console口必备工具

    Virtual.Serial.Port.Driver 6.9

    Virtual Serial Ports Driver XP 这款配置实用工具使用可以被包含到你自己的软件当中提供直接从你的应用软件创建和配置虚拟端口方式,通过虚拟非调制解调器电缆模拟 RS232 串口连接。使用 VSPD XP 你可以在你的系统...

    virtual serial port driver 6.9[crack]

    Virtual Serial Port Driver主要功能 1、创建任意数量的虚拟COM端口 Virtual Serial Port Driver使您能够创建无限数量的虚拟串行端口。创建的端口位于设备管理器中的“端口”组中,这意味着它们将被所有安装的所有...

Global site tag (gtag.js) - Google Analytics