原地址:http://www.cnblogs.com/alongu3d/archive/2013/05/02/3054962.html

/*******************************/
//串口接收,采用多线程+数据池设计模式,使用队列数据结构队列,避免线程阻塞//
/*******************************/
using UnityEngine;
using System.Collections;
//Other libraries
using System;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
//串口命名空间
using System.IO.Ports;
using System.Text.RegularExpressions;
using System.Text;

public class ComTest : MonoBehaviour {
    /******定义一个串口字段*******/
   private SerialPort sp;
    /*******定义三个外部接口***************/
public static float FangXiangJiao;
public static float YangJiao;
public static float XuanZhuanJiao;
/*******定义三个角度存储的临时字段***********/
public static float _FangXiangJiao;
public static float _YangJiao;
public static float _XuanZhuanJiao;
    /***********三种角度的循环队列****************/
    private Queue<float> AVEFangXiangJiao = new Queue<float>();
    private Queue<float> AVEYangJiao = new Queue<float>();
    private Queue<float> AVEXuanZhuanJiao = new Queue<float>();
private byte[] DataBuf;
    
    private bool flag = true;
    private bool showMessage = false;//显示消息
    private bool open = false;

private int NumberCount=0;
private Thread SerialPortThread;

private StringBuilder sbReadline;
    private string strOutPool = string.Empty;
private Queue<string> queueDataPool;
    private Thread tPort;
    private Thread tPortDeal;
    /***********Unity初始化方法*****************/
private void Start () {
        sbReadline = new StringBuilder();
        queueDataPool = new Queue<string>();
        //DataBuf = new byte[10];

sp = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
        if (!sp.IsOpen){
            // 开启串口
            sp.Open();
            open = true;
        }

//开启2个线程分别用于接收数据和处理数据
        tPort = new Thread(DealData);
        tPort.Start();
        tPortDeal = new Thread(ReceiveData);
        tPortDeal.Start();
//StartCoroutine(DealData());

}

/***************程序结束的时候,关闭串口**********************/
   void OnApplicationQuit() {
      sp.Close();
//SerialPortThread.Abort();//终止进程
   }

/*************Update方法********************/
//一帧之调用多次
   void FixedUpdate() {
       //定期回收垃圾
       if (Time.frameCount % 120 == 0) System.GC.Collect();

//处理数据的线程停止,那么重启该线程
       if (!tPort.IsAlive) {
           tPort = new Thread(DealData);
           tPort.Start();

}
       if (!tPortDeal.IsAlive) {
           tPortDeal = new Thread(ReceiveData);
           tPortDeal.Start();
       }
       // StartCoroutine(DealData());
//Debug.Log( SerialPortThread.ThreadState);
}

/// <summary>
/// 数据接收 进程, 使用队列来存储数据,避免数组的上锁和解锁问题
/// 设计模式  多线程+数据池
/// </summary>
/// <returns>
/// The data.
/// </returns>
   /*****************数据接收*************************/
private void ReceiveData () {
//读取数据,同时存入数据池中
//newline结束标记,同时使用readIlne()方法 
try {

//从输入缓存区中去读取第一次出现"AA"时的内容
            Byte[] buf=new Byte[120];
          if (open) sp.Read(buf,0,120);
            //如果没有接到到数据,就返回
            if (buf.Length ==0) {
                return;
            }
           string sbReadline2str = string.Empty;
           if (buf != null)
           {
               for (int i = 0; i < buf.Length; i++)
               {
                   sbReadline2str += buf[i].ToString("X2");
               }
           }         
          //sbReadline2str = System.Text.Encoding.Default.GetString(buf, 0,buf.Length);
       //  Debug.LogError(sbReadline2str.ToString());
        // sbReadline2str = buf.ToString();
           // sbReadline2str = sbReadline.ToString();
                //提取完整的一个数据包,压入数据池中(队列中)
       if (sbReadline2str.StartsWith("DB90"))
         {       //分组数据包
             string[] _str = Regex.Split(sbReadline2str, "55AA", RegexOptions.IgnoreCase);
             foreach (string s in _str)
             {
                 if (s.Length == 16)
                 {
                     //数据进入队列
                     queueDataPool.Enqueue(s + "55AA");
                     //Debug.LogError(s+"55AA");
                 }
                
             }
         }
         else {
            
            sbReadline2str.Remove(0,sbReadline2str.IndexOf("DB90")+1);
             string[] _str = Regex.Split(sbReadline2str, "55AA", RegexOptions.IgnoreCase);
             foreach (string s in _str)
             {
                 if (s.Length == 16)
                 {
                     //数据进入队列
                     queueDataPool.Enqueue(s + "55AA");
                    // Debug.LogError(s+"55AA");
                 }
                // Convert.ToByte(s,16);
                 
             }
         }

}catch (Exception ex) {
Debug.LogError(ex);
}
//yield return null;
}

/***************处理出队的数据***********************/
    private void DealData()
    {
        while (queueDataPool.Count != 0)
        {//循环检测队列
            //队列中有数据

//处理出队的数据
            //循环队列,首先加载第一包数据,只执行一次
            if (flag)
            {    //初始化第一组数据
                for (int i = 0; i < 7; i++)
                {   //出队列,同时移除这个数据
                    strOutPool = queueDataPool.Dequeue();
                    float[] jiaodu = DealReceivedDatanow(strOutPool);
                    AVEFangXiangJiao.Enqueue(jiaodu[0]);
                    AVEYangJiao.Enqueue(jiaodu[1]);
                    AVEXuanZhuanJiao.Enqueue(jiaodu[2]);

}
                FangXiangJiao = Caulation(AVEFangXiangJiao);
                YangJiao = Caulation(AVEYangJiao);
                XuanZhuanJiao = Caulation(AVEXuanZhuanJiao);
                flag = false;

}
            else
            {/*采用7点平滑滤波,消除抖动现象.注意特殊点的处理360到0之间的数据*/
                
              
                 //没有存在跳变的现象,那就直接存储数据
                    for (int i = 0; i < 7; i++)
                    {
                        //出队列,同时移除这个数据。
                        //加载7包数据,
                        strOutPool = queueDataPool.Dequeue();
                        //组合加载的数据,低字节在前,高字节在后,return 三个角度值
                        float[] jiaodu = DealReceivedDatanow(strOutPool);
                        //角度循环队列更新最新进入的数据
                        AVEFangXiangJiao.Dequeue();
                        //角度循环队列在队尾插入新的数据
                        AVEFangXiangJiao.Enqueue(jiaodu[0]);
                        //计算更新后的循环队列中的7个数据平均值
                        /*****************处理特殊数据************************/
                        int[] IntPanDuan = CheackDataTuBian(AVEFangXiangJiao);
                        //如果存在着跳变的现象
                        if (IntPanDuan[0] == 1)
                        {//保留队列前面的数据,移除后面的数据
                            float[] FXj = AVEFangXiangJiao.ToArray();
                            float sum = 0f;
                            //获取要移除数据的索引值
                            int indexOfRemovingData = IntPanDuan[2];
                             for (int j = 0; j < indexOfRemovingData; j++)
                            {
                                sum += FXj[j];
                            }
                            //计算平均值
                            FangXiangJiao = sum / indexOfRemovingData;
                        }
                        FangXiangJiao = Caulation(AVEFangXiangJiao);
                        /******************处理特殊数据结束*************************/

/*******************************************/
                        /*同上*/
                        AVEYangJiao.Dequeue();
                        AVEYangJiao.Enqueue(jiaodu[1]);
                        YangJiao = Caulation(AVEYangJiao);
                        /*同上*/
                        AVEXuanZhuanJiao.Dequeue();
                        AVEXuanZhuanJiao.Enqueue(jiaodu[2]);
                        XuanZhuanJiao = Caulation(AVEXuanZhuanJiao);
                        /******************************************/
                    }
                
            }

}

}

/************************检验特殊值***************************/
    private int[] CheackDataTuBian(Queue<float> cheackQueue)
    {
        float[] cheackDataArrary = cheackQueue.ToArray();
 
        //flag =0表示false;  flag=1表示true
        int flag = 0; 
        int[] BoolAndIndexOfNext=new int[2];
        for (int count = 0; count < 6; count++ )
        {float Previous =cheackDataArrary[count];
            float Next = cheackDataArrary[count+1];
            if (Mathf.Abs(Previous - Next)>350.0F && Mathf.Abs(Previous -Next)<360.0f) {
                flag = 1;
                BoolAndIndexOfNext[0] = flag;
                BoolAndIndexOfNext[1] = count + 1; break;
            }
        }

return BoolAndIndexOfNext;
    }

/*****************计算平均值****************************/
        private float Caulation(Queue<float> AVEf) {
        
        float _f=0.0f;
         foreach (float f in AVEf) {
             _f+=f;
         }
        return _f/7;
    }
    
    /*****************处理来自数据池的数据**************************/
private float[] DealReceivedDatanow (string DataBuf) {
//this is a whole frame data package,then convert the 
//First convert the Byte type into Char type
// Debug.Log("--starting");
        //Debug.Log("databuf----"+DataBuf);
        /*把16进制字符串转换成字节数组*/
        byte[] returnBytes = new byte[DataBuf.Length / 2];
        for (int i = 0; i < returnBytes.Length; i++)
            returnBytes[i] = Convert.ToByte(DataBuf.Substring(i * 2, 2), 16);
        /*消除抖动,因为眼镜传感器会不断的发送数据,即使是不动的状态下,也会有这样的现象*/
        float[] jiaoduCollection =new float[3];
        _FangXiangJiao = (float)((byte)returnBytes[2] + ((sbyte)returnBytes[3] << 8)) / 10;
jiaoduCollection[0] =_FangXiangJiao;
  // Debug.Log("fx-->"+FangXiangJiao);
        _YangJiao = (float)((byte)returnBytes[4] + ((sbyte)returnBytes[5] << 8)) / 10;
jiaoduCollection[1] =_YangJiao; 
        // Debug.Log("yj-->"+YangJiao);
        _XuanZhuanJiao = -(float)((byte)returnBytes[6] + ((sbyte)returnBytes[7] << 8)) / 10;
jiaoduCollection[2]=_XuanZhuanJiao;
        //Debug.Log("xz-->"+XuanZhuanJiao);
//Debug.Log("--ending");

return jiaoduCollection;
}

/********************处理来自数据池的数据**************************/
private void DealReceivedData (string dataOutPool) 
{

//读取串口的数据, 如果没有反应就会出现timeout 异常
// 数据格式:DB  90  AF  0C  A2  FF  2C  00  55  AA 
//包头是DB 90  包尾:55 AA 
//一帧发送一个数据包 总大小10个字节,
            //int DataNumber;  
 
       try { 
//读取数据

byte tempB;
tempB= (byte)sp.ReadByte();

//Time.time;
//Read the header first
if (tempB ==219)
{  
//Debug.Log("i get the 0XDB"+(byte)0xDB);
DataBuf[0]=tempB;
tempB= (byte)sp.ReadByte();

if (tempB ==144)
DataBuf[1]=tempB;
int DataNumber=2;
while(DataNumber<10){
tempB= (byte) sp.ReadByte();

DataBuf[DataNumber]=tempB;

DataNumber++;
  }

}

//read out the input data 
//cheack the header and tail for a data package.

//this is a whole frame data package,then convert the 
//First convert the Byte type into Char type
// Debug.Log("--starting");
    FangXiangJiao=(float)(DataBuf[2]+((sbyte)DataBuf[3]<<8))/10;
/*while(NumberCount <7) {
//_FangXiangJiao =
}*/
 
  // Debug.Log("fx-->"+FangXiangJiao);
YangJiao = (float)(DataBuf[4]+((sbyte)DataBuf[5]<<8))/10;
 // Debug.Log("yj-->"+YangJiao);
 XuanZhuanJiao = (float)(DataBuf[6]+((sbyte)DataBuf[7]<<8))/10;
  // Debug.Log("xz-->"+XuanZhuanJiao);
//Debug.Log("--ending");


       catch (Exception e) {
Debug.LogError(e);
       }
//Debug.Log("starting");
foreach(byte b in DataBuf) {
//Debug.LogError(Convert.ToString(b,16));
}
//Debug.Log("ending");
//yield return null;

}

/*********************************************/
    //在没有开启串口设备电源的时候,显示消息窗口,开启电源之后,点击确定按钮
    private void OnGUI() {
        if (showMessage)
        {
            GUI.BeginGroup(new Rect(Screen.width/2-100,Screen.height-60,400,400));
            GUI.Label(new Rect(Screen.width / 2 - 80, Screen.height - 60,200,150), "请打开串口设备电源!然后点击确定");
            if (GUI.Button(new Rect(Screen.width / 2 -80, Screen.height +95 , 100, 100), "确定"))
            {
                open = true;
            }
            GUI.EndGroup();
        }

}

}

Unity之串口通信(基于三姿态传感器)的更多相关文章

  1. Java串口通信--------基于RXTX (附带资源地址)

    最近帮老师做了一个小项目,一个牧场公司想用传感器收集一些环境信息,记录到数据库里去,然后加以分析查看.这里面和传感器通信用到了串口通信,我也是接触了一下,把用到的东西分享出来. 准备工作: RXTX: ...

  2. 基于FPGA的红外遥控解码与PC串口通信

    基于FPGA的红外遥控解码与PC串口通信 zouxy09@qq.com http://blog.csdn.net/zouxy09 这是我的<电子设计EDA>的课程设计作业(呵呵,这个月都拿 ...

  3. C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序

    C#中缓存的使用   缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可:  <%@ Outp ...

  4. Unity串口通信

    一.串口简介 串行接口(串口)通常指COM接口,是采用串行通信方式的扩展接口.串口按位(bit)发送和接收字节.尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接 ...

  5. VS2008基于对话框的MFC上位机串口通信(C++实现)简单例程

    首先,在 vs2008 环境下创建 MFC 运用程序 设置项目名称为 ComTest(这个地方随意命名,根据个人习惯),点击确定后,点击下一步 出现如下界面 选择"基于对话框"模式 ...

  6. [stm32][ucos] 1、基于ucos操作系统的LED闪烁、串口通信简单例程

    * 内容简述: 本例程操作系统采用ucos2.86a版本, 建立了5个任务            任务名                                             优先级 ...

  7. 电赛菜鸟营培训(三)——STM32F103CB之串口通信

    一.串口通信概念 1.缩写 USART:Universal Synchronous/Asynchronous Receiver/Transmitter 通用同步/异步接收和发送器 2.用处 (1)同步 ...

  8. (三)stm32之串口通信DMA传输完成中断

    一.DMA功能简介 首先唠叨一下DMA的基本概念,DMA的出现大大减轻了CPU的工作量.在硬件系统中,主要由CPU(内核).外设.内存(SRAM).总线等结构组成,数据经常要在内存和外设之间,外设和外 ...

  9. [python] 3 、基于串口通信的嵌入式设备上位机自动测试程序框架(简陋框架)

    星期一, 20. 八月 2018 01:53上午 - beautifulzzzz 1.前言 做类似zigbee.ble mesh...无线网络节点性能测试的时候,手动操作然后看表象往往很难找出真正的原 ...

随机推荐

  1. Sublime Text3自动保存的功能(失去焦点自动保存)

    这是最新版本的Sublime Text3的设置方法 (三部曲); 第一步:preferences 下面的settings:(和老版本的不一样了吧,之前有什么default 和 users,这里只有se ...

  2. [wordpress]后台自定义菜单字段和使用wordpress color picker

    Wordpress Version 4.4.2 参考链接 插件使用wordpress color picker:Add A New Color Picker To WordPress 后台菜单自定义字 ...

  3. js ie8不支持项总结

    不支持filter,trim  要用jquery 的$filter,$trim 数组不能用for in 要用for 数组没有indextOf方法 不能使用关键字,如true ,default IE8 ...

  4. 【Objective-C】4-空指针和野指针

    一.什么是空指针和野指针 1.空指针 1> 没有存储任何内存地址的指针就称为空指针(NULL指针) 2> 空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0. 下面两个都是空指针 ...

  5. 【高性能服务器】Tomcat剖析

    引言 Tomcat是一个流行的servlet容器,对于开发人员来说整体和容器打交道有必要花一些时间爱你了解其内部结构.本文将从一下几个方面来剖析其内部结构. 整体结构 连接器 初始化过程 如何处理一个 ...

  6. HashMap使用

    /* * 测试HashMap的应用,判断 */ import java.util.HashMap; public class HuaWeiTest { private static final Int ...

  7. Appium 解决中文输入问题

  8. JavaScript中的apply与call与arguments对象

    (一) call方法 语法:presentObj.call(thisObj,arg1,arg2,arg3...) 参数thisObj :将被用作当前对象presentObj的对象. 当thisObj无 ...

  9. SQL 不同的数据类型

    SQL 不同的数据类型 1.SQL TEXT 2.SQL VARCHAR(SIZE) VARCHAR(X) Case: user name, email, country, subject, pass ...

  10. C++对象模型与内存位对齐的简单分析(GNU GCC&VS2015编译器)

    以Fruit和Apple为例进行分析: Fruit和Apple的定义如下: 通过在两种编译环境下的测试(GNU GCC & VS2015),可以发现这两种编译器的对象模型是一样的,如下图所示: ...