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 Response
private 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;
else
return false;
}
#endregion
#region Get Response
private 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());
}
}
#endregion
public 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);
//存储到excel
exportTxt("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);
//存储到excel
exportTxt("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);
}
//存储到excel
exportTxt("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 + "次绘制";
//存储到excel
exportTxt("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("端口错误");
}
}
}
}