1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.IO;
    7. using System.IO.Ports;
    8. using System.Linq;
    9. using System.Security.Cryptography;
    10. using System.Text;
    11. using System.Threading.Tasks;
    12. using System.Windows.Forms;
    13. using static System.Windows.Forms.VisualStyles.VisualStyleElement;
    14. namespace WindowsFormsApp2
    15. {
    16. public partial class Form1 : Form
    17. {
    18. public Form1()
    19. {
    20. InitializeComponent();
    21. }
    22. //接收到的所有数据存储在这里
    23. List<byte> dataList = new List<byte>();
    24. //转换为10进制的数据
    25. List<int> data10List = new List<int>();
    26. //完成平均后的数据
    27. List<float> avgFloat = new List<float>();
    28. int loopCount = 1;
    29. /// <summary>
    30. /// modbus状态
    31. /// </summary>
    32. public string modbusStatus;
    33. /// <summary>
    34. /// 定义SerialPort变量
    35. /// </summary>
    36. public SerialPort Port = new SerialPort();
    37. /// <summary>
    38. /// 打开串口
    39. /// </summary>
    40. /// <param name="m_Port">串口号</param> com4
    41. /// <param name="BaudRate">波特率</param> 9600
    42. /// <param name="m_dataBits">数据位</param> 8
    43. /// <param name="m_Parity">奇偶校验</param> null
    44. /// <param name="m_StopBits">停止位</param> 1
    45. /// <returns>返回BOOL型,True为成功,False为失败</returns>
    46. public bool OpenPort(string m_Port, int BaudRate, int m_dataBits, Parity m_Parity, StopBits m_StopBits)
    47. {
    48. if (Port.IsOpen)
    49. {
    50. return true;
    51. }
    52. else
    53. {
    54. Port.PortName = m_Port;
    55. Port.BaudRate = BaudRate;
    56. Port.DataBits = m_dataBits;
    57. Port.Parity = m_Parity;
    58. Port.StopBits = m_StopBits;
    59. Port.Open();
    60. if (Port.IsOpen)
    61. {
    62. return true;
    63. }
    64. else
    65. {
    66. return false;
    67. }
    68. }
    69. }
    70. /// <summary>
    71. /// 关闭串口
    72. /// </summary>
    73. /// <returns>返回BOOL型,True为成功,False为失败</returns>
    74. public bool PortClose()
    75. {
    76. if (Port.IsOpen)
    77. {
    78. Port.Close();
    79. return true;
    80. }
    81. else
    82. {
    83. return false;
    84. }
    85. }
    86. public void GetCRC(byte[] message, byte[] CRC)
    87. {
    88. //Function expects a modbus message of any length as well as a 2 byte CRC array in which to
    89. //return the CRC values:
    90. ushort CRCFull = 0xFFFF;
    91. byte CRCHigh = 0xFF, CRCLow = 0xFF;
    92. char CRCLSB;
    93. for (int i = 0; i < (message.Length) - 2; i++)
    94. {
    95. CRCFull = (ushort)(CRCFull ^ message[i]);
    96. for (int j = 0; j < 8; j++)
    97. {
    98. CRCLSB = (char)(CRCFull & 0x0001);
    99. CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);
    100. if (CRCLSB == 1)
    101. CRCFull = (ushort)(CRCFull ^ 0xA001);
    102. }
    103. }
    104. CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
    105. CRC[0] = CRCLow = (byte)(CRCFull & 0xFF);
    106. }
    107. /// <summary>
    108. /// CRC16算法
    109. /// </summary>
    110. /// <param name="te">原始数组</param>
    111. /// <param name="message">保存变量</param>
    112. public void BuildMessage(byte[] te, ref byte[] message)
    113. {
    114. //Array to receive CRC bytes:
    115. byte[] CRC = new byte[2];
    116. for (int i = 0; i < te.Length; i++)
    117. {
    118. message[i] = te[i];
    119. }
    120. GetCRC(message, CRC);
    121. message[message.Length - 2] = CRC[0];
    122. message[message.Length - 1] = CRC[1];
    123. }
    124. /// <summary>
    125. /// 发送数据
    126. /// </summary>
    127. /// <param name="m_date">需写入的数据</param>
    128. /// <param name="type">操作类型0为多输出口控制与open参数不共用,1为单控制口输出open为255时线圈闭合0时线圈释放</param>
    129. /// <param name="open">1为单控制口输出open为255时线圈闭合0时线圈释放</param>
    130. /// <returns>返回True或false</returns>
    131. public bool SendMessage(byte m_date, int type, bool open = true)
    132. {
    133. if (!Port.IsOpen)
    134. {
    135. return false;
    136. }
    137. else
    138. {
    139. switch (type)
    140. {
    141. case 0://多个DO输出控制数据位{ 地址, 功能, 线圈起始地址前位, 线圈起始地址后位, 线圈结束地址前位, 线圈结束地址后位, 数据字节, 线圈状态 };
    142. byte[] data = new byte[10];
    143. byte[] dd = { 1, 15, 0, 0, 0, 8, 1, m_date };
    144. BuildMessage(dd, ref data);
    145. Port.Write(data, 0, data.Length);
    146. break;
    147. case 1://单个控制输出{ 地址, 功能, 线圈起始地址前位, 需控制的线圈地址, 开关状态255为开0为关, 线圈开关后位 };
    148. byte[] data_one = new byte[8];
    149. byte temp0;
    150. if (open)
    151. { temp0 = 255; }
    152. else
    153. { temp0 = 0; }
    154. byte[] dd1 = { 1, 5, 0, m_date, temp0, 0 };
    155. BuildMessage(dd1, ref data_one);
    156. Port.Write(data_one, 0, data_one.Length);
    157. break;
    158. case 2:
    159. byte[] getsig = new byte[8];
    160. byte[] getsige = { 1, 2, 0, 0, 0, m_date };
    161. BuildMessage(getsige, ref getsig);
    162. Port.Write(getsig, 0, getsig.Length);
    163. break;
    164. case 3:
    165. break;
    166. }
    167. return true;
    168. }
    169. }
    170. #region Check Response
    171. private bool CheckResponse(byte[] response)
    172. {
    173. //Perform a basic CRC check:
    174. byte[] CRC = new byte[2];
    175. GetCRC(response, CRC);
    176. if (CRC[0] == response[response.Length - 2] && CRC[1] == response[response.Length - 1])
    177. return true;
    178. else
    179. return false;
    180. }
    181. #endregion
    182. #region Get Response
    183. private void GetResponse(ref byte[] response)
    184. {
    185. //There is a bug in .Net 2.0 DataReceived Event that prevents people from using this
    186. //event as an interrupt to handle data (it doesn't fire all of the time). Therefore
    187. //we have to use the ReadByte command for a fixed length as it's been shown to be reliable.
    188. for (int i = 0; i < response.Length; i++)
    189. {
    190. response[i] = (byte)(Port.ReadByte());
    191. }
    192. }
    193. #endregion
    194. public bool GetModbusData()
    195. {
    196. if (Port.IsOpen)
    197. {
    198. int count = Port.BytesToRead;
    199. if (count > 0)
    200. {
    201. byte[] readBuffer = new byte[count];
    202. GetResponse(ref readBuffer);
    203. dataList.AddRange(readBuffer);
    204. Port.DiscardInBuffer();
    205. /*
    206. // CRC 验证
    207. if (CheckResponse(readBuffer))
    208. {
    209. //显示输入数据
    210. //values = readBuffer;
    211. Port.DiscardInBuffer();
    212. return true;
    213. }
    214. else
    215. {
    216. Port.DiscardInBuffer();
    217. return false;
    218. }
    219. */
    220. return true;
    221. }
    222. else return false;
    223. }
    224. else return false;
    225. }
    226. //获取原始数据
    227. private void timer1_Tick(object sender, EventArgs e)
    228. {
    229. GetModbusData();
    230. }
    231. //2个为一组转换为10进制
    232. private void timer2_Tick(object sender, EventArgs e)
    233. {
    234. //8000个为一组来分析
    235. if (dataList.Count >= 8000)
    236. {
    237. List<byte> dataListtmp = dataList.GetRange(0, 8000);
    238. dataList.RemoveRange(0, 8000);
    239. //存储到excel
    240. exportTxt("originData.txt", dataListtmp);
    241. //开始进行进制转换
    242. for (int i = 0; i < 4000; i++)
    243. {
    244. List<byte> bb = dataListtmp.GetRange(2 * i, 2);
    245. string strA = Convert.ToString(bb[0], 2);
    246. string strB = Convert.ToString(bb[1], 2);
    247. string str = strA.PadLeft(8, '0') + strB.PadLeft(8, '0');
    248. //string str = strB.PadLeft(8, '0') + strA.PadLeft(8, '0');
    249. int int10 = Convert.ToInt32(str, 2);
    250. data10List.Add(int10);
    251. }
    252. }
    253. }
    254. //算平均
    255. private void timer3_Tick(object sender, EventArgs e)
    256. {
    257. //开始取平均
    258. if (data10List.Count >= 4000 * loopCount)
    259. {
    260. List<int> data10Listtmp = data10List.GetRange(0, 4000 * loopCount);
    261. data10List.RemoveRange(0, 4000 * loopCount);
    262. //存储到excel
    263. exportTxt("int10Data.txt", data10Listtmp);
    264. for (int j = 0; j < 4000; j++)
    265. {
    266. int sum = 0;
    267. for (int i = 0; i < loopCount; i++)
    268. {
    269. //算平均
    270. sum += data10Listtmp[j + i * 4000];
    271. }
    272. avgFloat.Add(sum*1.0f / loopCount);
    273. }
    274. //存储到excel
    275. exportTxt("avgData.txt", avgFloat);
    276. }
    277. }
    278. int paintCount = 0;
    279. //绘图
    280. private void timer4_Tick(object sender, EventArgs e)
    281. {
    282. if (avgFloat.Count >= 4000)
    283. {
    284. List<float> floatListtmp = avgFloat.GetRange(0, 4000);
    285. avgFloat.RemoveRange(0, 4000);
    286. chart1.Series[0].Points.Clear();
    287. for (int i = 0; i < floatListtmp.Count; i++) {
    288. chart1.Series[0].Points.AddXY(i, floatListtmp[i]);
    289. }
    290. ++paintCount;
    291. label1.Text = "这是第" + paintCount + "次绘制";
    292. //存储到excel
    293. exportTxt("paintData.txt", floatListtmp);
    294. }
    295. }
    296. private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    297. {
    298. PortClose();
    299. }
    300. private void Form1_Load(object sender, EventArgs e)
    301. {
    302. }
    303. private void exportTxt(string fileName,List<float> paramList) {
    304. string text = "";
    305. foreach (var param in paramList) {
    306. text =text+ param+"\n";
    307. }
    308. File.WriteAllText("D:\\tmp\\"+fileName, text, Encoding.Default);
    309. }
    310. private void exportTxt(string fileName, List<int> paramList)
    311. {
    312. string text = "";
    313. foreach (var param in paramList)
    314. {
    315. text = text + param + "\n";
    316. }
    317. File.WriteAllText("D:\\tmp\\" + fileName, text, Encoding.Default);
    318. }
    319. private void exportTxt(string fileName, List<byte> paramList)
    320. {
    321. string text = "";
    322. foreach (var param in paramList)
    323. {
    324. text = text + Convert.ToInt32(param) + "\n";
    325. }
    326. File.WriteAllText("D:\\tmp\\" + fileName, text, Encoding.Default);
    327. }
    328. private void button1_Click(object sender, EventArgs e)
    329. {
    330. try
    331. {
    332. OpenPort("COM" + comboBox1.SelectedIndex, 9600, 8, Parity.None, StopBits.One);
    333. timer1.Enabled = true;
    334. MessageBox.Show("连接成功");
    335. }
    336. catch {
    337. MessageBox.Show("端口错误");
    338. }
    339. }
    340. }
    341. }