C# 学习笔记(15)自己的串口助手----波形显示

Posted 不咸不要钱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 学习笔记(15)自己的串口助手----波形显示相关的知识,希望对你有一定的参考价值。

C# 学习笔记(15)自己的串口助手----波形显示

chart控件

chart控件共有5大集合,最重要的两个集合就是绘图空间和线

在这里插入图片描述

坐标系

坐标系的设置在绘图空间集合内

设置坐标系样式
在这里插入图片描述

框选放大功能

在这里插入图片描述
在这里插入图片描述

显示鼠标坐标功能

在这里插入图片描述

开启游标回调函数
在这里插入图片描述

private void chartWave_CursorPositionChanged(object sender, System.Windows.Forms.DataVisualization.Charting.CursorEventArgs e)
{
    if (e.Axis.Name.ToLower().StartsWith("x"))
    {
        labX.Text = e.NewPosition.ToString();
    }
    else if (e.Axis.Name.ToLower().StartsWith("y"))
    {
        labY.Text = e.NewPosition.ToString();
    }
}

缩放位置设置

在这里插入图片描述
在这里插入图片描述
位置和大小可以在程序中直接通过代码控制,Y轴的也是如此

线

一个坐标轴空间可以绘制多条线

显示线上点数值

在这里插入图片描述

在这里插入图片描述

线类型

在这里插入图片描述
线的类型一般选FastPoint 或者FastLine 其他的会影响曲线绘制效率,绘制的点越多,刷新越慢

chart绑定数据源

和列表控件一样,chart控件可以绑定DataTable,绑定分为三步,首先为DataTable创建列,然后将DataTable的列名和线的x,y绑定起来,最后将chart和DataTable绑定起来,接下来向DataTable添加列数据,刷新图表即可显示曲线

 /// <summary>
 /// chart控件数据源类型
 /// </summary>
 private DataTable dataTableType = new DataTable("Wave");
 /// <summary>
 /// chart控件数据源列表
 /// </summary>
 List<DataTable> dataTables = new List<DataTable>();
 /// <summary>
 /// 图表刷新线程
 /// </summary>
 Thread thread;
 private void ChartWaveInit()
 {
     //1。 创建一个dataTable 10列 第一列存数据点x坐标 其它九列存y
     for(int i = 0; i < 10; i ++)
     {
         dataTableType.Columns.Add("Series"+i);
         dataTableType.Columns["Series" + i].DataType = typeof(int);
     }

     //2. 绑定数据列 给九条曲线指定x y列名
     for(int i = 0; i < chartWave.Series.Count; i++)
     {
         chartWave.Series[i].XValueMember = "Series0";
         chartWave.Series[i].YValueMembers = "Series"+ (i+1);
     }

     dataTables.Add(dataTableType.Clone());
     //3. 绑定数据源
     chartWave.DataSource = dataTables[0];

     //刷新图表
     chartWave.DataBind();
}

实际使用chart时,发现当数据点过多时,使用 chartWave.DataBind();刷新图表数据点越多越慢,因此程序中1s左右刷新一次图表。当数据点超过1w时,1s刷新一次都不行,因此创建了DataTables 列表,当DataTable行数大于1w后,切换图表数据源到下一个DataTable,防止数据点过多越来越卡。

/// <summary>
/// 帧头
/// </summary>
byte frameHead = 0xaa;
/// <summary>
/// 帧长
/// </summary>
int frameLen = 38;
private void Analysis()
{
    
    List<byte> listBytes = new List<byte>(1024);
    int counter = 0;
    int yValue = int.MaxValue;
    while (true)
    {
        Thread.Sleep(50);
        counter++;
        if (serialPortCOM.IsOpen)
        {
            byte[] bytes = new byte[serialPortCOM.BytesToRead];
            serialPortCOM.Read(bytes, 0, bytes.Length);
            this.Invoke(new Action(() => RxCounter += bytes.Length));
            listBytes.AddRange(bytes);

            while (listBytes.Contains(frameHead) && (listBytes.Count - listBytes.IndexOf(frameHead)) >= frameLen)
            {
                int Index = listBytes.IndexOf(frameHead);
                if (listBytes[Index + 1] == 0xFF && listBytes[Index + 2] == 0xF1 && listBytes[Index + 3] == 32)
                {
                    byte[] tempBytes = listBytes.ToArray();
                    int Wave1 = BitConverter.ToInt32(tempBytes, Index + 4);
                    int Wave2 = BitConverter.ToInt32(tempBytes, Index + 8);
                    int Wave3 = BitConverter.ToInt32(tempBytes, Index + 12);
                    int Wave4 = BitConverter.ToInt32(tempBytes, Index + 16);
                    int Wave5 = BitConverter.ToInt32(tempBytes, Index + 20);
                    int Wave6 = BitConverter.ToInt32(tempBytes, Index + 24);
                    int Wave7 = BitConverter.ToInt32(tempBytes, Index + 28);
                    int Wave8 = BitConverter.ToInt32(tempBytes, Index + 32);

                    lock (chartLock)
                    {
                        dataTables[dataTables.Count - 1].Rows.Add(WaveXIndex++, Wave1, Wave2, Wave3, Wave4, Wave5, Wave6, Wave7, Wave8);
                        
                        //记录y值, 后面修改y轴位置
                        for(int i = 1; i < 9; i++)
                        {
                            if(chartWave.Series[i].Enabled)
                            {   
                                yValue = (int)dataTables[dataTables.Count - 1].Rows[dataTables[dataTables.Count - 1].Rows.Count - 1][i];
                                break;
                            }
                        }

                        //表中超过 MaxSeriesLen 条数据 切换下一个表 一个表中数据越长则图表刷新时间越长
                        if (dataTables[dataTables.Count - 1].Rows.Count >= MaxSeriesLen)
                        {
                            dataTables.Add(dataTableType.Clone());
                            for (int i = MaxSeriesLen/2; i < MaxSeriesLen; i++)
                            {
                                dataTables[dataTables.Count - 1].Rows.Add(dataTables[dataTables.Count - 1 - 1].Rows[i].ItemArray);
                            }

                            this.BeginInvoke(new Action(() => trackBar1.Maximum += 10));

                            if (ckbUpdata.Checked)
                            {
                                //显示最新数据点
                                chartWave.DataSource = dataTables[dataTables.Count - 1];

                                this.BeginInvoke(new Action(() => { trackBar1.Value = trackBar1.Maximum; }));
                            }
                        }
                    }
                    listBytes.RemoveRange(0, Index + frameLen);
                }
                else
                {
                    listBytes.RemoveRange(0, Index);
                }
            }

            if (counter > 20 && yValue < int.MaxValue)
            {
                int temp = yValue;
                counter = 0;
                yValue = int.MaxValue;
                this.BeginInvoke(new Action(() => {
                    
                    lock (chartLock)
                    {
                        //X轴 滚动条位置 保持最新位置 - 99
                        if (ckbUpdata.Checked)
                        {
                            if (dataTables[dataTables.Count - 1].Rows.Count > chartWave.ChartAreas[0].AxisX.ScaleView.Size)
                            {
                                chartWave.ChartAreas[0].AxisX.ScaleView.Position = WaveXIndex - chartWave.ChartAreas[0].AxisX.ScaleView.Size;
                            }
                            else
                            {
                                chartWave.ChartAreas[0].AxisX.ScaleView.Position = 0;
                            }

                            //Y轴 滚动条位置 保持最新位置
                            chartWave.ChartAreas[0].AxisY.ScaleView.Position = temp - chartWave.ChartAreas[0].AxisY.ScaleView.Size/2;
                        }

                        //X轴 数据的起始位置和结束位置 
                        //chart1.ChartAreas[0].AxisX.Minimum = 1000;
                        //chart1.ChartAreas[0].AxisX.Maximum =  dataTables[dataTables.Count - 1].Rows.Count;


                        //刷新图表
                        chartWave.DataBind();
                    }

                }));
                
            }

        }
    }

}

传输协议

传输协议使用匿名上位机V7的用户自定义帧F1格式

#include "ANO_DT.h"
#include "stm32f1xx.h"


#define BYTE3(dwTemp)       ( *( (char *)(&dwTemp)		) )    
#define BYTE2(dwTemp)       ( *( (char *)(&dwTemp) + 1) )    
#define BYTE1(dwTemp)       ( *( (char *)(&dwTemp) + 2) )    
#define BYTE0(dwTemp)       ( *( (char *)(&dwTemp) + 3) )    
    
/*!
  * @brief    发送底层
  *
  * @param    dataToSend   :   发送数据
  * @param    length       :   发送数据长度
  *
  * @return   无
  *
  * @note     移植时,需要自己实现该发送函数
  *
  * @see      
  *
  * @date     2019/5/28 ???
  */
void ANO_DT_Send_Data(uint8_t *dataToSend , uint8_t length)
{
    extern UART_HandleTypeDef huart1;
    HAL_UART_Transmit(&huart1, dataToSend, length, 1000);
}
/**  ?????? */
uint8_t data_to_send[50];


/*!
  * @brief    发送8个int32 数据给上位机
  *
  * @param    data1 - data8  : 数据
  *
  * @return   无
  *
  * @note     
  *
  * @see      ANO_DT_send_int32(1, 2, 3, 0, 0, 0, 0, 0);
  *
  * @date     2019/5/28 ???
  */
void ANO_DT_send_int32(int32_t data1, int32_t data2, int32_t data3,int32_t data4 ,int32_t data5, int32_t data6, int32_t data7, int32_t data8)
{
  uint8_t _cnt=0;
  data_to_send[_cnt++] = 0xAA;      //帧头  0xAAAA
  data_to_send[_cnt++] = 0xFF;      
  data_to_send[_cnt++] = 0xF1;      //功能字 0xF1  
  data_to_send[_cnt++] = 32;        //帧长

  data_to_send[_cnt++]=BYTE3(data1);
  data_to_send[_cnt++]=BYTE2(data1);
  data_to_send[_cnt++]=BYTE1(data1);
  data_to_send[_cnt++]=BYTE0(data1);

  data_to_send[_cnt++]=BYTE3(data2);
  data_to_send[_cnt++]=BYTE2(data2);
  data_to_send[_cnt++]=BYTE1(data2);
  data_to_send[_cnt++]=BYTE0(data2);

  data_to_send[_cnt++]=BYTE3(data3);
  data_to_send[_cnt++]=BYTE2(data3);
  data_to_send[_cnt++]=BYTE1(data3);
  data_to_send[_cnt++]=BYTE0(data3);

  data_to_send[_cnt++]=BYTE3(data4);
  data_to_send[_cnt++]=BYTE2(data4);
  data_to_send[_cnt++]=BYTE1(data4);
  data_to_send[_cnt++]=BYTE0(data4);

  data_to_send[_cnt++]=BYTE3(data5);
  data_to_send[_cnt++]=BYTE2(data5);
  data_to_send[_cnt++]=BYTE1(data5);
  data_to_send[_cnt++]=BYTE0(data5);

  data_to_send[_cnt++]=BYTE3(data6);
  data_to_send[_cnt++]=BYTE2(data6);
  data_to_send[_cnt++]=BYTE1(data6);
  data_to_send[_cnt++]=BYTE0(data6);

  data_to_send[_cnt++]=BYTE3(data7);
  data_to_send[_cnt++]=BYTE2(data7);
  data_to_send[_cnt++]=BYTE1(data7);
  data_to_send[_cnt++]=BYTE0(data7);

  data_to_send[_cnt++]=BYTE3(data8);
  data_to_send[_cnt++]=BYTE2(data8);
  data_to_send[_cnt++]=BYTE1(data8);
  data_to_send[_cnt++]=BYTE0(data8);

  uint8_t sum = 0;
  uint8_t sumCheck = 0;
  for(uint8_t i=0;i<_cnt;i++)
  {
    sum += data_to_send[i];
    sumCheck+= sum;
  }
  data_to_send[_cnt++]=sum;
  data_to_send[_cnt++]=sumCheck;
  ANO_DT_Send_Data(data_to_send, _cnt);
}

最后,说实话这个串口助手的波形显示功能还是比较鸡肋的,刷新太慢了,后面有时间会研究一下github上的开源图表控件 https://github.com/beto-rodriguez/LiveCharts2

以上是关于C# 学习笔记(15)自己的串口助手----波形显示的主要内容,如果未能解决你的问题,请参考以下文章

C# 学习笔记(14)自己的串口助手----多行发送

C#上位机开发一:串口通讯之如何制作一个串口调试助手

推荐一款好用的串口波形显示助手----虚拟示波器

Qt5学习笔记之串口助手四:增加16进制/ASCII切换周期发送

学习笔记类目录一览--不定期更新

QT5.14串口调试助手:上位机接收数据解析数据帧+多通道波形显示+数据保存为csv文件