概述
三通道示波器
【说明】
【语言】: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;
}
}
}
}
最后
以上就是可靠金鱼为你收集整理的C#三通道示波器-串口通信的全部内容,希望文章能够帮你解决C#三通道示波器-串口通信所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复