您的位置:首页 > 其它

串口通信模块4:串口操作自定义类(1)

2016-10-02 18:04 351 查看
为了以后使用方便,将串口的属性及操作封装成一个类。对串口的操作可以直接通过调用这个串口类提供的几个函数接口即可。

1.CMySerial类的定义:MySerial.h

#pragma once
#include <Windows.h>
#include <afxwin.h>
class CMySerial
{
public:
CMySerial();
virtual ~CMySerial();
public:
bool OpenSerial(CWnd* pParent, UINT portnr, UINT baud, CHAR parity,
UINT databits, UINT stopbits, DWORD dwCommEvents, UINT writebuffersize);  //Open the Serial
void ClosePort();
// the control function of monitoring thread
BOOL  StartMonitoring();
BOOL  RestarMonitoring();
BOOL  StopMonitoring();
DWORD GetWriteBufferSize();
DWORD GetCommEvents();
DCB   GetDCB();
// Attain & Save the Data that will transfor and trigle the transfor event.
void WriteToPort(char* string);
void WriteToPort(char* string, int n);
void WriteToPort(LPCSTR string);
void WriteToPort(LPCSTR string, int n);

protected:
void        ProcessErrorMessage(char* ErrorText); //deal error event
static UINT CommTread(LPVOID pParam);             // function to deal serial thread
static void ReceiveChar(CMySerial* port,          //read serial data
COMSTAT comstat);
static void WriteChar(CMySerial* port);           //write data to serial

public:
HANDLE m_hComm;    //handle to operate serial
int m_nWriteSize;  //send data

protected:
CWinThread* m_Thread;                   // a pointer to thread
CRITICAL_SECTION m_csCommunicationSync; // critial临界 resourse
BOOL m_bThreadAlive;   // the alive state of serial
//serial event
HANDLE            m_hWriteEvent;      //write event
HANDLE            m_hShutdownEvent;   //shut down event
HANDLE            m_hEventArray[3];   //event array
DWORD             m_dwCommEvents;     //mask code of serial event
OVERLAPPED        m_ov;               //set asynchonous I/O operation
COMMTIMEOUTS      m_CommTimeouts;     //structure of serial overtime
DCB               m_dcb;              //DCB structure in serial communication
CWnd*             m_pParent;          //include window pointer of serial operation
UINT              m_nPortNr;          //port number
char*             m_szWriteBuffer;    //area of writedata buffer
DWORD             m_nWriteBufferSize; //size of writedata buffer
};

在这个类中,事件数组m_hEventArray中的每个数组元素都对应着一个事件。这个数组共有三个元素:一个是写事件,一个是收事件,还有一个是串口关闭事件。

2.CMySerial类的实现及代码解析:CMySerial.c

构造及解析函数的实现:
CMySerial::CMySerial()
{
m_hComm = NULL; //初始化串口句柄
//初始化异步操作成员变量
m_ov.Offset = 0;
m_ov.OffsetHigh = 0;
//创建异步操作的事件成员变量
m_ov.hEvent = NULL;
//初始化发送及关闭事件
m_hWriteEvent = NULL;
m_hShutdownEvent = NULL;
//初始化发送变量
m_szWriteBuffer = NULL;
m_nWriteBufferSize = 1;
m_bThreadAlive = FALSE;  //串口监控线程处于非激活状态
}
CMySerial::~CMySerial()
{
do
{
SetEvent(m_hShutdownEvent);
} while ( m_bThreadAlive );       //监控线程处于激活状态时,关闭串口
if (m_hComm != NULL)
{
CloseHandle(m_hComm);
m_hComm = NULL;     //如果上面串口关闭不成功,继续关闭窗口
}
if (m_hShutdownEvent != NULL)
CloseHandle( m_hShutdownEvent ); //关闭串口并关闭事件句柄
if (m_ov.hEvent != NULL)
CloseHandle( m_ov.hEvent );  //关闭串口异步操作事件句柄
if (m_hWriteEvent != NULL )
CloseHandle(m_hWriteEvent); //关闭串口写事件句柄
TRACE("Thread ended\n");
delete[] m_szWriteBuffer;   //释放发送缓冲区
}
打开串口
bool CMySerial::OpenSerial(CWnd* pParent, UINT portnr, UINT baud,
CHAR parity,UINT databits, UINT stopbits,
DWORD dwCommEvents, UINT writebuffersize)
{
assert(portnr > 0 && portnr < 5);
assert(pParent != NULL);
if (m_bThreadAlive) //如果串口监控程序处于激活态,那我们关闭它
{
do
{
SetEvent(m_hShutdownEvent);
} while (m_bThreadAlive);
TRACE("Thread ended\n");
}

if (m_ov.hEvent != NULL)  //创建串口异步通信事件
ResetEvent(m_ov.hEvent);
else
m_ov.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );

if (m_hWriteEvent != NULL) //创建数据发送事件
ResetEvent(m_hWriteEvent);
else
m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL );

if (m_hShutdownEvent != NULL) //创建关闭串口事件
ResetEvent(m_hShutdownEvent);
else
m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

//串口事件设定 及 优先级分配

m_hEventArray[0] = m_hShutdownEvent; //优先级最高
m_hEventArray[1] = m_ov.hEvent;
m_hEventArray[2] = m_hWriteEvent;
//初始化临界资源
InitializeCriticalSection(&m_csCommunicationSync);
m_pParent = pParent;           //保存串口操作窗口指针
if (m_szWriteBuffer != NULL)   //为发送缓存清理空间
{
delete[] m_szWriteBuffer;
}
m_szWriteBuffer = new char[writebuffersize]; //发送字符型的信息
m_nPortNr = portnr;                          //保存串口号
m_nWriteBufferSize = writebuffersize;        //将要发送的数据
m_dwCommEvents = dwCommEvents;               //串口事件
BOOL bResult = FALSE;
char *szPort = new char[50];                 //数据缓冲区
char *szBaud = new char[50];
EnterCriticalSection(&m_csCommunicationSync);//锁定临界变量

if (m_hComm != NULL)                         //确保串口处于关闭状态
{
CloseHandle(m_hComm);
m_hComm = NULL;
}

sprintf(szPort, "COM%d", portnr);            //串口状态信息
sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d",
baud, parity, databits, stopbits);
//打开串口
m_hComm = CreateFile((LPCWSTR)szPort,     //串口号 出现char*与LPCWSTR不兼容  强制转换
GENERIC_READ |       //读模式
GENERIC_WRITE,       //写模式
0,                   //必须为零
NULL,                //安全型属性结构
OPEN_EXISTING,       //必须置为此
FILE_FLAG_OVERLAPPED,//采用异步的输入输出形式
NULL);               //必须为NULL
if (m_hComm == INVALID_HANDLE_VALUE)
{//串口打开失败
delete [] szPort;
delete [] szBaud;
return FALSE;
}
//设置超时参数
m_CommTimeouts.ReadIntervalTimeout = 1000;
m_CommTimeouts.ReadTotalTimeoutConstant = 1000;
m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;
m_CommTimeouts.WriteTotalTimeoutConstant = 1000;
m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;

if (SetCommTimeouts(m_hComm, &m_CommTimeouts))//设置串口参数
{//超时设置
if (SetCommMask(m_hComm, dwCommEvents))
{//事件设置
if (GetCommState(m_hComm, &m_dcb))
{   //参数设置
m_dcb.EvtChar = 'q';
m_dcb.fRtsControl = RTS_CONTROL_ENABLE;
if (BuildCommDCB((LPCWSTR)szBaud, &m_dcb))
{
if (!SetCommState(m_hComm, &m_dcb))
ProcessErrorMessage("SetCommState()");
}
else //串口参数设置失败
ProcessErrorMessage("BuildCommDCB()");
}
else //参数获取失败
ProcessErrorMessage("GetCommState()");
}
else//串口事件设置失败
ProcessErrorMessage("SetCommMask()");
}
else//串口超时设置失败
ProcessErrorMessage("SetCommTimeouts()");
delete [] szPort;  //清空数据区
delete [] szBaud;
PurgeComm(m_hComm, PURGE_RXABORT | PURGE_TXABORT | PURGE_RXCLEAR | PURGE_TXCLEAR);
LeaveCriticalSection(&m_csCommunicationSync);//解锁临时变量

return TRUE;
}


打开串口代码设计的核心思想为:
1.判断串口监控线程是否处于激活状态?如果是,那么需要将它关闭;
2.创建并启动串口的3个事件;
3.创建的事件句柄保存到事件数组里;
4.初始化临界资源;并申请一段数据发送缓存区;
5.保存传入的参数,并锁定临界资源;

6.验证串口是否已关闭?如果没有关闭,则要关闭;
7.打开串口,并判断是否打开串口成功?否则需要我们释放资源后返回;
8.设置串口通信的超时参数。
9.将前面准备好的串口的所有属性设置到串口上,设置失败后需要调用消息盒子进行失败处理。
10.释放资源,清空缓存区,并解锁临界资源,使得其它进程以后可以使用这个临界资源。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: