vc 串口精灵软件分析
前几天找这个源码,没有找到,今天找到了,有打开串口参数设置对话框,梳理一下关键实现代码:
主界面如下:
打开软件,设置初始的变量,串口参数:
// CCommWizardDlg dialog CCommWizardDlg::CCommWizardDlg(CWnd* pParent /*=NULL*/) : CDialog(CCommWizardDlg::IDD, pParent) { bSend = FALSE;//自动发送标志 bReceive = FALSE;//自动接收标志 m_nPort = 1;//端口号 m_strSettings = _T("9600,n,8,1");//串口参数 m_strSendString = _T("");//发送的字符串 m_nTime = 1000;//时间间隔1s m_nInputMode = 1;//输入模式设置为1 //{{AFX_DATA_INIT(CCommWizardDlg) m_strReceive = _T("");//文本框内容清除 //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); }
初始化函数中:初始化输入模式选择,
// TODO: Add extra initialization here m_ctrlDataType.AddString(_T("按ASCII码")); m_ctrlDataType.AddString(_T("按2进制"));// m_ctrlDataType.AddString(_T("按16进制")); m_ctrlDataType.SetCurSel(m_nInputMode);//初始化时是1,即按2进制
改变组合框的输入模式代码:
void CCommWizardDlg::OnSelchangeType() { // TODO: Add your control notification handler code here m_nInputMode = m_ctrlDataType.GetCurSel(); }
清除接收文本框内容:
void CCommWizardDlg::OnClear() { // TODO: Add your control notification handler code here m_strReceive = _T("");//清除接收文本框内容 }
主对话框中定义声明的:
// CCommWizardDlg dialog class CCommWizardDlg : public CDialog { // Construction public: char CCommWizardDlg::ConvertHexChar(char ch); int String2Hex(CString str, CByteArray &senddata);//字符串到十六进制转换 void OpenPort();//打开串口 CCommWizardDlg(CWnd* pParent = NULL); // standard constructor BOOL bSend;//发送 BOOL bReceive;//接收 int m_nInputMode;//输入模式 int m_nPort;//端口号 CString m_strSettings;//参数 CString m_strSendString;//发送的字符串 int m_nTime;//间隔时间 // Dialog Data //{{AFX_DATA(CCommWizardDlg) enum { IDD = IDD_COMMWIZARD_DIALOG }; CButton m_ctrlReceive;//接收按钮控件 CButton m_ctrlSend;//发送按钮控件 CComboBox m_ctrlDataType;//控制数据类型 输入模式 组合框控件变量 CString m_strReceive;//接收到的字符串 CMSComm m_Com;//串口控件 //}}AFX_DATA
点击设置参数后,代码如下:
void CCommWizardDlg::OnSettings() { // TODO: Add your control notification handler code here CSettingDlg setDlg;//声明类对象 setDlg.nPort = m_nPort;//上次设置的端口号值 setDlg.nTime = m_nTime;//上次设置的间隔时间值 setDlg.strSettings = m_strSettings;//上次设置的串口参数值 setDlg.strSendString = m_strSendString;//上次设置的发送字符串值 if(setDlg.DoModal() == IDOK)//弹出对话框,点确定按钮后返回值设置。 { m_nPort = setDlg.nPort;//从setDlg(参数设置类)中获取端口号 m_nTime = setDlg.nTime;//间隔时间值 m_strSettings = setDlg.strSettings;//串口参数值 m_strSendString = setDlg.strSendString;//发送字符串值 } OpenPort();//打开串口 }
设置参数如下,设置串口相关参数。
点确定之后,选择的串口就被打开了,代码如下:
void CCommWizardDlg::OnSettings() { // TODO: Add your control notification handler code here CSettingDlg setDlg;//声明类对象 setDlg.nPort = m_nPort;//上次设置的端口号值 setDlg.nTime = m_nTime;//上次设置的间隔时间值 setDlg.strSettings = m_strSettings;//上次设置的串口参数值 setDlg.strSendString = m_strSendString;//上次设置的发送字符串值 if(setDlg.DoModal() == IDOK)//弹出对话框,点确定按钮后返回值设置。 { m_nPort = setDlg.nPort;//从setDlg(参数设置类)中获取端口号 m_nTime = setDlg.nTime;//间隔时间值 m_strSettings = setDlg.strSettings;//串口参数值 m_strSendString = setDlg.strSendString;//发送字符串值 } OpenPort();//打开串口 }
打开串口函数:
//打开串口 void CCommWizardDlg::OpenPort() { if(m_Com.GetPortOpen()) m_Com.SetPortOpen(FALSE);//关闭串口 m_Com.SetCommPort(m_nPort); //选择串口号 if( !m_Com.GetPortOpen()) m_Com.SetPortOpen(TRUE);//打开串口 else AfxMessageBox("cannot open serial port"); m_Com.SetSettings(m_strSettings); //波特率9600,无校验,8个数据位,1个停止位 m_Com.SetRThreshold(1); //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件 m_Com.SetInputMode(1); m_Com.SetInputLen(0); //设置当前接收区数据长度为0 m_Com.GetInput();//先预读缓冲区以清除残留数据 }
程序中的变量的声明定义:
// CSettingDlg dialog class CSettingDlg : public CDialog { // Construction public: CSettingDlg(CWnd* pParent = NULL); // standard constructor int nPort, nTime; CString strSettings, strSendString; // Dialog Data //{{AFX_DATA(CSettingDlg) enum { IDD = IDD_DIALOG1 }; int m_nPort; CString m_strSettings; CString m_strSendString; int m_nTime; //}}AFX_DATA
点确定后将数据保存在当前参数设置窗口类中。
自动发送:
自动发送代码:
void CCommWizardDlg::OnSend() { // TODO: Add your control notification handler code here bSend = !bSend;//取反。 if(bSend)//发送。 { m_ctrlSend.SetWindowText(_T("停止发送")); SetTimer(1,m_nTime,NULL);//发送时间为1000毫秒,启动发送。 } else//停止发送。 { m_ctrlSend.SetWindowText(_T("自动发送")); KillTimer(1); //取消发送定时。 } }
自动发送时启动定时器:
void CCommWizardDlg::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default OnManualsend();//手动发送函数 CDialog::OnTimer(nIDEvent); }
调用手动发送函数:
void CCommWizardDlg::OnManualsend() { // TODO: Add your control notification handler code here CString strSend;//发送字符串 if(m_nInputMode > 1)//输入模式大于1(字节数组,十六进制) { CByteArray hexdata;//字节数据, int len=String2Hex(m_strSendString ,hexdata);//字符串转十六进制字节数组 m_Com.SetOutput(COleVariant(hexdata));//发送字节数组 } else m_Com.SetOutput(COleVariant(m_strSendString));//发送数据,发送字符串 }
//字符串转十六进制字节数组 int CCommWizardDlg::String2Hex(CString str, CByteArray &senddata) { int hexdata,lowhexdata; int hexdatalen=0; int len=str.GetLength(); senddata.SetSize(len/2); for(int i=0;i<len;) { char lstr,hstr=str[i]; if(hstr==' ') { i++; continue; } i++; if(i>=len) break; lstr=str[i]; hexdata=ConvertHexChar(hstr); lowhexdata=ConvertHexChar(lstr); if((hexdata==16)||(lowhexdata==16)) break; else hexdata=hexdata*16+lowhexdata; i++; senddata[hexdatalen]=(char)hexdata; hexdatalen++; } senddata.SetSize(hexdatalen); return hexdatalen; }
接收回显方式的选择:
改变组合框输入模式选择:
void CCommWizardDlg::OnSelchangeType() { // TODO: Add your control notification handler code here m_nInputMode = m_ctrlDataType.GetCurSel(); }
接收数据:
//自动接收按钮 void CCommWizardDlg::OnReceive() { // TODO: Add your control notification handler code here m_Com.GetInput();//先预读缓冲区以清除残留数据 bReceive = !bReceive;//自动接收标志取反,,,定时器里有检测该变量 if(bReceive)//自动接收 m_ctrlReceive.SetWindowText(_T("停止接收"));//按钮控件文本设置 else//不自动接收 m_ctrlReceive.SetWindowText(_T("开始接收")); }
//这是一个将字符转换为相应的十六进制值的函数 //功能:若是在0-F之间的字符,则转换为相应的十六进制字符,否则返回-1 char CCommWizardDlg::ConvertHexChar(char ch) { if((ch>='0')&&(ch<='9')) return ch-0x30; else if((ch>='A')&&(ch<='F')) return ch-'A'+10; else if((ch>='a')&&(ch<='f')) return ch-'a'+10; else return (-1); }
串口控件:
BEGIN_EVENTSINK_MAP(CCommWizardDlg, CDialog) //{{AFX_EVENTSINK_MAP(CCommWizardDlg) ON_EVENT(CCommWizardDlg, IDC_COMMCTRL, 1 /* OnComm */, OnOnCommCommctrl, VTS_NONE) //}}AFX_EVENTSINK_MAP END_EVENTSINK_MAP()
接收函数:
void CCommWizardDlg::OnOnCommCommctrl() { // TODO: Add your control notification handler code here VARIANT variant_inp; COleSafeArray safearray_inp; LONG len,k; BYTE rxdata[2048]; //设置BYTE数组 An 8-bit integerthat is not signed. CString strtemp; if(bReceive) { if(m_Com.GetCommEvent()==2) //事件值为2表示接收缓冲区内有字符 { variant_inp = m_Com.GetInput(); //读缓冲区 safearray_inp = variant_inp; //VARIANT型变量转换为ColeSafeArray型变量 len=safearray_inp.GetOneDimSize(); //得到有效数据长度 for(k=0;k<len;k++) safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组 for(k=0;k<len;k++) //将数组转换为Cstring型变量 { BYTE bt=*(char*)(rxdata+k); //字符型 if(m_nInputMode == 2) strtemp.Format("%02X ",bt); //将字符以十六进制方式送入临时变量strtemp存放,注意这里加入一个空隔 else strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放 m_strReceive = m_strReceive + strtemp; //加入接收编辑框对应字符串 } m_strReceive += "\r\n"; } } UpdateData(FALSE); //更新编辑框内容 }
在主对话框中加入串口控件后,引入 头文件#include "mscomm.h"
串口h文件中有这几行代码:
// CMSComm wrapper class class CMSComm : public CWnd { protected: DECLARE_DYNCREATE(CMSComm) public: CLSID const& GetClsid() { static CLSID const clsid = { 0x648a5600, 0x2c6e, 0x101b, { 0x82, 0xb6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14 } }; return clsid; }
发现自己的不足,善于利用找到的方法去扬长避短。行动起来。