对项目进行代码重构.docx
《对项目进行代码重构.docx》由会员分享,可在线阅读,更多相关《对项目进行代码重构.docx(16页珍藏版)》请在冰豆网上搜索。
![对项目进行代码重构.docx](https://file1.bdocx.com/fileroot1/2023-2/8/fb3e0ae5-a359-4866-8e50-7f3221e57add/fb3e0ae5-a359-4866-8e50-7f3221e57add1.gif)
对项目进行代码重构
对项目进行代码重构
临近公司放假,也好在年前对这次项目的一项总结(包括代码)。
刚分配到这份项目时,我认为自己可以完成这次的项目,但是在项目的开发过程中,还是遇到许多的问题,总的来说,分为以下几点:
1.前期对项目的背景不是很清楚(我一开始以为只要拿到项目就开始Coding,完成项目,其实不是这样);
2.文档写的不够完善(只写了需求分析、概要设计、没有数据库设计,因为文件都是存放在XML文档里);
3.对使用的技术不会(操作RS232串口,以前在学校从来没学过这些,当然,也不需要学习这些。
本人认为,自己主动去学和学校所教最大的区别在于主动是有意识的去学,而学校所教是被动的);
4.与老板(客户)的沟通不够,客户那边一有新的需求,就马上换成新的需求,然后换来换去,弄的心情很不爽,特别是一个项目需要分成好几种类型,比如,四川省的我要这种,福建省的我要那种,北京市的又是另外的,而且还是同时更新。
所以改的比较痛苦,也很纠结。
(现在已改用OO的方法);
5.最重要的是我自己对技术看的太轻松了,我认为技术会了就是会了,其实太天真了~~(其实是看个人的心态拉,我认为自己还Ok)。
所以,我一直在改变、进步!
好了,下面是项目中一个串口操作类重构后的Code。
这里我专门写了一个类来处理对串口的操作,主要是write、read,其中有用到包括delegate、event、lock、多线程。
首先,实例化串行端口,有端口名称波特率奇偶校验位数据位停止位这些。
然后在Program实例化这个串口操作类。
SettingClasssc=newSettingClass();
publicclassSettingClass
{
///
///实例化串行端口资源端口名称波特率奇偶校验位数据位停止位.
///
publicstaticSerialPortserPort=null;
//声明委托
publicdelegatevoidInsertData(byte[]ByData);
//声明事件
publicstaticeventInsertDataGetData;
复制代码
写个构造函数,来处理串口对象的初始化
///
///构造函数,处理串口对象的初始化.
///
publicSettingClass()
{
try
{
serPort=newSerialPort("COM1",9600,Parity.None,8,StopBits.One);
serPort.DataReceived+=newSerialDataReceivedEventHandler(serPort_DataReceived);
serPort.Open();
}
catch(Exceptionex)
{
System.Windows.Forms.MessageBox.Show("未发现到串口COM1,请检查.!
\n"+ex.Message,"错误警告");
}
}
复制代码
我们还可以写个带参的构造函数,用来后续选择端口的初始化
///
///后续可以选择COM端口初始化
///
///
///
///
///
///
publicSettingClass(stringportName,intbaudRate,Parityparity,intdataBits,StopBitsstopBits)
{
try
{
serPort=newSerialPort(portName,baudRate,parity,dataBits,stopBits);
serPort.DataReceived+=newSerialDataReceivedEventHandler(serPort_DataReceived);
serPort.Open();
}
catch(Exceptionex)
{
System.Windows.Forms.MessageBox.Show("未发现到串口COM1,请检查.!
\n"+ex.Message,"错误警告");
}
}
复制代码
在操作serialport的时候,如果需要实行实时的监听来自设备的数据包,那么,在SerialPort类中有DataReceived事件,当串口的读缓存有数据到达时则触发DataReceived事件。
(这个在上一篇文章中有,这里只是提一下)
///
///处理来自设备的数据.事件.
///
///缓存数组
Listbuffer_list=newList();
privatevoidserPort_DataReceived(objectsender,SerialDataReceivedEventArgse)
{
try
{
//获取缓冲区的字节个数.
intintToRead=serPort.BytesToRead;
//声明临时数组存储串口数据.
byte[]byteData=newbyte[intToRead];
//读取来自缓冲区的数据.
serPort.Read(byteData,0,byteData.Length);
byte[]bytedata=newbyte[byteData.Length];
//把接收到的数据保存到缓存里
for(inti=0;i{
bytedata[i]+=byteData[i];
buffer_list.Add(bytedata[i]);
}
lock(_syncLock)
{
//开启新线程
Threadth=newThread(newThreadStart(ReturnBytaData));
th.Start();
//if(th.IsAlive)
//{
//th.Abort();
//}
}
}
catch{}
}
privatestaticreadonlyobject_syncLock=newobject();
复制代码
在上面这个事件里面,可以看到我声明了一个缓存数组来接收数据,作用是:
如果设备发包只发了一个、或者多个、又或者1个半,因为包是由Code+Length+Data+CRC组成,接收的时候怕只接收到了Code+Length,后面的没接收到,那么这个buffer的用处就来了,可以把前面的包和后面的包拼接成一个完整的包,然后传输到form的接收函数里。
设备发的数据包不可能只发一个Code+Length,后面在发一个Code+Length,规则协议和TCP传输原理一样。
下面的函数是用来处理从设备接收到的数据包,最后只返回Code和Data,返回Code是因为我一个界面上有不同的命令,但是会有相同的参数,视情况而定。
在这个函数中,也处理了
buffer缓存,对设备的数据包进行校验。
note:
下面代码第19行,返回的是setok,返回的是成功的数据包格式,需要进行处理。
复制代码
1///
2///校验从设备得到的数据包
3///
4///缓存数组
5///去除length+crc的数据包
6publicvoidReturnBytaData()
7{
8try
9{
10//查询缓存是否还存在完整数据包
11while(buffer_list.Count>4)
12{
13//缓存里第一个数据包
14intbytelength=buffer_list[1];
15
16//声明需要返回的数据包
17byte[]returndata=newbyte[bytelength-1];
18
19if(bytelength!
=101)
20{
21//把缓存内完整的数据包遍历到字节数组
22byte[]returnbytedata=newbyte[bytelength+2];
23for(inti=0;i24{
25returnbytedata[i]+=buffer_list[i];
26}
27
28//判断数据包的数据是否真实
29if(bytelength==returnbytedata.Length-2)
30{
31//得到高八位、低八位
32bytej1=returnbytedata[returnbytedata.Length-2];
33bytej2=returnbytedata[returnbytedata.Length-1];
34
35intsum=0;
36
37//校验高八位、低八位.
38for(intj=0;j39{
40sum+=returnbytedata[j];
41}
42byteg=(byte)(sum>>8);
43byted=(byte)(sum);
44if(j1==g&&j2==d)
45{
46//得到datadata=-crc,-code,-length
47intdatalength=returnbytedata.Length-4;
48byte[]byteData=newbyte[datalength];
49Array.Copy(returnbytedata,2,byteData,0,datalength);
50
51//得到code
52byte[]bytecode=newbyte[1];
53Array.Copy(returnbytedata,0,bytecode,0,1);
54
55//返回code+data
56for(inti=0;i57{
58returndata[i]+=bytecode[i];
59}
60for(intn=0;n61{
62returndata[n+1]+=byteData[n];
63}
64
65buffer_list.RemoveRange(0,returnbytedata.Length);
66
67if(GetData!
=null)
68{
69//绑定到事件
70GetData(returndata);
71}
72}
73else
74{
75buffer_list.RemoveRange(0,returnbytedata[1]+2);
76return;
77}
78}
79else
80{
81return;
82}
83}
84else
85{
86buffer_list.RemoveRange(0,buffer_list.Count);
87}
88}
89}
90catch{}
91}
复制代码
最后面的是接收来自form传过来的data.
///
///处理各个窗体传来的数据.各窗体只需要传送命令+数据即可.
///
///接收到的数据.
publicstaticvoidInsertserPortData(byte[]Data)
{
try
{
//因为各窗体发来的数据不包括CRC校验,所以长度+2.
byte[]byteText=newbyte[Data.Length+2];
intsum=0;
for(inti=0;i{
byteText[i]+=Convert.ToByte(Data[i]);
}
//遍历sum的累加和,判断高八位和低八位.
for(intn=0;n{
sum+=byteText[n];
}
//高八位.
byteg=(byte)(sum>>8);
//低八位.
byted=(byte)(sum);
//把检验加到字节数组中.
byteText[byteText.Length-2]+=g;
byteText[byteText.Length-1]+=d;
//写入串口.
serPort.Write(byteText,0,byteText.Length);
}
catch{}
}
复制代码
最后,在需要接收数据包的form里面注册下这个事件。
SettingClass.GetData+=newSettingClass.InsertData(SettingClass_GetData);
下面的ByData是数据包(去除Length+CRC).
voidSettingClass_GetData(byte[]ByData)
{
//处理接收到的数据包,显示到界面里...
}
复制代码
这个项目对我的意义重大,我会一直对它进行重构下去。
下次应该就是用OO的方法来写文章了。
这个项目是我今年毕业以来独立负责的第一个项目。
所以,帮助真的很大,在这里我非常感谢我的公司,相信我,给了我锻炼的机会,也很感谢我的同事FHW、LB、FBY、RJB等。
操作串口通信类(IO.Ports)-SerialPort
公司项目接近尾部,从刚开始接触SerialPort到现在,用的最多算是它了。
所以,现在做个总结。
刚开始接到这个项目的时候,就从没接触过SerialPort,不知道如何下手,像最基本的PortName(通信端口)、BaudRate(波特率)、Parity(奇偶校验)、DataBits(数据位长度)、StopBits(停止位数)都不知道,后来网上google别人的经验,知道了最基本的用法,原来串口通信还需要下层的同事把协议写好,烧到硬件上去。
串口的使用:
1,串口控件位于工具箱—组件—SerialPort,拖动到窗体上,设置属性(Name),命名。
可在属性处进行设置,也可以在后台代码页进行手动写:
需导入命名空间:
usingSystem.IO.Ports;
///
///串行端口资源端口名称波特率奇偶校验位数据位停止位
///
publicSerialPortport=newSerialPort("COM1",115200,Parity.None,8,StopBits.One);
复制代码
设置好串行端口等属性之后,便可以操作串口进行通信了,如要对设备进行全部开启操作。
///
/////设备全开、关
///
protectedvoidAllOpenOrClose()
{
try
{
//打开串口
port.Open();
//判断是否选中开
if(chb_CheckAll.Checked==true)
{
//用字节的形式发送数据全开解释:
order1是控制命令,后面是2个byte的校验(高8位与低8位),0x00可以不写,直接写成(byte)((order1)>>8)
byte[]b={order1,(byte)((order1+0x00)>>8),(byte)(order1+0x00)};
//把b数组中的数据以字节的形式写入串行端口
port.Write(b,0,b.Length);
//提示信息!
lab_Message.Text="设备已经全部打开!
";
}
else
{
//用字节的形式发送数据全关
byte[]b={order2,(byte)((order2+0x00)>>8),(byte)(order2+0x00)};
v.port.Write(b,0,b.Length);
lab_Message.Text="设备已经全部关闭!
";
}
//关闭串口记得开启端口之后一定要关闭,和ADO.NET的Connection对象一样,用过之后必须关闭。
port.Close();
}
catch(Exceptionex)
{
//捕获的异常信息
MessageBox.Show(ex.Message,"提示");
}
}
复制代码
2,如果要对设备的状态进行实时监听,有一个很好的事件,在SerialPort类中有DataReceived事件,当串口的读缓存有数据到达时则触发DataReceived事件,其中SerialPort.ReceivedBytesThreshold属性决定了当串口读缓存中数据多少个时才触发DataReceived事件,默认为1。
我们把串口的属性定义在InitializeComponent()方法下面,(不会连这个方法都不知道把?
!
!
)。
在页面命名空间下的第一个方法,是VisualStudio设计器自动生成的方法。
publicSettingsTimePlay()
{
InitializeComponent();
//串行端口号
seriaSettingPlay.PortName="COM1";
//波特率
seriaSettingPlay.BaudRate=115200;
//奇偶校验位
seriaSettingPlay.Parity=Parity.None;
//数据位
seriaSettingPlay.DataBits=8;
//停止位
seriaSettingPlay.StopBits=StopBits.One;
textChanged+=newUpdateTextEventHandler(ChangeText);
try
{
//打开串口
seriaSettingPlay.Open();
}
catch(Exceptionex)
{
//捕获的异常信息,没检查到串口或串口设置不正确。
MessageBox.Show("请检查是否已经连接串口!
\n"+ex.Message,"提示");
}
}
复制代码
属性定义完成之后,需要,
//定义委托
privatedelegatevoidGetText(stringtext);
//定义事件
privateeventGetTexttextChanged;
//事件处理方法
privatevoidChangeText(stringtext)
{
//这里为处理接收到的值,赋值到控件上。
...........
}
复制代码
现在就是DataReceived事件进行实时监听了,
//定义接收的字节
privatebyte[]Data=newbyte[8];
privatevoidseriaSettingPlay_DataReceived(objectsender,SerialDataReceivedEventArgse)
{
//读取来自监听到的字节
seriaSettingPlay.Read(be,0,be.Length);
//把第一个命名赋值到text变量
text=be[0].Tostring();
seriaSettingPlay.DiscardInBuffer();
this.Invoke(textChanged,newstring[]{text});
}
复制代码
最后,记得在Load事件里去读取。
还有取出来的数据最好也进行校验,因为不校验容易受到干扰。
希望对大家学习串口知识有所帮助。