對項目進行代碼重構


    臨近公司放假,也好在年前對這次項目的一項總結(包括代碼)。剛分配到這份項目時,我認為自己可以完成這次的項目,但是在項目的開發過程中,還是遇到許多的問題,總的來說,分為以下幾點:

    1.前期對項目的背景不是很清楚(我一開始以為只要拿到項目就開始Coding,完成項目,其實不是這樣);

    2.文檔寫的不夠完善(只寫了需求分析、概要設計、沒有數據庫設計,因為文件都是存放在XML文檔里);

    3.對使用的技術不會(操作RS232串口,以前在學校從來沒學過這些,當然,也不需要學習這些。本人認為,自己主動去學和學校所教最大的區別在於主動是有意識的去學,而學校所教是被動的);

    4.與老板(客戶)的溝通不夠,客戶那邊一有新的需求,就馬上換成新的需求,然后換來換去,弄的心情很不爽,特別是一個項目需要分成好幾種類型,比如,四川省的我要這種,福建省的我要那種,北京市的又是另外的,而且還是同時更新。所以改的比較痛苦,也很糾結。(現在已改用OO的方法);

    5.最重要的是我自己對技術看的太輕松了,我認為技術會了就是會了,其實太天真了~ ~(其實是看個人的心態拉,我認為自己還Ok)。

 

     所以,我一直在改變、進步!好了,下面是項目中一個串口操作類重構后的Code。

     這里我專門寫了一個類來處理對串口的操作,主要是write、read,其中有用到包括delegate、event、lock、多線程。

     首先,實例化串行端口,有端口名稱 波特率 奇偶校驗位 數據位 停止位這些。然后在Program實例化這個串口操作類。

 SettingClass sc=new SettingClass();
    public class SettingClass
{
/// <summary>
/// 實例化串行端口資源 端口名稱 波特率 奇偶校驗位 數據位 停止位.
/// </summary>
public static SerialPort serPort = null;


//聲明委托
public delegate void InsertData(byte[] ByData);
//聲明事件
public static event InsertData GetData;

    寫個構造函數,來處理串口對象的初始化

        /// <summary>
/// 構造函數,處理串口對象的初始化.
/// </summary>
public SettingClass()
{
try
{
serPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
serPort.DataReceived += new SerialDataReceivedEventHandler(serPort_DataReceived);
serPort.Open();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("未發現到串口COM1,請檢查.!\n" + ex.Message, "錯誤警告");
}
}

    我們還可以寫個帶參的構造函數,用來后續選擇端口的初始化

        /// <summary>
/// 后續可以選擇COM端口初始化
/// </summary>
/// <param name="portName"></param>
/// <param name="baudRate"></param>
/// <param name="parity"></param>
/// <param name="dataBits"></param>
/// <param name="stopBits"></param>
public SettingClass(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
{
try
{
serPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
serPort.DataReceived += new SerialDataReceivedEventHandler(serPort_DataReceived);
serPort.Open();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("未發現到串口COM1,請檢查.!\n" + ex.Message, "錯誤警告");
}
}


    在操作serialport的時候,如果需要實行實時的監聽來自設備的數據包,那么,在SerialPort類中有DataReceived事件,當串口的讀緩存有數據到達時則觸發DataReceived事件。(這個在上一篇文章中有,這里只是提一下)

        /// <summary>
/// 處理來自設備的數據.事件.
/// </summary>
/// 緩存數組
List<byte> buffer_list = new List<byte>();
private void serPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
//獲取緩沖區的字節個數.
int intToRead = serPort.BytesToRead;

//聲明臨時數組存儲串口數據.
byte[] byteData = new byte[intToRead];

//讀取來自緩沖區的數據.
serPort.Read(byteData, 0, byteData.Length);

byte[] bytedata = new byte[byteData.Length];
//把接收到的數據保存到緩存里
for (int i = 0; i < byteData.Length; i++)
{
bytedata[i] += byteData[i];
buffer_list.Add(bytedata[i]);
}

lock (_syncLock)
{
// 開啟新線程
Thread th = new Thread(new ThreadStart(ReturnBytaData));
th.Start();
//if (th.IsAlive)
//{
// th.Abort();
//}
}
}
catch { }

}
        private static readonly object _syncLock = new object();

    在上面這個事件里面,可以看到我聲明了一個緩存數組來接收數據,作用是:如果設備發包只發了一個、或者多個、又或者1個半,因為包是由Code+Length+Data+CRC組成,接收的時候怕只接收到了Code+Length,后面的沒接收到,那么這個buffer的用處就來了,可以把前面的包和后面的包拼接成一個完整的包,然后傳輸到form的接收函數里。設備發的數據包不可能只發一個Code+Length,后面在發一個Code+Length,規則協議和TCP傳輸原理一樣。

   下面的函數是用來處理從設備接收到的數據包,最后只返回Code和Data,返回Code是因為我一個界面上有不同的命令,但是會有相同的參數,視情況而定。在這個函數中,也處理了
buffer緩存,對設備的數據包進行校驗。
note:下面代碼第19行 ,返回的是set ok,返回的是成功的數據包格式,需要進行處理。
 1       /// <summary>
2 /// 校驗從設備得到的數據包
3 /// </summary>
4 /// <param name="listbytedata">緩存數組</param>
5 /// <returns>去除length+crc的數據包</returns>
6 public void ReturnBytaData()
7 {
8 try
9 {
10 //查詢緩存是否還存在完整數據包
11 while (buffer_list.Count > 4)
12 {
13 //緩存里第一個數據包
14 int bytelength = buffer_list[1];
15
16 //聲明需要返回的數據包
17 byte[] returndata = new byte[bytelength - 1];
18
19 if (bytelength != 101)
20 {
21 //把緩存內完整的數據包遍歷到字節數組
22 byte[] returnbytedata = new byte[bytelength + 2];
23 for (int i = 0; i < buffer_list[1] + 2; i++)
24 {
25 returnbytedata[i] += buffer_list[i];
26 }
27
28 //判斷數據包的數據是否真實
29 if (bytelength == returnbytedata.Length - 2)
30 {
31 //得到高八位、低八位
32 byte j1 = returnbytedata[returnbytedata.Length - 2];
33 byte j2 = returnbytedata[returnbytedata.Length - 1];
34
35 int sum = 0;
36
37 //校驗高八位、低八位.
38 for (int j = 0; j < returnbytedata.Length - 2; j++)
39 {
40 sum += returnbytedata[j];
41 }
42 byte g = (byte)(sum >> 8);
43 byte d = (byte)(sum);
44 if (j1 == g && j2 == d)
45 {
46 //得到data data=-crc,-code,-length
47 int datalength = returnbytedata.Length - 4;
48 byte[] byteData = new byte[datalength];
49 Array.Copy(returnbytedata, 2, byteData, 0, datalength);
50
51 //得到code
52 byte[] bytecode = new byte[1];
53 Array.Copy(returnbytedata, 0, bytecode, 0, 1);
54
55 //返回code+data
56 for (int i = 0; i < bytecode.Length; i++)
57 {
58 returndata[i] += bytecode[i];
59 }
60 for (int n = 0; n < datalength; n++)
61 {
62 returndata[n + 1] += byteData[n];
63 }
64
65 buffer_list.RemoveRange(0, returnbytedata.Length);
66
67 if (GetData != null)
68 {
69 //綁定到事件
70 GetData(returndata);
71 }
72 }
73 else
74 {
75 buffer_list.RemoveRange(0, returnbytedata[1] + 2);
76 return;
77 }
78 }
79 else
80 {
81 return;
82 }
83 }
84 else
85 {
86 buffer_list.RemoveRange(0, buffer_list.Count);
87 }
88 }
89 }
90 catch { }
91 }


    最后面的是接收來自form傳過來的data.

        /// <summary>
/// 處理各個窗體傳來的數據.各窗體只需要傳送命令+數據即可.
/// </summary>
/// <param name="by">接收到的數據.</param>
public static void InsertserPortData(byte[] Data)
{
try
{
//因為各窗體發來的數據不包括CRC校驗,所以長度+2.
byte[] byteText = new byte[Data.Length + 2];
int sum = 0;
for (int i = 0; i < Data.Length; i++)
{
byteText[i] += Convert.ToByte(Data[i]);
}
//遍歷sum的累加和,判斷高八位和低八位.
for (int n = 0; n < byteText.Length; n++)
{
sum += byteText[n];
}
//高八位.
byte g = (byte)(sum >> 8);
//低八位.
byte d = (byte)(sum);
//把檢驗加到字節數組中.
byteText[byteText.Length - 2] += g;
byteText[byteText.Length - 1] += d;

//寫入串口.
serPort.Write(byteText, 0, byteText.Length);

}
catch { }
}


    最后,在需要接收數據包的form里面注冊下這個事件。

SettingClass.GetData += new SettingClass.InsertData(SettingClass_GetData);

   下面的ByData是數據包(去除Length+CRC).

void SettingClass_GetData(byte[] ByData)

//處理接收到的數據包,顯示到界面里...


   這個項目對我的意義重大,我會一直對它進行重構下去。下次應該就是用OO的方法來寫文章了。這個項目是我今年畢業以來獨立負責的第一個項目。所以,幫助真的很大,在這里我非常感謝我的公司,相信我,給了我鍛煉的機會,也很感謝我的同事FHW、LB、FBY、RJB等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM