C#上位机(绘制波形)

1.绘制图形相关参数设置

//绘图相关定义
private const int Unit_length = 32;//单位格大小
private int DrawStep = 8;          //默认绘制单位
private const int Y_Max = 512;     //Y轴最大数值
private const int MaxStep = 33;    //绘制单位最大值
private const int MinStep = 1;     //绘制单位最小值
private const int StartPrint = 32; //点坐标偏移量
private List<byte> DataList = new List<byte>();                  //数据结构----线性链表
private Pen TablePen = new Pen(Color.FromArgb(0x00, 0x00, 0x00));//轴线颜色
private Pen LinesPen = new Pen(Color.FromArgb(0xa0, 0x00, 0x00));//波形颜色

2.开启双缓冲

开启双缓冲的目的是防止闪烁,因为数据一致在更新的过程中,波形会一直闪烁

//Drawer窗口初始化|防止闪烁
public Drawer()
{
    this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint |
                   ControlStyles.AllPaintingInWmPaint,
                   true);//开启双缓冲 防止闪烁 【因为一直 更新数据 会闪烁】 
    this.UpdateStyles();
    InitializeComponent();
}

3.绘制xy轴网格,绘制波形

//绘制xy轴网格,绘制波形
private void Form1_Paint(object sender, PaintEventArgs e)//画
{
    String Str = "";
    System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
    e.Graphics.FillRectangle(Brushes.White, e.Graphics.ClipBounds);
    //Draw Y 纵向轴绘制(y坐标绘制)
    for (int i = 0; i <= this.ClientRectangle.Width / Unit_length; i++)
    {
        e.Graphics.DrawLine(TablePen, StartPrint + i * Unit_length, StartPrint, StartPrint + i * Unit_length, StartPrint + Y_Max);//画线

        gp.AddString((i * (Unit_length / DrawStep)).ToString(), this.Font.FontFamily, (int)FontStyle.Regular, 12, new RectangleF(StartPrint + i * Unit_length - 7, this.ClientRectangle.Height - StartPrint + 4, 400, 50), null);//添加文字
    }

    //Draw X 横向轴绘制(x坐标绘制)
    for (int i = 0; i <= this.ClientRectangle.Height / Unit_length; i++)
    {
        e.Graphics.DrawLine(TablePen, StartPrint, (i + 1) * Unit_length, this.ClientRectangle.Width, (i + 1) * Unit_length);//画线
        Str = ((16 - i) * 16).ToString("X");
        Str = "0x" + (Str.Length == 1 ? Str + "0" : Str);
        if (i == 0)
            Str = "0xFF";
        if (i == 17)
            break;
        gp.AddString(Str, this.Font.FontFamily, (int)FontStyle.Regular, 14, new RectangleF(0, StartPrint + i * Unit_length - 8, 400, 50), null);//添加文字
    }
    e.Graphics.DrawPath(Pens.Black, gp);//写文字


    if (DataList.Count - 1 >= (this.ClientRectangle.Width - StartPrint) / DrawStep) //如果数据量大于可容纳的数据量,即删除最左数据 | 波形左移
    {
        DataList.RemoveRange(0, DataList.Count - (this.ClientRectangle.Width - StartPrint) / DrawStep - 1);
    }

    //绘制波形 DataList.Count;
    for (int i = 0; i < DataList.Count - 1; i++)//绘制
    {
        e.Graphics.DrawLine(LinesPen, StartPrint + i * DrawStep, 17 * Unit_length - DataList[i] * 2, StartPrint + (i + 1) * DrawStep, 17 * Unit_length - DataList[i + 1] * 2);
    }
}

4.获取串口数据,并添加至链表中

//把数据加到链表中———在MainForm的串口数据接收函数调用
public void AddData(byte[] Data)
{
    for (int i = 0; i < Data.Length; i++)
        DataList.Add(Data[i]);//链表尾部添加数据
    Invalidate();//刷新显示
}

5.实例化委托

//实例化委托对象
public ShowWindow ShowMainWindow; //定义显示主窗口委托访问权限为public
public HideWindow HideMainWindow; //定义隐藏主窗口委托
public OpenPort OpenSerialPort;   //定义打开串口委托
public ClosePort CloseSerialPort; //定义关闭串口委托
public GetMainPos GetMainPos;     //定义获取主窗口信息委托(自动对齐)
public GetMainWidth GetMainWidth; //定义获取主窗口宽度(自动对齐)

6.定义委托

//定义委托
public delegate void ShowWindow();
public delegate void HideWindow();
public delegate void OpenPort();
public delegate void ClosePort();
public delegate Point GetMainPos();
public delegate int GetMainWidth();

7.委托函数

//委托函数编写
//关闭串口,供委托调用
 public void ClosePort()
 {
     try
     {
         serialPort1.Close();
     }
     catch (System.Exception)
     {

     }
 }

 //打开串口,供委托调用
 public void OpenPort()
 {
     try
     {
         serialPort1.Open();
     }
     catch (System.Exception)
     {
         MessageBox.Show("串口打开失败,请检查", "错误");
     }
 }

 //供委托调用
 private Point GetMyPos()
 {
     return this.Location;
 }

 //供委托调用
 public void ShowMe()
 {
     this.Show();
 }

 //供委托调用
 public void HideMe()
 {
     this.Hide();
 }

 //供委托调用
 int GetMyWidth()
 {
     return this.Width;
 }

8.显示绘图窗口

//实例化Drawer窗口,使得在MainForm可操作Drawer
Drawer Displayer;

 //创建&显示绘图窗口 | 初始化类成员委托
 private void CreateNewDrawer()//创建Drawer窗口
 {
     //创建新对象
     Displayer = new Drawer();
     //初始化类成员委托            
     Displayer.ShowMainWindow = new ShowWindow(ShowMe);
     Displayer.HideMainWindow = new HideWindow(HideMe);
     Displayer.GetMainPos = new GetMainPos(GetMyPos);
     Displayer.CloseSerialPort = new ClosePort(ClosePort);
     Displayer.OpenSerialPort = new OpenPort(OpenPort);
     Displayer.GetMainWidth = new GetMainWidth(GetMyWidth);
     //显示窗口
     Displayer.Show();                                 
 }

9.设置主窗口大小

//主窗口设置自己 的 大小位——在MainForm的CreateDisplayer调用
public void SetWindow(int width, Point Pt)//允许主窗口设置自己
{
    int height = this.ClientRectangle.Height;
    height = this.Height - height;
    int BorderWeigh = this.Width - this.ClientRectangle.Width;
    this.Size = new Size(width - (width - BorderWeigh) % Unit_length, height + Y_Max + StartPrint + Unit_length);
    this.Location = Pt;
}

10.定义快捷键状态

//定义快捷键状态
private bool KeyShift, KeyShowMain, KeyHideMain, KeyExit, KeyOpen, KeyClose, KeyStepUp, KeyStepDown;

11.实现快捷键

//按下松开后才判断
private void Form1_KeyUp(object sender, KeyEventArgs e)//按键弹开,执行对应动作
{
    if (KeyShift)
    {
        if (KeyShowMain)//显示主窗体快捷键
        {
            ShowMainWindow();
            Rectangle Rect = Screen.GetWorkingArea(this);
            SetWindow(Rect.Width - GetMainWidth(), new Point(GetMainWidth(), GetMainPos().Y));//缩小自己
            KeyShowMain = false;
        }
        else
        {
            if (KeyOpen)
            {
                OpenSerialPort();//打开主窗口串口
                KeyOpen = false;
            }
            else
            {
                if (KeyClose)
                {
                    CloseSerialPort();//关闭主窗口串口
                    KeyClose = false;
                }
                else
                {
                    if (KeyExit)
                    {
                        KeyExit = false;//退出自己
                        Close();
                    }
                    else
                    {
                        if (KeyStepUp)
                        {
                            if (DrawStep < MaxStep)//绘制单位递增
                                DrawStep++;
                            Invalidate();
                            KeyStepUp = false;
                        }
                        else
                        {
                            if (KeyStepDown)
                            {
                                if (DrawStep > MinStep)//绘制单位递减
                                    DrawStep--;
                                Invalidate();
                                KeyStepDown = false;
                            }
                            else
                            {
                                if (KeyHideMain)
                                {
                                    HideMainWindow();//隐藏主窗口并扩大自己
                                    Rectangle Rect = Screen.GetWorkingArea(this);
                                    SetWindow(Rect.Width, new Point(0, GetMainPos().Y));
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    else//如果是其他按键,清空所有标志位
    {
        KeyClose = false;
        KeyOpen = false;
        KeyShowMain = false;
        KeyExit = false;
        KeyStepUp = false;
        KeyStepDown = false;
    }
    KeyShift = false;//清空shift标志位
}
private void Form1_KeyDown(object sender, KeyEventArgs e)//快捷键检测
{
    if (e.Shift)//shift功能键按下
        KeyShift = true;//标志位置位
    switch (e.KeyCode)//功能标志置位
    {
        case Keys.S://显示主窗口
            KeyShowMain = true;
            break;
        case Keys.E://退出波形显示
            KeyExit = true;
            break;
        case Keys.O://打开串口
            KeyOpen = true;
            break;
        case Keys.C://关闭串口
            KeyClose = true;
            break;
        case Keys.Up://放大波形
            KeyStepUp = true;
            break;
        case Keys.H://隐藏主窗口
            KeyHideMain = true;
            break;
        case Keys.Down://缩小波形
            KeyStepDown = true;
            break;
        default:
            break;
    }
}

12.关闭绘图窗口

//关闭绘图窗口事件处理函数
private void Drawer_FormClosing(object sender, FormClosingEventArgs e)
{
    ShowMainWindow();//关闭自己,显示主窗口
}

13.波形显示按钮

//波形显示按钮
private void button3_Click(object sender, EventArgs e)
{
    if (Displayer == null)//第一次创建Displayer = null
    {
        CreateDisplayer();
    }
    else
    {
        //多次创建通过判断IsDisposed确定串口是否已关闭,避免多次创建
        if (Displayer.IsDisposed)
        {
            CreateDisplayer();
        }
    }
}

14.创建绘图界面

//创建绘图界面 & 设置界面大小 与 主窗口 在 显示器屏幕 平行最大化显示
private void CreateDisplayer()
{
    this.Left = 0;
    CreateNewDrawer();
    Rectangle Rect = Screen.GetWorkingArea(this);
    Displayer.SetWindow(Rect.Width - this.Width, new Point(this.Width, this.Top));//设置绘制窗口宽度,以及坐标
}

15.打开串口

//打开串口
private void button1_Click(object sender, EventArgs e)
{
    try
    {
        serialPort1.PortName = comboBox1.Text;                                              //端口号
        serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);                             //波特率
        serialPort1.Open();                                                                 //打开串口
        button1.Enabled = false;
        button2.Enabled = true;
    }
    catch
    {
        MessageBox.Show("端口错误", "错误");
    }
}

16.关闭串口

//关闭串口
private void button2_Click(object sender, EventArgs e)
{
    try
    {
        serialPort1.Close();                                                            //关闭串口        
        button1.Enabled = true;
        button2.Enabled = false;
    }
    catch
    {

    }
}

17.发送数据

private void button4_Click(object sender, EventArgs e)
{
    byte[] Data = new byte[1];                                                         //单字节发数据     
    if (serialPort1.IsOpen)
    {
        if (textBox2.Text != "")
        {
            if (!radioButton1.Checked)
            {
                try
                {
                    serialPort1.Write(textBox2.Text);
                    //serialPort1.WriteLine();                             //字符串写入
                }
                catch
                {
                    MessageBox.Show("串口数据写入错误", "错误");
                }
            }
            else                                                                    //数据模式
            {
                try                                                                 //如果此时用户输入字符串中含有非法字符(字母,汉字,符号等等,try,catch块可以捕捉并提示)
                {
                    for (int i = 0; i < (textBox2.Text.Length - textBox2.Text.Length % 2) / 2; i++)//转换偶数个
                    {
                        Data[0] = Convert.ToByte(textBox2.Text.Substring(i * 2, 2), 16);           //转换
                        serialPort1.Write(Data, 0, 1);
                    }
                    if (textBox2.Text.Length % 2 != 0)
                    {
                        Data[0] = Convert.ToByte(textBox2.Text.Substring(textBox2.Text.Length - 1, 1), 16);//单独处理最后一个字符
                        serialPort1.Write(Data, 0, 1);                              //写入
                    }
                }
                catch
                {
                    MessageBox.Show("数据转换错误,请输入数字。", "错误");
                }
            }
        }
    }
}

18.串口接收数据处理函数

//串口接收数据处理函数
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    if (!radioButton3.Checked)
    {
        textBox1.AppendText(serialPort1.ReadExisting());                                //串口类会自动处理汉字,所以不需要特别转换
    }
    else
    {
        try
        {
            byte[] data = new byte[serialPort1.BytesToRead];                                //定义缓冲区,因为串口事件触发时有可能收到不止一个字节
            serialPort1.Read(data, 0, data.Length);
            if (Displayer != null)
                Displayer.AddData(data);    //添加到绘图窗口到数据链表 
            foreach (byte Member in data)                                                   //遍历用法
            {
                string str = Convert.ToString(Member, 16).ToUpper();
                textBox1.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + " ");
            }
        }
        catch { }
    }
}

19.窗体设置

 public Form1()
{
    //串口接收编码--实现汉字显示
    //serialPort1.Encoding = Encoding.GetEncoding("GB2312");  
    //不检查线程 
    System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
    InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
    for (int i = 1; i < 20; i++)
    {
        comboBox1.Items.Add("COM" + i.ToString());//添加串口
    }
    comboBox1.Text = "COM1";                      //默认选项
    comboBox2.Text = "4800";
}
  • 11
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值