Windows 串口通信简单示例

为了方便串口程序的调试,使用了如下两款工具软件

[1]. 串口调试助手

该软件可以通过串口收发数据。可以通过串口发送数据,也可以查看串口收到的数据。

[2]. 虚拟串口

可以虚拟串口,每次虚拟出一对串口,这对串口相互连通。如图中虚拟出了串口COM2和COM3,这样通过COM2发送的数据,会由COM3接收到,反之亦然。

串口通信的基本步骤

(1) 通过CreateFile(“COMx:“,…) 打开串口

(2) 通过配置DCB结构体和SetCommState函数,设置串口的参数。

(3) 通过ReadFile()和WriteFile 读写串口

Windows 串口通信实例

封装了一个串口通信的C++类CSerial,通过CSerial类的OpenSerialPort()可以打开一个串口,串口打开后后自动新建线程读取串口数据,并通过MessageBox简单的显示出数据。通过CSerial类的SendData()方法可以向串口发送数据。

主函数中,新建了一个CSerial类对象,打开串口2,然后简单的通过一个消息框循环来控制向串口不断的发送数据。

程序的效果图如下:


使用虚拟串口工具虚拟出串口对COM2和COM3,本实例程序读写COM2,使用串口调试助手打开COM3。

-> 在“是否向串口发送数据”消息框中,点击”是(Y)” 会向串口发送一条”This is a example” 数据。如图,在串口调试助手中收到该数据包

-> 在串口调试助手中,手动发送”jarvischu”,程序会读取到该数据并弹出消息框显示。

源码如下:

Serial.h

#pragma once

#include <windows.h>

class CSerial
{
public:
	CSerial(void);
	~CSerial(void);

	//打开串口
	BOOL OpenSerialPort(TCHAR* port, UINT baud_rate, BYTE date_bits, BYTE stop_bit, BYTE parity = NOPARITY);

	//发送数据
	BOOL SendData(char* data, int len);
public:
	HANDLE m_hComm;
};


Serial.cpp
#include"StdAfx.h"
#include"Serial.h"
#include<process.h>
typedef unsigned(__stdcall *PTHREEA_START) (void *);

CSerial::CSerial(void)
{
	m_hComm = INVALID_HANDLE_VALUE;
}

CSerial::~CSerial(void)
{
	if (m_hComm!= INVALID_HANDLE_VALUE) {
		CloseHandle(m_hComm);
	}
}

/*********************************************************************************************
 * 功能    :	读串口线程回调函数 
  * 描述	   :	收到数据后,简单的显示出来
   ********************************************************************************************/
DWORD WINAPI CommProc(LPVOID lpParam) {

	CSerial* pSerial = (CSerial*)lpParam;

	//清空串口
	PurgeComm(pSerial->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);

	char buf[512];
	DWORD dwRead;
	while (pSerial->m_hComm != INVALID_HANDLE_VALUE) {
		BOOL bReadOK  = ReadFile(pSerial->m_hComm, buf, 512, &dwRead, NULL);
		if (bReadOK  && (dwRead > 0)) {
			buf[dwRead] = '\0';
			MessageBoxA(NULL, buf, "串口收到数据", MB_OK);
		}
	}
	return 0;
}

/*******************************************************************************************
 * 功能     :	打开串口
  * port     :	串口号, 如_T("COM1:")
   * baud_rate:	波特率
    * date_bits:	数据位(有效范围4~8)
	 * stop_bit :	停止位
	  * parity   :	奇偶校验。默认为无校验。NOPARITY 0; ODDPARITY 1;EVENPARITY 2;MARKPARITY 3;SPACEPARITY 4
********************************************************************************************/
BOOL CSerial::OpenSerialPort(TCHAR* port, UINT baud_rate, BYTE date_bits, BYTE stop_bit, BYTE parity)
{
	//打开串口
	m_hComm  = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);//独占方式打开串口

	TCHAR err[512];

	if (m_hComm  == INVALID_HANDLE_VALUE) {
		_stprintf(err, _T("打开串口%s 失败,请查看该串口是否已被占用"), port);
		MessageBox(NULL, err, _T("提示"), MB_OK);
		return FALSE;
	}

	//MessageBox(NULL,_T("打开成功"),_T("提示"),MB_OK);

	//获取串口默认配置
	DCB dcb;
	if (!GetCommState(m_hComm, &dcb)) {
		MessageBox(NULL, _T("获取串口当前属性参数失败"), _T("提示"), MB_OK);
	}

	//配置串口参数
	dcb.BaudRate  = baud_rate;	//波特率
	dcb.fBinary  = TRUE;			//二进制模式。必须为TRUE
	dcb.ByteSize  = date_bits;	//数据位。范围4-8
	dcb.StopBits  = ONESTOPBIT;	//停止位

	if (parity  == NOPARITY) {
		dcb.fParity  = FALSE;	//奇偶校验。无奇偶校验
		dcb.Parity  = parity;	//校验模式。无奇偶校验
	}
	else {
		dcb.fParity  = TRUE;		//奇偶校验。
		dcb.Parity  = parity;	//校验模式。无奇偶校验
	}

	dcb.fOutxCtsFlow  = FALSE;	//CTS线上的硬件握手
	dcb.fOutxDsrFlow  = FALSE;	//DST线上的硬件握手
	dcb.fDtrControl  = DTR_CONTROL_ENABLE;//DTR控制
	dcb.fDsrSensitivity  = FALSE;
	dcb.fTXContinueOnXoff  = FALSE;//
	dcb.fOutX  = FALSE;			//是否使用XON/XOFF协议
	dcb.fInX  = FALSE;			//是否使用XON/XOFF协议
	dcb.fErrorChar  = FALSE;		//是否使用发送错误协议
	dcb.fNull  = FALSE;			//停用null stripping
	dcb.fRtsControl  = RTS_CONTROL_ENABLE;//
	dcb.fAbortOnError  = FALSE;	//串口发送错误,并不终止串口读写

								//设置串口参数
	if(!SetCommState(m_hComm, &dcb)) {
		MessageBox(NULL, _T("设置串口参数失败"), _T("提示"), MB_OK);
		return FALSE;
	}

	//设置串口事件
	SetCommMask(m_hComm, EV_RXCHAR);//在缓存中有字符时产生事件
	SetupComm(m_hComm, 16384, 16384);

	//设置串口读写时间
	COMMTIMEOUTS CommTimeOuts;
	GetCommTimeouts(m_hComm, &CommTimeOuts);
	CommTimeOuts.ReadIntervalTimeout  = MAXDWORD;
	CommTimeOuts.ReadTotalTimeoutMultiplier  = 0;
	CommTimeOuts.ReadTotalTimeoutConstant  = 0;
	CommTimeOuts.WriteTotalTimeoutMultiplier  = 10;
	CommTimeOuts.WriteTotalTimeoutConstant  = 1000;

	if (!SetCommTimeouts(m_hComm, &CommTimeOuts)) {
		MessageBox(NULL, _T("设置串口时间失败"), _T("提示"), MB_OK);
		return FALSE;
	}

	//创建线程,读取数据
	HANDLE hReadCommThread = (HANDLE)_beginthreadex(NULL, 0, (PTHREEA_START)CommProc, (LPVOID) this, 0, NULL);
	return TRUE;
}

/********************************************************************************************
 * 功能    :	通过串口发送一条数据
  ********************************************************************************************/
BOOL CSerial::SendData(char* data, int len) {
	if (m_hComm == INVALID_HANDLE_VALUE) {
		MessageBox(NULL, _T("串口未打开"), _T("提示"), MB_OK);
		return FALSE;
	}

	//清空串口
	PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);

	//写串口
	DWORD dwWrite  = 0;
	DWORD dwRet  = WriteFile(m_hComm, data, len, &dwWrite, NULL);

	//清空串口
	PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);

	if (!dwRet) {
		MessageBox(NULL, _T("发送数据失败"), _T("提示"), MB_OK);
		return FALSE;
	}
	return TRUE;
}

主程序  ManipulateCom.cpp

#include <windows.h>
#include "Serial.h"
#include <string.h>

int main(int argc, _TCHAR* argv[])
{
	CSerial serial;
	serial.OpenSerialPort(_T("COM2:"),9600,8,1);  //打开串口后,自动接收数据

	//向串口发送数据
	char* data = "This is a example\n";
	int ret = 1;
	while(ret != IDNO ){
		serial.SendData(data,strlen(data));
		ret = MessageBox(NULL,_T(""),_T("是否向串口发送数据"),MB_YESNO); //YES继续发送一条数据,NO不发送,退出
	}
	return 0;
}




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值