天天看點

序列槽通訊項目0x00 boost配置0x01 簡單mfc小程式0x02 序列槽通訊函數與軟體0x03 簡單的winform程式0x04

起因:

周一王老師給了我一個小項目,獨立的小程式,用啥語言都行

可是當時我電腦硬碟壞了,啥東西都沒有,就放了幾天

今天想來就花些時間搞定它

一個從沒玩過的方向獨立做程式,内容涉及較多,總用時6個半小時。

涉及内容C++boost庫配置 簡單的mfc 簡單的winform 序列槽通訊相關軟體和資料 C#字元格式處理(這些我都不熟悉)

本篇部落格是今天獨立完成項目的完全過程,類似于日志,為的是以後遇到類似問題的時候可以節省時間。

0x00 boost配置

剛上手的時候看看需求,序列槽通訊相關的,就想起來以前做過的一個Box項目,裡面用到過這些東西,就拿出來看看,不錯,可以用,于是打算用MFC寫一個,因為boost庫被我弄沒了,就打算再弄一個,想想再編譯一個花太長時間了,就去網上找了一個編譯好的1.55版本的,直接拿來用。

//boost 1.55已編譯,已傳到百度雲http://pan.baidu.com/s/1gfxeXsZ

配置的話,點開項目,目前項目的屬性,然後直接看圖,改包含目錄,和庫目錄,

包含目錄就是整個的頭檔案所在的目錄,比如#include “boost/format.hpp”,包含目錄就是boost這個檔案夾的上級目錄,

庫目錄就是實作的cpp或者連結庫所在的地方,總之這兩個就是頭檔案在的地方和實作檔案所在的地方。

結合下圖了解

序列槽通訊項目0x00 boost配置0x01 簡單mfc小程式0x02 序列槽通訊函數與軟體0x03 簡單的winform程式0x04

0x01 簡單mfc小程式

搞定了,用MFC拖幾個控件進去,弄個界面,然後發現自己不能改裡面的内容,很是尴尬

想起來以前TCP老師好像做的時候加了變量什麼的,于是去網上查一查。

才明白MFC是要加變量才能玩文本框控件。

序列槽通訊項目0x00 boost配置0x01 簡單mfc小程式0x02 序列槽通訊函數與軟體0x03 簡單的winform程式0x04

如上圖,添加一個 value型的 CString類型的變量,

我就可以對 結果右邊那欄 的内容進行控制了。

于是我又添加了三個,順便改了 他們的初始内容

例如這樣:

序列槽通訊項目0x00 boost配置0x01 簡單mfc小程式0x02 序列槽通訊函數與軟體0x03 簡單的winform程式0x04

tb1 tb2 tb3 tb4就是我給這些變量起的名字

會玩了變量,這個MFC就算入門了把,這個就算我一個MFC程式了。

0x02 序列槽通訊函數與軟體

項目要求是打開序列槽并向序列槽發送資料

那麼至少要實作這兩個功能,可是我都不知道序列槽是個啥子,百度呗

通過百度我知道了這兩個軟體。

一個功能是 虛拟序列槽 另一個是 操作和檢視序列槽傳入傳出的資料

這個東西可以讓我知道 我的程式管不管用,因為第一個軟體的功能是這樣的

模拟兩個虛拟序列槽,你可以打開他們,你可以并通過這個軟體檢視這兩個序列槽的狀态

最重要的是,這兩個序列槽是連接配接的,意味着 其中一個序列槽發送消息,一定是另一個序列槽接受消息,

利用這一點,我們 測試的時候,用自己的軟體打開第一個序列槽,發送消息,就可以通過第二個序列槽檢視我們是否發送成功。程式是否成功了。

序列槽通訊項目0x00 boost配置0x01 簡單mfc小程式0x02 序列槽通訊函數與軟體0x03 簡單的winform程式0x04

//這兩個軟體 百度雲http://pan.baidu.com/s/1kU4Odkb

函數的話,用到了boost庫

而且我調試的時候出了點問題還沒有解決,是以我換成了C#來做

下面這倆可以不用看,因為C#實作更友善,畢竟語言隻是工具,什麼實用用什麼。

實作檔案

#include "stdafx.h"
//  COM.c//---------------------------------------------------------------------------
#pragma hdrstop
#include <stdio.h>

#include "MyNewCom_tt.h"

#include <string>

#include <boost/format.hpp>
using namespace std;
//---------------------------------------------------------------------------
#pragma package( smart_init)


//序列槽句柄
HANDLE m_COM_Handle = NULL;
//兩個信号全局變量(序列槽操作用)
OVERLAPPED m_OverlappedRead, m_OverlappedWrite;


//*************************************************************************
//函 數 名:OpenCom
//輸 入:long lngPort,序列槽号
// char *cfgMessage,配置資訊,形如"9600,e,8,1" 
// long lngInSize,接收緩沖區大小
// long lngOutSize 發送緩沖區大小 
//輸 出:long
//功能描述:打開序列槽
//全局變量:
//調用子產品:
//作 者:葉帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本:
//*************************************************************************
long OpenCom(long nPort, char *cfgMessage, long lngInSize, long lngOutSize)
{
    try {
//      wchar_t szMsg[255];
        DCB dcb; //打開端口
        wstring sPort;

        if (nPort>)
            sPort = (boost::wformat(L"\\\\.\\COM%d") % nPort).str();
        else
            sPort = (boost::wformat(L"COM%d") % nPort).str();

        m_COM_Handle = CreateFile((LPCSTR)sPort.c_str(),
            GENERIC_READ | GENERIC_WRITE,
            , NULL, OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
            NULL);
        if (m_COM_Handle == NULL)
            return(  );
        //清空異步讀寫參數
        memset(&(m_OverlappedRead),
            , sizeof
            (OVERLAPPED));
        memset(&(m_OverlappedWrite),
            , sizeof
            (OVERLAPPED));
        //設定dcb塊
        dcb.DCBlength   =   sizeof(DCB); //長度 
        GetCommState(m_COM_Handle, &dcb ); //波特率,奇偶校驗,資料位,停止位如:9600, n, 8, 1 
        auto szMsg = (boost::wformat(L"COM%d:%s")%nPort%cfgMessage).str();
        BuildCommDCB((LPCSTR)szMsg.c_str(), &dcb);
            //------------------------------
            dcb.fBinary = TRUE;
            //二進制方式
            dcb.fOutxCtsFlow = FALSE;
            //不用CTS檢測發送流控制
            dcb.fOutxDsrFlow = FALSE;
            //不用DSR檢測發送流控制
            dcb.fDtrControl = DTR_CONTROL_DISABLE;
            //禁止DTR流量控制
            dcb.fDsrSensitivity = FALSE;
            //對DTR信号線不敏感
            dcb.fTXContinueOnXoff = TRUE;
            //檢測接收緩沖區
            dcb.fOutX = FALSE;
            //不做發送字元控制
            dcb.fInX = FALSE;
            //不做接收控制
            dcb.fErrorChar = FALSE;
            //是否用指定字元替換校驗錯的字元
            dcb.fNull = FALSE;
            //保留NULL字元
            dcb.fRtsControl = RTS_CONTROL_ENABLE;
            //允許RTS流量控制
            dcb.fAbortOnError = FALSE;
            //發送錯誤後,繼續進行下面的讀寫操作
            dcb.fDummy2 = ;
            //保留 dcb.wReserved=0;
            //沒有使用,必須為0
            dcb.XonLim = ;
            //指定在XOFF字元發送之前接收到緩沖區中可允許的最小位元組數
            dcb.XoffLim = ;
            //指定在XOFF字元發送之前緩沖區中可允許的最小可用位元組數
            dcb.XonChar = ;
            //發送和接收的XON字元
            dcb.XoffChar = ;
            //發送和接收的XOFF字元
            dcb.ErrorChar = ;
            //代替接收到奇偶校驗錯誤的字元
            dcb.EofChar = ;
            //用來表示資料的結束
            dcb.EvtChar = ;
            //事件字元,接收到此字元時,會産生一個事件
            dcb.wReserved1 = ;
            //沒有使用
            //
            dcb.BaudRate = ; //波特率
            //
            dcb.Parity=;   //奇偶校驗
            //
            dcb.ByteSize=;
            //資料位 //dcb.StopBits=0;
            //停止位 //------------------------------
            if (dcb.Parity ==  )
                //              0 - 4 = None, Odd, Even, Mark, Space
            {
                dcb.fParity = FALSE;
                //奇偶校驗無效
            }
            else
            {
                dcb.fParity = TRUE; //奇偶校驗有效
            }
            szMsg = (boost::wformat(L"COM%d:%d,%d,%d,%d(InSize:%ld, OutSize : %ld)")
                %nPort%dcb.BaudRate% dcb.Parity%dcb.ByteSize%dcb.StopBits%lngInSize%lngOutSize).str();
            //讀寫逾時設定
            //西門子參數
            COMMTIMEOUTS CommTimeOuts; 
            CommTimeOuts.ReadIntervalTimeout = ;
            SetCommTimeouts(m_COM_Handle, &CommTimeOuts);
            //擷取信号句柄
            m_OverlappedRead.hEvent =CreateEvent(NULL,TRUE,FALSE,NULL); 
            m_OverlappedWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
            if (!SetCommState(m_COM_Handle, &dcb)  //判斷設定參數是否成功
                || !SetupComm(m_COM_Handle, lngInSize, lngOutSize) || //設定輸入和輸出緩沖區是否成功
                m_OverlappedRead.hEvent == NULL ||
                m_OverlappedWrite.hEvent == NULL)
            {
                DWORD dwError = GetLastError();
                //擷取最後的錯誤資訊
                if (m_OverlappedRead.hEvent != NULL) 
                    CloseHandle(m_OverlappedRead.hEvent); 
                if ( m_OverlappedWrite.hEvent != NULL) 
                    CloseHandle(m_OverlappedWrite.hEvent);
                CloseHandle(m_COM_Handle);
                m_COM_Handle = NULL; 
                return  dwError;
            } 
            return ();
    }
    catch (...)
    {
        return -;
    }
} //*************************************************************************
//函 數 名:CloseCom
//輸 入:
//輸出:long //功能描述:關閉序列槽
//全局變量:
//調用子產品:
//作 者:葉帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本:
//*************************************************************************
long CloseCom()
{
    try {
        if (m_COM_Handle    ==NULL)
            return();
        SetCommMask(m_COM_Handle, NULL); SetEvent(m_OverlappedRead.hEvent);
        SetEvent(m_OverlappedWrite.hEvent); 
        if (m_OverlappedRead.hEvent != NULL) 
            CloseHandle(m_OverlappedRead.hEvent);
        if (m_OverlappedWrite.hEvent != NULL)
            CloseHandle(m_OverlappedWrite.hEvent);
        if (CloseHandle(m_COM_Handle) == FALSE)
            return ();
        m_COM_Handle=NULL;
    }
    catch (...)
    {
        return();
    }
    return( );
}
//*************************************************************************
//函 數 名:SendData
//輸 入:BYTE *bytBuffer,資料 
// long lngSize 個數
//輸 出:long
//功能描述:發送資料
//全局變量:
//調用子產品:
//作 者:葉帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本: //*************************************************************************
long SendData(uchar*bytBuffer, long lngSize)
{
    try {
        if (m_COM_Handle    ==  NULL)
            return( -); 
        DWORD dwBytesWritten = lngSize;
        BOOL bWriteStat;
        COMSTAT ComStat; DWORD dwErrorFlags;
        ClearCommError(m_COM_Handle, &dwErrorFlags, &ComStat);
        bWriteStat = WriteFile(m_COM_Handle,bytBuffer, lngSize, &dwBytesWritten,
            &(m_OverlappedWrite));
        if (!bWriteStat) {
            if (GetLastError() == ERROR_IO_PENDING)
            {
                GetOverlappedResult(m_COM_Handle, &(m_OverlappedWrite), &dwBytesWritten, TRUE);
                //等待直到發送完畢
            }
            else
            {
                dwBytesWritten = ;
            }
        }
        return  (long)dwBytesWritten;
    }
    catch (...)
    {
        return  -;
    }
} //*************************************************************************
//函 數 名:AcceptData
//輸 入:BYTE *bytBuffer,資料 
// long lngSize 個數
//輸 出:long
//功能描述:讀取資料
//全局變量:
//調用子產品:
//作 者:葉帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本:
//*************************************************************************
long AcceptData(uchar *bytBuffer, long lngSize)
{
    try {
        if (m_COM_Handle == NULL)
            return( -); 
        DWORD lngBytesRead = lngSize;
        BOOL fReadStat;
        DWORD dwRes = ; 
        //讀資料 
        fReadStat=ReadFile(m_COM_Handle,bytBuffer,lngSize,&lngBytesRead,&(m_OverlappedRead));
        //Sleep(1);
        if (!fReadStat) {
            if (GetLastError()==ERROR_IO_PENDING)
                //重疊 I/O 操作在進行中
            {
                dwRes = WaitForSingleObject(m_OverlappedRead.hEvent, );
                //等待,直到逾時
                switch (dwRes)
                {
                    case
                    WAIT_OBJECT_0:
                        //讀完成 if(GetOverlappedResult(m_COM_Handle,&(m_OverlappedRead),&lngBytesRead,FALSE)==0)
                    { //錯誤
                        return -; } break;
                    case
                    WAIT_TIMEOUT:
                        //逾時 
                        return -; break;
                    default:
                        //WaitForSingleObject錯誤
                        break;
                }
            }
        }
        return lngBytesRead;
    }
    catch (...)
    {
        return
            -;
    }
} //*************************************************************************
//函 數名:ClearAcceptBuffer //輸 入:
//輸出:long //功能描述:清除接收緩沖區
//全局變量:
//調用子產品:
//作 者:葉帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本: //*************************************************************************
long  ClearAcceptBuffer()
{
    try {
        if (m_COM_Handle == NULL)
            return( -);
        PurgeComm(m_COM_Handle, PURGE_RXABORT | PURGE_RXCLEAR);
        //
    }
    catch (...)
    {
        return();
    }
    return();
} //*************************************************************************
//函 數 名:ClearSendBuffer //輸 入:
//輸出:long //功能描述:清除發送緩沖區
//全局變量:
//調用子產品:
//作 者:葉帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本: 
//*************************************************************************
long  ClearSendBuffer()
{
    try {
        if (m_COM_Handle == NULL)
            return( -);
        PurgeComm(m_COM_Handle, PURGE_TXABORT | PURGE_TXCLEAR);
        //
    }
    catch (...)
    {
        return ();
    } 
    return ();
}
           

頭檔案

//COM.h
#ifndef  COMH_WWQ
#define  COMH_WWQ
//#include "vcl.h"
#include <Windows.h>
#pragma package( smart_init)
#define uchar unsigned char
long  OpenCom(long, char *, long, long);
long CloseCom();
long SendData(uchar*, long);
long  AcceptData(uchar *bytBuffer, long);
long ClearAcceptBuffer();
long  ClearSendBuffer();



#endif
           

0x03 簡單的winform程式

對于.net 我以前做資料結構課設的時候接觸過,玩過兩周的WPF,感覺真的簡單,友善還漂亮。

winform還是一個程式都沒寫過。不過感覺差不多吧,就是醜了點 =v=。

同樣的整個界面,拖控件。

序列槽通訊項目0x00 boost配置0x01 簡單mfc小程式0x02 序列槽通訊函數與軟體0x03 簡單的winform程式0x04

比MFC友善的是這裡不用添加變量。

每一個控件都是一個對象,它的所有屬性和方法給用的都基本能用。

比如上圖的控件,都有一個屬性叫做Text,我們可以直接在背景代碼修改Text來改界面裡Text的值

比MFC友善不知道那裡去了。

同樣的是輕按兩下控件添加函數,對于Button控件就是點選觸發,對于textbox就是改變值觸發。

接下來就是序列槽相關的了。

首先整個全局變量

System.IO.Ports.SerialPort com1 = null;

然後這樣

string Port = "com1";
com1 = new System.IO.Ports.SerialPort(Port);
           

就是弄了一個操作序列槽相關的對象了

接下來

就是打開

寫序列槽資料

和關閉

com1.Open();
com1.Write("233");
com1.Close();
           

是不是超級簡單。。封裝好的東西就是這麼用。。在VS2015下還有函數的中文提示,寫不出來都難。

0x04

然後就是一個字元串處理相關的東西

用到了Convert這個類

直接上需求和我的解決代碼

序列槽通訊項目0x00 boost配置0x01 簡單mfc小程式0x02 序列槽通訊函數與軟體0x03 簡單的winform程式0x04
int calccc(string[] send)
        {
            int cc = ;
            foreach (string i in send) cc += Convert.ToInt32(i, );
            cc = (~cc) + ;
            return cc;
        }
           
textBox2.Text = "000911";
string sendA = "A5 FF 08 1E";
string id = "";
foreach (int i in textBox2.Text)
    id += " " + Convert.ToString(i, );

string[] sendB = (sendA + id).Split(' ');
int cc = calccc(sendB);

string CC = Convert.ToString(cc, );
string send = sendA + id + " " + CC[CC.Length - ] + CC[CC.Length - ];
string[] sendC = send.Split(' ');

byte[] buff = new byte[];
for (int i = ; i < ; ++i)
    buff[i] = (byte)Convert.ToInt32(sendC[i], );

com1.Write(buff, , );
           

總結:

感覺還可以,自己解決問題的思路還是沒問題,每次都玩一個沒玩過新領域,解決問題的能力還是比較強的,最近感受越來越深的是:知識總是有用的,隻要學會了,早晚會用的到。

換句話說就是 多一份知識,多一條思路。