赞
踩
.h文件
自定义函数
public:
int WriteBlock(char* abOut, int MaxLength); //写串口
.cpp文件
//写串口 int C***Dlg::WriteBlock(char *abOut, int MaxLength) { BOOL JudgeWrite;//写入串行端口数据操作的返回值 COMSTAT ComStat;//通信状态缓冲区的指针 DWORD dwErrorFlags, dwLength, lentest; //接收错误代码变量的指针,要写的字节数,被写入的字节数的变量地址 m_osWrite.Offset = 0; ClearCommError(m_hCom, &dwErrorFlags, &ComStat);//清除串行端口错误或读取串行端口现在的状态==> //串口句柄,接收错误代码变量的指针,通信状态缓冲区的指针 if(dwErrorFlags > 0) //如果接收到错误代码 { AfxMessageBox("写串口错!请检查参数设置。"); PurgeComm(m_hCom, PURGE_TXABORT|PURGE_TXCLEAR); //清空缓冲区==> return 0; } dwLength = MaxLength;//要写的字节数 lentest = 0;//实际字节数的指针置0 JudgeWrite = WriteFile(m_hCom, abOut, dwLength, &lentest, &m_osWrite); //写入串行端口数据==> //句柄,预发送的数据,写入的字节数,被写入的字节数的变量地址,OVERLAPPED结构体指针(不使用异步传输设为null) if(!JudgeWrite)//写失败 { if(GetLastError() == ERROR_IO_PENDING) //重叠 I/O 操作在进行中。 { GetOverlappedResult(m_hCom, &m_osWrite, &lentest, TRUE);//返回重叠操作结果==> //句柄;重叠结构的指针;实际字节数的指针;TRUE,那么只有当操作完成才会返回 } else lentest = 0;//实际字节数的指针置0 } return lentest;//返回字节数的指针 }
清除串行端口错误或读取串行端口现在的状态时,可用函数ClearCommError
。Windows系统利用此函数清除硬件的通讯错误以及获取通讯设备的当前状态
ClearCommError()函数原型:
BOOL ClearCommError(
HANDLE hFile, //通信设备的句柄
LPDWORD lpErrors,//接收错误代码变量的指针
LPCOMSTAT lpStat //通信状态缓冲区的指针
);
learCommError()函数参数说明:
hFile: 串行端冂的Handle值,此值即为使用CreateFile
函数后所返回的值。
lpError: 返回错误数值,错误常数如下:
CE_BREAK:检测到中断信号。
CE_DNS:Windows95专用,未被选择的并行端口。
CE_FRAME:硬件检到框架错误
CE_IOE:通信设备发生输入/输出綹误,
CE_MODE:设置模式错误,或是hFile值错误。
CE_OOP:Wmdows95专用,并行端口发生缺纸错误。
CE_OVERRUN:缓冲区容量不足,数据将遗失。
CE_PTO:Windows95专用,并行端口发生超时错误。
CE_RXOVER:接收区满溢或在文件结尾被接收到后仍有数据发送过来。
CE_RXPARITY:硬件检测到校验位检查错误。
CE_TXFULL:发送缓存区已满后,应用程序仍要发送数据。
lpStat: 指向通信端口状态的结构变量。此结构的原始声明如下:
typedef struct _COMSTAT { //cst
DWORD fCtsHold : 1; //Tx正在等待CTS信号
DWORD fDsrHold : 1; //Tx正在等待DSR信号
DWORD fRlsdHold : 1; //Tx正在等待RLSD信号
DWORD fXoffHold : 1; //Tx由于接收XOFF字符而在等待
DWORD fXoffSent : 1; //Tx由于发送XOFF字符而在等待
DWORD fEof : 1; //发送EOF字符
DWORD fTxim : 1; //字符在等待Tx
DWORD fReserved : 25; //保留
DWORD cbInQue; //输入缓冲区中的字节数
DWORD cbOutQue; //输出缓冲区中的字节数
}
COMSTAT, *LPCOMSTAT;
此结构屮有关参数说明如下:
fCtsHold:是否正在等待CTS信号。占一个位的位置。
fDsrHold:是否正在等待DSR信号。占一个位的位置。
fRlsdHoId:是否正在等待RLSD信号。占一个位的位置。
fXoftHoId:是否因收到xoff字符而在等待。占一个位的位置。
fXoffHold:是否因送出xoff字符而使得发送的动作在等待。占一个位置
cbInQue:在输入缓冲区尚未被ReadFile函数读取的数据字节数。这个参数经常被用来进行状态检查。
cbOutQue:在发送缓冲区而尚未被发送的据字节数。
PurgeComm()函数原型:
BOOL PurgeComm( HANDLE hFile, DWORD dwFlags )
PurgeComm()函数函数参数说明:
hFile: 串口句柄
dwFlags: 需要完成的操作
参数dwFlags指定要完成的操作,可以是下列值的组合:
PURGE_TXABORT:终止所有正在进行的字符输出操作,完成一个正处于等待状态的重叠i/o操作,他将产生一个事件,指明完成了写操作
PURGE_RXABORT:终止所有正在进行的字符输入操作,完成一个正在进行中的重叠I/O操作,并带有已设置得适当事件
PURGE_TXCLEAR:这个命令指导设备驱动程序 清除输出缓冲区,经常与PURGE_TXABORT命令标志一起使用
PURGE_RXCLEAR:这个命令用于设备驱动程序 清除输入缓冲区,经常与PURGE_RXABORT命令标志一起使用
WriteFile
函数,可以将数据写入一个文件或者I/O设备。该函数比fwrite
函数要灵活的多,也可将这个函数应用于对通信设备、管道、套接字以及邮槽的处理。
windows将串行端口当成文件来使用,因此写入串行端口数据的函数也是WriteFile。
WriteFile()函数原型:
BOOL WriteFile(
HANDLE hFile, //文件句柄
LPCVOID lpBuffer, //数据缓存区指针
DWORD nNumberOfBytesToWrite, //要写的字节数
LPDWORD lpNumberOfBytesWritten, //用于保存实际写入字节数的存储区域的指针
LPOVERLAPPED lpOverlapped //OVERLAPPED结构体指针
);
WriteFile()函数参数说明:
hFile: 串行端口的Handle值,句柄
lpBuffer: 指向欲发送的数据
nNumberOfBytesToWrite: 写入的字节数
lpNumberOfBytesWritten: 指向被写入的字节数的变量地址
lpOverlapped: 指向overlapped I/O的结构地址,通常用来作背景工作时同步检查用,在串行通信中若不使用异步传输,则可不使用,设成NULL即可。
GetOverlappedResult()函数原型:
BOOL GetOverlappedResult (
HANDLE hFile, //文件、管道或通信设备的句柄
LPOVERLAPPED lpOverlapped, //指向重叠结构的指针
LPDWORD lpNumberOfBytesTransferred, //指向实际字节数的指针
BOOL bWait //等待标志
);
GetOverlappedResult()函数参数说明:
hFile: 串行端口的Handle值,句柄
lpOverlapped: LPOVERLAPPED 结构体的指针,用于说明重叠操作是否开始,该参数和readfile函数或writefile函数中的LPOVERLAPPED 结构体的even参数相匹配;
lpNumberOfBytesTransferred: 一个指向字节数的指针,该字节数是读操作或写操作的实际传输字节数。
bWait: 当LPOVERLAPPED 结构体的内部参数为STATUS_PENDING,且该参数为TRUE,那么只有当操作完成才会返回。当该参数为FALSE,且操作正在等待,则返回FALSE,用GetLastError 函数会返回ERROR_IO_INCOMPLETE。
.h文件
绑定按钮与复选框变量
public:
afx_msg void OnBnClickedButtonSent(); //发送编辑框数据
CButton m_cHexSend; //复选框:十六进制发送
.cpp文件
//按钮事件 void C***Dlg::OnBnClickedButtonSent() { char abOut[MAXBLOCK]; int OutNum, length; if (!m_bConnected) { AfxMessageBox(_T("串口未打开!")); return; } memset(abOut, 0, MAXBLOCK); //读文本框内容 CString str; GetDlgItem(IDC_EDIT_TXDATA)->GetWindowText(str); char SendOut[MAXBLOCK]; int len = str.GetLength(); for (int i = 0; i < len; i++) abOut[i] = str.GetAt(i); if (m_cHexSend.GetCheck()) //十六进制发送复选框选中时 { CString StrHexData; abOut[len] = NULL; StrHexData = CString(abOut); len = String2Hex(StrHexData, SendOut); length = WriteBlock(SendOut, len); } else //按字符发送 length = WriteBlock(abOut, len); m_txlen += length; DisplayStatus(); return; }
.h文件
public:
afx_msg void OnBnClickedButtonDefaultsend(); //发送默认数据
.cpp文件
void C***Dlg::OnBnClickedButtonDefaultsend() // TODO: 在此添加控件通知处理程序代码 vector<CString> str_vec; str_vec.push_back("EB"); //帧头 str_vec.push_back("90"); str_vec.push_back("00"); //长度 str_vec.push_back("02"); str_vec.push_back("11"); //数据 str_vec.push_back("01"); str_vec.push_back("00"); //校验码 str_vec.push_back("12"); str_vec.push_back("09"); //帧尾 str_vec.push_back("D7"); //写串口 for (int i = 0; i < str_vec.size(); i++) { char abOut[MAXBLOCK]; int length; if (!m_bConnected) { AfxMessageBox("串口未打开!"); return; } memset(abOut, 0, MAXBLOCK); CString str; str = str_vec[i]; char SendOut[MAXBLOCK]; int len = str.GetLength(); for (int j = 0; j < len; j++) abOut[j] = str.GetAt(j); //十六进制发送 CString StrHexData; abOut[len] = NULL; StrHexData = CString(abOut); len = String2Hex(StrHexData, SendOut); length = WriteBlock(SendOut, len); m_txlen += length; DisplayStatus(); } return; }
.h文件
public:
//复选框函数
afx_msg void OnCheckAutoEncoder(); //自动加密
afx_msg void OnTimer(UINT nIDEvent); //自动发送时间间隔
.cpp文件
//定时器 void C***Dlg::OnCheckAutoEncoder() { CString str; GetDlgItem(IDC_EDIT_CYCLE)->GetWindowText(str); if(m_Btn_Loop.GetCheck()) SetTimer(1, atoi(str.GetBuffer(str.GetLength())), NULL); else KillTimer(1); } //自动发送时间间隔 void C***Dlg::OnTimer(UINT nIDEvent) { if(nIDEvent == 1) ==重复事件== CDialog::OnTimer(nIDEvent); } }
⚠️ 注意:
最重要的,建立定时器消息映射。没有以下语句,则即便定时器被成功创建,也不会执行OnTimer函数
BEGIN_MESSAGE_MAP(CTestTimerDlg, CDialog)
...
ON_WM_TIMER()
END_MESSAGE_MAP()
当然也可以自动覆写OnTimer函数,方法是,在类视图中,对CTestTimer类右键,属性,在属性页中,点击消息,找到WM_TIMER,点击添加OnTimer
之后系统会自动生成OnTimer函数,并且建立消息映射,我们只需要在OnTimer函数中写入相关代码就可以了
atoi()函数原型:
int atoi(const char* str)
参数str是要转换的字符串,返回值是转换后的整数。
SetTimer()函数原型:
UINT_PTR SetTimer(
HWND hWnd, // 窗口句柄。在MFC程序中SetTimer被封装在CWnd类中,调用就不用指定窗口句柄了
UINT_PTR nIDEvent, // 定时器ID,多个定时器时,可以通过该ID判断是哪个定时器
UINT uElapse, // 时间间隔,单位为毫秒
TIMERPROC lpTimerFunc // 回调函数
);
SetTimer()函数返回值:
类型: UINT_PTR
如果函数成功,hWnd参数为0,则返回新建立的时钟编号,可以把这个时钟编号传递给KillTimer来销毁时钟.
如果函数成功,hWnd参数为非0,则返回一个非零的整数,可以把这个非零的整数传递给KillTimer来销毁时钟.
如果函数失败,返回值是零.若想获得更多的错误信息,调用GetLastError函数.
SetTimer()函数示例
SetTimer(1,1000,NULL);
参数含义
1: 计时器的名称;
1000: 时间间隔,单位是毫秒;
NULL: 使用OnTimer函数。当不需要计时器的时候调用KillTimer(nIDEvent);
KillTimer()函数原型:
BOOL KillTimer(UINT_PTR nIDEvent); //nIDEvent —— 传递给 SetTimer的计时器事件的值。
SetTimer()函数返回值:
如果事件已终止,则值为非零值。
如果 KillTimer 成员函数找不到指定的计时器事件,则为0。
.h文件
public:
//自定义函数
char Char2Hex(char ch); //字符转换为16进制数据
int String2Hex(CString str, char* SendOut); //字符串转换为16进制数据
.cpp文件
//字符转换为16进制数据 char CSprDlg::Char2Hex(char ch) { if ((ch >= '0') && (ch <= '9')) return ch - 0x30; if ((ch >= 'A') && (ch <= 'F')) return ch - 'A' + 10; if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10; else return(-1); } //字符串转换为16进制数据 int CSprDlg::String2Hex(CString str, char* SendOut) { int hexdata, lowhexdata; int hexdatalen = 0; int len = str.GetLength(); for (int i = 0; i < len;) { char lstr, hstr = str[i]; if (hstr == ' ' || hstr == '\r' || hstr == '\n') { i++; continue; } i++; if (i >= len) break; lstr = str[i]; hexdata = Char2Hex(hstr); lowhexdata = Char2Hex(lstr); if ((hexdata == 16) || (lowhexdata == 16)) break; else hexdata = hexdata * 16 + lowhexdata; i++; SendOut[hexdatalen] = (char)hexdata; hexdatalen++; } return hexdatalen; }
以上就是今天要讲的内容。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。