###应用环境:
MFC
VS2008下测试通过
###需要添加文件
- SerialPort.h
- SerialPort.cpp
- SerialPortApi.h
- SerialPortApi.cpp
设置头文件: #include "SerialPortApi.h" 添加API变量:
CSerialPortApi COMPort;
打开串口并设置定时器:
if(OPEN_PORT_SUCCESS == COMPort.OpenPort("COM3",57600,8,NOPARITY,ONESTOPBIT))
{
SetTimer(RECV_TIMER_ID,50,NULL);
}
else
{
AfxMessageBox(COMPort.ErrorMsg());
}
定时器内部读取数据:
if(COMPort.ReceiveFlag)
{
CString str += COMPort.ReadRecv();
//Todo
}
发送数据:COMPort.Send(str);
关闭串口:COMPort.ClosePort();
INT CSerialPortApi::OpenPort(CString sPort,DWORD dwBaudRate,BYTE byDataBits,BYTE byParity,BYTE byStopBits);
输入参数:
- sPort:端口号,一定要属于
PortList
元素,否则会返回错误; - dwBaudRate:波特率,使用宏
BAUDRATE
中的元素,否则会返回错误;
static const DWORD BAUDRATE[] =
{CBR_110,CBR_300,CBR_600,CBR_1200,CBR_2400,
CBR_4800,CBR_9600,CBR_14400,CBR_19200,
CBR_38400,CBR_56000 ,CBR_57600,CBR_115200,
CBR_128000 ,CBR_256000 };
- byDataBits:数据位,可选值只有
6
,7
,8
,否则返回错误; - byParity:校验位,使用宏
PARITY
中的元素(分别表示无校验
,奇校验
,偶校验
,标记
,空格
),否则会返回错误;
static const DWORD PARITY[] = {NOPARITY,ODDPARITY,EVENPARITY,MARKPARITY,SPACEPARITY};
- byStopBits:停止位,使用宏
STOPBITS
中的元素(分别表示1
,1.5
,2
),否则会返回错误;
static const DWORD STOPBITS[]={ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS};
返回值:
- 串口名有误:
PORT_NUM_INVALID
- 波特率有误:
BAUDRATE_INVALID
- 数据位有误:
DATABITS_INVALID
- 校验位有误:
PARITY_INVALID
- 停止位有误:
STOPBIT_INVALID
- 成功:
OPEN_PORT_SUCCESS
- 失败:
OPEN_PORT_FAIL
OPEN_PORT_FAIL
的详细错误信息可以用CString CSerialPortApi::ErrorMsg()
获取,另外如果打开串口失败又找不到原因的话,可以将SerialPortApi.h
中的:
#define PORT_DEBUG_MODE 0
改成:
#define PORT_DEBUG_MODE 1
这样出错了会以弹窗显示错误原因;
INT CSerialPortApi::ClosePort();
返回值:
- 成功:
CLOSE_PORT_SUCCESS
- 失败:
CLOSR_PORT_FAIL
void CSerialPortApi::Send(CString str);
输入参数:
- str:待发送数据
void CSerialPortApi::Send( uchar str[], size_t SendLength);
输入参数:
- str:待发送数据
- SendLength:发送的数据长度
注:如果发送的数据里面包含'\0',那么只能用第二个函数
Send( uchar str[], size_t SendLength)
CString CSerialPortApi::ReadRecv();
返回值:
- 读取到的数据
**说明:**读取数据之前请先判断
ReceiveFlag
是否为TRUE
,否则读到的是空字符串;
deque<BYTE> CSerialPortApi::ReadRecvByte();
返回值:
- 读取到的数据(字节队列)
**说明:**读取数据之前请先判断
ReceiveFlag
是否为TRUE
,否则读到的是空字符串;
注:如果接受的数据里面包含'\0',那么只能用第二个函数
ReadRecvByte()
vector<CString> ReadRecvByteSplite(char ch);
输入参数:
- ch:分隔符
返回值:
- 读取到的数据(字符串数组)
根据结束符
ch
把接收池的数据分割到向量中返回,如果接收池最后一段不完整,继续留在接收池;比如说接受数据以'\r\n'结尾,然后某一次接收池数据是"aaa\r\nbbb\r\nccc\r\ndd",那么调用ReadRecvByteSplite('\n'),返回结果每一项分别是"aaa\r\n","bbb\r\n","ccc\r\n",而"dd"因为数据不完整,继续留在接收池,等待之后的数据拼接再次读取;
CString CSerialPortApi::ErrorMsg();
返回值:
- 错误代码和错误消息
说明:这一部分说明使用者原则上无需知晓,可作为原理了解;
基于读取注册表项HARDWARE\DEVICEMAP\SERIALCOMM
,理论上和设备管理器看到的一样。
调用后将会初始化CSerialPortApi
内的两个变量:PortNum
,PortList
,分别表示读取到的串口的数目(size_t
)和列表(CString
)
CSerialPortApi
类变量外部读取PortNum
要使用size_t GetPortNum();
函数;
该函数放在了CSerialPortApi
的构造函数中,所以定义变量后即可读取PortList
;
线程开启后,只要b_portIsOpen
为TRUE
,即一直在一个while
循环中等待,由m_hSendEvent
变量激活发送模块,激活方法是:SetEvent(m_hSendEvent);
,激活后即会发送Str4Send
中的信息;
该线程如果接收到数据,会把数据放到deque<BYTE> m_dequeRevData;
中的尾部,并且设置ReceiveFlag
为TRUE
;
如果检测到ReceiveFlag
为TRUE
,可以调用ReadRecv()
读取数据,转为为CString
变量返回,并且清空队列m_dequeRevData
,设置ReceiveFlag
为FALSE
;
由于有锁机制,所以不会产生因为RevThreadProc
对m_dequeRevData
写信息而同时ReadRecv()
对m_dequeRevData
读信息这种事情;
如果想像串口助手等辅助软件一样添加若干个CComboBox,然后供用户选择的话,可以设置如下五个CComboBox
变量关联相关控件:
CComboBox m_port;
CComboBox m_baudrate;
CComboBox m_parity;
CComboBox m_databits;
CComboBox m_stopbits;
然后使用下面代码初始化即可:
m_port.ResetContent();
//Set Port
for(size_t i = 0;i < COMPort.GetPortNum();i++)
{
m_port.AddString(COMPort.PortList[i]);
}
m_port.SetCurSel(0);
//Set Baudrate
CString str = "";
m_baudrate.ResetContent();
int i = 0;
for(i = 0;i<sizeof(BAUDRATE)/sizeof(DWORD);i++)
{
str.Format(_T("%d"),BAUDRATE[i]);
m_baudrate.AddString(str);
}
m_baudrate.SelectString(-1,"57600");
m_parity.ResetContent();
m_parity.AddString(_T("无校验"));
m_parity.AddString(_T("奇校验"));
m_parity.AddString(_T("偶校验"));
m_parity.AddString(_T("标记"));
m_parity.AddString(_T("空格"));
m_parity.SetCurSel(0);
m_databits.ResetContent();
m_databits.AddString(_T("6"));
m_databits.AddString(_T("7"));
m_databits.AddString(_T("8"));
m_databits.SelectString(-1,"8");
m_stopbits.ResetContent();
m_stopbits.AddString(_T("1"));
m_stopbits.AddString(_T("1.5"));
m_stopbits.AddString(_T("2"));
m_stopbits.SetCurSel(0);