C#三通道示波器-串口通信

tech2022-08-05  160

三通道示波器

【说明】 【语言】:C# 【平台】:Win10 .NETFrameWork 【硬件】:采用CH340作TTL转串口电平转换器 【信道复用方式】:分时复用 【下位机软件要求】:见代码注释 【代码使用方式】:使用vs建立C#窗体应用后直接将代码作为主文件即可 【注意事项】:目前的设定是PC连上串口设备后才能运行


下位机软件要求截取:

/*FuncTip * * @Name:YlocsOfChannlesInload * @Arg:None * @Func:将ylocs的数据加载到各通道缓冲区ylocsofChannelX * 下位机发送数据格式: * ————————————————————— * 标志数据|CH1数据|CH2数据|CH3数据|标志数据... * ————————————————————— * 数据长度:8bits * 建议二进制形式发送 * 如使用标准库printf * 建议采用%c格式发送数据 * */

完整代码:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Timers; using System.IO.Ports; using System.Threading; namespace RubbishDrawer { public partial class Form1 : Form { //窗体初始化 public Form1() { InitializeComponent(); /* 绘制作图区域边框 */ DrawTable(); /* 添加按钮 */ AddbtnStop(); ylocsInit(); /* 初始化时钟 */ TimerConfig(100);//时钟TIC间隔搞长点----<帧数>搞低点 /* 初始化串口 */ PortConfig(115200);//波特率设置为9600 串口在连接后才可被检测到 } /* ----------A-作图---------- */ /* 作图区相关常量 */ private const short TableLength = 63;//图板的长度 private const short TableHeight = 70;//图版的高度 private const int TableLeft = 50;//图板左边沿 private const int TableTop = 20;//图板上边沿 int[] ylocs = new int[TableLength * 4];//缓存发来的数据,用作points的y坐标元数据 int[] ylocsOfCh1 = new int[TableLength]; int[] ylocsOfCh2 = new int[TableLength]; int[] ylocsOfCh3 = new int[TableLength]; /* 计时器相关常量 */ private const int TicMax = TableLength + 2;//TIMENOW的上限(周期TIC数) /*FuncTip * * @Name:ylocsInit * @Arg:None * @Func:将各通道缓冲区ylocsofchX初始化位对应Y轴0刻度位置 * */ public void ylocsInit() { for(int ptr=0;ptr<TableLength;ptr++){ ylocsOfCh1[ptr] = TableTop; ylocsOfCh2[ptr] = TableTop + TableHeight / 3; ylocsOfCh3[ptr] = TableTop + 2 * TableHeight / 3; } } /*FuncTip * * @Name:DrawTable * @Arg:None * @Func:绘制作图区域边界 * */ public void DrawTable() { Point[] Edges = { new Point(TableLeft-1, TableTop), new Point(TableLeft+TableLength-1, TableTop), new Point(TableLeft+TableLength-1, TableTop+TableHeight-1), new Point(TableLeft-1, TableTop+TableHeight-1), new Point(TableLeft-1, TableTop), }; Graphics Table = CreateGraphics(); Table.PageUnit = GraphicsUnit.Millimeter; Pen TablePen = new Pen(Color.Black, 0.1F); Table.DrawLines(TablePen, Edges); Point[] CrossLines = { new Point(TableLeft-1, TableTop+TableHeight/3), new Point(TableLeft+TableLength-1, TableTop+TableHeight/3), new Point(TableLeft+TableLength-1, TableTop+2*TableHeight/3), new Point(TableLeft-1, TableTop+2*TableHeight/3), }; //TablePen.Width = 0.5F; Table.DrawLines(TablePen, CrossLines); } /* 添加控制按钮(绘图允许控制) */ /*FuncTip * * @Name:AddbtnStop * @Arg:None * @Func:添加按钮btnStop到窗体 * */ public void AddbtnStop() { Button btnStop = new Button(); btnStop.Text = "Stop"; btnStop.Top = TableTop + TableHeight + 2; btnStop.Left = TableLeft; btnStop.Click += new System.EventHandler(btnStopClk); this.Controls.Add(btnStop); } /*VarTip * * @Name:ShowOrNot * Function:绘图允许标志 * */ bool ShowOrNot = true; /*FuncTip * * @Name:btnStopClk * @Arg:sender触发事件的控件 * e事件(通用写法) * @Func:按键btnStop的单击事件响应函数 * 改变Var:ShowOrNot的值 * */ public void btnStopClk(object sender, EventArgs e) { ShowOrNot = ShowOrNot == true ? false : true; } /*FuncTip * * @Name:TimerConfig * @Arg:None * @Func:时钟(计时器)配置 * */ public void TimerConfig(int TimerTic) { /* 获取timer对象 */ System.Timers.Timer ATimer = new System.Timers.Timer(TimerTic); ATimer.AutoReset = true;//自动回填 ATimer.Elapsed += new System.Timers.ElapsedEventHandler(TimerEvent); ATimer.Enabled = true;//使能时钟 } /*FuncTip * * @Name:TimerEvent * @Arg:通用写法 * @Func:计时器事件响应函数 * 清空绘图区图像 * 读取串口数据 * 绘制新数据图像 * */ public void TimerEvent(object sender, ElapsedEventArgs e) { if (!ShowOrNot) return; /* 更新ylocs */ //清空图板 { Graphics ForNext = CreateGraphics(); PointF[] points = new PointF[TableLength]; PointF[] pointsForCh1 = new PointF[TableLength]; PointF[] pointsForCh2 = new PointF[TableLength]; PointF[] pointsForCh3 = new PointF[TableLength]; for (int jj = 0; jj < TableLength; jj++)//填充本次绘制的部分 { points[jj] = new PointF((float)jj + TableLeft, ylocs[jj]); pointsForCh1[jj] = new PointF((float)jj + TableLeft, ylocsOfCh1[jj]); pointsForCh2[jj] = new PointF((float)jj + TableLeft, ylocsOfCh2[jj]); pointsForCh3[jj] = new PointF((float)jj + TableLeft, ylocsOfCh3[jj]); } ForNext.PageUnit = GraphicsUnit.Millimeter; //ForNext.DrawCurve(new Pen(this.BackColor, 5F), points); ForNext.DrawCurve(new Pen(this.BackColor, 5F), pointsForCh1); ForNext.DrawCurve(new Pen(this.BackColor, 5F), pointsForCh2); ForNext.DrawCurve(new Pen(this.BackColor, 5F), pointsForCh3); /* 获取y坐标数据到ylocs[] -- GetData() */ //RandYlocs();//-测试阶段用randylocs ReadData(); } /* 按TIMENOW特征绘图 */ /* * 绘图方式为从低到高刷新图样 * TIMENOW作为刷新尺度的标定 */ /* 按参数绘制数据对应图像 */ //if(TIMENOW<TableLength-3)//3是前后两种颜色曲线的隔离区-否则“清空”操作不好做 MkPntAndDraw(); } /*FuncTip * * @Name:MkPntAndDraw * @Arg:None * @Func:在TimerEvent中被调用 * 将串口数据转换成绘图区坐标点 * 加载到ylocsofChannelX中 * */ public void MkPntAndDraw() { DrawTable(); PointF[] points = new PointF[TableLength]; PointF[] pointsForCh1 = new PointF[TableLength]; PointF[] pointsForCh2 = new PointF[TableLength]; PointF[] pointsForCh3 = new PointF[TableLength]; for (int jj = 0; jj < TableLength; jj++)//填充本次绘制的部分 { points[jj] = new PointF((float)jj + TableLeft, ylocs[jj]); pointsForCh1[jj] = new PointF((float)jj+TableLeft,ylocsOfCh1[jj]); pointsForCh2[jj] = new PointF((float)jj + TableLeft, ylocsOfCh2[jj]); pointsForCh3[jj] = new PointF((float)jj + TableLeft, ylocsOfCh3[jj]); } /* 两种色笔 */ Pen RedPen = new Pen(Color.Red, 0.5F); Pen GreenPen = new Pen(Color.Green, 0.5F); /* 获取 graphis实列对象 -- 用于调用drawCurve() */ Graphics Drawer = CreateGraphics(); Drawer.PageUnit = GraphicsUnit.Millimeter;//以毫米为单位绘制图形 //Drawer.DrawCurve(GreenPen, points); Drawer.DrawCurve(GreenPen, pointsForCh1); Drawer.DrawCurve(GreenPen, pointsForCh2); Drawer.DrawCurve(GreenPen, pointsForCh3); Drawer.Dispose(); } /* ---------B-串口通信---------- */ /*VarcTip * * @Name:_SerialPort * @Func:串口通信封装类 对象实例 * 用于读取串口数据 * */ System.IO.Ports.SerialPort _serialPort = new SerialPort(); /*FuncTip * * @Name:PortConfig * @Arg:BaudRate 串口的波特率 * @Func:配置串口 * */ public void PortConfig(int BaudRate)///需要读取数据--使用thread类 多线程 - 再看看哦 { //配置COM口参数 /* 端口名 串口在连接后才可被检测到 */ try { string[] portnames = SerialPort.GetPortNames(); _serialPort.PortName = portnames[0]; } catch (Exception e) { MessageBox.Show("未在COM口检测到设备,请连接串口通信设备后重新启动应用程序\n" + e.ToString()); } /* 波特率 */ _serialPort.BaudRate = BaudRate; /* 数据位 */ _serialPort.DataBits = 8; /* 校验位 */ _serialPort.Parity = Parity.None; /* 停止位 */ _serialPort.StopBits = StopBits.One; /* 配置COM口超时参数 */ _serialPort.ReadTimeout = SerialPort.InfiniteTimeout; _serialPort.WriteTimeout = SerialPort.InfiniteTimeout; /* 打开COM口 */ _serialPort.Open(); } /*FuncTip * * @Name:ReadData * @Arg:None * @Func:读取数据到ylocs * */ public void ReadData() { byte[] buffer = new byte[TableLength * 4];/* (通道数3+起始标志1)四个 */ _serialPort.Read(buffer, 0, TableLength * 4); int ptrForYlocs = 0; /* 将byte数据转换成int16(short)类型 */ //for(int ptr = 0; ptr+2 < buffer.Length; ptr +=2){ for (int ptr = 0; ptr < ylocs.Length; ptr++) { ylocs[ptrForYlocs] = buffer[ptr];//BitConverter.ToInt16(buffer,ptr); ptrForYlocs++; } //MessageBox.Show(ylocs[0].ToString()); /* 将ylocs中的数数据分配到各个通道的缓冲区 */ /**使用readInt方法读取数据到ylocs,已经废弃 **/ /**ylocs[ptr] = ReadInt() % (TableHeight - 5) + TableTop;**/ /* 装填ylocs到各个通道的缓冲区(ptrforchX) */ YlocsOfChannlesInload(); /* 清空_serialport数据缓冲区 */ _serialPort.DiscardInBuffer(); _serialPort.DiscardOutBuffer(); } /*FuncTip * * @Name:YlocsOfChannlesInload * @Arg:None * @Func:将ylocs的数据加载到各通道缓冲区ylocsofChannelX * 下位机发送数据格式: * ————————————————————— * 标志数据|CH1数据|CH2数据|CH3数据|标志数据... * ————————————————————— * 数据长度:8bits * 建议二进制形式发送 * 如使用标准库printf * 建议采用%c格式 * */ private void YlocsOfChannlesInload() { short ptrofylocsstart = 0;/* 数据开始位置标志,找到第一个255的位置 */ /* 检索第一个数据包&找到刷新后第一个完整数据包的起始位置 */ while ((ptrofylocsstart < 5) && (ylocs[ptrofylocsstart] != 88)) { ptrofylocsstart++; } int ptrforinload = 0;/* 装填数据时的迭代器,每个channel都re0 */ for (int ptrforch1 = ptrofylocsstart + 1; ptrforch1 + 4 < ylocs.Length; ptrforch1 += 4) { ylocsOfCh1[ptrforinload] = ylocs[ptrforch1] % (TableHeight / 3) + TableTop; ptrforinload++; } ptrforinload = 0; for (int ptrforch2 = ptrofylocsstart + 2; ptrforch2 + 4 < ylocs.Length; ptrforch2 += 4) { ylocsOfCh2[ptrforinload] = ylocs[ptrforch2] % (TableHeight / 3) + TableTop + TableHeight / 3; ptrforinload++; } ptrforinload = 0; for (int ptrforch3 = ptrofylocsstart + 3; ptrforch3 + 4 < ylocs.Length; ptrforch3 += 4) { ylocsOfCh3[ptrforinload] = ylocs[ptrforch3] % (TableHeight / 3) + TableTop + 2 * TableHeight / 3; ptrforinload++; } for (int ptrforfinalPoints = TableLength - 1; ptrforfinalPoints >= TableLength - 2; ptrforfinalPoints--) { ylocsOfCh1[ptrforfinalPoints] = TableTop; ylocsOfCh2[ptrforfinalPoints] = TableTop + TableHeight / 3; ylocsOfCh3[ptrforfinalPoints] = TableTop + 2 * TableHeight / 3; } } } }
最新回复(0)