zoukankan      html  css  js  c++  java
  • 对项目进行代码重构

        临近公司放假,也好在年前对这次项目的一项总结(包括代码)。刚分配到这份项目时,我认为自己可以完成这次的项目,但是在项目的开发过程中,还是遇到许多的问题,总的来说,分为以下几点:

        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等。

  • 相关阅读:
    leetcode 122. Best Time to Buy and Sell Stock II
    leetcode 121. Best Time to Buy and Sell Stock
    python 集合(set)和字典(dictionary)的用法解析
    leetcode 53. Maximum Subarray
    leetcode 202. Happy Number
    leetcode 136.Single Number
    leetcode 703. Kth Largest Element in a Stream & c++ priority_queue & minHeap/maxHeap
    [leetcode]1379. Find a Corresponding Node of a Binary Tree in a Clone of That Tree
    正则表达式
    十种排序算法
  • 原文地址:https://www.cnblogs.com/aehoo/p/a_20120117.html
Copyright © 2011-2022 走看看