【红色飓风Nano二代测评】上位机显示
0赞前面的博客已将底层的东西准备好了,现在就开始做上位机。我用的是C#,刚开始接触这个C#没多久,有什么表达不当的欢迎拍砖哦。
首先上位机这边最主要的就是接受串口的数据,我们先声明一个串口:
SerialPort sp = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
然后给串口初始化:
private void UartInit()
{
sp.ReadBufferSize = 1024;
sp.WriteBufferSize = 1024;
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
sp.Open();
sp.ReceivedBytesThreshold = 1;
sp.DiscardInBuffer();
sp.DiscardOutBuffer();
}
在这里我们创建了一个事件,只要是收到一个字节的数据,程序就会跳转到这个事件中处理。我们底层的数据格式是0xAA,(4个字节组成的32位编码器数据),0x55.此时我们需要将0xAA和0x55之间的数据截取出来。怎么拼接这4个字节呢?我想了好多的方法,要是FPGA处理这个东西那就相当的简单了,后来发现可以用类似的方法,那就是使用联合共用体。
//定义一个联合共用体
[StructLayout(LayoutKind.Explicit)]
public struct TestUnion
{
[FieldOffset(0)]
public int encoder;
[FieldOffset(0)]
public Byte encoder0;
[FieldOffset(1)]
public Byte encoder1;
[FieldOffset(2)]
public Byte encoder2;
[FieldOffset(3)]
public Byte encoder3;
}
这个代码就是定义一个共用体,可以看到encoder是一个32位的变量,下面的是4个八位的变量,可以看到这四个八位的变量有不同的偏移量,这样就拼接成了一个32位的变量了。只要我们给这个4个八位的变量分别赋值(串口接收到的数据),那么我们从encoder中就可以读取所需要的值了。
在串口接事件中代码如下:
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Byte read = (Byte) sp.ReadByte();
if (start)
{
readdata[count] = read;
count++;
if (count >= 5)
{
count = 0;
start = false;
if (readdata[4] != 0x55)
{
return;
}
tu.encoder0 = readdata[3];
tu.encoder1 = readdata[2];
tu.encoder2 = readdata[1];
tu.encoder3 = readdata[0];
lednumshow.LEDText = tu.encoder.ToString();
}
}
if (read == 0xAA)
{
start = true;
}
}
现在我想在屏幕上将编码器的值显示出来,我这把调用的是LEDNumber.dll、ZedGraphControl.dll这两个库。大家可以在网上搜索这两个库,LEDNumber.dll这个使用起来相当的简单,我们只要将数值赋值过去就可以了:
lednumshow.LEDText = tu.encoder.ToString();
ZedGraphControl.dll这个库使用起来有些纠结哦,首先我们需要设置一个集合:
//设置图像显示集合
ZedGraph.PointPairList listV = new ZedGraph.PointPairList();
创建图像:
private void GreateGraph(ZedGraph.ZedGraphControl zgc)
{
//获取GraphPane的引用
ZedGraph.GraphPane myPane = zgc.GraphPane;
//设置标题
myPane.Title.Text = "nano测评---旋转编码器状态图";
myPane.XAxis.Title.Text = "X----时间轴";
myPane.YAxis.Title.Text = "Y----转速";
ZedGraph.LineItem myCurve1 = myPane.AddCurve("V", listV, Color.Black, ZedGraph.SymbolType.None);
}
剩下的就是给刚才创建的集合赋值,赋值函数写在定时器中:
private void timer1_Tick(object sender, EventArgs e)
{
xTime = xTime + 0.5;
nowDat = tu.encoder;
//lednumshow.LEDText = ((nowDat - lastDat)/100).ToString();
zedGraphControl1.GraphPane.XAxis.Scale.Max = xTime;
zedGraphControl1.GraphPane.XAxis.Scale.Min = xTime - 200;
listAdd(xTime, nowDat - lastDat, 500);//
zedGraphControl1.AxisChange();
zedGraphControl1.Refresh();
lastDat = nowDat;
}
private void listAdd(double x, double w, int fifo)
{
listV.Add(x, w);
if (listV.Count > fifo)
{
listV.Remove(listV[0]);
}
}
几个主要的函数就在这里了,下面我们看看效果吧,如下图1所示
为整体平台显示。
图1 整体框架
当转动旋转编码器时,上位机界面显示如下图2所示,数码管中显示的是当前编码器的脉冲数。曲线显示的是编码器的转速。
图2 上位机界面1
如下图3所示,为动态图
图3 动态效果
东西基本上做完了,好像似乎有些东西没有忘了,哦现在可以将底层的数据采集通过上位机显示,上位机的指令也要传达下去哦。我们创建8个CheckBox控件,在事件中创建一个CheckedChanged的事件,然后将LED1-LED7的CheckedChanged全部指向LED0的CheckedChanged事件。然后添加如下代码:
private void LED0_CheckedChanged(object sender, EventArgs e)
{
LED[0] = 0x00;
if (LED0.Checked) LED[0] |= 0x01;
else LED[0] &= 0xFE;
if (LED1.Checked) LED[0] |= 0x02;
else LED[0] &= 0xFD;
if (LED2.Checked) LED[0] |= 0x04;
else LED[0] &= 0xFB;
if (LED3.Checked) LED[0] |= 0x08;
else LED[0] &= 0xF7;
if (LED4.Checked) LED[0] |= 0x10;
else LED[0] &= 0xEF;
if (LED5.Checked) LED[0] |= 0x20;
else LED[0] &= 0xDF;
if (LED6.Checked) LED[0] |= 0x40;
else LED[0] &= 0xBF;
if (LED7.Checked) LED[0] |= 0x80;
else LED[0] &= 0x7F;
sp.Write(LED, 0, 1);
}
如下图4所示,上位机这边勾选了LED0、LED3、LED4、LED6和LED7这几个选项。
图4 上位机指令界面
如下图5所示,为开发板LED显示效果。
图5 开发板显示效果
