485串口通讯保存流量计的数据到Excel

时间:2021-12-08 14:51:53

全是我个人理解,不对的请大神指教

流量计说明书:

485串口通讯保存流量计的数据到Excel

实现UI界面:

485串口通讯保存流量计的数据到Excel

添加using:

using System.IO.Ports;
using INIFILE;
using System.Text.RegularExpressions;
using System.IO;
using Microsoft.Office;
using System.Reflection;


//实例化串口

SerialPort sp1 = new SerialPort();

窗体加载时:

 private void Form1_Load(object sender, EventArgs e)
        {
            INIFILE.Profile.LoadProfile();//加载所有
            
           // 预置波特率
            switch (Profile.G_BAUDRATE)
            {
                case "300":
                    cbBaudRate.SelectedIndex = 0;
                    break;
                case "600":
                    cbBaudRate.SelectedIndex = 1;
                    break;
                case "1200":
                    cbBaudRate.SelectedIndex = 2;
                    break; 
                case "2400":
                    cbBaudRate.SelectedIndex = 3;
                    break;
                case "4800":
                    cbBaudRate.SelectedIndex = 4;
                    break;
                case "9600":
                    cbBaudRate.SelectedIndex = 5;
                    break;
                case "19200":
                    cbBaudRate.SelectedIndex = 6;
                    break; 
                case "38400":
                    cbBaudRate.SelectedIndex = 7;
                    break;
                case "115200":
                    cbBaudRate.SelectedIndex = 8;
                    break;
                default:
                    {
                        MessageBox.Show("波特率预置参数错误。");
                        return;
                    }                  
            }

            //预置波特率
            switch (Profile.G_DATABITS)
            {
                case "5":
                    cbDataBits.SelectedIndex = 0;
                    break;
                case "6":
                    cbDataBits.SelectedIndex = 1;
                    break; 
                case "7":
                    cbDataBits.SelectedIndex = 2;
                    break; 
                case  "8":
                    cbDataBits.SelectedIndex = 3;
                    break;
                default:
                    {
                        MessageBox.Show("数据位预置参数错误。");
                        return;
                    }

            }
            //预置停止位
            switch (Profile.G_STOP)
            {
                case "1":
                    cbStop.SelectedIndex = 0;
                        break;
                case "1.5":
                    cbStop.SelectedIndex = 1;
                    break;
                case "2":
                    cbStop.SelectedIndex = 2;
                    break;
                default:
                    {
                        MessageBox.Show("停止位预置参数错误。");
                        return;
                    }
            }

            //预置校验位
            switch(Profile.G_PARITY)
            {
                case "NONE":
                    cbParity.SelectedIndex = 0;
                    break;
                case "ODD":
                    cbParity.SelectedIndex = 1;
                    break;
                case "EVEN":
                    cbParity.SelectedIndex = 2;
                    break;
                default:
                    {
                        MessageBox.Show("校验位预置参数错误。");
                        return;
                    }
            }

            //检查是否含有串口
            string[] str = SerialPort.GetPortNames();
            if (str == null)
            {
                MessageBox.Show("本机没有串口!", "Error");
                return;
            }

            //添加串口项目
            foreach (string s in System.IO.Ports.SerialPort.GetPortNames())
            {//获取有多少个COM口
                //System.Diagnostics.Debug.WriteLine(s);
                cbSerial.Items.Add(s);
            }

            //串口设置默认选择项
            cbSerial.SelectedIndex = 1;         //note:获得COM9口,但别忘修改
            //cbBaudRate.SelectedIndex = 5;
           // cbDataBits.SelectedIndex = 3;
           // cbStop.SelectedIndex = 0;
          //  cbParity.SelectedIndex = 0;
            sp1.BaudRate = 9600;

            Control.CheckForIllegalCrossThreadCalls = false;    //这个类中我们不检查跨线程的调用是否合法(因为.net 2.0以后加强了安全机制,,不允许在winform中直接跨线程访问控件的属性)
            sp1.DataReceived += new SerialDataReceivedEventHandler(sp1_DataReceived);
            //sp1.ReceivedBytesThreshold = 1;

            radio1.Checked = true;  //单选按钮默认是选中的
            rbRcvStr.Checked = true;

            //准备就绪              
            sp1.DtrEnable = true;
            sp1.RtsEnable = true;
            //设置数据读取超时为1秒
            sp1.ReadTimeout = 1000;

            sp1.Close();
        }
定义缓冲器和excel实例:
 List<byte> buffer = new List<byte>(4096);

        Microsoft.Office.Interop.Excel.Application excelApp = null;  // 定义Application 对象,此对象表示整个Excel 程序
        Microsoft.Office.Interop.Excel.Workbook workBook=null;// 定义Workbook对象,此对象代表工作薄

        //Microsoft.Office.Interop.Excel.Worksheet ws = new Microsoft.Office.Interop.Excel.Worksheet(); // 定义Worksheet 对象,此对象表示Execel 中的一张工作表
        Microsoft.Office.Interop.Excel.Worksheet ws = null;
用p表示存储位置
private int p = 2;//存储位置指针;

写入excel的方法:

private void wrExcel(string AccFlowdata,string Flowdata)
        {
            string time = System.DateTime.Now.ToLongTimeString().ToString();

            ws.Cells[p, 1] = time;
            ws.Cells[p, 2] = AccFlowdata.ToString();
            ws.Cells[p, 3] = Flowdata.ToString();

            p = p + 1;
        }

串口接收事件

void sp1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (sp1.IsOpen)     //此处可能没有必要判断是否打开串口,但为了严谨性,我还是加上了
            {
                //输出当前时间
            //    DateTime dt = DateTime.Now;
           //    txtReceive.Text += dt.GetDateTimeFormats('f')[0].ToString() + "\r\n";
                txtReceive.SelectAll();
                txtReceive.SelectionColor = Color.Blue;         //改变字体的颜色

                byte[] byteRead = new byte[sp1.BytesToRead];    //BytesToRead:sp1接收的字符个数
                

                System.Threading.Thread.Sleep(100);             //在接收之前加一个延时,给计算机时间接收数据,不然会导致接收的数据显示不全。

                if (rdSendStr.Checked)                          //'发送字符串'单选按钮
                {
                    txtReceive.Text += sp1.ReadLine() + "\r\n"; //注意:回车换行必须这样写,单独使用"\r"和"\n"都不会有效果
                    sp1.DiscardInBuffer();                      //清空SerialPort控件的Buffer 
                }
                else                                            //'发送16进制按钮'
                {
                    try
                    {
                        

                        Byte[] receivedData = new Byte[sp1.BytesToRead];        //创建接收字节数组
                        sp1.Read(receivedData, 0, receivedData.Length);         //读取数据
                        //string text = sp1.Read();   //Encoding.ASCII.GetString(receivedData);
                        sp1.DiscardInBuffer();                                  //清空SerialPort控件的Buffer
                        //这是用以显示字符串
                        //    string strRcv = null;
                        //    for (int i = 0; i < receivedData.Length; i++ )
                        //    {
                        //        strRcv += ((char)Convert.ToInt32(receivedData[i])) ;
                        //    }
                        //    txtReceive.Text += strRcv + "\r\n";             //显示信息
                        //}

                        int 字节数组大小 = receivedData.Length;
                        txtReceive.Text += "收到" + 字节数组大小 + "字节" + "\r\n";

                        
                        buffer.AddRange(receivedData);
                        
                        
                                 
                        if (buffer.Count == 17)
                        {
                            byte[] AccFlowCODint = new byte[4] {buffer[3], buffer[4], buffer[5], buffer[6] };//累积流量整数部分放在一个字节数组中
                            AccFlowCODint = AccFlowCODint.Reverse().ToArray(); //转换顺序
                            AccFlow_int = BitConverter.ToInt32(AccFlowCODint, 0);//转换成整数


                            byte[] AccFlowCODdec = new byte[4] { buffer[7], buffer[8], buffer[9], buffer[10] };//累积流量小数部分放在一个字节数组中
                            AccFlowCODdec = AccFlowCODdec.Reverse().ToArray();  //转换顺序
                            AccFlow_dec = BitConverter.ToSingle(AccFlowCODdec, 0);  //转换成小数

                            byte[] FlowCOD = new byte[4] { buffer[11], buffer[12], buffer[13], buffer[14] };//瞬时流量放在一个字节数组中
                            FlowCOD = FlowCOD.Reverse().ToArray(); //转换顺序
                            Flow = BitConverter.ToSingle(FlowCOD, 0);//转换成小数

                            AccFlow = AccFlow_int + AccFlow_dec;

                            
                            txtReceive.Text += "累积流量为:" + AccFlow + "\r\n";


                            txtAccFlow.Text  = AccFlow.ToString();
                            txtFlow.Text     = Flow.ToString();

                            if (wsd==true  )
                            {

                                wrExcel(AccFlow.ToString(), Flow.ToString());
                            }

                            buffer.Clear();
                        }


                      


                        string strRcv = null;

                        //int decNum = 0;//存储十进制
                        

                        for (int i = 0; i < receivedData.Length; i++) //窗体显示
                        {
                          
                            strRcv += receivedData[i].ToString("X2");  //16进制显示
                            

                        }


                        txtReceive.Text += strRcv + "\r\n";

                        
                    }
                    catch (System.Exception ex)
                    {
                        MessageBox.Show(ex.Message, "出错提示");
                        txtSend.Text = "";
                    }
                }
            }
            else
            {
                MessageBox.Show("请打开某个串口", "错误提示");
            }
        }

打开串口按钮

private void btnSwitch_Click(object sender, EventArgs e)
        {
            //serialPort1.IsOpen
            if (!sp1.IsOpen)
            {
                try
                {
                    //设置串口号
                    string serialName = cbSerial.SelectedItem.ToString();
                    sp1.PortName = serialName;

                    //设置各“串口设置”
                    string strBaudRate = cbBaudRate.Text;
                    string strDateBits = cbDataBits.Text;
                    string strStopBits = cbStop.Text;
                    Int32 iBaudRate = Convert.ToInt32(strBaudRate);
                    Int32 iDateBits = Convert.ToInt32(strDateBits);

                    sp1.BaudRate = iBaudRate;       //波特率
                    sp1.DataBits = iDateBits;       //数据位
                    switch (cbStop.Text)            //停止位
                    {
                        case "1":
                            sp1.StopBits = StopBits.One;
                            break;
                        case "1.5":
                            sp1.StopBits = StopBits.OnePointFive;
                            break;
                        case "2":
                            sp1.StopBits = StopBits.Two;
                            break;
                        default:
                            MessageBox.Show("Error:参数不正确!", "Error");
                            break;
                    }
                    switch (cbParity.Text)             //校验位
                    {
                        case "无":
                            sp1.Parity = Parity.None;
                            break;
                        case "奇校验":
                            sp1.Parity = Parity.Odd;
                            break;
                        case "偶校验":
                            sp1.Parity = Parity.Even;
                            break;
                        default:
                            MessageBox.Show("Error:参数不正确!", "Error");
                            break;
                    }

                    if (sp1.IsOpen == true)//如果打开状态,则先关闭一下
                    {
                        sp1.Close();
                    }
                    //状态栏设置
                    tsSpNum.Text = "串口号:" + sp1.PortName + "|";
                    tsBaudRate.Text = "波特率:" + sp1.BaudRate + "|";
                    tsDataBits.Text = "数据位:" + sp1.DataBits + "|";
                    tsStopBits.Text = "停止位:" + sp1.StopBits + "|";
                    tsParity.Text = "校验位:" + sp1.Parity + "|";

                    //设置必要控件不可用
                    cbSerial.Enabled = false;
                    cbBaudRate.Enabled = false;
                    cbDataBits.Enabled = false;
                    cbStop.Enabled = false;
                    cbParity.Enabled = false;

                    sp1.Open();     //打开串口
                    btnSwitch.Text = "关闭串口";
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show("Error:" + ex.Message, "Error");
                    tmSend.Enabled = false;
                    return;
                }
            }
            else
            {
                //状态栏设置
                tsSpNum.Text = "串口号:未指定|";
                tsBaudRate.Text = "波特率:未指定|";
                tsDataBits.Text = "数据位:未指定|";
                tsStopBits.Text = "停止位:未指定|";
                tsParity.Text = "校验位:未指定|";
                //恢复控件功能
                //设置必要控件不可用
                cbSerial.Enabled = true;
                cbBaudRate.Enabled = true;
                cbDataBits.Enabled = true;
                cbStop.Enabled = true;
                cbParity.Enabled = true;

                sp1.Close();                    //关闭串口
                btnSwitch.Text = "打开串口";
                tmSend.Enabled = false;         //关闭计时器
            }
        }

开始保存按钮,其实是创建Excel文档,用wsd这个布尔量判断是否创建好文档

private void cbStartSave_CheckedChanged(object sender, EventArgs e)
        {
            if (cbStartSave.Checked == true)
            {
                cbStartSave.Text = "停止保存";

                try
                {
                    //初始化 Application 对象 excelApp
                     excelApp = new Microsoft.Office.Interop.Excel.Application();

                    //在工作薄的第一个工作表上创建任务列表
                     workBook = excelApp.Workbooks.Add(Type.Missing);
                    //workBook = excelApp.Workbooks.Add(Microsoft.Office.Interop.Excel.XlWBATemplate.xlWBATWorksheet);

                    ws = (Microsoft.Office.Interop.Excel.Worksheet)workBook.Worksheets[1];

                    ws.Name = "文件名称";
                    // 居中 
                    ws.Rows.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;

                    // 单元格的宽度
                    ((Microsoft.Office.Interop.Excel.Range)ws.Columns["B", Type.Missing]).ColumnWidth = 17;
                    ((Microsoft.Office.Interop.Excel.Range)ws.Columns["C", Type.Missing]).ColumnWidth = 17;
                    ((Microsoft.Office.Interop.Excel.Range)ws.Columns["D", Type.Missing]).ColumnWidth = 17;
                    ((Microsoft.Office.Interop.Excel.Range)ws.Columns["E", Type.Missing]).ColumnWidth = 17;
                    ((Microsoft.Office.Interop.Excel.Range)ws.Columns["F", Type.Missing]).ColumnWidth = 17;
                    ((Microsoft.Office.Interop.Excel.Range)ws.Columns["G", Type.Missing]).ColumnWidth = 17;

                    ws.Cells[1, 1] = "时间";
                    ws.Cells[1, 2] = "累积流量";
                    ws.Cells[1, 3] = "瞬时流量";
                    wsd = true;

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }

            }

            else
            {
                cbStartSave.Text = "开始保存";
                wsd = false;
                string path = "";
                string time = System.DateTime.Now.ToLongTimeString().ToString();
                time = time.Replace(":", "-");
                path = @"G:\" + time;
                ws.SaveAs(path + ".xls",
                            Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                            Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
                //保存后是否打开 Excel
                excelApp.Visible = true;
                //excelApp.Quit();// 去掉  任务管理器的进程
                workBook = null;
                p = 2;
            }
        }