using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.IO;using System.IO.Ports;using System.Linq;using System.Security.Cryptography;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using static System.Windows.Forms.VisualStyles.VisualStyleElement;namespace WindowsFormsApp2{ public partial class Form1 : Form{public Form1(){InitializeComponent();}//接收到的所有数据存储在这里List<byte> dataList = new List<byte>();//转换为10进制的数据List<int> data10List = new List<int>();//完成平均后的数据List<float> avgFloat = new List<float>();int loopCount = 1;/// <summary>/// modbus状态/// </summary>public string modbusStatus;/// <summary>/// 定义SerialPort变量/// </summary>public SerialPort Port = new SerialPort();/// <summary>/// 打开串口/// </summary>/// <param name="m_Port">串口号</param> com4/// <param name="BaudRate">波特率</param> 9600/// <param name="m_dataBits">数据位</param> 8/// <param name="m_Parity">奇偶校验</param> null/// <param name="m_StopBits">停止位</param> 1/// <returns>返回BOOL型,True为成功,False为失败</returns>public bool OpenPort(string m_Port, int BaudRate, int m_dataBits, Parity m_Parity, StopBits m_StopBits){if (Port.IsOpen){return true;}else{Port.PortName = m_Port;Port.BaudRate = BaudRate;Port.DataBits = m_dataBits;Port.Parity = m_Parity;Port.StopBits = m_StopBits;Port.Open();if (Port.IsOpen){return true;}else{return false;}}}/// <summary>/// 关闭串口/// </summary>/// <returns>返回BOOL型,True为成功,False为失败</returns>public bool PortClose(){if (Port.IsOpen){Port.Close();return true;}else{return false;}}public void GetCRC(byte[] message, byte[] CRC){//Function expects a modbus message of any length as well as a 2 byte CRC array in which to //return the CRC values: ushort CRCFull = 0xFFFF;byte CRCHigh = 0xFF, CRCLow = 0xFF;char CRCLSB;for (int i = 0; i < (message.Length) - 2; i++){CRCFull = (ushort)(CRCFull ^ message[i]);for (int j = 0; j < 8; j++){CRCLSB = (char)(CRCFull & 0x0001);CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);if (CRCLSB == 1)CRCFull = (ushort)(CRCFull ^ 0xA001);}}CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);CRC[0] = CRCLow = (byte)(CRCFull & 0xFF);}/// <summary>/// CRC16算法/// </summary>/// <param name="te">原始数组</param>/// <param name="message">保存变量</param>public void BuildMessage(byte[] te, ref byte[] message){//Array to receive CRC bytes: byte[] CRC = new byte[2];for (int i = 0; i < te.Length; i++){message[i] = te[i];}GetCRC(message, CRC);message[message.Length - 2] = CRC[0];message[message.Length - 1] = CRC[1];}/// <summary>/// 发送数据/// </summary>/// <param name="m_date">需写入的数据</param>/// <param name="type">操作类型0为多输出口控制与open参数不共用,1为单控制口输出open为255时线圈闭合0时线圈释放</param>/// <param name="open">1为单控制口输出open为255时线圈闭合0时线圈释放</param>/// <returns>返回True或false</returns>public bool SendMessage(byte m_date, int type, bool open = true){if (!Port.IsOpen){return false;}else{switch (type){case 0://多个DO输出控制数据位{ 地址, 功能, 线圈起始地址前位, 线圈起始地址后位, 线圈结束地址前位, 线圈结束地址后位, 数据字节, 线圈状态 };byte[] data = new byte[10];byte[] dd = { 1, 15, 0, 0, 0, 8, 1, m_date };BuildMessage(dd, ref data);Port.Write(data, 0, data.Length);break;case 1://单个控制输出{ 地址, 功能, 线圈起始地址前位, 需控制的线圈地址, 开关状态255为开0为关, 线圈开关后位 };byte[] data_one = new byte[8];byte temp0;if (open){ temp0 = 255; }else{ temp0 = 0; }byte[] dd1 = { 1, 5, 0, m_date, temp0, 0 };BuildMessage(dd1, ref data_one);Port.Write(data_one, 0, data_one.Length);break;case 2:byte[] getsig = new byte[8];byte[] getsige = { 1, 2, 0, 0, 0, m_date };BuildMessage(getsige, ref getsig);Port.Write(getsig, 0, getsig.Length);break;case 3:break;}return true;}}#region Check Responseprivate bool CheckResponse(byte[] response){//Perform a basic CRC check: byte[] CRC = new byte[2];GetCRC(response, CRC);if (CRC[0] == response[response.Length - 2] && CRC[1] == response[response.Length - 1])return true;elsereturn false;}#endregion#region Get Responseprivate void GetResponse(ref byte[] response){//There is a bug in .Net 2.0 DataReceived Event that prevents people from using this //event as an interrupt to handle data (it doesn't fire all of the time). Therefore //we have to use the ReadByte command for a fixed length as it's been shown to be reliable. for (int i = 0; i < response.Length; i++){response[i] = (byte)(Port.ReadByte());}}#endregionpublic bool GetModbusData(){if (Port.IsOpen){int count = Port.BytesToRead;if (count > 0){byte[] readBuffer = new byte[count];GetResponse(ref readBuffer);dataList.AddRange(readBuffer);Port.DiscardInBuffer();/*// CRC 验证 if (CheckResponse(readBuffer)){//显示输入数据 //values = readBuffer;Port.DiscardInBuffer();return true;}else{Port.DiscardInBuffer();return false;}*/return true;}else return false;}else return false;}//获取原始数据private void timer1_Tick(object sender, EventArgs e){GetModbusData();}//2个为一组转换为10进制private void timer2_Tick(object sender, EventArgs e){//8000个为一组来分析if (dataList.Count >= 8000){List<byte> dataListtmp = dataList.GetRange(0, 8000);dataList.RemoveRange(0, 8000);//存储到excelexportTxt("originData.txt", dataListtmp);//开始进行进制转换for (int i = 0; i < 4000; i++){List<byte> bb = dataListtmp.GetRange(2 * i, 2);string strA = Convert.ToString(bb[0], 2);string strB = Convert.ToString(bb[1], 2);string str = strA.PadLeft(8, '0') + strB.PadLeft(8, '0');//string str = strB.PadLeft(8, '0') + strA.PadLeft(8, '0');int int10 = Convert.ToInt32(str, 2);data10List.Add(int10);}}}//算平均private void timer3_Tick(object sender, EventArgs e){//开始取平均if (data10List.Count >= 4000 * loopCount){List<int> data10Listtmp = data10List.GetRange(0, 4000 * loopCount);data10List.RemoveRange(0, 4000 * loopCount);//存储到excelexportTxt("int10Data.txt", data10Listtmp);for (int j = 0; j < 4000; j++){int sum = 0;for (int i = 0; i < loopCount; i++){//算平均sum += data10Listtmp[j + i * 4000];}avgFloat.Add(sum*1.0f / loopCount);}//存储到excelexportTxt("avgData.txt", avgFloat);}}int paintCount = 0;//绘图private void timer4_Tick(object sender, EventArgs e){if (avgFloat.Count >= 4000){List<float> floatListtmp = avgFloat.GetRange(0, 4000);avgFloat.RemoveRange(0, 4000);chart1.Series[0].Points.Clear();for (int i = 0; i < floatListtmp.Count; i++) {chart1.Series[0].Points.AddXY(i, floatListtmp[i]);}++paintCount;label1.Text = "这是第" + paintCount + "次绘制";//存储到excelexportTxt("paintData.txt", floatListtmp);}}private void Form1_FormClosing(object sender, FormClosingEventArgs e){PortClose();}private void Form1_Load(object sender, EventArgs e){}private void exportTxt(string fileName,List<float> paramList) {string text = "";foreach (var param in paramList) {text =text+ param+"\n";}File.WriteAllText("D:\\tmp\\"+fileName, text, Encoding.Default);}private void exportTxt(string fileName, List<int> paramList){string text = "";foreach (var param in paramList){text = text + param + "\n";}File.WriteAllText("D:\\tmp\\" + fileName, text, Encoding.Default);}private void exportTxt(string fileName, List<byte> paramList){string text = "";foreach (var param in paramList){text = text + Convert.ToInt32(param) + "\n";}File.WriteAllText("D:\\tmp\\" + fileName, text, Encoding.Default);}private void button1_Click(object sender, EventArgs e){try{OpenPort("COM" + comboBox1.SelectedIndex, 9600, 8, Parity.None, StopBits.One);timer1.Enabled = true;MessageBox.Show("连接成功");}catch {MessageBox.Show("端口错误");}}}}