C#winform上位机开发学习笔记11-串口助手接收数据用波形显示功能添加

1.功能描述

接收串口数据,并将收到的十六进制数据用坐标系的方式将数据波形展示出来

2.代码部分

步骤1:定义链表,用于数据保存

        //数据结构-线性链表private List<byte> DataList = new List<byte>();

步骤2:定义波形颜色

        //定义波形颜色private Pen LinesPen = new Pen(Color.FromArgb(0xFF,0x00,0x00));//FF 00 00 为红色

步骤3:绘制接收数据的波形

            //如果数据量大于可容纳的数据量,则删除最左数据if (DataList.Count >= (this.ClientRectangle.Width - StartPrint) / DrawStep){DataList.RemoveRange(0, DataList.Count - (this.ClientRectangle.Width - StartPrint) / DrawStep);}//绘制波形for(int i = 0; i < DataList.Count - 1; i++){//点与点之间做直线连接e.Graphics.DrawLine(LinesPen, StartPrint + i * DrawStep, StartPrint + Unit_length * 16 - DataList[i] * (Unit_length / 16), StartPrint + (i + 1) * DrawStep, StartPrint + Unit_length * 16 - DataList[i + 1] * (Unit_length / 16));}

步骤4:定义数据添加函数

//定义链表尾部添加数据public void AddDataToWaveList(byte[] Data){for (int i = 0; i < Data.Length; i++)DataList.Add(Data[i]);this.Invalidate();//刷新显示}

步骤5:串口接收函数中添加代码

                    //更新波形显示窗体的链表数据if(WaveForm != null){WaveForm.AddDataToWaveList(data);}

完整接收函数

//串口接收事件private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e){//接收格式为ASCII码if (!checkBox16.Checked)//复用框没有被选择时{try{textBox1.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "->");string str = serialPort1.ReadExisting();//将接收到的数据存在自定义的字符串变量中textBox1.AppendText(str + "\r\n");//统计接收字节数UInt32 RBytes = Convert.ToUInt32(textBox7.Text, 10);//定义接收字节数变量,并初始化为已接收字节数RBytes += (UInt32)str.Length;//加ASCII码字节数textBox7.Text = Convert.ToString(RBytes, 10);//显示总接收字节数}catch{textBox1.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "->");textBox1.AppendText("ASCII格式接收错误!\r\n");}}//接收格式为HEXelse{try{//断帧功能if (Timer4_Flag == true){Timer4_Flag = false;textBox1.AppendText("\r\n");textBox1.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "->");}//textBox1.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "->"); //此处被断帧功能替代换行byte[] data = new byte[serialPort1.BytesToRead];//定义接收缓冲区,长度为串口接收的数据长度serialPort1.Read(data, 0, data.Length);//形参,起始位置,终止位置,将读取的数据存放在缓冲区//遍历用法foreach (byte Member in data)//循环函数{string str = Convert.ToString(Member, 16).ToUpper();//转化为十六进制大写textBox1.AppendText((str.Length == 1 ? "0" + str : str) + " ");//数据+空格“”}//textBox1.AppendText("\r\n"); //此处被断帧功能替代换行//统计接收字节数UInt32 RBytes = Convert.ToUInt32(textBox7.Text, 10);//定义接收字节数变量,并初始化为已接收字节数RBytes += (UInt32)data.Length;//加HEX字节数textBox7.Text = Convert.ToString(RBytes, 10);//显示总接收字节数//更新波形显示窗体的链表数据if(WaveForm != null){WaveForm.AddDataToWaveList(data);}}catch{textBox1.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "->");textBox1.AppendText("HEX格式接收错误!\r\n");}}}

步骤6:接收HEX数据波形显示时,子窗体出现抖动现象原因:缓存不足,启动双缓存显示,缓存1用于窗体显示,缓存2用于波形更新

        public WaveForm(){//波形稳定刷新//开启双缓冲this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint    |ControlStyles.AllPaintingInWmPaint,true);this.UpdateStyles();InitializeComponent();}

#加入此代码后波形显示不再抖动

步骤7:打开波形显示时同步打开串口及HEX勾选

方便再重复两次操作

这里参考了博客CheckBox控件的用法

            //打开波形显示按钮时同步打开串口if (!serialPort1.IsOpen){    button2.PerformClick();//打开串口按钮单击事件this.checkBox16.Checked = true; //打开HEX勾选}

3.完整代码

//主窗体程序
//串口接收事件private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e){//接收格式为ASCII码if (!checkBox16.Checked)//复用框没有被选择时{try{textBox1.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "->");string str = serialPort1.ReadExisting();//将接收到的数据存在自定义的字符串变量中textBox1.AppendText(str + "\r\n");//统计接收字节数UInt32 RBytes = Convert.ToUInt32(textBox7.Text, 10);//定义接收字节数变量,并初始化为已接收字节数RBytes += (UInt32)str.Length;//加ASCII码字节数textBox7.Text = Convert.ToString(RBytes, 10);//显示总接收字节数}catch{textBox1.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "->");textBox1.AppendText("ASCII格式接收错误!\r\n");}}//接收格式为HEXelse{try{//断帧功能if (Timer4_Flag == true){Timer4_Flag = false;textBox1.AppendText("\r\n");textBox1.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "->");}//textBox1.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "->"); //此处被断帧功能替代换行byte[] data = new byte[serialPort1.BytesToRead];//定义接收缓冲区,长度为串口接收的数据长度serialPort1.Read(data, 0, data.Length);//形参,起始位置,终止位置,将读取的数据存放在缓冲区//遍历用法foreach (byte Member in data)//循环函数{string str = Convert.ToString(Member, 16).ToUpper();//转化为十六进制大写textBox1.AppendText((str.Length == 1 ? "0" + str : str) + " ");//数据+空格“”}//textBox1.AppendText("\r\n"); //此处被断帧功能替代换行//统计接收字节数UInt32 RBytes = Convert.ToUInt32(textBox7.Text, 10);//定义接收字节数变量,并初始化为已接收字节数RBytes += (UInt32)data.Length;//加HEX字节数textBox7.Text = Convert.ToString(RBytes, 10);//显示总接收字节数//更新波形显示窗体的链表数据if(WaveForm != null){WaveForm.AddDataToWaveList(data);}}catch{textBox1.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "->");textBox1.AppendText("HEX格式接收错误!\r\n");}}}
//波形显示按钮事件private void button30_Click(object sender, EventArgs e){//第一次创建WaveForm实体if (WaveForm == null){//创建新窗体WaveForm = new WaveForm();}else{//多次创建通过判断IsDisposed确定窗口是否已经关闭,避免同窗口多开if (WaveForm.IsDisposed == true)//判断该控件有无释放,若释放则重新创建窗体{//如果窗体已经关闭,需要重新创新WaveForm = new WaveForm();}}//新建窗体//WaveForm = new WaveForm();//发现不用if语句判断直接创建窗体也能实现一样的功能//窗体展示WaveForm.Show();//设置波形窗体紧靠主窗体this.Left = 0;//主窗体左边的坐标为0WaveForm.Location = this.Location;//主窗体坐标赋给子窗体WaveForm.Left = this.Right;//主窗体的右显示坐标赋给子窗体左显示坐标//打开波形显示按钮时同步打开串口if (!serialPort1.IsOpen){button2.PerformClick();//打开串口按钮单击事件this.checkBox16.Checked = true; //打开HEX勾选}
//子窗体程序
namespace 上位机初始界面
{public partial class WaveForm : Form{//点坐标偏移量private const int StartPrint = 40;//单位格大小private const int Unit_length = 32;//默认绘制单位//脚距越大容纳数据越小,脚距越小容纳数据越大private int DrawStep = 8;//每一单元格的成分格子长度为8,影响横轴数字宽度,此处参数设置是4倍//绘制单位最大值private const int MaxStep = 32;//绘制单位最小值private const int MinStep = 1;//定义轴线颜色private Pen TablePen = new Pen(Color.FromArgb(0x00,0x00,0x00));//00 00 00 为黑色//用于波形显示的变量声明//数据结构-线性链表private List<byte> DataList = new List<byte>();//定义波形颜色private Pen LinesPen = new Pen(Color.FromArgb(0xFF,0x00,0x00));//FF 00 00 为红色public WaveForm(){//波形稳定刷新//开启双缓冲this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint    |ControlStyles.AllPaintingInWmPaint,true);this.UpdateStyles();InitializeComponent();}//加载子窗体事件private void WaveForm_Load(object sender, EventArgs e){//重新设定波形显示窗体尺寸int Width = Screen.GetWorkingArea(this).Width - Form1.MainForm.Width;//显示宽度为屏幕尺寸-主窗体尺寸int Heigth = this.Height - this.ClientRectangle.Height;//显示整个高度 - 工作区矩形 = 只剩下菜单栏Heigth += Unit_length * 16;//32*16Heigth += StartPrint * 2;this.Size = new Size(Width, Heigth);}
//定义链表尾部添加数据-数据从串口输入public void AddDataToWaveList(byte[] Data){for (int i = 0; i < Data.Length; i++)DataList.Add(Data[i]);this.Invalidate();//刷新窗体显示}//子窗体绘制事件private void WaveForm_Paint(object sender, PaintEventArgs e){String Str = "";System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();//绘制横轴线for(int i = 0; i < (this.ClientRectangle.Height - StartPrint) / Unit_length; i++){//画横线-----画笔颜色,起始坐标,终点坐标e.Graphics.DrawLine(TablePen, StartPrint, StartPrint + i * Unit_length, this.ClientRectangle.Width, StartPrint + i * Unit_length);//绘制纵坐标Str = ((16 - i) * 16).ToString("X");Str = "0x" + (Str.Length == 1 ? Str + "0" : Str);if(i == 0)Str = "0xFF";//添加文字gp.AddString(Str, this.Font.FontFamily, (int)FontStyle.Regular, 13, new RectangleF(0, StartPrint + i * Unit_length - 8, 400, 50), null);                        }//绘制纵轴线for(int i = 0; i <=(this.ClientRectangle.Width - StartPrint) / Unit_length; i++){//画纵线e.Graphics.DrawLine(TablePen, StartPrint + i * Unit_length, StartPrint, StartPrint + i * Unit_length, StartPrint + Unit_length * 16);//绘制横坐标gp.AddString((i * (Unit_length / DrawStep)).ToString(), this.Font.FontFamily,(int)FontStyle.Regular,13,new RectangleF(StartPrint + i * Unit_length - 7,this.ClientRectangle.Height - StartPrint + 4, 400, 50),null);}//绘制文字e.Graphics.DrawPath(Pens.Black, gp);//如果数据量大于可容纳的数据量,则删除最左数据if (DataList.Count >= (this.ClientRectangle.Width - StartPrint) / DrawStep){DataList.RemoveRange(0, DataList.Count - (this.ClientRectangle.Width - StartPrint) / DrawStep);}//绘制波形for(int i = 0; i < DataList.Count - 1; i++){//点与点之间做直线连接e.Graphics.DrawLine(LinesPen, StartPrint + i * DrawStep, StartPrint + Unit_length * 16 - DataList[i] * (Unit_length / 16), StartPrint + (i + 1) * DrawStep, StartPrint + Unit_length * 16 - DataList[i + 1] * (Unit_length / 16));}}}
}

4.测试结果

接收下位机十六进制数据并显示在子窗体的坐标系中,数据波形显示

参考自B站硬件家园

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/643485.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

shell脚本2

在自定义变量当中&#xff0c;不可以以数字开头 变量追加值 在变量名后要写的东西 read -p &#xff1a;交互式输入变量值&#xff0c;然后使用变量 自定义变量 export 全局变量 如果想要bash里面的所有进程都能看见变量&#xff0c;加入export 父进程 子进程…

计算机毕业设计 基于SpringBoot的民宿租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Sentinel 新版本发布,提升配置灵活性以及可观测配套

作者&#xff1a;屿山 基本介绍 Sentinel 是阿里巴巴集团开源的&#xff0c;面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;承接了阿里巴巴近 15 年的双十一大促流量的核心场景&#xff0c;例如秒杀、冷启动、消息削峰填谷、集群流量控制、实时熔断下游不可用服…

考研C语言刷题基础篇之分支循环结构基础(二)

目录 第一题分数求和 第二题&#xff1a;求10 个整数中最大值 第三题&#xff1a;在屏幕上输出9*9乘法口诀表 第四题&#xff1a;写一个代码&#xff1a;打印100~200之间的素数 第五题&#xff1a;求斐波那契数的第N个数 斐波那契数的概念&#xff1a;前两个数相加等于第三…

2023 工业 AR 关键词:纵深和开拓

2023 年&#xff0c;以虚实融合、工业元宇宙为代表的“新数字化”升级在工业制造领域达成共识。 ▲五部委联合印发元宇宙行动计划 通过发展元宇宙赋能新型工业化 而相对过去几年的行业渗透广、落地场景多样的 AR 业务拓展与合作&#xff0c;#纵深和#开拓&#xff0c;成为 2023…

80端口被占用解决思路

普及一个概念&#xff1a;80端口是 HTTP&#xff08;HyperText Transport Protocol)即超文本传输协议开放的&#xff0c;此为上网冲浪使用次数最多的协议&#xff0c;主要用于WWW&#xff08;World Wide Web&#xff09;即万维网传输信息的协议。 我们使用 http 域名访问时都会…

Vue3 ref与reactive

✨ 专栏介绍 在当今Web开发领域中&#xff0c;构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架&#xff0c;正是为了满足这些需求而诞生。它采用了MVVM架构模式&#xff0c;并通过数据驱动和组件化的方式&#xff0c;使…

HarmonyOS鸿蒙学习基础篇 - 基本语法概述

书接上文 HarmonyOS鸿蒙学习基础篇 - 运行第一个程序 Hello World 基本语法概述 打开 entry>src>main>ets>pages>index.ets 代码如下代码详细解释如下&#xff1a; Entry //Entry装饰的自定义组件将作为UI页面的入口。在单个UI页面中&#xff0c;最多可以使用…

Dify学习笔记-应用发布(四)

1、发布为公开 Web 站点 使用 Dify 创建 AI 应用的一个好处在于&#xff0c;你可以在几分钟内就发布一个可供用户使用的 Web 应用&#xff0c;该应用将根据你的 Prompt 编排工作。 如果你使用的是自部署的开源版&#xff0c;该应用将运行在你的服务器上 如果你使用的是云服务&…

2024年跨境电商上半年有哪些营销节日?

2024年伊始&#xff0c;跨境电商开启新一轮的营销竞技&#xff0c;那么首先需要客户需求&#xff0c;节假日与用户需求息息相关&#xff0c;那么接下来小编为大家整理2024上半年海外都有哪些节日和假期&#xff1f;跨境卖家如何见针对营销日历选品&#xff0c;助力卖家把握2024…

Java框架篇面试题

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于java面试题系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基…

flutter底层架构初探

本文出处&#xff1a;​​​​​​​​​​​​​Flutter 中文开发者网站 架构 embedder嵌入层 提供程序入口&#xff08;其他原生应用也采用此方式&#xff09;&#xff0c;程序由此和底层操作系统协调&#xff08;surface渲染、辅助功能和输入服务&#xff0c;管理事件循环…

书生·浦语大模型--第四节课笔记--XTuner大模型单卡低成本微调

文章目录 Finetune简介指令跟随微调增量预训练微调LoRA QLoRA XTuner介绍快速上手 8GB显卡玩转LLM动手实战环节 Finetune简介 增量预训练和指令跟随 通过指令微调获得instructed LLM 指令跟随微调 一问一答的方式进行 对话模板 计算损失 增量预训练微调 不需要问题只…

微签电子印章系统赋能国泰基金办公自动化升级

近期&#xff0c;国泰基金引入微签电子印章系统&#xff0c;通过印章服务器自动化印章方案&#xff0c;成功搭建起电子印章自动化平台&#xff0c;主要解决了其账单数量过多、极度耗费人力的难题&#xff0c;缩短了印章发送流程和时间&#xff0c;提升了国泰基金的整体办公效率…

Prometheus 架构全面解析

在本指南中&#xff0c;我们将详细介绍 Prometheus 架构。 Prometheus 是一个用 Golang 编写的开源监控和告警系统&#xff0c;能够收集和处理来自各种目标的指标。您还可以查询、查看、分析指标&#xff0c;并根据阈值收到警报。 此外&#xff0c;在当今世界&#xff0c;可观…

通过代理服务器的方式解决跨域问题

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学&#xff0c;可以点心心支持一下哈 这里以本地访问https://heimahr.itheima.net/api/sys/permission接口为列子 Node.js 代理服务器 (server.js) 本次考虑使用JSONP或CORS代理来…

助力医疗数字化转型,贝锐x医百科技案例解析

在医疗数字化这个历史进程的大浪潮中&#xff0c;医药企业扮演着重要的角色&#xff0c;其重要程度恐怕仅次于医疗机构本身。同时&#xff0c;数字化转型对于医药企业的赋能作用也是十分明显的&#xff0c;尤其在营销端&#xff0c;一系列的数字化管理、数字化推广方案已经成为…

安装IIS及搭建asp.net程序遇到的问题

一、安装IIS 在服务器管理中选择IIS&#xff0c;右键选择添加角色和功能 在服务器角色中&#xff0c;应用程序开发中要选择ASP.NET3.5、ASP.NET4.6功能。 单击下一步执行安装即可。 二、常见问题 问题1. HTTP 错误404.17 - Not Found 解决方法&#xff1a; 出现以上问题没有…

SpringBoot使用Swagger2生成接口文档

一、导入依赖 <!-- knife4j--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>2.0.7</version></dependency> 二、配置类 通过一下配置&am…

USRP相关报错解决办法

文章目录 前言一、本地环境二、相关报错信息二、解决办法1、更换电脑操作系统2、升级最新版固件 前言 在进行 USRP 开发时遇到了一些报错&#xff0c;这里做个记录解决问题的方法。 一、本地环境 电脑操作系统&#xff1a;Windows11MATLAB 版本&#xff1a;MATLAB 2021aUSRP …