管道流量採集實驗指導書

管道流量採集實驗指導書

      項目較大,是我畢業設計的成果之一,完成整個項目需要的時間大概爲8小時(1天,非常熟悉MFC編程),24小時(3天,熟悉MFC編程),48小時(6天,較熟悉),2周(只懂得語法)

一、 實驗目的

1.1 瞭解485現場總線;
1.2 瞭解Visual Studio 2015編譯環境;
1.3 瞭解磁漩渦流量傳感器測量原理;
1.4 掌握MODBUS協議
1.5 掌握C++中MFC類庫編程;
1.6 掌握MFC程序打包;
1.7 掌握MySQL數據庫;
1.8 掌握CRC校驗碼計算;
1.9 掌握串口編程。

二、 實驗環境及設備

      Windows系統、MySQL數據庫、Visual Studio 2015、水倉系統、KJ402-F1礦用本安型水文檢測分站、GLC30/50礦用磁漩渦流量傳感器、FD15直流穩壓電源。

三、 設備簡介

3.1 RS-485現場總線

      電子工業協會於 1983 年在 RS-422 工業總線標準的基礎之上,制訂併發布了 RS-485 總線工業標準。RS-485 工業總線標準能夠有效支持多個分節點和通信距離遠,並且對於信息的接收靈敏度較高等特性。在工業通信網絡中,RS-485 總線一般主要用於與外部各種工業設備進行信息傳輸和數據交換,所具備的對於噪聲的有效抑制能力、高效的數據傳輸速率與良好的數據傳輸的可靠性能以及可擴展的通信電纜的長度是其他的許多工業通信標準所無法比擬的。因此,RS-485 總線在諸多個領域得到了廣泛的應用,比如在工業控制領域、交通的自動化控制領域和現場總線通信網絡等。
      RS-485 總線標準規定了總線接口的電氣特性標準即對於 2 個邏輯狀態的定義:正電平在+2V~+6V 之間,表示一個邏輯狀態;負電平在-2V~-6V 之間,則表示另一個邏輯狀態;數字信號採用差分傳輸方式,能夠有效減少噪聲信號的干擾。

3.2 MODBUS協議

      MODBUS通信協議是在1978年由美國的可編程控制器供應商莫迪康公司進行制定的一種工業現場總線控制器的通信網絡協議。由於MODBUS通信協議具有高度的自由開放性以及用戶可以快速熟悉的掌握通信協議,使得變得簡單且易學,從而使得它比很多其他受商業利益驅使的工業控制通信協議標準取得更快的發展,因此普遍受到大量的第三方產品設計廠商、各種各樣的終端用戶以及大量的系統芯片集成商的廣泛支持,並且被應用於智能化儀表通信網絡和現場總線控制技術等領域。
      MODBUS通信協議是可以認爲是屬於在應用層的工業控制技術的通信協議,在物理層方面將可以遵循RS-485總線標準或者光纖等信息傳輸線路,將會主要應用於主機和從機以及遠程通信控制模塊三者之間進行的網絡信息傳輸。現在在世界各地已經有大量釆用MODBUS通信協議的工業現場總線技術和設備以及各種工業通信網絡的控制模塊應用於國內外的各種工業控制現場。
      通過MODBUS通信協議構建各種現場總線網絡,某一個控制器可以與其他各種控制器之間進行相互通信或者控制器的數據信息經由一個通信網絡與其它在網絡中互連的通信設備之間可以實現通信。因此,MODBUS通信協議通過逐漸發展已經成爲一種通用的工業通信標準。
      標準的MODBUS口是使用RS-232C兼容串行接口,它定義了連接口的針腳、電纜、信號位、傳輸波特率、奇偶校驗等,控制器能直接或經由Modem組網。
控制器通信使用主/從技術,即僅主設備能初始化傳輸(查詢),其它設備(從設備)根據主設備查詢提供的數據做出響應。無論是主設備查詢還是從設備響應,每個MODBUS幀都包括地址域、功能域、數據域、錯誤檢測域。該協議分RTU和ASCII兩種傳輸模式,相對於ASC1I模式,RTU模式表達相同的信息需要較少的位數,且在相同通訊速率下具有更大的數據流量,因此通常情況下,一般工業智能儀器儀表都是採用RTU模式。
      在RTU模式下,信息幀以3.5個字符的靜態時間間隔爲起始符和結束符,在信息幀格式中均用T1-T2-T3-T4表示。每兩個字符之間發送或者接收的時間間隔不能超過1.5倍字符傳輸時間。如果兩個字符時間問隔超過了3.5倍的字符傳輸時間,協議就認爲一幀數據已經接收,新的一幀數據傳輸開始。地址域用來寫入從設備的地址。功能域用來寫入主設備要求從設備執行的功能代碼,如03或06。數據域用來寫入主設備告之從設備的一些額外的信息,如連續的寄存器的起始地址、寄存器的數量等。CRC校驗是RTU模式下的錯誤校驗方式。數據幀中的數據採用十六進制數。如表1所示。

表1 RTU模式下的信息幀格式 幀起始地| 址域功 | 能碼域 | 數據域 | CRC校驗域 | 結束 :—-| :——- |:——-|:———|:———–|:—— T1-T2-T3-T4|8bits|8bits|n * 8bits|16bits|T1-T2-T3-T4 T1-T2-T3-T4|1B|1B|nB|2B|T1-T2-T3-T4       根據MODBUS協議規定,不同功能碼對應數據域格式不盡相同,常用的功能碼有1、2、3、4、5、6、15和16,分別表示讀線圈、讀輸入狀態、讀保持寄存器、讀輸入寄存器、寫單個線圈、寫單個輸入狀態、寫多個線圈,寫多個保持寄存器。

3.3 水倉系統

      水倉系統由大水倉、蓄水池、應急水泵、變頻器水泵、放水閥門、明渠、暗渠、水舌組成;在水倉系統設置有管道流量傳感器、明渠水位傳感器、水舌溫度水位傳感器、水倉水位溫度傳感器、蓄水池水位溫度傳感器、管道壓力溫度傳感器。水倉系統的工作方式:首先打開放水閥門,水從大水倉通過放水閥門流入明渠,經過水舌流入暗渠,然後彙集於蓄水池,最後通過變頻器水泵把水從蓄水池抽入大水倉,完成整個循環。在使用過程中,需要注意蓄水池水位需要保持一定的水位,否則水泵中進入空氣,無法工作;同時也要注意蓄水池中的水不能溢出。

3.4 KJ402-F1礦用本安型水文檢測分站

      KJ402-F1 礦用本安型水文監測分站是一個數據監測控制分站,具有4 路模擬量採集和4 路數字量採集接口、1 路485 對上通訊接口、2 路對下通訊接口和一個液晶顯示屏。液晶顯示屏顯示分站掛接的傳感器採集到的各種數據。
      分站集電子技術、計算機技術與數據通信技術於一體,具有測量精度高、實時性強、運行穩定和自動化程度高等特點,其體積小、重量輕、安裝方便,能夠長期在無人值守的條件下自動對各類水文等進行監測與控制。

  • 分站具有與傳輸接口雙向通訊及工作狀態指示和顯示功能。
  • 分站具有模擬量採集和數字量採集功能以及開關量控制功能。
  • 初始化參數通過上位機軟件設置。
  • 分站具有自診斷和故障指示功能。
  • 分站具有外接備用電源

3.5 GLC30/50礦用磁漩渦流量傳感器

      GLC30/50 礦用磁旋渦流量傳感器(以下簡稱傳感器)是採用最先進磁旋渦數字檢測技術開發出的新型智能流量傳感器。該傳感器是將雙檢測抗震渦街傳感器和電磁傳感器技術結合爲一體的流量測量儀表。傳感器採用先進的單片機技術和微功耗高新技術,具有以下特點:耐腐蝕性能好、結構簡單、使用壽命長、性能穩定,能識別流量與振動數據,消除所有干擾信號,具有良好的抗震,抗干擾能力,可耐 1g 振動(壓電式耐振≤0.2g),使計量性能穩定、可靠;下限流量低,量程比大,測量準確、精度高。
      GLC30/50 礦用磁旋渦流量傳感器是根據法拉第電磁感應原裏研製的,在錶殼底部放置一個磁鋼產生強磁場,磁力線穿過管道,當介質流過傳感器強磁場時,切割磁力線感應出脈動的磁動勢,用電極拾取此電信號,在一定的流速範圍內其頻率正比於流量。
磁漩渦流量傳感器原理圖


圖1磁漩渦流量傳感器原理圖
1—磁鋼 2—電極 3—錶殼 4—電極壓緊螺絲
5—信號插頭 6—顯示儀 7—功能鍵 8—接地端子 9—信號輸出接線口

3.6 FD15直流穩壓電源

      FD15 專用直流穩壓採用先進的補償式技術設計製造,適應用於礦山、鄉鎮等地區電網電壓波動較大的工作環境,能自動保持輸出電壓的穩定,以保證用電設備的正常運行。輸入電壓範圍寬,輸出電壓穩定。具有過流保護,短路保護,過壓保護,增強了電源的安全性與可靠性。

四、 實驗原理

4.1 發送幀

發送幀解析圖


圖2發送幀解析圖

  • 長度:長度是除去地址碼的幀的長度,最後以16進制保存。
  • 屬性:00表示查詢單條數據,分站只需要回覆一條數據即可,回覆的數據由站號和通道號指定
  • 站號:指定回覆的分站設備
  • 通道號:指定回覆的傳感器測量值
  • 時間BCD碼:用4位二進制數來表示1位十進制數中的0~9這10個數碼。是一種二進制的數字編碼形式,用二進制編碼的十進制代碼。通俗的說就是把十進制數字看作16進制數字,比如10進制的18轉換爲16進製爲12,但是使用BCD碼16進制還是18。
  • CRC校驗碼:在CRC計算時只用8個數據位,起始位及停止位,如有奇偶校驗位也包括奇偶校驗位,都不參與CRC計算。
    CRC計算方法是:
    1、加載一值爲0XFFFF的16位寄存器,此寄存器爲CRC寄存器。
    2、把第一個8位二進制數據(即通訊信息幀的第一個字節)與16位的CRC寄存器的相異或,異或的結果仍存放於該CRC寄存器中。
    3、把CRC寄存器的內容右移一位,用0填補最高位,並檢測移出位是0還是1。
    4、如果移出位爲零,則重複第三步(再次右移一位);如果移出位爲1,CRC寄存器與0XA001進行異或。
    5、重複步驟3和4,直到右移8次,這樣整個8位數據全部進行了處理。
    6、重複步驟2和5,進行通訊信息幀下一個字節的處理。
    7、將該通訊信息幀所有字節按上述步驟計算完成後,得到的16位CRC寄存器的高、低字節進行交換
    8、最後得到的CRC寄存器內容即爲:CRC校驗碼。

4.2 接收幀

接收幀解析圖

圖3接收幀解析圖
  • 標誌:FF表示高電平爲1
  • 長度:長度是除去地址碼的幀的長度,最後以16進制保存。
  • 屬性:發送幀的屬性碼加0X80
  • 站號:回覆的分站設備
  • 通道號:回覆的傳感器測量值
  • 數據1:3個字節
  • 數據2:3個字節
  • 數據3:3個字節
  • 隨機位:兩次查詢的時間如果較短,那麼回覆的內容可能完全相同,此時回覆數據幀的接收會
    把兩個回覆幀誤認爲是一個回覆幀,這樣就出現僞丟幀,所以,隨機位解決這種情況,防止在短時間內回覆的數據幀完全相同,而造成僞丟幀。

      數據有三個是因爲分站設備需要適配所有的傳感器,磁漩渦流量傳感器只有一個數據,所以需要數據1即可,但是其他的傳感器比如溫度壓力傳感器需要2個數據,而明渠中的水位有三個數據(水位、泥位、溫度),所以數據位有三個,如果無數據,默認用0來補全。

五、 實驗步驟

5.1系統框架構建

首先創建一個基於對話框的空工程,不需要關於框和系統菜單。
這裏寫圖片描述


圖4工程預設圖

VS2015會自動生成基於工程名字的App和Dlg文件。
這裏寫圖片描述


圖5工程自動生成文件圖

接下來創建額外的7個對話框,對話框的名字和ID如表所示。

表2對話框和ID映射表

幀起始地 址域功
流量統計分析表 IDD_EXCEL
流量預測 IDD_FORECAST
歷史流量數據 IDD_HISTORY
原理講解 IDD_INTERPRET
查看參數 IDD_LOOKDATA
設置參數 IDD_SETDATA
協議測試 IDD_TEXT

爲添加的對話框綁定各自的類,右鍵對話框->【添加類】->【輸入類名】->【確定】。

這裏寫圖片描述


圖6創建的類

5.2外部插件導入

5.2.1串口插件導入

      系統中需要使用串口編程,所以需要使用到串口插件。首先在互聯網上下載串口插件的ocx文件,然後把ocx文件放到系統盤的System32文件夾下;最後使用管理員身份打開CMD,在CMD中切換到System32文件夾下,運行命令:Regsvr32 串口插件的ocx名字.ocx。
      CMD會提示註冊成功,此時可以在VS2015中【工具】->【選擇工具箱】->【COM組件】->【瀏覽】->找到串口插件的ocx文件->【確定】。如果插件導入成功,可以在VS2015的工具箱中找到,或者可以在對話框中畫出一個電話類似的圖標。

5.2.2折線圖插件導入

      系統中畫折線圖需要用到TeeChart的一個插件。首先在互聯網上下載TeeChart插件的ocx文件,然後註冊插件,並導入到VS2015中;導入成功後,VS2015的工具箱中不會顯示插件,但是可以畫出一個折線圖的樣子,此時導入成功。

5.3對話框設計

其中對話框的控件和屬性如下:

5.3.1查看參數


表3查看參數控件表

類型 ID標識符 屬性
對話框 IDD_LOOKDATA Caption:查看參數;Style:Popup;System Menu:false;
按鈕 IDOK Caption:確定;
靜態文本框 IDC_STATIC Align Text:Left;Caption:服務器IP地址:;
按鈕 IDCANCEL Caption:取消;
組合框 IDC_STATIC Caption:數據庫參數;
組合框 IDC_STATIC Caption:通信參數;
靜態文本框 IDC_STATIC Align Text:Left;Caption:服務器端口號:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:登陸用戶名:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:登陸密碼:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:連接數據庫名:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:COM端口:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:波特率:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:校驗位:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:數據位:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:停止位:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:自動刷新時間:;
靜態文本框 IDC_L_IPADD Align Text:Center;Caption:;
靜態文本框 IDC_L_COM Align Text:Center;Caption:;
靜態文本框 IDC_L_PASSWORD Align Text:Center;Caption:;
靜態文本框 IDC_L_USERNAME Align Text:Center;Caption:;
靜態文本框 IDC_L_DATABASE Align Text:Center;Caption:;
靜態文本框 IDC_L_COMM Align Text:Center;Caption:;
靜態文本框 IDC_L_BOTELV Align Text:Center;Caption:;
靜態文本框 IDC_L_JIAOYAN Align Text:Center;Caption:;
靜態文本框 IDC_L_SHUJU Align Text:Center;Caption:;
靜態文本框 IDC_L_TINGZHI Align Text:Center;Caption:;
靜態文本框 IDC_L_TIME Align Text:Center;Caption:;

這裏寫圖片描述


圖7查看參數效果圖

圖中紅框就是有各自ID的靜態文本框。

5.3.2歷史流量


表4歷史流量折線圖控件表

類型 ID標識符 屬性
對話框 IDD_HISTORY Caption:歷史流量數據;Style:Popup;System Menu:false;
靜態文本框 IDC_STATIC Align Text:Left;Caption:選擇日期:;
時間 IDC_H_DATE Format:短日期;
折線圖 IDC_H_TCHART
按鈕 IDOK Caption:確定;
靜態文本框 IDC_H_TITLE Align Text:Center;Caption:;
按鈕 IDCANCEL Caption:取消;


表5歷史流量折線圖控件變量映射表

控件ID 類別 變量類型 變量名
IDC_DATAVIEW Value Cstring m_Dataview
IDC_H_DATE Control CDateTimeCtrl c_HDate
IDC_H_TCHART Control CTchart1 c_HTChart

折線圖插件設置:
雙擊插件會彈出設置對話框:
這裏寫圖片描述


圖8折線圖插件設置圖

      其中General調節查看折線圖時鼠標的樣式,Axis設置座標系,Titles設置折線圖標題,第一行的Series菜單設置折線圖連線的樣式。
這裏寫圖片描述


圖9歷史流量對話框效果圖

5.3.3流量預測


表6流量預測控件表

類型 ID標識符 屬性
對話框 IDD_FORECAST Caption:流量預測;Style:Popup;System Menu:false;
靜態文本框 IDC_STATIC Align Text:Left;Caption:預測結果:;
輸入框 IDC_F_RESULT Align Text:Left;
輸入框 IDC_F_REASON Align Text:Left;
按鈕 IDOK Caption:確定;
靜態文本框 IDC_STATIC Align Text:Left;Caption:預測理由:;

這裏寫圖片描述


圖10流量預測對話框效果圖

5.3.4設置參數


表7設置參數控件表

類型 ID標識符 屬性
對話框 IDD_LOOKDATA Caption:查看參數;Style:Popup;System Menu:false;
按鈕 IDOK Caption:確定;
靜態文本框 IDC_STATIC Align Text:Left;Caption:服務器IP地址:;
按鈕 IDCANCEL Caption:取消;
組合框 IDC_STATIC Caption:數據庫參數;
組合框 IDC_STATIC Caption:通信參數;
靜態文本框 IDC_STATIC Align Text:Left;Caption:服務器端口號:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:登陸用戶名:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:登陸密碼:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:連接數據庫名:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:COM端口:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:波特率:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:校驗位:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:數據位:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:停止位:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:自動刷新時間:;
IP地址輸入框 IDC_S_IPADD
輸入框 IDC_S_COM Align Text:Left;
輸入框 IDC_S_USERNAME Align Text:Left;
輸入框 IDC_S_PASSWORD Align Text:Left;Password:true;
輸入框 IDC_S_DATABASE Align Text:Left;
下拉列表 IDC_S_COMM Type:Dropdown;
下拉列表 IDC_S_BOTELV Type:Dropdown;
下拉列表 IDC_S_JIAO Type:Dropdown;
下拉列表 IDC_S_SHUJU Type:Dropdown;
下拉列表 IDC_S_TING Type:Dropdown;
輸入框 IDC_S_TIME Align Text:Left;
單選按鈕 IDC_S_HOUR Caption:小時(h);
單選按鈕 IDC_S_MINTE Caption:分鐘(m);
單選按鈕 IDC_S_SECEND Caption:秒(s);


表8設置參數控件變量映射表

控件ID 類別 變量類型 變量名
IDC_S_IPADD Value DWORD m_SetIpadd
IDC_S_COMM Control CComboBox c_Comm
IDC_S_BOTELV Control CComboBox c_Botelv
IDC_S_COM Value Cstring m_SetCom
IDC_S_USERNAME Value Cstring m_SetUsername
IDC_S_PASSWORD Value Cstring m_SetPassword
IDC_S_DATABASE Value Cstring m_SetDatabase
IDC_S_JIAO Control CComboBox c_Jiaoyan
IDC_S_SHUJU Control CComboBox c_Shuju
IDC_S_TING Control CComboBox c_Tingzhi
IDC_S_TIME Control CEdit c_Time
IDCANCEL Control CButton c_ButtonH

這裏寫圖片描述


圖11設置參數對話框效果圖

5.3.5統計表


表9統計表控件表

類型 ID標識符 屬性
對話框 IDD_EXCEL Caption:流量統計分析表;Style:Popup;System Menu:false;
靜態文本框 IDC_E_TITLE Align Text:Center;
列表 IDC_E_LIST Alignment:Left;View:Report;
時間 IDC_E_DATE Format:短日期;
按鈕 IDOK Caption:確定;
靜態文本框 IDC_STATIC Align Text:Left;Caption:選擇日期:;
按鈕 IDCANCEL Caption:取消;


表10統計表控件變量映射表

控件ID 類別 變量類型 變量名
IDC_E_TITLE Value Cstring m_ETitle
IDC_E_LIST Control CListCtrl c_EList
IDC_E_DATE Control CDateTimeCtrl c_EDate

這裏寫圖片描述


圖12統計表對話框效果圖

5.3.6協議測試


表11協議測試控件表

類型 ID標識符 屬性
對話框 IDD_TEXT Caption:協議測試;Style:Popup;System Menu:false;
靜態文本框 IDC_E_TITLE Align Text:Center;
輸入框 IDC_T_INPUT Align Text:Left;
時間 IDC_T_DATA Format:短日期;
按鈕 IDOK Caption:確定;
靜態文本框 IDC_STATIC Align Text:Left;Caption:(必須以空格分割);
按鈕 IDCANCEL Caption:取消;
靜態文本框 IDC_STATIC Align Text:Left;Caption:請輸入協議幀:;
靜態文本框 IDC_STATIC Align Text:Left;Caption:測試結果:;
時間 IDC_T_TIME Format:時間;
按鈕 IDC_BUTTON1 Caption:生成協議幀;


表12協議測試控件變量映射表

控件ID 類別 變量類型 變量名
IDC_DATAVIEW Value Cstring m_Dataview
IDC_T_DATA Control CDateTimeCtrl c_Data
IDC_T_TIME Control CDateTimeCtrl c_Time

這裏寫圖片描述


圖13協議測試對話框效果圖

5.3.7原理講解


表13協議測試控件表

類型 ID標識符 屬性
對話框 IDD_INTERPRET Caption:原理講解;Style:Popup;System Menu:false;
圖片 IDC_I_PIC
按鈕 IDC_I_LAST Caption:上一頁;
按鈕 IDC_I_NEXT Caption:下一頁;


表14協議測試控件變量映射表

控件ID 類別 變量類型 變量名
IDC_I_LAST Control CButton m_InterpretLast
IDC_I_NEXT Control CButton m_InterpretNext

這裏寫圖片描述


圖14協議測試對話框效果圖

5.3.8主對話框


表15主對話框控件表

類型 ID標識符 屬性
對話框 IDD_DIA_DIALOG Caption:管道流量採集;Style:Popup;System Menu:true;
靜態文本框 IDC_DATAVIEW Align Text:Center;
靜態文本框 IDC_XIEYIZHEN Align Text:Left;
折線圖 IDC_TC_DATA
串口 IDC_MSCOMM1


表16主對話框控件變量映射表

控件ID 類別 變量類型 變量名
IDC_DATAVIEW Value Cstring m_Dataview
IDC_TC_DATA Control CTchart1 c_TChartData
IDC_MSCOMM1 Control CMscomm1 c_Comm

這裏寫圖片描述


圖15主對話框效果圖

5.4單例類

      在整個系統中,有些數據必須一直保持唯一,比如設置參數在系統運行的全部時間裏必須唯一,否則就會出錯,所以,需要爲必須保持唯一性的數據使用單例類來調用,這樣就可以保證唯一性。單例類是單例模式的實現,單例模式是說當一個類中只有一個實例化的對象時,這個類就是單例類。單例類的寫法很簡單,首先私有化類的構造方法,並且類中含有一個靜態的本類的私有實例化對象,然後創建一個靜態的公有方法來獲取此實例,這樣,每次獲取的實例對象,都是類的私有化的對象。
      在系統中數據庫、對話框、設置參數都需要唯一的調用,所以設置三個單例類來保存數據DataConfig.h:
      注意,所有的代碼在理解的基礎上自行輸入,不要拷貝,否則會出錯,其中的省略號自行按照前面的補充完整。

#pragma once
#include "Configdata.h"
class CDataConfig
{
public:
    static CDataConfig * GetCDataConfig() {
        static CDataConfig * m_CDataConfig;
        if (NULL == m_CDataConfig) {
            m_CDataConfig = new CDataConfig();
        }
        return m_CDataConfig;
    }
    ~CDataConfig();
private:
    CDataConfig();
    // 連接數據庫服務器的IP地址
    CString m_IPAdress;
    //連接數據庫服務器的端口號
    CString m_ComNum;
    // 連接數據庫的用戶名,默認爲root
    CString m_Username;
    // 連接數據庫的密碼,默認爲root
    CString m_Password;
    // 連接數據庫的數據庫名字
    CString m_Database;
    //COM端口
    CString m_Comm;
    //波特率
    CString m_Botelv;
    //校驗碼
    CString m_Jiaoyan;
    //數據位
    CString m_Shuju;
    //停止位
    CString m_Tingzhi;
    //時間
    CString m_Time;
public:
    // 獲取數據庫服務器的IP地址
    CString getIpAddress();
    // 獲取數據庫服務器端口號
    CString getComnum();
    // 獲取連接的數據庫名字
    CString getDatabase();
    // 獲取連接數據庫的密碼
    CString getPassword();
    // 獲取連接數據庫的用戶名
    CString getUsername();
    CString getComm();
    CString getBotelv();
    CString getJiaoyan();
    CString getShuju();
    CString getTingzhi();
    CString getTime();
    void setComm(CString m_Comm);
    void setBotelv(CString m_Botelv);
    void setJiaoyan(CString m_Jiaoyan);
    void setShuju(CString m_Shuju);
    void setTingzhi(CString m_Tingzhi);
    void setTime(CString m_Time);
    // 設置數據庫服務器端口號
    void setComnum(CString m_ComNum);
    void setDatabase(CString m_Database);
    void setIpAddress(CString m_IpAddress);
    void setPassword(CString m_Password);
    void setUsername(CString m_Username);
};

DataConfig.cpp:

#include "stdafx.h"
#include "DataConfig.h"
CDataConfig::CDataConfig()
    : m_IPAdress(_T(""))
    , m_ComNum(_T(""))
    , m_Username(_T(""))
    , m_Password(_T(""))
    , m_Database(_T(""))
    , m_Comm(_T(""))
    , m_Botelv(_T(""))
    , m_Jiaoyan(_T(""))
    , m_Shuju(_T(""))
    , m_Tingzhi(_T(""))
    , m_Time(_T(""))
{
}
CDataConfig::~CDataConfig()
{
}
// 獲取數據庫服務器的IP地址
CString CDataConfig::getIpAddress()
{
    if (!this->m_IPAdress.IsEmpty()) {
        return this->m_IPAdress;
    }
    else
    {
        return NULL;
    }
}
// 獲取數據庫服務器端口號
CString CDataConfig::getComnum()
{
    if (!this->m_ComNum.IsEmpty()) {
        return this->m_ComNum;
    }
    else {
        return 0;
    }
}
// 獲取連接的數據庫名字
CString CDataConfig::getDatabase()
{
    if (!this->m_Database.IsEmpty()) {
        return this->m_Database;
    }
    else {
        return NULL;
    }
}
// 獲取連接數據庫的密碼
CString CDataConfig::getPassword()
{
    if (!this->m_Password.IsEmpty()) {
        return this->m_Password;
    }
    else {
        return NULL;
    }
}
// 獲取連接數據庫的用戶名
CString CDataConfig::getUsername()
{
    if (!this->m_Username.IsEmpty()) {
        return this->m_Username;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getComm() {
    if (!this->m_Comm.IsEmpty()) {
        return this->m_Comm;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getBotelv() {
    if (!this->m_Botelv.IsEmpty()) {
        return this->m_Botelv;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getJiaoyan() {
    if (!this->m_Jiaoyan.IsEmpty()) {
        return this->m_Jiaoyan;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getShuju() {
    if (!this->m_Shuju.IsEmpty()) {
        return this->m_Shuju;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getTingzhi() {
    if (!this->m_Tingzhi.IsEmpty()) {
        return this->m_Tingzhi;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getTime() {
    if (!this->m_Time.IsEmpty()) {
        return this->m_Time;
    }
    else {
        return NULL;
    }
}
void CDataConfig::setComnum(CString m_ConNum) {
    this->m_ComNum = m_ConNum;
}
void CDataConfig::setDatabase(CString m_Database) {
    this->m_Database = m_Database;
}
void CDataConfig::setIpAddress(CString m_IpAddress) {
    this->m_IPAdress = m_IpAddress;
}
void CDataConfig::setPassword(CString m_Password) {
    this->m_Password = m_Password;
}
void CDataConfig::setUsername(CString m_Username) {
    this->m_Username = m_Username;
}
void CDataConfig::setComm(CString m_Comm) {
    this->m_Comm = m_Comm;
}
void CDataConfig::setBotelv(CString m_Botelv) {
    this->m_Botelv = m_Botelv;
}
void CDataConfig::setJiaoyan(CString m_Jiaoyan) {
    this->m_Jiaoyan = m_Jiaoyan;
}
void CDataConfig::setShuju(CString m_Shuju) {
    this->m_Shuju = m_Shuju;
}
void CDataConfig::setTingzhi(CString  m_Tingzhi) {
    this->m_Tingzhi = m_Tingzhi;
}
void CDataConfig::setTime(CString m_Time) {
    this->m_Time = m_Time;
}

MysqlConnection.h

#pragma once
//頭文件
#include "mysql.h"
#include "DataConfig.h"
#include "Configdata.h"
#include "TeeData.h"
class CMysqlConnection
{
private:
    CMysqlConnection();
    MYSQL m_mysql;
public:
    static CMysqlConnection * GetMysqlConn() {
        static CMysqlConnection * m_MysqlConn;
        if (NULL == m_MysqlConn) {
            m_MysqlConn = new CMysqlConnection();
        }
        return m_MysqlConn;
    }
    ~CMysqlConnection();
    BOOL setData(double m_FlowValue, CString time);
    CObArray * getData(SYSTEMTIME time);
    void ConnectionMysql();
};

MysqlConnection.cpp:

#include "stdafx.h"
#include "Single.h"
#include "MysqlConnection.h"
#include "管道流量採集Dlg.h"
CMysqlConnection::CMysqlConnection()
{
}
CMysqlConnection::~CMysqlConnection()
{
}
BOOL CMysqlConnection::setData(double m_FlowValue, CString time) {
    CString sql;
    CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
    CString temp;
    temp.Format("%.3f", m_FlowValue);
    //INSERT INTO `data` (`time`, `value`) VALUES ('2018-5-4 12:51:52', '0.00');
    sql.Format("INSERT INTO `data` (`time`, `value`) VALUES ('%s', '%s');",time,temp);
    if (!mysql_query(&m_MysqlConnection->m_mysql, sql)) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}
CObArray * CMysqlConnection::getData(SYSTEMTIME time) {
    CObArray * m_QueryData = new CObArray();
    CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
    CString sql;
    MYSQL_RES * m_res;
    MYSQL_ROW m_row;
    sql.Format("SELECT * FROM `data` WHERE time BETWEEN '%2d-%d-%d' AND '%2d-%d-%d' ORDER BY time;",
        time.wYear, time.wMonth, time.wDay, time.wYear, time.wMonth, time.wDay + 1);
    mysql_query(&m_MysqlConnection->m_mysql, sql);
    m_res = mysql_store_result(&m_MysqlConnection->m_mysql);
    if (NULL != m_res) {
        if (0 != m_res->row_count) {
            while (m_row = mysql_fetch_row(m_res)) {
                m_QueryData->Add(new CTeeData(atof(m_row[1]), m_row[0]));
                //CString b = m_row[0];//時間
                //CString a = m_row[1];//值
            }
            return m_QueryData;
        }
        else
        {
            AfxMessageBox("數據庫沒有數據");
            return NULL;
        }
    }
    return NULL;
}
void CMysqlConnection::ConnectionMysql()
{
    CConfigdata * m_Configdata = new CConfigdata();
    m_Configdata->getConfigdata();
    CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
    mysql_init(&this->m_mysql);
    //localhost:服務器 root/123456爲賬號密碼 managesystemdb爲數據庫名 3306爲端口    
    //if (!mysql_real_connect(&m_sqlCon, "localhost", "root", "123456", "managesystemdb", 3306, NULL, 0))
    if (!mysql_real_connect(&this->m_mysql,
        m_DataConfig->getIpAddress(),
        m_DataConfig->getUsername(),
        m_DataConfig->getPassword(),
        m_DataConfig->getDatabase(),
        atoi(m_DataConfig->getComnum()),
        NULL,
        0)
        ) {
        AfxMessageBox(mysql_error(&this->m_mysql));
        CSingle * m_Single = CSingle::GetSingle();
        if (m_Single->m_dlgSetdata->DoModal() == IDOK) {
            SetTimer(AfxGetMainWnd()->GetSafeHwnd(), 1, atoi(m_DataConfig->getTime()), NULL);
            //AfxMessageBox("開啓定時器");
        }
    }
    else {
        CString sql;
        AfxMessageBox("連接數據庫成功");
        mysql_query(&this->m_mysql, "SET NAMES 'utf-8'");
        //如果數據表不存在則重新創建
        sql.Format("CREATE TABLE If Not Exists `data` (`time` datetime NOT NULL,`value` double(5, 2) DEFAULT NULL,PRIMARY KEY(`time`)) ENGINE = InnoDB DEFAULT CHARSET = utf8; ");
        mysql_query(&this->m_mysql, sql);
        SetTimer(AfxGetMainWnd()->GetSafeHwnd(), 1, atoi(m_DataConfig->getTime()), NULL);
        //AfxMessageBox("定時器開始");
    }
    //mysql_query(&m_sqlCon, "SET NAMES 'GB2312'");//解決從數據庫中讀取數據後漢字亂碼顯示的問題  
}

Single.h

#pragma once
//include
#include "DlgInterpret.h"
#include "DlgText.h"
#include "DlgForecast.h"
#include "DlgHistory.h"
#include "DlgExcel.h"
#include "DlgSetdata.h"
#include "DlgLookdata.h"
#include "Resource.h"
class CSingle
{
private:
    CSingle();
public:
    ~CSingle();
    // 獲取單例
    static CSingle* GetSingle() {
        static CSingle* m_Single;
        if (NULL == m_Single) {
            m_Single = new CSingle();
        }
        return m_Single;
    }
    CDlgExcel * m_dlgExcel;
    CDlgForecast * m_dlgForecast;
    CDlgHistory * m_dlgHistory;
    CDlgInterpret * m_dlgInterpret;
    CDlgText * m_dlgText;
    CDlgSetdata * m_dlgSetdata;
    CDlgLookdata * m_dlgLookdata;
};

Single.cpp:

#include "stdafx.h"
#include "Single.h"
CSingle::CSingle()
{
    if (NULL == this->m_dlgExcel) {
        this->m_dlgExcel = new CDlgExcel();
    }
    if (NULL == this->m_dlgForecast) {
        this->m_dlgForecast = new CDlgForecast();
    }
    if (NULL == this->m_dlgHistory) {
        this->m_dlgHistory = new CDlgHistory();
    }
    if (NULL == this->m_dlgInterpret) {
        this->m_dlgInterpret = new CDlgInterpret();
    }
    if (NULL == this->m_dlgText) {
        this->m_dlgText = new CDlgText();
    }
    if (NULL == this->m_dlgSetdata) {
        this->m_dlgSetdata = new CDlgSetdata();
    }
    if (NULL == this->m_dlgLookdata) {
        this->m_dlgLookdata = new CDlgLookdata();
    }
}
CSingle::~CSingle()
{
}

5.5註冊表讀寫

ConfigData.h

#pragma once
//頭文件
#include "DataConfig.h"
#include "DlgSetdata.h"
class CConfigdata
{
public:
    CConfigdata();
    ~CConfigdata();
    // 保存數據到註冊表
    void setConfigdata();
    // 讀取註冊表數據到單例
    void getConfigdata();
};

ConfigData.cpp:

#include "stdafx.h"
#include "Configdata.h"
#include "MysqlConnection.h"
CConfigdata::CConfigdata()
{
}
CConfigdata::~CConfigdata()
{
}
/*
從註冊表讀取數據庫參數
包括:
IP:localhost
com:3306
username:root
password:root
database:flowdata
*/
// 保存數據到註冊表
void CConfigdata::setConfigdata()
{
    CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
    HKEY hKey;
    if (!RegOpenKeyEx(HKEY_CURRENT_USER,
        "SOFTWARE\\Flowtest", NULL, KEY_READ, &hKey)) {
        //如果在SOFTWARE下沒有Folwtest文件夾那麼就需要創建文件夾
        RegCreateKey(HKEY_CURRENT_USER, "Software\\Flowtest", &hKey);
        //AfxMessageBox("創建註冊表項");
    }
    RegSetValue(hKey,"IPAddress",
        REG_SZ,m_DataConfig->getIpAddress(),
        strlen(m_DataConfig->getIpAddress()));
    RegSetValue(hKey, "COM",
        REG_SZ, m_DataConfig->getComnum(),
        strlen(m_DataConfig->getComnum()));
    RegSetValue(hKey, "Username",
        REG_SZ, m_DataConfig->getUsername(),
        strlen(m_DataConfig->getUsername()));
    RegSetValue(hKey, "Password",
        REG_SZ, m_DataConfig->getPassword(),
        strlen(m_DataConfig->getPassword()));
    RegSetValue(hKey, "Database",
        REG_SZ, m_DataConfig->getDatabase(),
        strlen(m_DataConfig->getDatabase()));
    RegSetValue(hKey, "Comm",
        REG_SZ, m_DataConfig->getComm(),
        strlen(m_DataConfig->getComm()));
    RegSetValue(hKey, "Botelv",
        REG_SZ, m_DataConfig->getBotelv(),
        strlen(m_DataConfig->getBotelv()));
    RegSetValue(hKey, "Jiaoyan",
        REG_SZ, m_DataConfig->getJiaoyan(),
        strlen(m_DataConfig->getJiaoyan()));
    RegSetValue(hKey, "Shuju",
        REG_SZ, m_DataConfig->getShuju(),
        strlen(m_DataConfig->getShuju()));
    RegSetValue(hKey, "Tingzhi",
        REG_SZ, m_DataConfig->getTingzhi(),
        strlen(m_DataConfig->getTingzhi()));
    RegSetValue(hKey, "Time",
        REG_SZ, m_DataConfig->getTime(),
        strlen(m_DataConfig->getTime()));
    AfxMessageBox("註冊表寫入成功");
}
// 讀取註冊表數據到單例
void CConfigdata::getConfigdata()
{
    CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
    HKEY hKey;
    char * temp;
    long a;
    if (ERROR_SUCCESS !=
        RegOpenKeyEx(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest", NULL, KEY_READ, &hKey)) {
        //如果註冊表中沒有數據,那麼調用設置模態對話框提示輸入
        //同時創建註冊表
        CDlgSetdata m_dlgSetdata;
        if (m_dlgSetdata.DoModal() == IDOK) {
            this->setConfigdata();
            //AfxMessageBox("創建後從註冊表讀取到單例");
        }
    }
    else {
        //RegQueryValue(HKEY_CURRENT_USER,
        //"SOFTWARE\\ArwenSoft\\dataip", ipadd, &a);
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\IPAddress", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\IPAddress", temp, &a);
        m_DataConfig->setIpAddress(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\COM", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\COM", temp, &a);
        m_DataConfig->setComnum(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Username", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Username", temp, &a);
        m_DataConfig->setUsername(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Password", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Password", temp, &a);
        m_DataConfig->setPassword(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Database", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Database", temp, &a);
        m_DataConfig->setDatabase(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Comm", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Comm", temp, &a);
        m_DataConfig->setComm(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Botelv", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Botelv", temp, &a);
        m_DataConfig->setBotelv(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Jiaoyan", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Jiaoyan", temp, &a);
        m_DataConfig->setJiaoyan(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Shuju", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Shuju", temp, &a);
        m_DataConfig->setShuju(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Tingzhi", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Tingzhi", temp, &a);
        m_DataConfig->setTingzhi(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Time", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Time", temp, &a);
        m_DataConfig->setTime(temp);
        delete temp;
        AfxMessageBox("直接從註冊表讀取參數");
    }
}

5.6折線圖、統計表、數據庫bean類

      Bean類是對應於數據表中一行數據的類,一個bean類的對象就是表中存儲的一行,在本系統中,數據處理,這是最小的單位
TeeData.h

#pragma once
class CTeeData : public CObject
{
public:
    CTeeData();
    ~CTeeData();
    double m_Viewvalue;
    CString m_ViewData;
    CTeeData(double m_Viewvalue,CString m_ViewData);
};

TeeData.cpp:


5.7對話框功能實現

5.7.1統計表

消息中重寫OnCtlColor方法:

// TODO:  在此更改 DC 的任何特性
CFont m_SetFont;switch (pWnd->GetDlgCtrlID()){case IDC_E_TITLE:
m_SetFont.CreatePointFont(400,"楷體");pDC->SelectObject(&m_SetFont);
pDC->SetTextColor(RGB(0, 255, 0));pDC->SetBkColor(RGB(103, 103, 103));break;
default:break;}

重寫OnInitDialog方法:

// TODO:  在此添加額外的初始化
SYSTEMTIME m_System;GetLocalTime(&m_System);
this->c_EList.InsertColumn(0, "時間", LVCFMT_CENTER, 200);
this->c_EList.InsertColumn(1, "流量", LVCFMT_CENTER, 100);
this->c_EList.InsertColumn(2, "時間", LVCFMT_CENTER, 200);
this->c_EList.InsertColumn(3, "流量", LVCFMT_CENTER, 100);
this->c_EList.InsertColumn(4, "時間", LVCFMT_CENTER, 200);
this->c_EList.InsertColumn(5, "流量", LVCFMT_CENTER, 100);
this->c_EList.InsertColumn(6, "時間", LVCFMT_CENTER, 200);
this->c_EList.InsertColumn(7, "流量", LVCFMT_CENTER, 100);
this->c_EList.InsertColumn(8, "時間", LVCFMT_CENTER, 200);
this->c_EList.InsertColumn(9, "流量", LVCFMT_CENTER, 100);setExcel(m_System);

增加參數寫入到統計表控件中的方法setExcel:

void CDlgExcel::setExcel(SYSTEMTIME m_Systime)
{CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
CObArray * m_ExcelData = new CObArray();double flowsum = 0.0;//總流量數
double max = 0.0;//最大值double min = 0.0;//最小值int nItem = 0;//行數
int sum = 0;//總記錄數CTeeData * m_tmpTeedata;//一個數據元CString temp;
m_ExcelData = m_MysqlConnection->getData(m_Systime);if (m_ExcelData != NULL) {
this->c_EList.DeleteAllItems();
for (int i = 0; i < (m_ExcelData->GetSize() + 4) / 5; i++) {//添加一行
this->c_EList.InsertItem(nItem, "");for (int j = 0; j < 10; j++) {//添加一行中的一個元組數據
m_tmpTeedata = (CTeeData *)m_ExcelData->GetAt(sum);
flowsum += m_tmpTeedata->m_Viewvalue;
max=max>=m_tmpTeedata->m_Viewvalue?max:tmpTeedata->m_Viewvalue;
min=min<=m_tmpTeedata->m_Viewvalue?min:m_tmpTeedata->m_Viewvalue;
temp.Format("%.3f", m_tmpTeedata->m_Viewvalue);
this->c_EList.SetItemText(nItem, j, m_tmpTeedata->m_ViewData);//時間
this->c_EList.SetItemText(nItem, j + 1, temp);//值sum++;j++;
if (sum >= m_ExcelData->GetSize()) {    break;}}    nItem++;}//添加分析數據
this->c_EList.InsertItem(nItem, "");this->c_EList.SetItemText(nItem, 0, "最大值");
temp.Format("%.3f", max);this->c_EList.SetItemText(nItem, 1, temp);
this->c_EList.SetItemText(nItem, 2, "最小值");temp.Format("%.3f", min);
this->c_EList.SetItemText(nItem, 3, temp);this->c_EList.SetItemText(nItem, 4, "平均值");
temp.Format("%.6f", flowsum / m_ExcelData->GetSize());
this->c_EList.SetItemText(nItem, 5, temp);this->c_EList.SetItemText(nItem, 6, "總流量");
temp.Format("%.3f", flowsum);this->c_EList.SetItemText(nItem, 7, temp);
this->c_EList.SetItemText(nItem, 8, "總數據");temp.Format("%d", m_ExcelData->GetSize());
this->c_EList.SetItemText(nItem, 9, temp);
this->m_ETitle.Format("%2d-%d-%d的流量統計表", m_Systime.wYear, m_Systime.wMonth, m_Systime.wDay);GetDlgItem(IDC_E_TITLE)->SetWindowText(this->m_ETitle);}}

添加統計表中確定按鈕的事件處理OnBnClickedEOk:

CTime m_ExcelTime;SYSTEMTIME m_tmpTime;this->c_EDate.GetTime(m_ExcelTime);
m_tmpTime.wYear = m_ExcelTime.GetYear();
m_tmpTime.wMonth = m_ExcelTime.GetMonth();
m_tmpTime.wDay = m_ExcelTime.GetDay();
m_tmpTime.wHour = m_ExcelTime.GetHour();
m_tmpTime.wMinute = m_ExcelTime.GetMinute();
m_tmpTime.wSecond = m_ExcelTime.GetSecond();setExcel(m_tmpTime);

DlgExcel.h:

#pragma once
#include "afxcmn.h"
#include "afxdtctl.h"
#include "MysqlConnection.h"
#include "TeeData.h"
// CDlgExcel 對話框
class CDlgExcel : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgExcel)
public:
    CDlgExcel(CWnd* pParent = NULL);   // 標準構造函數
    virtual ~CDlgExcel();
// 對話框數據
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_EXCEL };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    DECLARE_MESSAGE_MAP()
public:
    // 統計表標題
    CString m_ETitle;
    // 列表
    CListCtrl c_EList;
    // 日期
    CDateTimeCtrl c_EDate;
    afx_msg void OnBnClickedEOk();
    virtual BOOL OnInitDialog();
    void setExcel(SYSTEMTIME m_Systime);
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
};

DlgExcel.cpp:

// DlgExcel.cpp : 實現文件
#include "stdafx.h"
#include "管道流量採集.h"
#include "DlgExcel.h"
#include "afxdialogex.h"
// CDlgExcel 對話框
IMPLEMENT_DYNAMIC(CDlgExcel, CDialogEx)
CDlgExcel::CDlgExcel(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_EXCEL, pParent)
    , m_ETitle(_T(""))
{
}
CDlgExcel::~CDlgExcel()
{
}
void CDlgExcel::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_E_TITLE, m_ETitle);
    DDX_Control(pDX, IDC_E_LIST, c_EList);
    DDX_Control(pDX, IDC_E_DATE, c_EDate);
}
BEGIN_MESSAGE_MAP(CDlgExcel, CDialogEx)
    ON_BN_CLICKED(IDOK, &CDlgExcel::OnBnClickedEOk)
    ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
// CDlgExcel 消息處理程序
void CDlgExcel::OnBnClickedEOk()
{
    // TODO: 在此添加控件通知處理程序代碼
    /*
    統計表模塊:
    在開始的時候查詢當前時間的數據
    然後顯示
    調用此方法知識獲取到選擇的日期
    另一個查詢的函數
    接收需要查詢的日期
    然後按照日期進行查詢
    第一次打開的時候以當前的日期爲查詢日期
    查詢到的數據在繪製函數中進行繪製
    表格只有兩項
    時間     流量值

    最後手動添加
    最大值
    最小值
    總量
    平均值
    超過檢測值的次數
    等等
    10列
    */
    CTime m_ExcelTime;
    SYSTEMTIME m_tmpTime;
    this->c_EDate.GetTime(m_ExcelTime);
    m_tmpTime.wYear = m_ExcelTime.GetYear();
    m_tmpTime.wMonth = m_ExcelTime.GetMonth();
    m_tmpTime.wDay = m_ExcelTime.GetDay();
    m_tmpTime.wHour = m_ExcelTime.GetHour();
    m_tmpTime.wMinute = m_ExcelTime.GetMinute();
    m_tmpTime.wSecond = m_ExcelTime.GetSecond();
    setExcel(m_tmpTime);
}
BOOL CDlgExcel::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加額外的初始化
    SYSTEMTIME m_System;
    GetLocalTime(&m_System);
    this->c_EList.InsertColumn(0, "時間", LVCFMT_CENTER, 200);
    this->c_EList.InsertColumn(1, "流量", LVCFMT_CENTER, 100);
    this->c_EList.InsertColumn(2, "時間", LVCFMT_CENTER, 200);
    this->c_EList.InsertColumn(3, "流量", LVCFMT_CENTER, 100);
    this->c_EList.InsertColumn(4, "時間", LVCFMT_CENTER, 200);
    this->c_EList.InsertColumn(5, "流量", LVCFMT_CENTER, 100);
    this->c_EList.InsertColumn(6, "時間", LVCFMT_CENTER, 200);
    this->c_EList.InsertColumn(7, "流量", LVCFMT_CENTER, 100);
    this->c_EList.InsertColumn(8, "時間", LVCFMT_CENTER, 200);
    this->c_EList.InsertColumn(9, "流量", LVCFMT_CENTER, 100);
    setExcel(m_System);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // 異常: OCX 屬性頁應返回 FALSE
}
void CDlgExcel::setExcel(SYSTEMTIME m_Systime)
{
    CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
    CObArray * m_ExcelData = new CObArray();
    double flowsum = 0.0;//總流量數
    double max = 0.0;//最大值
    double min = 0.0;//最小值
    int nItem = 0;//行數
    int sum = 0;//總記錄數
    CTeeData * m_tmpTeedata;//一個數據元
    CString temp;
    m_ExcelData = m_MysqlConnection->getData(m_Systime);
    if (m_ExcelData != NULL) {
        this->c_EList.DeleteAllItems();
        for (int i = 0; i < (m_ExcelData->GetSize() + 4) / 5; i++) {
            //添加一行
            this->c_EList.InsertItem(nItem, "");
            for (int j = 0; j < 10; j++) {
                //添加一行中的一個元組數據
                m_tmpTeedata = (CTeeData *)m_ExcelData->GetAt(sum);
                flowsum += m_tmpTeedata->m_Viewvalue;
                max = max >= m_tmpTeedata->m_Viewvalue ? max : m_tmpTeedata->m_Viewvalue;
                min = min <= m_tmpTeedata->m_Viewvalue ? min : m_tmpTeedata->m_Viewvalue;
                temp.Format("%.3f", m_tmpTeedata->m_Viewvalue);
                this->c_EList.SetItemText(nItem, j, m_tmpTeedata->m_ViewData);//時間
                this->c_EList.SetItemText(nItem, j + 1, temp);//值
                sum++;
                j++;
                if (sum >= m_ExcelData->GetSize()) {
                    break;
                }
            }
            nItem++;
        }
        //添加分析數據
        this->c_EList.InsertItem(nItem, "");
        this->c_EList.SetItemText(nItem, 0, "最大值");
        temp.Format("%.3f", max);
        this->c_EList.SetItemText(nItem, 1, temp);
        this->c_EList.SetItemText(nItem, 2, "最小值");
        temp.Format("%.3f", min);
        this->c_EList.SetItemText(nItem, 3, temp);
        this->c_EList.SetItemText(nItem, 4, "平均值");
        temp.Format("%.6f", flowsum / m_ExcelData->GetSize());
        this->c_EList.SetItemText(nItem, 5, temp);
        this->c_EList.SetItemText(nItem, 6, "總流量");
        temp.Format("%.3f", flowsum);
        this->c_EList.SetItemText(nItem, 7, temp);
        this->c_EList.SetItemText(nItem, 8, "總數據");
        temp.Format("%d", m_ExcelData->GetSize());
        this->c_EList.SetItemText(nItem, 9, temp);
        this->m_ETitle.Format("%2d-%d-%d的流量統計表", m_Systime.wYear, m_Systime.wMonth, m_Systime.wDay);
        GetDlgItem(IDC_E_TITLE)->SetWindowText(this->m_ETitle);
    }
}
HBRUSH CDlgExcel::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    // TODO:  在此更改 DC 的任何特性
    CFont m_SetFont;
    switch (pWnd->GetDlgCtrlID())
    {
    case IDC_E_TITLE:
        m_SetFont.CreatePointFont(400,"楷體");
        pDC->SelectObject(&m_SetFont);
        pDC->SetTextColor(RGB(0, 255, 0));
        pDC->SetBkColor(RGB(103, 103, 103));
        break;
    default:
        break;
    }
    // TODO:  如果默認的不是所需畫筆,則返回另一個畫筆
    return hbr;
}

5.7.2流量預測

添加流量預測保存按鈕的事件處理方法OnBnClickedOk:

CString m_result;CString m_reason;char temp[255];CString t;CString strPath;CFile file;
GetDlgItemText(IDC_F_RESULT, m_result);GetDlgItemText(IDC_F_REASON, m_reason);
SHGetSpecialFolderPath(0, temp, CSIDL_DESKTOPDIRECTORY, 0);t.Format(temp);
t += "\\流量預測分析";m_result += "\r\n";m_result += m_reason;
CFileDialog saveDlg(FALSE,"txt",t,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, "文本文檔(*.txt)", this);
if (saveDlg.DoModal() == IDOK) {strPath = saveDlg.GetPathName();
file.Open(strPath, CFile::modeCreate | CFile::modeWrite);//str爲CString類型 
file.Write(m_result.GetBuffer(),m_result.GetLength()*sizeof(TCHAR));
file.Flush();file.Close();AfxMessageBox("保存成功");}
else {AfxMessageBox("沒有傳入路徑");}

DlgForecast.h:

#pragma once
// CDlgForecast 對話框
class CDlgForecast : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgForecast)
public:
    CDlgForecast(CWnd* pParent = NULL);   // 標準構造函數
    virtual ~CDlgForecast();
// 對話框數據
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_FORECAST };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedOk();
};

DlgForecast.cpp:

#include "stdafx.h"
#include "管道流量採集.h"
#include "DlgForecast.h"
#include "afxdialogex.h"
// CDlgForecast 對話框
IMPLEMENT_DYNAMIC(CDlgForecast, CDialogEx)
CDlgForecast::CDlgForecast(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_FORECAST, pParent)
{
}
CDlgForecast::~CDlgForecast()
{
}
void CDlgForecast::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CDlgForecast, CDialogEx)
    ON_BN_CLICKED(IDOK, &CDlgForecast::OnBnClickedOk)
END_MESSAGE_MAP()
void CDlgForecast::OnBnClickedOk()
{
    // TODO: 在此添加控件通知處理程序代碼
    CString m_result;
    CString m_reason;
    char temp[255];
    CString t;
    CString strPath;
    CFile file;
    GetDlgItemText(IDC_F_RESULT, m_result);
    GetDlgItemText(IDC_F_REASON, m_reason);
    SHGetSpecialFolderPath(0, temp, CSIDL_DESKTOPDIRECTORY, 0);
    t.Format(temp);
    t += "\\流量預測分析";
    m_result += "\r\n";
    m_result += m_reason;
    CFileDialog saveDlg(FALSE, "txt", t, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "文本文檔(*.txt)", this);
    if (saveDlg.DoModal() == IDOK) {
        strPath = saveDlg.GetPathName();
        file.Open(strPath, CFile::modeCreate | CFile::modeWrite);
        file.Write(m_result.GetBuffer(), m_result.GetLength() * sizeof(TCHAR));//str爲CString類型 
        file.Flush();
        file.Close();
        AfxMessageBox("保存成功");
    }
    else {
        AfxMessageBox("沒有傳入路徑");
    }
    //CDialogEx::OnOK();
}

5.7.3歷史流量折線圖

重寫OnCtlColor方法:

CFont m_SetFont;switch (pWnd->GetDlgCtrlID()){case IDC_H_TITLE:
m_SetFont.CreatePointFont(400, "楷體");pDC->SelectObject(&m_SetFont);
pDC->SetTextColor(RGB(0, 255, 0));pDC->SetBkColor(RGB(103, 103, 103));break;
default:break;}

重寫OnInitDialog,使用當前日期作爲查詢條件並顯示:

SYSTEMTIME m_Systime;GetLocalTime(&m_Systime);setTeeChart(m_Systime);

增加數據顯示到折線圖插件的方法:

void CDlgHistory::setTeeChart(SYSTEMTIME m_Systime)
{CObArray * m_Viewdatas = new CObArray();
CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
CTeeData * m_OneData;CSeries viewdata = this->c_HTChart.Series(0);CString temp;
temp.Format("%2d-%d-%d的流量數據折線圖", m_Systime.wYear, m_Systime.wMonth, m_Systime.wDay);
GetDlgItem(IDC_H_TITLE)->SetWindowText(temp);
m_Viewdatas =  m_MysqlConnection->getData(m_Systime);viewdata.Clear();
if (NULL != m_Viewdatas) {for (int i = 0; i < m_Viewdatas->GetSize(); i++) {
m_OneData = (CTeeData *)m_Viewdatas->GetAt(i);
viewdata.Add(m_OneData->m_Viewvalue,m_OneData->m_ViewData, NULL);}}}

添加確定按鈕的事件處理方法OnBnClickedOk,當用戶重寫選擇日期後確定,此方法就會被調用。

CTime m_tmpTime;SYSTEMTIME m_Datetime;this->c_HDate.GetTime(m_tmpTime);
m_Datetime.wYear = m_tmpTime.GetYear();m_Datetime.wMonth = m_tmpTime.GetMonth();
m_Datetime.wDay = m_tmpTime.GetDay();m_Datetime.wHour = m_tmpTime.GetHour();
m_Datetime.wMinute = m_tmpTime.GetMinute();
m_Datetime.wSecond = m_tmpTime.GetSecond();setTeeChart(m_Datetime);

DlgHistory.h:

#pragma once
#include "afxdtctl.h"
#include "tchart1.h"
#include "TeeData.h"
#include "CSeries.h"
// CDlgHistory 對話框
class CDlgHistory : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgHistory)
public:
    CDlgHistory(CWnd* pParent = NULL);   // 標準構造函數
    virtual ~CDlgHistory();
// 對話框數據
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_HISTORY };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    DECLARE_MESSAGE_MAP()
public:
    CDateTimeCtrl c_HDate;
    CTchart1 c_HTChart;
    virtual BOOL OnInitDialog();
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
    void setTeeChart(SYSTEMTIME m_Systime);
    afx_msg void OnBnClickedOk();
};

DlgHistory.cpp:

// DlgHistory.cpp : 實現文件
#include "stdafx.h"
#include "管道流量採集.h"
#include "DlgHistory.h"
#include "afxdialogex.h"
#include "MysqlConnection.h"
// CDlgHistory 對話框
IMPLEMENT_DYNAMIC(CDlgHistory, CDialogEx)
CDlgHistory::CDlgHistory(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_HISTORY, pParent)
{
}
CDlgHistory::~CDlgHistory()
{
}
void CDlgHistory::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_H_DATE, c_HDate);
    DDX_Control(pDX, IDC_H_TCHART, c_HTChart);
}
BEGIN_MESSAGE_MAP(CDlgHistory, CDialogEx)
    ON_WM_CTLCOLOR()
    ON_BN_CLICKED(IDOK, &CDlgHistory::OnBnClickedOk)
END_MESSAGE_MAP()
// CDlgHistory 消息處理程序
BOOL CDlgHistory::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加額外的初始化
    SYSTEMTIME m_Systime;
    GetLocalTime(&m_Systime);
    setTeeChart(m_Systime);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // 異常: OCX 屬性頁應返回 FALSE
}
HBRUSH CDlgHistory::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    // TODO:  在此更改 DC 的任何特性
    CFont m_SetFont;
    switch (pWnd->GetDlgCtrlID())
    {
    case IDC_H_TITLE:
        m_SetFont.CreatePointFont(400, "楷體");
        pDC->SelectObject(&m_SetFont);
        pDC->SetTextColor(RGB(0, 255, 0));
        pDC->SetBkColor(RGB(103, 103, 103));
        break;
    default:
        break;
    }
    // TODO:  如果默認的不是所需畫筆,則返回另一個畫筆
    return hbr;
}
void CDlgHistory::setTeeChart(SYSTEMTIME m_Systime)
{
    CObArray * m_Viewdatas = new CObArray();
    CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
    CTeeData * m_OneData;
    CSeries viewdata = this->c_HTChart.Series(0);
    CString temp;
    temp.Format("%2d-%d-%d的流量數據折線圖",m_Systime.wYear,m_Systime.wMonth,m_Systime.wDay);
    GetDlgItem(IDC_H_TITLE)->SetWindowText(temp);
    m_Viewdatas =  m_MysqlConnection->getData(m_Systime);
    viewdata.Clear();
    if (NULL != m_Viewdatas) {
        for (int i = 0; i < m_Viewdatas->GetSize(); i++) {
            m_OneData = (CTeeData *)m_Viewdatas->GetAt(i);
            viewdata.Add(m_OneData->m_Viewvalue, m_OneData->m_ViewData, NULL);
        }
    }   
}
void CDlgHistory::OnBnClickedOk()
{
    // TODO: 在此添加控件通知處理程序代碼
    CTime m_tmpTime;
    SYSTEMTIME m_Datetime;
    this->c_HDate.GetTime(m_tmpTime);
    m_Datetime.wYear = m_tmpTime.GetYear();
    m_Datetime.wMonth = m_tmpTime.GetMonth();
    m_Datetime.wDay = m_tmpTime.GetDay();
    m_Datetime.wHour = m_tmpTime.GetHour();
    m_Datetime.wMinute = m_tmpTime.GetMinute();
    m_Datetime.wSecond = m_tmpTime.GetSecond();
    setTeeChart(m_Datetime);
}

5.7.4原理講解

重寫OnInitDialog方法:

this->m_BmpId.Add(IDB_BITMAP1);this->m_BmpId.Add(IDB_BITMAP2);
this->m_BmpId.Add(IDB_BITMAP3);this->m_BmpId.Add(IDB_BITMAP4);
this->m_BmpId.Add(IDB_BITMAP5);this->m_BmpId.Add(IDB_BITMAP6);

重寫OnPaint方法:

//如果是第一張圖片,設置上一頁按鈕不可用
if (0 == this->m_BmpFlag) {m_InterpretLast.EnableWindow(0);}
else if (0 != this->m_BmpFlag && !m_InterpretLast.IsWindowEnabled()) {
m_InterpretLast.EnableWindow(1);}
//如果是最後一張圖片,設置下一頁按鈕不可用
if (this->m_BmpFlag == this->m_BmpId.GetSize() - 1) {m_InterpretNext.EnableWindow(0);}
else if (this->m_BmpFlag != this->m_BmpId.GetSize() - 1 &&
!m_InterpretNext.IsWindowEnabled()) {m_InterpretNext.EnableWindow(1);}
ShowPic(this->m_BmpId.GetAt(this->m_BmpFlag));

增加圖片自適應方法ShowPic:

CBitmap bitmap; CStatic * p;BITMAP bmpInfo;
CDC dcMemory;   CDC * pDC;  CBitmap * pOldBitmap;CRect rect;int nX, nY;
//加載指定位圖資源 Bmp圖片ID  
bitmap.LoadBitmap(m_PicID);//獲取對話框上的句柄 圖片控件ID  
p = (CStatic *)GetDlgItem(IDC_I_PIC);//設置靜態控件窗口風格爲位圖居中顯示   
p->ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE);//將圖片設置到Picture控件上  
p->SetBitmap(bitmap);bitmap.GetBitmap(&bmpInfo);
pDC = GetDlgItem(IDC_I_PIC)->GetDC();dcMemory.CreateCompatibleDC(pDC);
pOldBitmap = dcMemory.SelectObject(&bitmap);p->GetClientRect(&rect);
nX = rect.left + (rect.Width() - bmpInfo.bmWidth) / 2;
nY = rect.top + (rect.Height() - bmpInfo.bmHeight) / 2;
pDC->SetStretchBltMode(COLORONCOLOR);
pDC->StretchBlt(0, 0, rect.Width(), rect.Height(),&dcMemory, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, SRCCOPY);dcMemory.SelectObject(pOldBitmap);ReleaseDC(pDC);

增加上一頁按鈕的事件處理方法OnBnClickedILast:

this->m_BmpFlag--;if (this->m_BmpFlag < 0) {this->m_BmpFlag = 0;}
CDlgInterpret::OnPaint();

增加下一頁按鈕的事件處理方法OnBnClickedINext

this->m_BmpFlag++;  if (this->m_BmpFlag >= this->m_BmpId.GetSize()) {
this->m_BmpFlag = this->m_BmpId.GetSize() - 1;} CDlgInterpret::OnPaint();

DlgInterpret.h:

#pragma once
#include "afxwin.h"
// CDlgInterpret 對話框
class CDlgInterpret : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgInterpret)
public:
    CDlgInterpret(CWnd* pParent = NULL);   // 標準構造函數
    virtual ~CDlgInterpret();
// 對話框數據
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_INTERPRET };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    DECLARE_MESSAGE_MAP()
public:
    void ShowPic(int m_PicID);
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    CButton m_InterpretLast;
    CButton m_InterpretNext;
    CArray<int, int> m_BmpId;
    int m_BmpFlag;
    afx_msg void OnBnClickedINext();
    afx_msg void OnBnClickedILast();
};

DlgInterpret.cpp:

// DlgInterpret.cpp : 實現文件
#include "stdafx.h"
#include "管道流量採集.h"
#include "DlgInterpret.h"
#include "afxdialogex.h"
// CDlgInterpret 對話框
IMPLEMENT_DYNAMIC(CDlgInterpret, CDialogEx)
CDlgInterpret::CDlgInterpret(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_INTERPRET, pParent)
    , m_BmpFlag(0)
{
}
CDlgInterpret::~CDlgInterpret()
{
}
void CDlgInterpret::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_I_LAST, m_InterpretLast);
    DDX_Control(pDX, IDC_I_NEXT, m_InterpretNext);
}
BEGIN_MESSAGE_MAP(CDlgInterpret, CDialogEx)
    ON_WM_PAINT()
    ON_BN_CLICKED(IDC_I_NEXT, &CDlgInterpret::OnBnClickedINext)
    ON_BN_CLICKED(IDC_I_LAST, &CDlgInterpret::OnBnClickedILast)
END_MESSAGE_MAP()
// CDlgInterpret 消息處理程序
void CDlgInterpret::ShowPic(int m_PicID)
{
    CBitmap bitmap;
    CStatic * p;
    BITMAP bmpInfo;
    CDC dcMemory;
    CDC * pDC;
    CBitmap * pOldBitmap;
    CRect rect;
    int nX, nY;
    //加載指定位圖資源 Bmp圖片ID  
    bitmap.LoadBitmap(m_PicID);
    //獲取對話框上的句柄 圖片控件ID  
    p = (CStatic *)GetDlgItem(IDC_I_PIC);
    //設置靜態控件窗口風格爲位圖居中顯示   
    p->ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE);
    //將圖片設置到Picture控件上  
    p->SetBitmap(bitmap);
    bitmap.GetBitmap(&bmpInfo);
    pDC = GetDlgItem(IDC_I_PIC)->GetDC();
    dcMemory.CreateCompatibleDC(pDC);
    pOldBitmap = dcMemory.SelectObject(&bitmap);
    p->GetClientRect(&rect);
    nX = rect.left + (rect.Width() - bmpInfo.bmWidth) / 2;
    nY = rect.top + (rect.Height() - bmpInfo.bmHeight) / 2;
    pDC->SetStretchBltMode(COLORONCOLOR);
    pDC->StretchBlt(0, 0, rect.Width(), rect.Height(), 
        &dcMemory, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, SRCCOPY);
    dcMemory.SelectObject(pOldBitmap);
    ReleaseDC(pDC);
}
BOOL CDlgInterpret::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加額外的初始化
    this->m_BmpId.Add(IDB_BITMAP1);
    this->m_BmpId.Add(IDB_BITMAP2);
    this->m_BmpId.Add(IDB_BITMAP3);
    this->m_BmpId.Add(IDB_BITMAP4);
    this->m_BmpId.Add(IDB_BITMAP5);
    this->m_BmpId.Add(IDB_BITMAP6);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // 異常: OCX 屬性頁應返回 FALSE
}
void CDlgInterpret::OnPaint()
{
    CPaintDC dc(this); // device context for painting
                       // TODO: 在此處添加消息處理程序代碼
                       // 不爲繪圖消息調用 CDialogEx::OnPaint()
    //如果是第一張圖片,設置上一頁按鈕不可用
    if (0 == this->m_BmpFlag) {
        m_InterpretLast.EnableWindow(0);
    }
    else if (0 != this->m_BmpFlag && !m_InterpretLast.IsWindowEnabled()) {
        m_InterpretLast.EnableWindow(1);
    }
    //如果是最後一張圖片,設置下一頁按鈕不可用
    if (this->m_BmpFlag == this->m_BmpId.GetSize() - 1) {
        m_InterpretNext.EnableWindow(0);
    }
    else if (this->m_BmpFlag != this->m_BmpId.GetSize() - 1 &&
        !m_InterpretNext.IsWindowEnabled()) {
        m_InterpretNext.EnableWindow(1);
    }
    ShowPic(this->m_BmpId.GetAt(this->m_BmpFlag));
}
void CDlgInterpret::OnBnClickedINext()
{
    // TODO: 在此添加控件通知處理程序代碼
    this->m_BmpFlag++;
    if (this->m_BmpFlag >= this->m_BmpId.GetSize()) {
        this->m_BmpFlag = this->m_BmpId.GetSize() - 1;
    }
    CDlgInterpret::OnPaint();
}
void CDlgInterpret::OnBnClickedILast()
{
    // TODO: 在此添加控件通知處理程序代碼
    this->m_BmpFlag--;
    if (this->m_BmpFlag < 0) {
        this->m_BmpFlag = 0;
    }
    CDlgInterpret::OnPaint();
}

5.7.5查看參數

重寫OnInitDialog方法:

CString temp;CConfigdata * m_Configdata = new CConfigdata();
m_Configdata->getConfigdata();
CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
SetDlgItemText(IDC_L_IPADD,m_DataConfig->getIpAddress());
SetDlgItemText(IDC_L_COM, m_DataConfig->getComnum());
SetDlgItemText(IDC_L_USERNAME, m_DataConfig->getUsername());
SetDlgItemText(IDC_L_PASSWORD, m_DataConfig->getPassword());
SetDlgItemText(IDC_L_DATABASE, m_DataConfig->getDatabase());temp = "COM";
temp += m_DataConfig->getComm();SetDlgItemText(IDC_L_COMM, temp);
SetDlgItemText(IDC_L_BOTELV, m_DataConfig->getBotelv());
SetDlgItemText(IDC_L_JIAOYAN, m_DataConfig->getJiaoyan());
SetDlgItemText(IDC_L_SHUJU, m_DataConfig->getShuju());
SetDlgItemText(IDC_L_TINGZHI, m_DataConfig->getTingzhi());
temp = m_DataConfig->getTime();long tt = atol(temp);tt /= 1000;
if (tt <= 60) {temp.Format("%d", tt);temp += "秒";}if (tt > 60 && tt <= 3600) {
temp.Format("%d", tt / 60);temp += "分鐘";}if (tt > 3600) {   temp.Format("%d", (tt / 60) / 60);
temp += "小時";}SetDlgItemText(IDC_L_TIME, temp);UpdateData(FALSE);

DlgLookdata.h:

#pragma once
#include "DataConfig.h"
#include "Configdata.h"
// CDlgLookdata 對話框
class CDlgLookdata : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgLookdata)
public:
    CDlgLookdata(CWnd* pParent = NULL);   // 標準構造函數
    virtual ~CDlgLookdata();
// 對話框數據
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_LOOKDATA };
#endif
protected:
    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
};

DlgLookdata.cpp:

// DlgLookdata.cpp : 實現文件
#include "stdafx.h"
#include "管道流量採集.h"
#include "DlgLookdata.h"
#include "afxdialogex.h"
// CDlgLookdata 對話框
IMPLEMENT_DYNAMIC(CDlgLookdata, CDialogEx)
CDlgLookdata::CDlgLookdata(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_LOOKDATA, pParent)
{
}
CDlgLookdata::~CDlgLookdata()
{
}
BEGIN_MESSAGE_MAP(CDlgLookdata, CDialogEx)
END_MESSAGE_MAP()
// CDlgLookdata 消息處理程序
BOOL CDlgLookdata::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加額外的初始化
    CString temp;
    CConfigdata * m_Configdata = new CConfigdata();
    m_Configdata->getConfigdata();
    CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
    SetDlgItemText(IDC_L_IPADD,m_DataConfig->getIpAddress());
    SetDlgItemText(IDC_L_COM, m_DataConfig->getComnum());
    SetDlgItemText(IDC_L_USERNAME, m_DataConfig->getUsername());
    SetDlgItemText(IDC_L_PASSWORD, m_DataConfig->getPassword());
    SetDlgItemText(IDC_L_DATABASE, m_DataConfig->getDatabase());
    temp = "COM";
    temp += m_DataConfig->getComm();
    SetDlgItemText(IDC_L_COMM, temp);
    SetDlgItemText(IDC_L_BOTELV, m_DataConfig->getBotelv());
    SetDlgItemText(IDC_L_JIAOYAN, m_DataConfig->getJiaoyan());
    SetDlgItemText(IDC_L_SHUJU, m_DataConfig->getShuju());
    SetDlgItemText(IDC_L_TINGZHI, m_DataConfig->getTingzhi());
    temp = m_DataConfig->getTime();
    long tt = atol(temp);
    tt /= 1000;
    if (tt <= 60) {
        temp.Format("%d", tt);
        temp += "秒";
    }
    if (tt > 60 && tt <= 3600) {
        temp.Format("%d", tt / 60);
        temp += "分鐘";
    }
    if (tt > 3600) {
        temp.Format("%d", (tt / 60) / 60);
        temp += "小時";
    }
    SetDlgItemText(IDC_L_TIME, temp);
    UpdateData(FALSE);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // 異常: OCX 屬性頁應返回 FALSE
}

5.7.6設置參數

重寫OnInitDialog方法,設置參數的默認參數:

//初始化下拉選擇框
SetDlgItemText(IDC_S_IPADD, "127.0.0.1");SetDlgItemText(IDC_S_COM, "3305");
SetDlgItemText(IDC_S_USERNAME, "root"); SetDlgItemText(IDC_S_PASSWORD, "root");
SetDlgItemText(IDC_S_DATABASE, "flowdata"); this->c_Comm.ResetContent();
this->c_Comm.AddString("COM1");
…….
this->c_Comm.AddString("COM8");this->c_Comm.SetCurSel(2);//默認爲COM3
this->c_Botelv.ResetContent();this->c_Botelv.AddString("300");
……
this->c_Botelv.AddString("38400");this->c_Botelv.SetCurSel(2);//默認1200
this->c_Jiaoyan.ResetContent();this->c_Jiaoyan.AddString("無");
this->c_Jiaoyan.AddString("奇校驗");this->c_Jiaoyan.AddString("偶校驗");
this->c_Jiaoyan.SetCurSel(0);//默認無校驗this->c_Shuju.ResetContent();
this->c_Shuju.AddString("8");this->c_Shuju.AddString("7");this->c_Shuju.AddString("6");
this->c_Shuju.SetCurSel(0);//默認8個數據位this->c_Tingzhi.ResetContent();
this->c_Tingzhi.AddString("1");this->c_Tingzhi.AddString("2");
this->c_Tingzhi.SetCurSel(0);//默認1個停止位SetDlgItemText(IDC_S_TIME, "30");
CButton * radioS = (CButton *)GetDlgItem(IDC_S_SECEND);radioS->SetCheck(1);

重寫PreTranslateMessage方法,此方法可以讓用戶通過Tab鍵來選擇下一個:

if ((pMsg->message == WM_KEYDOWN) && (VK_TAB == (int)pMsg->wParam)) {
CWnd *mwnd = GetFocus();if (NULL != mwnd) {
if (mwnd == GetDlgItem(IDC_S_IPADD)) {GetDlgItem(IDC_S_COM)->SetFocus();
return TRUE;}else if (mwnd == GetDlgItem(IDC_S_COM)) {
GetDlgItem(IDC_S_USERNAME)->SetFocus();return TRUE;}
…….}}

增加確定按鈕的事件處理方法OnBnClickedOk:

CString temp;CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
GetDlgItemText(IDC_S_COM, temp);    m_DataConfig->setComnum(temp);
GetDlgItemText(IDC_S_IPADD, temp);m_DataConfig->setIpAddress(temp);
GetDlgItemText(IDC_S_USERNAME, this->m_SetUsername);
m_DataConfig->setUsername(this->m_SetUsername);
GetDlgItemText(IDC_S_PASSWORD, this->m_SetPassword);
m_DataConfig->setPassword(this->m_SetPassword);
GetDlgItemText(IDC_S_DATABASE, this->m_SetDatabase);
m_DataConfig->setDatabase(this->m_SetDatabase);
//沒有COM0
switch (this->c_Comm.GetCurSel()) {case 0:temp = "1";break;case 1:temp = "2";break;
case 2:temp = "3";break;case 3:temp = "4";break;case 4:temp = "5";break;
case 5:temp = "6";break;case 6:temp = "7";break;case 7:temp = "8";break;    default:break;}
m_DataConfig->setComm(temp);GetDlgItemText(IDC_S_BOTELV, temp);
m_DataConfig->setBotelv(temp);switch (this->c_Jiaoyan.GetCurSel())
{case 0:temp = "n";break;   case 1:temp = "1";break;case 2:temp = "2";break;
default:temp = "n";break;}m_DataConfig->setJiaoyan(temp);
GetDlgItemText(IDC_S_SHUJU, temp);m_DataConfig->setShuju(temp);
GetDlgItemText(IDC_S_TING, temp);   m_DataConfig->setTingzhi(temp);
GetDlgItemText(IDC_S_TIME, temp);   long tt;tt = atol(temp);CButton * pTemp = NULL;
pTemp = (CButton * )GetDlgItem(IDC_S_HOUR);if (pTemp->GetCheck()) {
tt = tt * 60 * 60 * 1000;}pTemp = (CButton *)GetDlgItem(IDC_S_MINTE);
if (pTemp->GetCheck()) {tt = tt * 60 * 1000;}
pTemp = (CButton *)GetDlgItem(IDC_S_SECEND);if (pTemp->GetCheck()) {
tt = tt * 1000;}temp.Format("%d", tt);m_DataConfig->setTime(temp);
CConfigdata m_Configdata;m_Configdata.setConfigdata();
SetTimer(1, atoi(m_DataConfig->getTime()), NULL);CDialogEx::OnOK();

DlgSetdata.h:

#pragma once
//頭文件
#include "afxwin.h"
#include "Configdata.h"
// CDlgSetdata 對話框
class CDlgSetdata : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgSetdata)
    CDlgSetdata(CWnd* pParent = NULL);   // 標準構造函數
public:
    virtual ~CDlgSetdata();
// 對話框數據
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_SETDATA };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    DECLARE_MESSAGE_MAP()
public:
    // IP地址
    DWORD m_SetIpadd;
    // 端口號
    CString m_SetCom;
    // 用戶名
    CString m_SetUsername;
    // 密碼
    CString m_SetPassword;
    // 數據庫名
    CString m_SetDatabase;
    afx_msg void OnBnClickedOk();
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    virtual BOOL OnInitDialog();
    CComboBox c_Comm;
    CComboBox c_Botelv;
    CComboBox c_Jiaoyan;
    CComboBox c_Shuju;
    CComboBox c_Tingzhi;
    CEdit c_Time;
    CButton c_ButtonH;
};

DlgSetdata.cpp:

// DlgSetdata.cpp : 實現文件
#include "stdafx.h"
#include "管道流量採集.h"
#include "DlgSetdata.h"
#include "afxdialogex.h"
// CDlgSetdata 對話框
IMPLEMENT_DYNAMIC(CDlgSetdata, CDialogEx)
CDlgSetdata::CDlgSetdata(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_SETDATA, pParent)
    , m_SetIpadd(0)
    , m_SetUsername(_T(""))
    , m_SetPassword(_T(""))
    , m_SetDatabase(_T(""))
{
}
CDlgSetdata::~CDlgSetdata()
{
}
void CDlgSetdata::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_IPAddress(pDX, IDC_S_IPADD, m_SetIpadd);
    DDX_Text(pDX, IDC_S_COM, m_SetCom);
    DDX_Text(pDX, IDC_S_USERNAME, m_SetUsername);
    DDX_Text(pDX, IDC_S_PASSWORD, m_SetPassword);
    DDX_Text(pDX, IDC_S_DATABASE, m_SetDatabase);
    DDX_Control(pDX, IDC_S_COMM, c_Comm);
    DDX_Control(pDX, IDC_S_BOTELV, c_Botelv);
    DDX_Control(pDX, IDC_S_JIAO, c_Jiaoyan);
    DDX_Control(pDX, IDC_S_SHUJU, c_Shuju);
    DDX_Control(pDX, IDC_S_TING, c_Tingzhi);
    DDX_Control(pDX, IDC_S_TIME, c_Time);
    DDX_Control(pDX, IDCANCEL, c_ButtonH);
}
BEGIN_MESSAGE_MAP(CDlgSetdata, CDialogEx)
    ON_BN_CLICKED(IDOK, &CDlgSetdata::OnBnClickedOk)
END_MESSAGE_MAP()
// CDlgSetdata 消息處理程序
void CDlgSetdata::OnBnClickedOk()
{
    // TODO: 在此添加控件通知處理程序代碼
    CString temp;
    CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
    GetDlgItemText(IDC_S_COM, temp);
    m_DataConfig->setComnum(temp);
    GetDlgItemText(IDC_S_IPADD, temp);
    m_DataConfig->setIpAddress(temp);
    GetDlgItemText(IDC_S_USERNAME, this->m_SetUsername);
    m_DataConfig->setUsername(this->m_SetUsername);
    GetDlgItemText(IDC_S_PASSWORD, this->m_SetPassword);
    m_DataConfig->setPassword(this->m_SetPassword);
    GetDlgItemText(IDC_S_DATABASE, this->m_SetDatabase);
    m_DataConfig->setDatabase(this->m_SetDatabase);
    switch (this->c_Comm.GetCurSel()) {
    case 0:
        temp = "1";
        break;
    case 1:
        temp = "2";
        break;
    case 2:
        temp = "3";
        break;
    case 3:
        temp = "4";
        break;
    case 4:
        temp = "5";
        break;
    case 5:
        temp = "6";
        break;
    case 6:
        temp = "7";
        break;
    case 7:
        temp = "8";
        break;
    default:
        break;
    }
    m_DataConfig->setComm(temp);
    GetDlgItemText(IDC_S_BOTELV, temp);
    m_DataConfig->setBotelv(temp);
    switch (this->c_Jiaoyan.GetCurSel())
    {
    case 0:
        temp = "n";
        break;
    case 1:
        temp = "1";
        break;
    case 2:
        temp = "2";
        break;
    default:
        temp = "n";
        break;
    }
    m_DataConfig->setJiaoyan(temp);
    GetDlgItemText(IDC_S_SHUJU, temp);
    m_DataConfig->setShuju(temp);
    GetDlgItemText(IDC_S_TING, temp);
    m_DataConfig->setTingzhi(temp);
    GetDlgItemText(IDC_S_TIME, temp);
    long tt;
    tt = atol(temp);
    CButton * pTemp = NULL;
    pTemp = (CButton * )GetDlgItem(IDC_S_HOUR);
    if (pTemp->GetCheck()) {
        tt = tt * 60 * 60 * 1000;
    }
    pTemp = (CButton *)GetDlgItem(IDC_S_MINTE);
    if (pTemp->GetCheck()) {
        tt = tt * 60 * 1000;
    }
    pTemp = (CButton *)GetDlgItem(IDC_S_SECEND);
    if (pTemp->GetCheck()) {
        tt = tt * 1000;
    }
    temp.Format("%d", tt);
    m_DataConfig->setTime(temp);
    CConfigdata m_Configdata;
    m_Configdata.setConfigdata();
    SetTimer(1, atoi(m_DataConfig->getTime()), NULL);
    //AfxMessageBox("定時器開始");
    CDialogEx::OnOK();
}
BOOL CDlgSetdata::PreTranslateMessage(MSG* pMsg)
{
    // TODO: 在此添加專用代碼和/或調用基類
    if ((pMsg->message == WM_KEYDOWN) && (VK_TAB == (int)pMsg->wParam)) {
        CWnd *mwnd = GetFocus();
        if (NULL != mwnd) {
            if (mwnd == GetDlgItem(IDC_S_IPADD)) {
                GetDlgItem(IDC_S_COM)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDC_S_COM)) {
                GetDlgItem(IDC_S_USERNAME)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDC_S_USERNAME)) {
                GetDlgItem(IDC_S_PASSWORD)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDC_S_PASSWORD)) {
                GetDlgItem(IDC_S_DATABASE)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDC_S_DATABASE)) {
                GetDlgItem(IDOK)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDOK)) {
                GetDlgItem(IDCANCEL)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDCANCEL)) {
                GetDlgItem(IDC_S_IPADD)->SetFocus();
                return TRUE;
            }
        }
    }
    return CDialogEx::PreTranslateMessage(pMsg);
}
BOOL CDlgSetdata::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加額外的初始化
    //初始化下拉選擇框
    SetDlgItemText(IDC_S_IPADD, "127.0.0.1");
    SetDlgItemText(IDC_S_COM, "3305");
    SetDlgItemText(IDC_S_USERNAME, "root");
    SetDlgItemText(IDC_S_PASSWORD, "root");
    SetDlgItemText(IDC_S_DATABASE, "flowdata");
    this->c_Comm.ResetContent();
    this->c_Comm.AddString("COM1");
    this->c_Comm.AddString("COM2");
    this->c_Comm.AddString("COM3");
    this->c_Comm.AddString("COM4");
    this->c_Comm.AddString("COM5");
    this->c_Comm.AddString("COM6");
    this->c_Comm.AddString("COM7");
    this->c_Comm.AddString("COM8");
    this->c_Comm.SetCurSel(2);//默認爲COM3
    this->c_Botelv.ResetContent();
    this->c_Botelv.AddString("300");
    this->c_Botelv.AddString("600");
    this->c_Botelv.AddString("1200");
    this->c_Botelv.AddString("2400");
    this->c_Botelv.AddString("3600");
    this->c_Botelv.AddString("4800");
    this->c_Botelv.AddString("9600");
    this->c_Botelv.AddString("19200");
    this->c_Botelv.AddString("38400");
    this->c_Botelv.SetCurSel(2);//默認1200
    this->c_Jiaoyan.ResetContent();
    this->c_Jiaoyan.AddString("無");
    this->c_Jiaoyan.AddString("奇校驗");
    this->c_Jiaoyan.AddString("偶校驗");
    this->c_Jiaoyan.SetCurSel(0);//默認無校驗
    this->c_Shuju.ResetContent();
    this->c_Shuju.AddString("8");
    this->c_Shuju.AddString("7");
    this->c_Shuju.AddString("6");
    this->c_Shuju.SetCurSel(0);//默認8個數據位
    this->c_Tingzhi.ResetContent();
    this->c_Tingzhi.AddString("1");
    this->c_Tingzhi.AddString("2");
    this->c_Tingzhi.SetCurSel(0);//默認1個停止位
    SetDlgItemText(IDC_S_TIME, "30");
    CButton * radioS = (CButton *)GetDlgItem(IDC_S_SECEND);
    radioS->SetCheck(1);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // 異常: OCX 屬性頁應返回 FALSE
}

5.7.7協議測試

添加CRC校驗碼的計算方法,頭文件:

#include <stdint.h>
uint16_t CRC16( uint8_t * pucFrame, uint16_t usLen );

實現文件:

#include "stdafx.h"#include "crc.h"
static const uint8_t aucCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40};
static const uint8_t aucCRCLo[] = {
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
    0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
    0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
    0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
    0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
    0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
    0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
    0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
    0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
    0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
    0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
    0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
    0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
    0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
    0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
    0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
    0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
    0x41, 0x81, 0x80, 0x40};
uint16_t CRC16( uint8_t * pucFrame, uint16_t usLen )
{uint8_t ucCRCHi = 0xFF;uint8_t ucCRCLo = 0xFF;int iIndex;
while( usLen-- ){iIndex = ucCRCLo ^ *( pucFrame++ );
ucCRCLo = ( uint8_t )( ucCRCHi ^ aucCRCHi[iIndex] );ucCRCHi = aucCRCLo[iIndex];}
return ( uint16_t )( ucCRCLo << 8 | ucCRCHi );}

自動生成協議幀的按鈕事件處理方法OnBnClickedButton1:

CString result;CTime tmpTime;SYSTEMTIME systim;uint8_t len;uint8_t prop;
uint8_t station;uint8_t pass;uint8_t timey;uint8_t timem;   uint8_t timed;
uint8_t timeh;uint8_t timemin;uint8_t times;uint16_t crc_result;CString temp;
len = 0X0C;prop = 0X00;station = 0X02;pass = 0X02;result = "自動生成的協議幀\n";
result += "EB 90 0C 00 02 02 ";this->c_Data.GetTime(tmpTime);
timey = tmpTime.GetYear()%100;  temp.Format("%02d", timey);result += temp;result += " ";
timey = strtol(temp, NULL, 16);
…….
uint8_t crc_mess[] = { len, prop, station, pass, timey, timem, timed, timeh, timemin, times };
crc_result = CRC16((uint8_t*)crc_mess, 10);temp.Format("%04X", crc_result);
result += temp;result.Insert(result.GetLength() - 2, " ");
SetDlgItemText(IDC_T_RESULT, result);

確定按鈕的事件處理方法OnBnClickedOk:

CString m_input;    CString m_result = "測試結果:";GetDlgItemText(IDC_T_INPUT, m_input);
if (m_input.GetLength() < 41) {m_result += "幀總長度不夠";}
else {uint16_t address;CString addrtemp;addrtemp += m_input.GetAt(0);
addrtemp += m_input.GetAt(1);addrtemp += m_input.GetAt(3);
addrtemp += m_input.GetAt(4);address = strtol(addrtemp, NULL, 16);if (0xEB90 != address) {
m_result += "\n前四位地址碼爲EB 90";}else {m_result += "\n地址碼測試通過";}
uint8_t len;CString lentemp;lentemp += m_input.GetAt(6);
lentemp += m_input.GetAt(7);len = strtol(lentemp, NULL, 16);
if ((m_input.GetLength() - 17) / 2 != len) {m_result += "\t長度計算錯誤,正確的是:";
lentemp.Format("%02X", (m_input.GetLength() - 17) / 2);m_result += lentemp; }
else {m_result += "\t長度測試通過";}
uint8_t prop;   CString proptemp;proptemp += m_input.GetAt(9);
proptemp += m_input.GetAt(10);prop = strtol(proptemp, NULL, 16);
if (0 != prop) {m_result += "\n屬性碼錯誤,正確的爲:00";}
else {m_result += "\n屬性碼測試通過";}uint8_t station;CString stationtemp;
stationtemp += m_input.GetAt(12);stationtemp += m_input.GetAt(13);
station = strtol(stationtemp, NULL, 16);
if (0x02 != station) {m_result += "\t站號錯誤,正確爲:02";}
else {m_result += "\t站號測試通過";}
uint8_t pass;   CString passtemp;passtemp += m_input.GetAt(15);
passtemp += m_input.GetAt(16);pass = strtol(passtemp, NULL, 16);
if (0x02 != pass) {m_result += "\n通道號錯誤,正確爲:02";}
else {m_result += "\n通道號測試通過";}
uint8_t timey;uint8_t timem;uint8_t timed;uint8_t timeh;uint8_t timemin;
uint8_t times;CString timetemp = "";timetemp += m_input.GetAt(18);
timetemp += m_input.GetAt(19);timey = strtol(timetemp, NULL, 16);
timetemp = "";timetemp += m_input.GetAt(21);
timetemp += m_input.GetAt(22);timem = strtol(timetemp, NULL, 16);
timetemp = "";timetemp += m_input.GetAt(24);timetemp += m_input.GetAt(25);
timed = strtol(timetemp, NULL, 16);timetemp = "";timetemp += m_input.GetAt(27);
timetemp += m_input.GetAt(28);timeh = strtol(timetemp, NULL, 16);timetemp = "";
timetemp += m_input.GetAt(30);timetemp += m_input.GetAt(31);
timemin = strtol(timetemp, NULL, 16);timetemp = "";
timetemp += m_input.GetAt(33);timetemp += m_input.GetAt(34);
times = strtol(timetemp, NULL, 16);uint16_t crc_y;timetemp = "";
timetemp += m_input.GetAt(36);timetemp += m_input.GetAt(37);
timetemp += m_input.GetAt(39);timetemp += m_input.GetAt(40);
crc_y = strtol(timetemp, NULL, 16);
uint8_t crc_mess[]={len,prop,station,pass, timey, timem, timed, timeh, timemin, times };
uint16_t crc_result = CRC16((uint8_t*)crc_mess, 10);
if (crc_result != crc_y) {CString t;m_result += "\t校驗碼錯誤,正確爲:";
t.Format("%04X", crc_result);   t.Insert(t.GetLength() - 2, " ");m_result += t;}
else {m_result += "\t校驗碼測試通過";}}SetDlgItemText(IDC_T_RESULT, m_result);

DlgText.h

#pragma once
#include "afxdtctl.h"
// CDlgText 對話框
class CDlgText : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgText)
public:
    CDlgText(CWnd* pParent = NULL);   // 標準構造函數
    virtual ~CDlgText();
// 對話框數據
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_TEXT };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedOk();
    afx_msg void OnBnClickedButton1();
    CDateTimeCtrl c_Data;
    CDateTimeCtrl c_Time;
};

DlgText.cpp:

// DlgText.cpp : 實現文件
#include "stdafx.h"
#include "管道流量採集.h"
#include "DlgText.h"
#include "afxdialogex.h"
#include "stdio.h"
#include "stdint.h"
#include "crc.h"
// CDlgText 對話框
IMPLEMENT_DYNAMIC(CDlgText, CDialogEx)
CDlgText::CDlgText(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_TEXT, pParent)
{
}
CDlgText::~CDlgText()
{
}
void CDlgText::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_T_DATA, c_Data);
    DDX_Control(pDX, IDC_T_TIME, c_Time);
}
BEGIN_MESSAGE_MAP(CDlgText, CDialogEx)
    ON_BN_CLICKED(IDOK, &CDlgText::OnBnClickedOk)
    ON_BN_CLICKED(IDC_BUTTON1, &CDlgText::OnBnClickedButton1)
END_MESSAGE_MAP()
// CDlgText 消息處理程序
void CDlgText::OnBnClickedOk()
{
    // TODO: 在此添加控件通知處理程序代碼
    CString m_input;
    CString m_result = "測試結果:";
    GetDlgItemText(IDC_T_INPUT, m_input);
    if (m_input.GetLength() < 41) {
        m_result += "幀總長度不夠";
    }
    else {
        uint16_t address;
        CString addrtemp;
        addrtemp += m_input.GetAt(0);
        addrtemp += m_input.GetAt(1);
        addrtemp += m_input.GetAt(3);
        addrtemp += m_input.GetAt(4);
        address = strtol(addrtemp, NULL, 16);
        if (0xEB90 != address) {
            m_result += "\n前四位地址碼爲EB 90";
        }
        else {
            m_result += "\n地址碼測試通過";
        }
        uint8_t len;
        CString lentemp;
        lentemp += m_input.GetAt(6);
        lentemp += m_input.GetAt(7);
        len = strtol(lentemp, NULL, 16);
        if ((m_input.GetLength() - 17) / 2 != len) {
            m_result += "\t長度計算錯誤,正確的是:";
            lentemp.Format("%02X", (m_input.GetLength() - 17) / 2);
            m_result += lentemp;
        }
        else {
            m_result += "\t長度測試通過";
        }
        uint8_t prop;
        CString proptemp;
        proptemp += m_input.GetAt(9);
        proptemp += m_input.GetAt(10);
        prop = strtol(proptemp, NULL, 16);
        if (0 != prop) {
            m_result += "\n屬性碼錯誤,正確的爲:00";
        }
        else {
            m_result += "\n屬性碼測試通過";
        }
        uint8_t station;
        CString stationtemp;
        stationtemp += m_input.GetAt(12);
        stationtemp += m_input.GetAt(13);
        station = strtol(stationtemp, NULL, 16);
        if (0x02 != station) {
            m_result += "\t站號錯誤,正確爲:02";
        }
        else {
            m_result += "\t站號測試通過";
        }
        uint8_t pass;
        CString passtemp;
        passtemp += m_input.GetAt(15);
        passtemp += m_input.GetAt(16);
        pass = strtol(passtemp, NULL, 16);
        if (0x02 != pass) {
            m_result += "\n通道號錯誤,正確爲:02";
        }
        else {
            m_result += "\n通道號測試通過";
        }
        uint8_t timey;
        uint8_t timem;
        uint8_t timed;
        uint8_t timeh;
        uint8_t timemin;
        uint8_t times;
        CString timetemp = "";
        timetemp += m_input.GetAt(18);
        timetemp += m_input.GetAt(19);
        timey = strtol(timetemp, NULL, 16);
        timetemp = "";
        timetemp += m_input.GetAt(21);
        timetemp += m_input.GetAt(22);
        timem = strtol(timetemp, NULL, 16);
        timetemp = "";
        timetemp += m_input.GetAt(24);
        timetemp += m_input.GetAt(25);
        timed = strtol(timetemp, NULL, 16);
        timetemp = "";
        timetemp += m_input.GetAt(27);
        timetemp += m_input.GetAt(28);
        timeh = strtol(timetemp, NULL, 16);
        timetemp = "";
        timetemp += m_input.GetAt(30);
        timetemp += m_input.GetAt(31);
        timemin = strtol(timetemp, NULL, 16);
        timetemp = "";
        timetemp += m_input.GetAt(33);
        timetemp += m_input.GetAt(34);
        times = strtol(timetemp, NULL, 16);
        uint16_t crc_y;
        timetemp = "";
        timetemp += m_input.GetAt(36);
        timetemp += m_input.GetAt(37);
        timetemp += m_input.GetAt(39);
        timetemp += m_input.GetAt(40);
        crc_y = strtol(timetemp, NULL, 16);
        //EB90 0C 00 02 02 180512162835 C1CF
        uint8_t crc_mess[] = { len, prop, station, pass, timey, timem, timed, timeh, timemin, times };
        uint16_t crc_result = CRC16((uint8_t*)crc_mess, 10);
        if (crc_result != crc_y) {
            CString t;
            m_result += "\t校驗碼錯誤,正確爲:";
            t.Format("%04X", crc_result);
            t.Insert(t.GetLength() - 2, " ");
            m_result += t;
        }
        else {
            m_result += "\t校驗碼測試通過";
        }
    }
    SetDlgItemText(IDC_T_RESULT, m_result);
    //CDialogEx::OnOK();
}
void CDlgText::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知處理程序代碼
    CString result;
    CTime tmpTime;
    SYSTEMTIME systim;
    uint8_t len;
    uint8_t prop;
    uint8_t station;
    uint8_t pass;
    uint8_t timey;
    uint8_t timem;
    uint8_t timed;
    uint8_t timeh;
    uint8_t timemin;
    uint8_t times;
    uint16_t crc_result;
    CString temp;
    len = 0X0C;
    prop = 0X00;
    station = 0X02;
    pass = 0X02;
    result = "自動生成的協議幀\n";
    result += "EB 90 0C 00 02 02 ";
    this->c_Data.GetTime(tmpTime);
    timey = tmpTime.GetYear()%100;
    temp.Format("%02d", timey);
    result += temp;
    result += " ";
    timey = strtol(temp, NULL, 16);
    timem = tmpTime.GetMonth();
    temp.Format("%02d", timem);
    result += temp;
    result += " ";
    timem = strtol(temp, NULL, 16);
    timed = tmpTime.GetDay();
    temp.Format("%02d", timed);
    result += temp;
    result += " ";
    timed = strtol(temp, NULL, 16);
    this->c_Time.GetTime(tmpTime);
    timeh = tmpTime.GetHour();
    temp.Format("%02d", timeh);
    result += temp;
    result += " ";
    timeh = strtol(temp, NULL, 16);
    timemin = tmpTime.GetMinute();
    temp.Format("%02d", timemin);
    result += temp;
    result += " ";
    timemin = strtol(temp, NULL, 16);
    times = tmpTime.GetSecond();
    temp.Format("%02d", times);
    result += temp;
    result += " ";
    times = strtol(temp, NULL, 16);
    uint8_t crc_mess[] = { len, prop, station, pass, timey, timem, timed, timeh, timemin, times };
    crc_result = CRC16((uint8_t*)crc_mess, 10);
    temp.Format("%04X", crc_result);
    result += temp;
    result.Insert(result.GetLength() - 2, " ");
    SetDlgItemText(IDC_T_RESULT, result);
}

5.7.8主對話框(實時流量)

首先爲主對話框添加菜單欄:
這裏寫圖片描述


圖16增加資源示意圖
這裏寫圖片描述

圖17菜單分佈圖

所有的菜單都是一級菜單:
表17菜單ID映射表 菜單名|ID :——–|:—– 原理講解(&I)|ID_INTERPRET 協議測試(&T)|ID_TEST 流量預測(&F)|ID_FORECAST 歷史流量數據(&H)|ID_HISTORY 統計分析表(&E)|ID_EXCEL 設置參數(&S)|ID_SETDATA 查看參數(&L)|ID_LOOKDATA 添加菜單的快捷鍵,資源的添加方式和菜單的資源添加相同,只是資源格式爲Accelerator。 ![這裏寫圖片描述](https://img-blog.csdn.net/20180701125308716?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExODc5MjcyMTgzMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
圖18快捷鍵鍵位圖 把菜單和快捷鍵和主對話框綁定,重寫OnInitDialog方法:
ShowWindow(SW_MAXIMIZE);    CMenu menu;menu.LoadMenu(IDR_MENU);
SetMenu(&menu);//添加快捷鍵//加載資源列表
m_Haccel = LoadAccelerators(theApp.m_hInstance, (LPCTSTR)IDR_ACCELERATOR);
CMysqlConnection * m_MysqlConnectin = CMysqlConnection::GetMysqlConn();
m_MysqlConnectin->ConnectionMysql();//設置串口參數setComm();//設置折線圖數據
setTChartData();

爲菜單添加事件處理方法,在主對話框屬性中選擇事件添加COMMAND處理方法:

void C管道流量採集Dlg::OnExcel()
{// TODO: 在此添加命令處理程序代碼//統計分析表對話框
CSingle *single = CSingle::GetSingle();single->m_dlgExcel->DoModal();}

其餘類似,確保所有的菜單都添加了事件處理方法。
重寫OnCancel方法,在此方法中添加連接關閉的方法:

if (this->c_Comm.get_PortOpen()) {this->c_Comm.put_PortOpen(FALSE);
AfxMessageBox("串口關閉成功");}
else {AfxMessageBox("串口關閉失敗,請重試");}

重寫OnCtlColor方法:

CFont m_SetFont;switch (pWnd->GetDlgCtrlID())
{case IDC_STATIC_DATAVIEW:pDC->SetTextColor(RGB(255, 0, 0));break;
case IDC_STATIC_MS:pDC->SetTextColor(RGB(255, 0, 0));break;
case IDC_DATAVIEW:m_SetFont.CreatePointFont(400, _T("TimesNewRoman"));
pDC->SelectObject(&m_SetFont);pDC->SetTextColor(RGB(0, 255, 0));
pDC->SetBkColor(RGB(103, 103, 103));break;
case IDC_XIEYIZHEN:m_SetFont.CreatePointFont(200, _T("TimesNewRoman"));
pDC->SelectObject(&m_SetFont);pDC->SetTextColor(RGB(0, 0, 255));
pDC->SetBkColor(RGB(0, 255, 0));break;default:break;}

增加打開串口的方法setComm:

CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
CString temp;temp += m_DataConfig->getBotelv(); temp += ",";
temp += m_DataConfig->getJiaoyan(); temp += ",";    temp += m_DataConfig->getShuju();
temp += ",";    temp += m_DataConfig->getTingzhi();
this->c_Comm.put_CommPort(atoi(m_DataConfig->getComm()));
this->c_Comm.put_InBufferSize(1024);this->c_Comm.put_OutBufferSize(1024);
this->c_Comm.put_InputLen(0);this->c_Comm.put_InputMode(1);
this->c_Comm.put_RThreshold(1);this->c_Comm.put_Settings(temp);
if (!this->c_Comm.get_PortOpen()) {this->c_Comm.put_PortOpen(TRUE);
AfxMessageBox("串口打開成功");this->c_Comm.put_InBufferCount(0);}
else {AfxMessageBox("串口打開失敗,請重試");}

增加數據顯示到實時流量折線圖的方法setTChartData:

CTeeData * m_Onedata;CString temp;
CString tt;CSeries viewdata= CSeries)this->c_TChartData.Series(0);
tt = "實時流量:";temp.Format("%.3f", this->m_Dataview);
tt += temp;tt += "  m3/s";GetDlgItem(IDC_DATAVIEW)->SetWindowText(tt);
viewdata.Clear();   for (int i = 0; i < this->m_ViewDatas->GetSize(); i++) {
m_Onedata = (CTeeData *)this->m_ViewDatas->GetAt(i);
viewdata.Add(m_Onedata->m_Viewvalue, m_Onedata->m_ViewData, NULL);}

增加字符串轉16進制數的方法String2Hex:

int C管道流量採集Dlg::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;}

增加串口數據幀格式化方法:

char C管道流量採集Dlg::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);}

增加16進制轉10進制的方法:

int C管道流量採集Dlg::HexToDem(CString str)
{int dem = 0;for (int i = 0; i<str.GetLength(); i++){dem = dem * 16;
if ((str[i] <= '9') && (str[i] >= '0'))        //0~9之間的字符dem += str[i] - '0';
else if ((str[i] <= 'F') && (str[i] >= 'A'))   //A~F之間的字符dem += str[i] - 'A' + 10;
else if ((str[i] <= 'f') && (str[i] >= 'a'))   //a~f之間的字符dem += str[i] - 'a' + 10;
else    return -1;                          //出錯時返回-1}return dem;}

增加串口數據接收的事件處理方法OnCommMscomm1:

VARIANT variant_inp;COleSafeArray safearray_inp;LONG len, k;
BYTE rxdata[2048]; //設置BYTE數組 An 8-bit integerthat is not signed.
CString strtemp = "";CString resultmess = "";BYTE bt;
if (this->c_Comm.get_CommEvent() == 2) //事件值爲2表示接收緩衝區內有字符
{variant_inp = this->c_Comm.get_Input(); //讀緩衝區
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型變量{bt = *(char*)(rxdata + k); //字符型
strtemp.Format("%02X", bt);resultmess += strtemp;   strtemp = "";}}
this->message += resultmess;    this->c_Comm.put_InBufferCount(0);
this->timerflag++;if(this->timerflag == 3)SetTimer(2, 300, NULL);

增加定時器時間到的處理方法,在屬性的消息中重寫WM_TIMER的處理方法OnTimer。

CString temp;
CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
CString send;CString strtemp;CString tmp;SYSTEMTIME m_Systm;//添加發送數據
//在接收數據裏處理//添加到數據庫等等
CByteArray hexdata;uint8_t addressh;uint8_t addressl;uint8_t len;uint8_t prop;
uint8_t station;uint8_t pass;uint8_t timey;uint8_t timem;uint8_t timed;uint8_t timeh;
uint8_t timemin;uint8_t times;uint16_t crc_result;uint8_t crc_y[10];
CString xieyizhentemp = "";CString ttt = "";CString xieyizhen = "";switch (nIDEvent) {
case 1:temp = "";   send = "";GetLocalTime(&m_Systm);this->m_Datatime = m_Systm;
addressh = strtol("EB", NULL, 16);addressl = strtol("90", NULL, 16);
len = strtol("0C", NULL, 16);prop = strtol("00", NULL, 16);
station = strtol("02", NULL, 16);pass = strtol("02", NULL, 16);
tmp.Format("%d", m_Systm.wYear % 100);timey = strtol(tmp, NULL, 16);
tmp.Format("%d", m_Systm.wMonth);   timem = strtol(tmp, NULL, 16);
tmp.Format("%d", m_Systm.wDay);timed = strtol(tmp, NULL, 16);
tmp.Format("%d", m_Systm.wHour);timeh = strtol(tmp, NULL, 16);
tmp.Format("%d", m_Systm.wMinute);timemin = strtol(tmp, NULL, 16);
tmp.Format("%d", m_Systm.wSecond);times = strtol(tmp, NULL, 16);
crc_y[0] = len;crc_y[1] = prop;crc_y[2] = station;crc_y[3] = pass;crc_y[4] = timey;
crc_y[5] = timem;crc_y[6] = timed;crc_y[7] = timeh;crc_y[8] = timemin;
crc_y[9] = times;   crc_result = CRC16((uint8_t*)crc_y, 10);
temp.Format("%02X ", addressh);send += temp;temp.Format("%02X ", addressl);
send += temp;temp.Format("%02X ", len);send += temp;temp.Format("%02X ", prop);
send += temp;temp.Format("%02X ", station);send += temp;
temp.Format("%02X ", pass);send += temp;temp.Format("%02X ", timey);
send += temp;temp.Format("%02X ", timem);send += temp;
temp.Format("%02X ", timed);send += temp;temp.Format("%02X ", timeh);
send += temp;temp.Format("%02X ", timemin);send += temp;
temp.Format("%02X ", times);send += temp;temp.Format("%04X", crc_result);
send += temp;send.Insert(send.GetLength() - 2, " ");    xieyizhen = "發送:";
xieyizhen += send;SetDlgItemText(IDC_XIEYIZHEN, xieyizhen);
String2Hex(send, hexdata);this->c_Comm.put_Output(COleVariant(hexdata));break;
case 2:if (this->message.GetLength() == 38 && this->timerflag == 3 && KillTimer(2)) {
xieyizhentemp = this->message;for (int i = 2; i < xieyizhentemp.GetLength(); i += 3) {
xieyizhentemp.Insert(i, " ");}
GetDlgItemText(IDC_XIEYIZHEN, ttt);ttt += "\n返回:";ttt += xieyizhentemp;
SetDlgItemText(IDC_XIEYIZHEN, ttt);
this->timerflag = 0;strtemp += this->message.GetAt(14);
strtemp += this->message.GetAt(15);strtemp += this->message.GetAt(16);
strtemp += this->message.GetAt(17);strtemp += this->message.GetAt(18);
strtemp += this->message.GetAt(19);this->m_Dataview = HexToDem(strtemp) / 1000.0;
strtemp.Format("%d:%d:%d",this->m_Datatime.wHour,his->m_Datatime.wMinute,this->m_Datatime.wSecond);CTeeData * m_Onedata = new CTeeData(this->m_Dataview, strtemp);
this->m_ViewDatas->Add(m_Onedata);setTChartData();
strtemp.Format("%2d-%d-%d %d:%d:%d",this->m_Datatime.wYear,this->m_Datatime.wMonth,this->m_Datatime.wDay,this->m_Datatime.wHour,this->m_Datatime.wMinute,this->m_Datatime.wSecond);if (m_MysqlConnection->setData(this->m_Dataview, strtemp)) {
this->message = "";}else    {AfxMessageBox("加入數據庫失敗");return;}  }break;efault:break;}

對話框實現大小自適應,在自適應中控件的大小需要對應的改變。
首先增加自使用的頭文件easysize.h:

#ifndef __EASYSIZE_H_#define __EASYSIZE_H_#define ES_BORDER 0xffffffff
#define ES_KEEPSIZE 0xfffffffe#define ES_HCENTER 0x00000001
#define ES_VCENTER 0x00000002#define DECLARE_EASYSIZE \void __ES__RepositionControls(BOOL bInit);\void __ES__CalcBottomRight(CWnd *pThis, BOOL bBottom, int &bottomright, int &topleft, UINT id, UINT br, int es_br, CRect &rect, int clientbottomright);#define INIT_EASYSIZE __ES__RepositionControls(TRUE); __ES__RepositionControls(FALSE)#define UPDATE_EASYSIZE if(GetWindow(GW_CHILD)!=NULL) __ES__RepositionControls(FALSE)#define EASYSIZE_MINSIZE(mx,my,s,r) if(r->right-r->left < mx) { if((s == WMSZ_BOTTOMLEFT)||(s == WMSZ_LEFT)||(s == WMSZ_TOPLEFT)) r->left = r->right-mx; else r->right = r->left+mx; } if(r->bottom-r->top < my) { if((s == WMSZ_TOP)||(s == WMSZ_TOPLEFT)||(s == WMSZ_TOPRIGHT)) r->top = r->bottom-my; else r->bottom = r->top+my; }#define BEGIN_EASYSIZE_MAP(class) \void class::__ES__CalcBottomRight(CWnd *pThis, BOOL bBottom, int &bottomright, int &topleft, UINT id, UINT br, int es_br, CRect &rect, int clientbottomright) {\if(br==ES_BORDER) bottomright = clientbottomright-es_br;\else if(br==ES_KEEPSIZE) bottomright = topleft+es_br;\else { CRect rect2;\pThis->GetDlgItem(br)->GetWindowRect(rect2); pThis->ScreenToClient(rect2);\bottomright = (bBottom?rect2.top:rect2.left) - es_br;}}\void class::__ES__RepositionControls(BOOL bInit) { CRect rect,rect2,client; GetClientRect(client);#define END_EASYSIZE_MAP Invalidate(); UpdateWindow(); }#define EASYSIZE(id,l,t,r,b,o) \static int id##_es_l, id##_es_t, id##_es_r, id##_es_b;\if(bInit) {\GetDlgItem(id)->GetWindowRect(rect); ScreenToClient(rect);\if(o & ES_HCENTER) id##_es_l = rect.Width()/2; else {\if(l==ES_BORDER) id##_es_l = rect.left; else if(l==ES_KEEPSIZE) id##_es_l = rect.Width(); else {\GetDlgItem(l)->GetWindowRect(rect2); ScreenToClient(rect2);\id##_es_l = rect.left-rect2.right;}}\if(o & ES_VCENTER) id##_es_t = rect.Height()/2; else {\if(t==ES_BORDER) id##_es_t = rect.top; else if(t==ES_KEEPSIZE) id##_es_t = rect.Height(); else {\GetDlgItem(t)->GetWindowRect(rect2); ScreenToClient(rect2);\id##_es_t = rect.top-rect2.bottom;}}\if(o & ES_HCENTER) id##_es_r = rect.Width(); else { if(r==ES_BORDER) id##_es_r = client.right-rect.right; else if(r==ES_KEEPSIZE) id##_es_r = rect.Width(); else {\GetDlgItem(r)->GetWindowRect(rect2); ScreenToClient(rect2);\id##_es_r = rect2.left-rect.right;}}\if(o & ES_VCENTER) id##_es_b = rect.Height(); else { if(b==ES_BORDER) id##_es_b = client.bottom-rect.bottom; else if(b==ES_KEEPSIZE) id##_es_b = rect.Height(); else {\GetDlgItem(b)->GetWindowRect(rect2); ScreenToClient(rect2);\id##_es_b = rect2.top-rect.bottom;}}\} else {\int left,top,right,bottom; BOOL bR = FALSE,bB = FALSE;\if(o & ES_HCENTER) { int _a,_b;\if(l==ES_BORDER) _a = client.left; else { GetDlgItem(l)->GetWindowRect(rect2); ScreenToClient(rect2); _a = rect2.right; }\if(r==ES_BORDER) _b = client.right; else { GetDlgItem(r)->GetWindowRect(rect2); ScreenToClient(rect2); _b = rect2.left; }\left = _a+((_b-_a)/2-id##_es_l); right = left + id##_es_r;} else {\if(l==ES_BORDER) left = id##_es_l;\else if(l==ES_KEEPSIZE) { __ES__CalcBottomRight(this,FALSE,right,left,id,r,id##_es_r,rect,client.right); left = right-id##_es_l;\} else { GetDlgItem(l)->GetWindowRect(rect2); ScreenToClient(rect2); left = rect2.right + id##_es_l; }\if(l != ES_KEEPSIZE) __ES__CalcBottomRight(this,FALSE,right,left,id,r,id##_es_r,rect,client.right);}\if(o & ES_VCENTER) { int _a,_b;\if(t==ES_BORDER) _a = client.top; else { GetDlgItem(t)->GetWindowRect(rect2); ScreenToClient(rect2); _a = rect2.bottom; }\
if(b==ES_BORDER) _b = client.bottom; else { GetDlgItem(b)->GetWindowRect(rect2); ScreenToClient(rect2); _b = rect2.top; }\top = _a+((_b-_a)/2-id##_es_t); bottom = top + id##_es_b;} else {\if(t==ES_BORDER) top = id##_es_t;\else if(t==ES_KEEPSIZE) { __ES__CalcBottomRight(this,TRUE,bottom,top,id,b,id##_es_b,rect,client.bottom); top = bottom-id##_es_t;\} else { GetDlgItem(t)->GetWindowRect(rect2); ScreenToClient(rect2); top = rect2.bottom + id##_es_t; }\if(t != ES_KEEPSIZE) __ES__CalcBottomRight(this,TRUE,bottom,top,id,b,id##_es_b,rect,client.bottom);}\GetDlgItem(id)->MoveWindow(left,top,right-left,bottom-top,FALSE);\}#endif //__EASYSIZE_H_

然後重寫OnSize方法:

UPDATE_EASYSIZE;

在主對話框的cpp文件中最後部分添加控件映射:

BEGIN_EASYSIZE_MAP(C管道流量採集Dlg)
    EASYSIZE(IDC_TC_DATA, ES_BORDER, IDC_XIEYIZHEN, ES_BORDER, ES_BORDER, 0)
    EASYSIZE(IDC_XIEYIZHEN, ES_BORDER, IDC_DATAVIEW, ES_BORDER, IDC_TC_DATA,0)
    EASYSIZE(IDC_DATAVIEW, ES_BORDER, ES_BORDER, ES_BORDER, IDC_XIEYIZHEN, 0)
END_EASYSIZE_MAP

在初始化方法中添加INIT_EASYSIZE;,在類的聲明中最開始添加DECLARE_EASYSIZE。
管道流量採集.h:

// 管道流量採集.h : PROJECT_NAME 應用程序的主頭文件
#pragma once
#ifndef __AFXWIN_H__
    #error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif
#include "resource.h"       // 主符號
// C管道流量採集App: 
// 有關此類的實現,請參閱 管道流量採集.cpp
//
class C管道流量採集App : public CWinApp
{
public:
    C管道流量採集App();
// 重寫
public:
    virtual BOOL InitInstance();
// 實現
    DECLARE_MESSAGE_MAP()
};
extern C管道流量採集App theApp;

管道流量採集.cpp:

// 管道流量採集.cpp : 定義應用程序的類行爲。
#include "stdafx.h"
#include "管道流量採集.h"
#include "管道流量採集Dlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// C管道流量採集App
BEGIN_MESSAGE_MAP(C管道流量採集App, CWinApp)
    ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
// C管道流量採集App 構造
C管道流量採集App::C管道流量採集App()
{
    // 支持重新啓動管理器
    m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
    // TODO: 在此處添加構造代碼,
    // 將所有重要的初始化放置在 InitInstance 中
}
// 唯一的一個 C管道流量採集App 對象
C管道流量採集App theApp;
// C管道流量採集App 初始化
BOOL C管道流量採集App::InitInstance()
{
    // 如果一個運行在 Windows XP 上的應用程序清單指定要
    // 使用 ComCtl32.dll 版本 6 或更高版本來啓用可視化方式,
    //則需要 InitCommonControlsEx()。  否則,將無法創建窗口。
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    // 將它設置爲包括所有要在應用程序中使用的
    // 公共控件類。
    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);
    OleInitialize(NULL);
    AfxEnableControlContainer();
    CWinApp::InitInstance();
    AfxEnableControlContainer();
    // 創建 shell 管理器,以防對話框包含
    // 任何 shell 樹視圖控件或 shell 列表視圖控件。
    CShellManager *pShellManager = new CShellManager;
    // 激活“Windows Native”視覺管理器,以便在 MFC 控件中啓用主題
CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
    // 標準初始化
    // 如果未使用這些功能並希望減小
    // 最終可執行文件的大小,則應移除下列
    // 不需要的特定初始化例程
    // 更改用於存儲設置的註冊表項
    // TODO: 應適當修改該字符串,
    // 例如修改爲公司或組織名
    SetRegistryKey(_T("應用程序嚮導生成的本地應用程序"));
    C管道流量採集Dlg dlg;
    m_pMainWnd = &dlg;
    INT_PTR nResponse = dlg.DoModal();
    if (nResponse == IDOK)
    {
        // TODO: 在此放置處理何時用
        //  “確定”來關閉對話框的代碼
    }
    else if (nResponse == IDCANCEL)
    {
        // TODO: 在此放置處理何時用
        //  “取消”來關閉對話框的代碼
    }
    else if (nResponse == -1)
    {
        TRACE(traceAppMsg, 0, "警告: 對話框創建失敗,應用程序將意外終止。\n");
        TRACE(traceAppMsg, 0, "警告: 如果您在對話框上使用 MFC 控件,則無法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");
    }
    // 刪除上面創建的 shell 管理器。
    if (pShellManager != NULL)
    {
        delete pShellManager;
    }
#ifndef _AFXDLL
    ControlBarCleanUp();
#endif
    // 由於對話框已關閉,所以將返回 FALSE 以便退出應用程序,
    //  而不是啓動應用程序的消息泵。
    return FALSE;
}

5.8數據庫額外操作

      首先在互聯網上下載32位的數據庫文件,如果本機系統是32的,那麼可以不用下載,如果實在找不到下載的地址,可以到32位的數據庫安裝目錄中拷貝文件:
這裏寫圖片描述


圖19數據庫32連接文件圖

【項目】->【屬性】->【配置屬性】->【常規屬性】->【字符集】->【多字節字符集】
【配置屬性】->【C/C++】->【常規】->【附加包含目錄】->【C:\Program Files\MySQL\MySQL Server 5.7\include;%(AdditionalIncludeDirectories)】
【鏈接器】->【常規】->【附加庫目錄】->【C:\Program Files\MySQL\MySQL Server 5.7\lib;%(AdditionalLibraryDirectories)】
【鏈接器】->【輸入】->【附加依賴項】->【libmysql32.lib;%(AdditionalDependencies)】
然後把libmysql32.dll重命名爲libmysql.dll並且放到Debug目錄下。

5.9常見錯誤

預編譯無法使用或這打開**預編譯文件:
【項目】->【屬性】->【配置屬性】->【C/C++】->【預編譯頭】->【預編譯頭】,如果原來是使用改成創建,原來是創建改成使用。
*.dll文件無法加載:
這裏寫圖片描述


圖20錯誤解決設置圖

第一次編譯時間會比較長,無法打開的dll文件會從互聯網上下載,所以必須聯網。

5.10替換標題欄圖標

      MFC默認的標題欄圖標替換首先需要找到自己需要替換的ico文件,然後類似導入圖片一樣導入到工程中,其ID爲IDI_ICON1,並且把ico文件放到res文件夾下,然後打開resource.hz增加:

#define IDI_ICON1                       100

最後在主對話框的構造方法中添加:

m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);

5.11打包

      在前面的操作都沒有問題,且debug調試全部通過後,即可進入這個操作。
首先切換到Release模式。
這裏寫圖片描述


圖21切換模式圖

      然後重寫設置第8部分的所有操作,操作成功後重新生成解決方案,當Release中調試通過後,到互聯網上下載打包模板。
這裏寫圖片描述


圖22打包模板詳細信息

      把打包模板安裝好後,在工程的解決方案視圖中右鍵整個解決方案->【添加】->【新建項目】。
這裏寫圖片描述


圖23創建安裝包工程圖

此時整個解決方案中有兩個項目:
這裏寫圖片描述


圖24解決方案圖

右鍵安裝包項目->【Add】->【項目輸出】->【主輸出】,其次:
這裏寫圖片描述


圖25添加模塊圖

添加所有32位的文件。
右鍵安裝包項目->【View】->【文件系統】,然後添加Release文件夾中除去exe文件的所有文件。
這裏寫圖片描述


圖26安裝包文件系統圖

      其中Pipe Line.ico是應用程序安裝成功後快捷方式的圖標,也需要導入;msiexec.exe是32位系統中卸載程序的,以及折線圖和串口的ocx文件,這些文件都是安裝目錄中的文件。User’s Desktop是安裝包安裝成功後在用戶桌面的快捷方式,首先創建一個主輸出的快捷方式和一個卸載程序的快捷方式,然後重命名爲自己需要的名字,設置主輸出的icon爲添加的ico圖標;修改卸載程序的快捷方式的Arguments的屬性值爲/x {D1AB7D8F-BCD0-4F41-857B-549373B3EDE5},大括號中的數字在安裝包的屬性的ProductCode中的數值。同樣在開始菜單中拷貝這兩個文件。
右鍵整個解決方案->【批生成】。
這裏寫圖片描述


圖27批生成配置圖

選中圖中的兩個勾,選擇重新生成。如果一切順利將會在輸出窗口顯示。
這裏寫圖片描述


圖28安裝包生成成功圖

此時,安裝包文件在工程文件下安裝包文件夾的Release文件夾下。
這裏寫圖片描述


圖29安裝包位置圖

六、 總結

      完成整個實驗可以掌握RS-485原理、磁漩渦流量傳感器、MODBUS通信等以及較強的MFC程序編程能力。
      在整個實驗中,實驗比較大,難點比較多,包括數據庫的連接、註冊表操作、外部插件的導入和使用、對話框菜單項添加、查詢數據幀的組裝和解析、定時器的使用、快捷鍵的添加、程序的打包等等。但是完成實驗後的收穫也是非常大的,是一個值得完成的實驗項目。
      我的畢業設計是工程類型的,並不是學術研究型的,所以要求有論文,實驗指導書,實例程序,軟件使用說明書四部分。
      這只是其中的實驗指導書,因爲有硬件設備,如果沒有硬件設備可以使用VSPD和串口調試助手來模擬。
      現在畢業設計已經完成了,包括論文查重,答辯等等。之前沒有寫出來一方面是沒有時間來上傳,我有pdf和word版本,但是上傳到csdn還是需要很多編輯的,我不會直接上傳這些格式的文章。另一方面實驗指導書和論文中有一部分是意思大致相同,擔心查重結果的影響。
      因爲畢業設計中使用的技術都是很老的技術,所以畢業設計論文怎麼寫重複率都很高,我盡力的降重了十好幾次,重複率還是在15左右,所以不敢在查重之前放出來。


      如果我的文章中有什麼錯誤,畢竟很大,可能是我沒有注意到的地方,請大家直接在評論區中指出,我看到後有時間盡力回覆。

      源代碼下載地址
https://download.csdn.net/download/a18792721831/10511739
      對話框控件資源文件下載地址
https://download.csdn.net/download/a18792721831/10511757
      easysize和crc文件下載地址
https://download.csdn.net/download/a18792721831/10511751
      對話框插件文件下載地址
https://download.csdn.net/download/a18792721831/10511759
      打包的卸載程序文件下載地址
https://download.csdn.net/download/a18792721831/10511754
打包卸載不建議下載,在32位windows操作系統可以找到,網上也有資源可以免費下載,但是csdn積分下載沒有0分,分數不足的請勿下載哦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章