前言:
这里是我的第一篇博文,记录一个菜鸟的成长之路。接触C#还是在学校的实验室里,第一个程序就是为了配合单片机写的简单的串口助手,另外还有移植的四旋翼地面站,还有基于TCP/IP协议的本地服务器。一直没有好好总结一下,但是值得自己骄傲的事情就是,一直在学习的路上~
说到C#,还是看中了它开发的简洁方便,其实并没有深入进去,但是做出来的小东西还是比较可人的,不是纯技术分享,而是将自己做过的小玩意写下来,一是记录,二是万一帮到别人呢?有不对的地方请不吝指正,转载请注明出处~
工具:VS2015,下载地址请点我
主要内容有:
C#传输串口数据
用C#做一个串口接收和发送的程序还是比较容易的,因为它封装了serialPort,在Designer 直接添加就好啦~添加完成后设置波特率,停止位,数据位等等,设置完成后,这个接口的雏形也就出来啦。
首先,要打开端口。
try//btn打开端口
{
serialPort1.PortName = comboBox1.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
serialPort1.Open();
button1.Enabled = false;//改变按钮状态
}
catch (Exception err)
{
MessageBox.Show(err.ToString(), "系统提示");
}
下面就是对接收的数据进行处理啦。
if (radioButton4.Checked)//如果文本方式被选中,添加的radioButton控件
{
byte[] readBuffer = new byte[serialPort1.ReadBufferSize];
serialPort1.Read(readBuffer, 0, readBuffer.Length);
string readstr = Encoding.UTF8.GetString(readBuffer);
richTextBox1.Text += readstr;//这个+= 是一直往容器添加而不是替换
string strr = readstr;
string[] sArray = strr.Split(',');
chache = int.Parse(sArray[A.Channel]);//A.Channel表示数组的元素位置0/1/2/3
textBox1.Text = Test_Value.ToString();
else//十六进制模式
}
else
{
try
{
byte[] data = new byte[serialPort1.BytesToRead];//定义缓冲区,因为串口事件触发时有可能收到不止一个字节
serialPort1.Read(data, 0, data.Length);
foreach (byte Member in data)
{
string str = Convert.ToString(Member, 16).ToUpper();
richTextBox1.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + " ");
}
}
catch (Exception err)//这里可以将异常打印到弹出的窗口中
{
MessageBox.Show(err.ToString(), "系统提示");
}
}
以上就是串口数据的接收函数啦,发送函数在下方。
if (!radioButton1.Checked)//选择数据格式
{
try
{
serialPort1.Write(richTextBox2.Text);
}
catch (Exception err)
{
MessageBox.Show(err.ToString(), "系统提示");
}
}
else
{
try
{
for (int i = 0; i < (richTextBox2.Text.Length - richTextBox2.Text.Length % 2) / 2; i++)//转换偶数个
{
Data[0] = Convert.ToByte(richTextBox2.Text.Substring(i * 2, 2), 16); //转换
serialPort1.Write(Data, 0, 1);
}
if (richTextBox2.Text.Length % 2 != 0)
{
Data[0] = Convert.ToByte(richTextBox2.Text.Substring(richTextBox2.Text.Length - 1, 1), 16);//单独处理最后一个字符
serialPort1.Write(Data, 0, 1);
}
}
catch (Exception err)
{
MessageBox.Show(err.ToString(), "系统提示");
}
}
}
}
以上就是串口的处理代码了~接下来绘制图表,是个问题!第一个想到的就是利用vs提供的chart控件来实现数据的绘制,但是,遇到的问题是:数据量大了之后,窗口滑动不成功,再就是接收数据造成的阻塞问题!当然了,这是我没有解决掉的问题!所以,还是采用毕业设计所用的GDI+绘图,虽然条条框框都需要自己绘制,但是还是比较稳定的呀!
这是我的程序中所有的引用:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Drawing2D;
using MathWorks.MATLAB.NET.Arrays;
看到了,还有一个 using MathWorks.MATLAB.NET.Arrays;嗯~ o(* ̄▽ ̄*)o这是刚get到的C# + Matlab混合编程的点,我掌握了方法之后会第一时间将方法奉上!
GDI+绘图首先要做的就是添加一个Picturebox控件,然后把画布绘制在上面!之后就是设置各种凌乱的参数,比如:
Graphics waveform;//封装一个GDI+绘图图面
//创建原点坐标(有序数对)
Point Origin;
int Original_X;//X值
int Original_Y;//Y值
//创建X轴顶点坐标(有序数对)
Point Top_X;
//创建X轴顶点坐标(有序数对)
Point Top_Y;
//X轴长度(单位:像素)
int LengthX;
int LengthY;
//设置坐标轴颜色轴变量
Color colorPen; //曲线上标记的数字
Color CoordinateAxis;//坐标轴
Color AxisFlagColor; //偏移量(字)
//设置轴的刻度数
int BlocksX = 15;
int BlocksY = 16;
如果想做测试的话,这里有个随机数发生器:
Random r; //伪随机数生成器
List<int> list; //可检索的列表
int seed; //种子变量
list = new List<int>();//初始化List实例
r = new Random();//初始化伪随机数容器
for (int i = 0; i < 100; i++)//添加随机数到List结尾
{
list.Add(r(seed));
}
窗口滑动的关键:
private void ChangeList()
{
list.RemoveAt(0);
list.Add(r(seed));
}
准备工作都差不多了,开始绘制画布吧!
waveform = e.Graphics; //使用封装过的 GDI+ 绘图
waveform.SmoothingMode = SmoothingMode.HighQuality;//平滑处理,高品质
Pen Axis = new Pen(CoordinateAxis, 1);//创建绘制坐标轴的画笔
Axis.EndCap = LineCap.ArrowAnchor;//坐标轴结尾形状 箭头
Top_Y = new Point(Original_X, Original_Y - LengthY); //计算Y轴顶点坐标 (X="0",坐标系原点Y值 - Y长度),由于屏幕左上为(0,0),所以要处理成负数
Top_X = new Point(Original_X + LengthX, Original_Y); //计算X轴顶点坐标 (坐标系原点X值 + X长度,Y="0")
Origin = new Point(Original_X, Original_Y);//原点(有序数对)
waveform.DrawLine(Axis, Origin, Top_X);//绘制X轴
waveform.DrawLine(Axis, Origin, Top_Y);//绘制Y轴
int Cell_X = LengthX / BlocksX;
int Cell_Y = LengthY / BlocksY;
Pen AxisFlag = new Pen(AxisFlagColor, 1);
AxisFlagBrush = new SolidBrush(AxisFlagColor);
//Y轴刻度、游标绘制
for (int i = 0; i <= BlocksY; i++)
{
waveform.DrawLine(AxisFlag, new Point(Original_X, Original_Y - i * (Cell_Y - 1)), new Point(Original_X - 3, Original_Y - i * (Cell_Y - 1)));
if (i * 10 >= 100)//游标
{
waveform.DrawString((i * 257).ToString(), AxisFont, AxisFlagBrush, new Point(Original_X - 30, Original_Y - i * (Cell_Y - 1) - 8));
}
else
{
waveform.DrawString((i * 257).ToString(), AxisFont, AxisFlagBrush, new Point(Original_X - 27, Original_Y - i * (Cell_Y - 1) - 8));
}
}
//X轴刻度、游标绘制
for (int j = 0; j <= BlocksX; j++) //可以根据需要调整疏密
{
waveform.DrawLine(AxisFlag, new Point(Original_X + j * Cell_X, Original_Y), new Point(Original_X + j * Cell_X, Original_Y + 3));
// 17为一个单位
waveform.DrawString((j * 1.488).ToString(), AxisFont, AxisFlagBrush, new Point(Original_X + j * Cell_X - 5-10, Original_Y + 5));
}
Axis.Dispose();//释放画笔资源
DrawWave(e); //调用绘制函数,下方的代码就是啦
如果画布绘制完成了的话,绘图工作就已经完成一大半了,毕竟绘制图形的方式和绘制画布的方式是一样的!
for (int i = 0; i < list.Count - 1; i++) //数据包含在列表内
{
Point sp = new Point(Original_X + i * 2, Original_Y - list[i]);
ep = new Point(Original_X + (i + 1) * 2, Original_Y - list[i + 1]);
g.DrawLine(Pens.DarkGreen, sp, ep);
}
以上。