标签:
使用VS2013
需要注册MSCOMM插件
1、添加串口变量
对话框上右键 插入Active X控件,选择 Micsrosft Commuunication Control,version 6.0 ,之后界面上有一个类似于电话的控件图标,把ID号改为 IDC_MSCOMM,右键这个控件 添加变量,命名为m_mscomm,(此时会新建mscomm的头文件和源文件),把DoDataExchange中的DDX_Control(pDX, IDC_MSCOMM, m_mscomm)这行删除掉。
2、初始化串口
//创建模块串口 if (!m_mscomm.Create(nullptr, WS_VISIBLE | WS_CHILD, CRect(0, 0, 0, 0), this, IDC_MSCOMM)) { MessageBox(_T("创建mscomm串口失败")); }
if (m_mscomm.get_PortOpen())//如果是打开的,则关闭 { m_mscomm.put_PortOpen(FALSE); GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]); return; } m_mscomm.put__CommPort(m_ci.comm);//选择串口 m_mscomm.put_InBufferSize(1024);//接收缓冲区 m_mscomm.put_OutBufferSize(1024);//发送缓冲区 m_mscomm.put_InputLen(0);//设置当前接受去数据长度为0,表示全部读取 m_mscomm.put_InputMode(1);//以二进制方式读写数据 m_mscomm.put_RThreshold(1);//接收缓冲区有1个及以上字符时,将响应接收数据事件 CString setting; setting.Format(_T("%s,%c,%s,%s"), m_ci.baudrate, m_ci.parity[0], m_ci.data, m_ci.stop); m_mscomm.put_Settings(setting);//波特率、校验位、数据位、停止位 try { m_mscomm.put_PortOpen(TRUE); GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSON]); } catch (CException*) { m_mscomm.put_OutBufferCount(0); CString errmsg; errmsg.Format(_T("打开串口失败[串口信息:串口号%d,波特率%s,校验位%s,数据位%s,停止位%s]"), m_ci.comm, m_ci.baudrate, m_ci.parity, m_ci.data, m_ci.stop); //AddShowInfo(errmsg); }
//CByteArray m_senddata;//发送的数据
//发送数据 m_mscomm.put_Output(COleVariant(m_senddata));5、接收数据
头文件:
DECLARE_EVENTSINK_MAP() void OnCommMscomm();//串口接收处理源文件消息映射
BEGIN_EVENTSINK_MAP(CKELONCommDlg, CDialogEx) ON_EVENT(CKELONCommDlg, IDC_MSCOMM, 1, CKELONCommDlg::OnCommMscomm, VTS_NONE) END_EVENTSINK_MAP()
if (m_mscomm.get_CommEvent() != 2) { return; } //读缓冲区信息 unsigned char rcvdata[1024] = { 0 };//接收的数据 COleSafeArray safearray_inp = m_mscomm.get_Input();//读缓冲区消息 DWORD len = safearray_inp.GetOneDimSize();//获取有效数据长度 for (long j = 0; j < len; j++)//转化为unsigned char数组 { safearray_inp.GetElement(&j, rcvdata + j); }6、完整程序
(不含组帧和解析帧)
头文件:
#ifndef KELONCommDlg_h__ #define KELONCommDlg_h__ // KELONCommDlg.h : 头文件 // #include "mscomm.h" #include "DLGCommConfig.h" #include "FrameHandle.h" #include "GridCtrl\GridCtrl.h" // CKELONCommDlg 对话框 class CKELONCommDlg : public CDialogEx { // 构造 public: CKELONCommDlg(CWnd* pParent = NULL); // 标准构造函数 ~CKELONCommDlg(); // 对话框数据 enum { IDD = IDD_KELONCOMM_DIALOG }; using comminfo = CDLGCommConfig::comminfo; struct ShowInfo//显示信息的格式 { const CString &info;//显示的信息 CString state;//显示状态,三种状态:发送、接收、无,有显示状态时一定会显示时间,一定要换行 bool breturnline;//是否换行 ShowInfo(const CString &info) :info(info) { breturnline = false; } }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() private: CMscomm m_mscomm;//串口控件 comminfo m_ci;//串口信息 FrameHandle m_rcvdata;//接收的数据 CByteArray m_senddata;//发送的数据 int m_sendtimes;//发送次数 UINT m_timesE, m_timesRetE;//多次发送事件句柄 CGridCtrl m_datagrid;//显示接收数据的表格 public: DECLARE_EVENTSINK_MAP() void OnCommMscomm();//串口接收处理 afx_msg void OnTimer(UINT_PTR nIDEvent); void SendData();//发送数据 afx_msg void OnBnClickedBtnOpencomm(); void GetConfigInfo(const CString &ifile);//读配置信息 void SetConfigInfo(const CString &ifile);//写配置信息 afx_msg void OnBnClickedBtnSenddata(); afx_msg void OnBnClickedBtnSetcomm(); void OnInitUI();//初始化界面 UIDataInfo GetUIDataInfo();//获取界面信息 //检测消息,消息合法返回真,并组织成unsigned char数组,消息不合法,存储错误消息 bool JudgeMsg(CString imsg,std::vector<unsigned char> &omsg,CString &errmsg); afx_msg void OnBnClickedOk(); void AddShowInfo(const ShowInfo &si);//添加显示信息 afx_msg void OnBnClickedBtnClearshowinfo(); afx_msg void OnBnClickedBtnAbout(); void AddGridData(const std::vector<UIDataInfo> &uidi);//添加接收数据到表格上 CString parseMsg(const UIDataInfo & uidi);//解析消息内容 unsigned long BCDToDec(const unsigned char *bcd, int length);//BCD码 void copy_V2A(std::vector<unsigned char>::const_iterator begin, unsigned char *arr, int length);//拷贝:vector -> 数组 afx_msg void OnBnClickedBtnCleargrid(); }; #endif // KELONCommDlg_h__源文件:
// KELONCommDlg.cpp : 实现文件 // #include "stdafx.h" #include "KELONComm.h" #include "KELONCommDlg.h" #include "afxdialogex.h" #include <map> #include <set> #include <vector> #include <chrono> #include <algorithm> //表格处理 #include "GridCtrl\CellRange.h" #include "GridCtrl\GridCell.h" #include "GridCtrl\GridCellBase.h" #include "GridCtrl\GridDropTarget.h" #include "GridCtrl\InPlaceEdit.h" #include "GridCtrl\MemDC.h" #include "GridCtrl\TitleTip.h" #ifdef _DEBUG #define new DEBUG_NEW #endif namespace { int g_timespan = 300;//多次发送的时间间隔,300ms int g_sendtimes = 3;//最多重发这么多次 CString g_configfilepath;//配置路径 struct MsgCmd//消息命令 { int cmdtype;//命令类型 int cmdsubtype;//命令子类型 int result;//操作结果 friend bool operator==(const MsgCmd &item1, const MsgCmd &item2) { return item1.cmdtype == item2.cmdtype && item1.cmdsubtype == item2.cmdsubtype && item1.result == item2.result; } }; std::map<CString,MsgCmd> g_msghead;//消息头:<描述,命令> const CString g_CommState[2] = { _T("打开串口"), _T("关闭串口") }; //enum CommState Index :关闭状态时显示"打开串口",打开状态时显示"关闭串口" enum g_eCSI{ CSOFF = 0, CSON }; const CString g_RSState[2] = { _T("receive:"), _T("send:") }; enum g_erssi{ RECV = 0, SEND };//enum reveive send state index } // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CKELONCommDlg 对话框 CKELONCommDlg::CKELONCommDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CKELONCommDlg::IDD, pParent) , m_timesE(1001) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } CKELONCommDlg::~CKELONCommDlg() { SetConfigInfo(g_configfilepath); } void CKELONCommDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CKELONCommDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_Btn_OpenComm, &CKELONCommDlg::OnBnClickedBtnOpencomm) ON_BN_CLICKED(IDC_Btn_SendData, &CKELONCommDlg::OnBnClickedBtnSenddata) ON_WM_TIMER() ON_BN_CLICKED(IDC_Btn_SetComm, &CKELONCommDlg::OnBnClickedBtnSetcomm) ON_BN_CLICKED(IDOK, &CKELONCommDlg::OnBnClickedOk) ON_BN_CLICKED(IDC_Btn_ClearShowInfo, &CKELONCommDlg::OnBnClickedBtnClearshowinfo) ON_BN_CLICKED(IDC_Btn_About, &CKELONCommDlg::OnBnClickedBtnAbout) ON_BN_CLICKED(IDC_Btn_ClearGrid, &CKELONCommDlg::OnBnClickedBtnCleargrid) END_MESSAGE_MAP() BEGIN_EVENTSINK_MAP(CKELONCommDlg, CDialogEx) ON_EVENT(CKELONCommDlg, IDC_MSCOMM, 1, CKELONCommDlg::OnCommMscomm, VTS_NONE) END_EVENTSINK_MAP() // CKELONCommDlg 消息处理程序 BOOL CKELONCommDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 //创建模块串口 if (!m_mscomm.Create(nullptr, WS_VISIBLE | WS_CHILD, CRect(0, 0, 0, 0), this, IDC_MSCOMM)) { MessageBox(_T("创建mscomm串口失败")); } //设置串口状态 GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]); //添加显示信息的滚动条 CEdit *pedit = (CEdit*)GetDlgItem(IDC_Edt_ShowInfo); pedit->ShowScrollBar(SB_VERT, TRUE);//显示滚动条 //获取程序目录 CString dirpath; GetModuleFileName(NULL, dirpath.GetBuffer(MAX_PATH), MAX_PATH);//获取程序的路径,注意GetBuffer里面的MAX_PATH dirpath.ReleaseBuffer();//需要释放,不然的话szPath的长度为0,也就是GetBuffer要和ReleaseBuffer配对使用 dirpath = dirpath.Left(dirpath.ReverseFind('\\')); //配置路径 g_configfilepath = dirpath + _T("\\configinfo.ini"); //获取串口信息 GetConfigInfo(g_configfilepath); //初始化界面 OnInitUI(); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CKELONCommDlg::OnInitUI() { //初始化表格 CRect rc; CWnd *pwnd = (this->GetDlgItem(IDC_STATIC_ShowGrid)); pwnd->GetWindowRect(&rc); ScreenToClient(&rc); m_datagrid.Create(rc, this, 100); m_datagrid.DeleteAllItems(); m_datagrid.SetBkColor(RGB(192, 192, 192)); m_datagrid.SetColumnCount(5); m_datagrid.SetRowCount(1); m_datagrid.SetFixedColumnCount(5); m_datagrid.SetFixedRowCount(1); m_datagrid.SetItemText(0, 0, _T("正确/错误")); m_datagrid.SetItemText(0, 1, _T("链路层信息")); m_datagrid.SetItemText(0, 2, _T("网络层信息")); m_datagrid.SetItemText(0, 3, _T("传输层信息")); m_datagrid.SetItemText(0, 4, _T("应用层消息头")); m_datagrid.AutoSizeColumns(); m_datagrid.ExpandColumnsToFit(); ////////////////////////////////////////////////////////////////////////// //初始化控件 CComboBox *pcombo; CString text; //链路层应答标识 pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_LinkRF); for (int i = 0; i != 9; i++) { text.Format(_T("%d"), i); pcombo->AddString(text); } pcombo->SetCurSel(0); //网络层应答标识 pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_NWRF); for (int i = 0; i != 9; i++) { text.Format(_T("%d"), i); pcombo->AddString(text); } pcombo->SetCurSel(0); //传输层应答标识 pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_TransPortRF); for (int i = 0; i != 9; i++) { text.Format(_T("%d"), i); pcombo->AddString(text); } pcombo->SetCurSel(0); //应用层命令类型消息头 pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_AppMsgHead); for (auto it = g_msghead.begin(); it != g_msghead.end(); ++it) { pcombo->AddString(it->first); } if (!g_msghead.empty()) { pcombo->SetCurSel(0); } } void CKELONCommDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CKELONCommDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CKELONCommDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void CKELONCommDlg::GetConfigInfo(const CString &ifile) { //串口信息 m_ci.comm = GetPrivateProfileInt(_T("comminfo"), _T("comm"), 1, ifile); GetPrivateProfileString(_T("comminfo"), _T("baudrate"), _T("9600"), m_ci.baudrate, 256, ifile); GetPrivateProfileString(_T("comminfo"), _T("parity"), _T("even"), m_ci.parity, 256, ifile); GetPrivateProfileString(_T("comminfo"), _T("data"), _T("8"), m_ci.data, 256, ifile); GetPrivateProfileString(_T("comminfo"), _T("stop"), _T("1"), m_ci.stop, 256, ifile); //时间处理 //多次发送的时间间隔 g_timespan = GetPrivateProfileInt(_T("timeinfo"), _T("timespan"), 300, ifile); //最多重发几次 g_sendtimes g_sendtimes = GetPrivateProfileInt(_T("timeinfo"), _T("sendtimes"), 3, ifile); using std::map; using std::set; //消息头处理 //std::map<CString,MsgCmd> g_msghead;//消息头:<描述,命令> int msgcount = GetPrivateProfileInt(_T("msghead"), _T("msgcount"), 0, ifile); for (int i = 0; i != msgcount; i++) { MsgCmd mc; CString indexstr; indexstr.Format(_T("msg%d"), i); mc.cmdtype = GetPrivateProfileInt(indexstr, _T("cmdtype"), 0, ifile); mc.cmdsubtype = GetPrivateProfileInt(indexstr, _T("cmdsubtype"), 0, ifile); mc.result = GetPrivateProfileInt(indexstr, _T("result"), 0, ifile); TCHAR szdescrip[1024]; GetPrivateProfileString(indexstr, _T("description"), _T(""), szdescrip, sizeof(szdescrip), ifile); CString descrip(szdescrip); //插入到消息头map中:std::map<CString,MsgCmd> g_msghead;//消息头:<描述,命令> //查找有没有这个消息头命令或消息描述 auto findit = std::find_if(g_msghead.begin(), g_msghead.end(), [&mc, &descrip](const std::pair<CString, MsgCmd> &item) {return item.second == mc || item.first == descrip; }); if (findit != g_msghead.end())//已存在这个描述或命令 { CString errmsg; errmsg.Format(_T("发现有重复的消息命令头或描述:\r\n [cmdtype : %d, cmdsubtype : %d, result : %d, description : %s]\r\n [cmdtype : %d, cmdsubtype : %d, result : %d, description : %s]"), findit->second.cmdtype, findit->second.cmdsubtype, findit->second.result, findit->first, mc.cmdtype, mc.cmdsubtype, mc.result, descrip ); MessageBox(errmsg); } else { g_msghead[descrip] = mc; } } } void CKELONCommDlg::SetConfigInfo(const CString &ifile) { //串口信息 CString commstr; commstr.Format(_T("%d"), m_ci.comm); WritePrivateProfileString(_T("comminfo"), _T("comm"), commstr, ifile); WritePrivateProfileString(_T("comminfo"), _T("baudrate"), m_ci.baudrate, ifile); WritePrivateProfileString(_T("comminfo"), _T("parity"), m_ci.parity, ifile); WritePrivateProfileString(_T("comminfo"), _T("data"), m_ci.data, ifile); WritePrivateProfileString(_T("comminfo"), _T("stop"), m_ci.stop, ifile); } void CKELONCommDlg::OnCommMscomm() { if (m_mscomm.get_CommEvent() != 2) { return; } //读缓冲区信息 unsigned char rcvdata[1024] = { 0 };//接收的数据 COleSafeArray safearray_inp = m_mscomm.get_Input();//读缓冲区消息 DWORD len = safearray_inp.GetOneDimSize();//获取有效数据长度 for (long j = 0; j < len; j++)//转化为unsigned char数组 { safearray_inp.GetElement(&j, rcvdata + j); } CString Temp; for (long i = 0; i < len; i++) { Temp.AppendFormat(_T("%.2X "), rcvdata[i]); } bool havenodata = m_rcvdata.GetDataLength() == 0; ShowInfo si(Temp); if (havenodata)//没有接收数据 { si.state = g_RSState[g_erssi::RECV]; } AddShowInfo(si); //数据处理 auto appret = m_rcvdata.appdata(rcvdata, len); //判断数据。。。 if (appret.first) { KillTimer(m_timesRetE); //显示接收到的数据 AddGridData(appret.second); } } void CKELONCommDlg::SendData() { //判断是否启动模块串口 CString ButtonText; GetDlgItem(IDC_Btn_OpenComm)->GetWindowText(ButtonText); if (ButtonText == g_CommState[g_eCSI::CSOFF]) { CString errmsg = _T("没有打开串口"); MessageBox(errmsg); return; } CString showinfo; for (int i = 0; i != m_senddata.GetSize(); i++) { showinfo.AppendFormat(_T("%.2X "), m_senddata.GetAt(i)); } ShowInfo si(showinfo); si.state = g_RSState[g_erssi::SEND]; AddShowInfo(si); //发送数据 m_mscomm.put_Output(COleVariant(m_senddata)); m_rcvdata.init();//初始化接收帧 m_sendtimes = 1;//第一次发送 //多次发送事件 m_timesRetE = SetTimer(m_timesE, g_timespan, NULL); } void CKELONCommDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 KillTimer(nIDEvent); if (nIDEvent == m_timesRetE)//多次发送事件 { m_sendtimes++; if (m_sendtimes <= g_sendtimes)//发送不满3次 { size_t sendtimes = m_sendtimes; SendData(); m_sendtimes = sendtimes; } else//发送了3次 { //AddShowInfo(_T("刷新失败")); } } CDialogEx::OnTimer(nIDEvent); } void CKELONCommDlg::OnBnClickedBtnOpencomm() { // TODO: 在此添加控件通知处理程序代码 if (m_mscomm.get_PortOpen())//如果是打开的,则关闭 { m_mscomm.put_PortOpen(FALSE); GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]); return; } m_mscomm.put__CommPort(m_ci.comm);//选择串口 m_mscomm.put_InBufferSize(1024);//接收缓冲区 m_mscomm.put_OutBufferSize(1024);//发送缓冲区 m_mscomm.put_InputLen(0);//设置当前接受去数据长度为0,表示全部读取 m_mscomm.put_InputMode(1);//以二进制方式读写数据 m_mscomm.put_RThreshold(1);//接收缓冲区有1个及以上字符时,将响应接收数据事件 CString setting; setting.Format(_T("%s,%c,%s,%s"), m_ci.baudrate, m_ci.parity[0], m_ci.data, m_ci.stop); m_mscomm.put_Settings(setting);//波特率、校验位、数据位、停止位 try { m_mscomm.put_PortOpen(TRUE); GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSON]); } catch (CException*) { m_mscomm.put_OutBufferCount(0); CString errmsg; errmsg.Format(_T("打开串口失败[串口信息:串口号%d,波特率%s,校验位%s,数据位%s,停止位%s]"), m_ci.comm, m_ci.baudrate, m_ci.parity, m_ci.data, m_ci.stop); //AddShowInfo(errmsg); } } void CKELONCommDlg::OnBnClickedBtnSenddata() { // TODO: 在此添加控件通知处理程序代码 UpdateData(TRUE); //获取界面数据信息 UIDataInfo di = GetUIDataInfo(); if (!di.bOK)//获取界面信息失败 { MessageBox(di.errmsg); return; } //发送数据 //对需要发送的数据组帧 auto framedata = FrameHandle::createFrame(di); if (!framedata.bok)//组帧失败 { MessageBox(framedata.errmsg); return; } else { m_senddata.RemoveAll(); m_senddata.SetSize(framedata.length); for (int i = 0; i < framedata.length; i++) { m_senddata.SetAt(i, framedata.data[i]); } SendData();//发送数据 } } void CKELONCommDlg::OnBnClickedBtnSetcomm() { // TODO: 在此添加控件通知处理程序代码 CDLGCommConfig commconfigdlg(m_ci, NULL); if (commconfigdlg.DoModal() == IDOK) { CString ButtonText; GetDlgItem(IDC_Btn_OpenComm)->GetWindowText(ButtonText); if (ButtonText == g_CommState[g_eCSI::CSON]) { if (m_mscomm.get_PortOpen()) { m_mscomm.put_PortOpen(FALSE); } GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]); } } } UIDataInfo CKELONCommDlg::GetUIDataInfo() { UIDataInfo di; //略 return di; } void CKELONCommDlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 OnBnClickedBtnSenddata(); //CDialogEx::OnOK(); } void CKELONCommDlg::AddShowInfo(const ShowInfo &si) { CString info; GetDlgItemText(IDC_Edt_ShowInfo, info); int nLen = info.GetLength(); if (nLen > 0xffffffff)//以前显示的信息很多,清空 { info.Empty(); } if (!si.state.IsEmpty())//有显示状态 { //获取时间 auto timepoint = std::chrono::system_clock::now(); time_t tm_t = std::chrono::system_clock::to_time_t(timepoint); tm t; localtime_s(&t, &tm_t); char sztime[100]; strftime(sztime, sizeof(sztime), "%Y/%m/%d %H:%M:%S", &t); if (!info.IsEmpty())//非空,添加两次换行 { info.Append(_T("\r\n\r\n")); } info.AppendFormat(_T("%-10s %s\r\n%s"), si.state, CString(sztime), si.info); } else if (si.breturnline)//没有显示状态,需要换行 { if (!info.IsEmpty())//非空,添加一次换行 { info.Append(_T("\r\n")); } info.AppendFormat(_T("%s"), si.info); } else//不需要换行 { info.AppendFormat(_T("%s"), si.info); } SetDlgItemText(IDC_Edt_ShowInfo, info);//收发框会闪烁 nLen = info.GetLength(); CEdit *pedit = (CEdit*)GetDlgItem(IDC_Edt_ShowInfo); pedit->SetSel(nLen - 1, nLen - 1);//滚动到底部 } void CKELONCommDlg::OnBnClickedBtnClearshowinfo() { // TODO: 在此添加控件通知处理程序代码 SetDlgItemText(IDC_Edt_ShowInfo, _T("")); } bool CKELONCommDlg::JudgeMsg(CString imsg, std::vector<unsigned char> &omsg, CString &oerrmsg) { oerrmsg.Empty(); omsg.clear(); USES_CONVERSION; //去除中间的空格 imsg.Remove(' '); //判断输入的长度是否为偶数 if (imsg.GetLength() % 2) { imsg = _T("0") + imsg; } int CurrPos = 0; for (; CurrPos < imsg.GetLength(); CurrPos++) { TCHAR currch = imsg.GetAt(CurrPos); if ((currch >= '0' && currch <= '9') || (currch >= 'a' && currch <= 'f') || (currch >= 'A' && currch <= 'F')) { } else { oerrmsg=_T("消息内容格式不对[应该为0-F]"); return false; } } //转换为字节数组 CurrPos = 0; int i = 0; for (; CurrPos < imsg.GetLength(); CurrPos += 2) { CString tmpbytestr = imsg.Mid(CurrPos, 2); int tmpbyte; sscanf_s(W2A(tmpbytestr), "%x", &tmpbyte); omsg.push_back(tmpbyte); } return true; } void CKELONCommDlg::OnBnClickedBtnAbout() { // TODO: 在此添加控件通知处理程序代码 CAboutDlg dlg; dlg.DoModal(); } void CKELONCommDlg::AddGridData(const std::vector<UIDataInfo> &uidi) { int rowcount = m_datagrid.GetRowCount(); m_datagrid.SetRowCount(rowcount + uidi.size()); for (int i = 0; i != uidi.size(); i++) { CString tmpstr(_T("√")); if (!uidi[i].bOK) { tmpstr.Format(_T("× : %s"), uidi[i].errmsg); } m_datagrid.SetItemText(rowcount + i, 0, tmpstr); tmpstr.Format(_T("%.2X / %.2X"), uidi[i].link.RF, uidi[i].link.flag); // 链路层信息 m_datagrid.SetItemText(rowcount + i, 1, tmpstr); tmpstr.Format(_T("%.2X / %.2X / %.2X%.2X / %.2X%.2X"), // 网络层信息 uidi[i].NW.RF, uidi[i].NW.flag, uidi[i].NW.addr1[0], uidi[i].NW.addr1[1], uidi[i].NW.addr2[0], uidi[i].NW.addr2[1] ); m_datagrid.SetItemText(rowcount + i, 2, tmpstr); tmpstr.Format(_T("%.2X / %.2X"), uidi[i].Transport.RF, uidi[i].Transport.flag); // 传输层信息 m_datagrid.SetItemText(rowcount + i, 3, tmpstr); tmpstr.Format(_T("%.2X / %.2X / %.2X"), // 应用层消息头 uidi[i].App.msghead[0], uidi[i].App.msghead[1], uidi[i].App.msghead[2]); m_datagrid.SetItemText(rowcount + i, 4, tmpstr); if (uidi[i].bOK) { const CString parsemsg = parseMsg(uidi[i]); ShowInfo si(parsemsg); si.breturnline = true; AddShowInfo(si); } } /*m_datagrid.AutoSizeColumns(); m_datagrid.ExpandColumnsToFit();*/ m_datagrid.EnsureVisible(rowcount, 0);//滚动到最后一行 } CString CKELONCommDlg::parseMsg(const UIDataInfo & uidi) { using namespace std; CString msg; //略 return msg; } unsigned long CKELONCommDlg::BCDToDec(const unsigned char *bcd, int length) { int i, tmp; unsigned long dec = 0; for (i = 0; i != length; i++) { tmp = bcd[i]; tmp = ((bcd[i] >> 4) & 0x0F) * 10 + (bcd[i] & 0x0F); dec = dec * 100 + tmp; } return dec; } void CKELONCommDlg::copy_V2A(std::vector<unsigned char>::const_iterator begin, unsigned char *arr, int length) { int i = 0; for (auto it = begin; it != begin + length; ++it,++i) { arr[i] = *it; } } void CKELONCommDlg::OnBnClickedBtnCleargrid() { // TODO: 在此添加控件通知处理程序代码 m_datagrid.SetRowCount(1); /*m_datagrid.AutoSizeColumns(); m_datagrid.ExpandColumnsToFit();*/ }配置文件:
//串口配置信息 //串口comm //波特率baudrate //校验位parity //数据位data //停止位stop [comminfo] comm=4 baudrate=9600 parity=even data=8 stop=1 //时间信息 //timespan ms 重发数据 // 重复发送sendtimes次 [timeinfo] timespan=500 sendtimes=1 //消息头配置 //每一个消息头有:命令类型、命令子类型、操作结果、描述信息 [msghead] msgcount=18 [msg0] cmdtype=7 cmdsubtype=1 result=0 description=查询设备版本号 //。。。。。。 [msg17] cmdtype=103 cmdsubtype=1 result=0 description=读电量模块型号和厂家信息
标签:
原文地址:http://blog.csdn.net/u011311985/article/details/51279740