Chinaunix首页 | 论坛 | 博客
  • 博客访问: 266194
  • 博文数量: 81
  • 博客积分: 2510
  • 博客等级: 少校
  • 技术积分: 961
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-31 21:31
文章存档

2009年(15)

2008年(66)

我的朋友

分类: WINDOWS

2008-09-28 21:49:21

  • 20, .Net Micro Framework研究—数据的永久存储

           作者: 刘洪峰

     

    .Net Micro Framework不支持文件系统(目前该项功能正在研发之中),所以无法像Windows和windows ce平台那样把需要永久保存的数据保存到文件之中。内存中保存的数据只要系统一掉电,所有的数据也都消失了,这对一些需要保存参数的应用来说真是不妙。
    这几天在研究MF触摸屏功能时就遇到该问题,因为触摸屏校准之后,需要保存校准后的参数,否则MF一重启,难道还需要重新校准不成?
     感谢Donald Thompson 和 Rob S. Miles,从他们的大作上找到了问题的解决办法。办法就是把对象保存到Flash(EEPROM)中(有点像对象的二进制序列化)。
    下面是我整理的示例代码(实现比较简单,但总觉得不太正规,不知道能存多大,也搞不清楚数据到底存放在什么位置了。):
    using System;
    using Microsoft.SPOT;
    using System.Collections;
    using System.Threading;
     
    namespace DataStorage
    {
        public class Program
        {      
            public static void Main()
            {
                FlashDatas fd = FlashDatas.Load();
                fd.dump();
                fd.Flag = "adfg";
                //fd.Items.Clear();               
                //fd.AddItem(new FlashData(55, "1aaa"));
                //fd.AddItem(new FlashData(66, "2bbb"));
                //fd.AddItem(new FlashData(77, "3ccc"));
                //fd.AddItem(new FlashData(88, "4ddd"));
                fd.Save();
                Thread.Sleep(3000);            
            }
     
            [Serializable]
            private class FlashData
            {
                public DateTime date;
                public int iData;
                public string sData;
                public FlashData(int iData, string sData)
                {
                    date = DateTime.Now;
                    this.iData = iData;
                    this.sData = sData;
                }
     
                public override string ToString()
                {
                    return date.ToString() + " " + iData.ToString() + " " + sData;
                }
            }
     
            [Serializable]
            private class FlashDatas
            {
                public DateTime CreateTime = DateTime.Now;
                public string Flag = @"http://blog.csdn.net/yefanqiu/";
                public ArrayList Items = new ArrayList();
     
                public void dump()
                {
                    Debug.Print(CreateTime.ToString());
                    Debug.Print(Flag);
                    foreach (FlashData Item in Items)
                    {
                        if (Item != null)
                        {
                            Debug.Print(Item.ToString());
                        }
                    }
                }
                public void AddItem(FlashData Item)
                {
                    Items.Add(Item);
                }
     
                //调入数据
                public static FlashDatas Load()
                {
                    ExtendedWeakReference ewr = ExtendedWeakReference.RecoverOrCreate(
                            typeof(FlashDatas),                       //类型,任意类都可以,其名称起到一个索引作用
                            0,                                        //ID号,这个数据比较有用,不同ID号代表不同数据
                            ExtendedWeakReference.c_SurvivePowerdown);//该标志和.c_SurviveBoot 区别不大
                    ewr.Priority = (Int32)ExtendedWeakReference.PriorityLevel.Important;
     
                    FlashDatas data = ewr.Target as FlashDatas;
                    if (data == null)
                    {
                        data = new FlashDatas();
                    }
                    return data;
                }        
     
                //保存数据
                public void Save()
                {
                    ExtendedWeakReference ewr = ExtendedWeakReference.RecoverOrCreate(typeof(FlashDatas), 0, ExtendedWeakReference.c_SurvivePowerdown);
                    ewr.Priority = (Int32)ExtendedWeakReference.PriorityLevel.Important;
                    ewr.Target = this;
                }
            }
        }
    }
    以上代码在Digi开发板上测试成功,断电之后,再上电,保存的数据确实没有丢失。
    MSDN中相关函数的说明如下:
    ExtendedWeakReference Members
    The following tables list the members exposed by the ExtendedWeakReference type.
    Public Constructors

     
    Name
    Description
    Initializes a new instance of the class, referencing a specified object.
    Public Fields

     
    Name
    Description
     
    Contains a flag specifying that the current weak reference will be recoverable after the device reboots.
     
    Contains a flag specifying that the current weak reference will be recoverable after the device powers down and restarts.
    Public Properties

     
    Name
    Description
    Gets the flags specifying the states from which the current weak reference should be recoverable.
    Gets the ID associated with the current object.
    Gets or sets the priority level for the current object.
    Gets the selector for the current object.
    Public Methods

     
    Name
    Description
    Flags an object as a candidate for recovery after the device reboots or powers down and restarts.
     
    Recovers a specific object.
     
    Attempts to recover a specific object, and creates a new instance of this class if the recovery attempt fails.
  • 19, .Net Micro Framework研究—用MF控制机器人

           作者: 刘洪峰

     
    机器人研究一直是我很早以前的梦想,没有想到在深入研究.Net Micro Framework同时能和机器人搭上了联系。
    美国iRobot作为一家大型的机器人军工机械厂,其家用机器人吸尘器(电不足时能自动充电的机器人)已经让iRobot公司名满天下。我们研究的机器人就是iRobot公司推出了的新作——一个可以自己编程的机器人移动平台iRobot Create。
    由于最近才从微软拿到这个机器人,所以我们第一步就是先要了解这个机器人,然后MF才能作为它的大脑控制该机器人。
    让我们先一睹iRobot Create的“芳容”。
    iRobot Create 和充电基座(Home Base)
    iRobot Create 和BAM蓝牙模块
     
    iRobot Create有六类共31条控制命令,即能控制机器人行走、旋转、播放音乐,也能获知32个内置传感器信息(轮是否抬起、是否是悬崖、前方是否有墙、左右碰撞检测等等)。通过串口和iRobot Create进行通信(默认波特率57600).
      //27号信息包
                public UInt16 WallSignal;                //墙反射的无线信号强度 0 - 4095 高字节在前
                //28号信息包
                public UInt16 CliffLeftSignal;           //左悬崖信号强度
                //29号信息包
                public UInt16 CliffFrontLeftSignal;      //左前悬崖信号强度
                //30号信息包
                public UInt16 CliffFrontRightSignal;     //右前悬崖信号强度
                //31号信息包
                public UInt16 CliffRightSignal;          //右悬崖信号强度
                //32号信息包
                public bool BpsChange;                   //波特率发生改变
                public bool DI_3;                        //DI输入
                public bool DI_2;
                public bool DI_1;
                public bool DI_0;
                //33号信息包
                public UInt16 AI;                        //模拟入 0 -1023(5V)   高字节在前
                //34号信息包
                public bool HomeBase;                    //是否到家
      public bool InternalCharger;             //是否充电
    随便拿出一段代码,你就会发现iRobot Create可获取大量有效的传感器信息(这样的信息包有四十多个)。
    为了便于研究iRobot Create,我先用C#编写一个Windows程序(该程序通信控制部分和MF程序没有太大的区别,仅串口操作有细微差别),通过蓝牙模块(串口)和机器人进行通信(也可以用串口线连接,但是这样控制起来不方便)。
    在调试过程中发现蓝牙模块的通信性能和串口线相比,有一定区别,那就是延时较大(一般串口线直连15ms延迟就能保证通信收发成功,蓝牙通信一般需要50ms之上延迟,才能保证通信成功)。控制界面如下。
     
    机器人控制本身就是一个很大的课题,所以我们这里也无法一次说个完整和明白,今后我会陆陆续续发些相关文章的。我们今天先说说iRobot Create该充电时是如何找到“家”的(我想大家一定对这个感兴趣)。
    iRobot Create毕竟是一个简单的机器人,所以千万不要和它捉迷藏,Homebase一定要放在室内开阔地带(iRobot Create是通过红外信号发现Homebase的所以中间最好不要有遮挡物,否则iRobot Create有可能要找一阵子)。
    Homebase有两个红外发射管,可充当位置标记(一个为Green Buoy,一个为Red Buoy)。在iRobot Create头上有一个全方位红外接收头,可以接收到Homebase发出的红外信息。
    可收到的红外指令如下:
          iRobot Create就是根据以上信息,不断地调整自己的方位,找到回家的路。 
  • 18,.Net Micro Framework研究—让MF支持鼠标

           作者: 刘洪峰

     

    MF的标准模块仅支持按键,并不支持鼠标功能。但是对一些常见应用来说,如果没有鼠标(或触摸屏)用起来就太不习惯了。有什么办法可以让MF支持鼠 标功能呢?第一,外部设备必须把鼠标信息传到MF应用程序,应用程序根据这些信息绘制鼠标及执行相应的动作。鼠标信息最少包含三种,鼠标按键状态(按下或 放开),鼠标坐标(x,y)。

          目前,Spi通道可以非常方便地建立设备和用户程序之间的联系,所以就考虑用Spi来实现该功能。

          第一步,还是从我编写的模拟器入手,添加了一个Spi驱动类。

    //MouseDevice
        public class MouseComponent : SpiDevice
        {
            public static Int16 State = 0;
            public static Int16 X = 0;
            public static Int16 Y = 0;
     
            protected override byte[] Write(byte[] data)
            {
                //------------
                //改写坐标值
                try
                {
                    //State = (Int16)((data[0] << 8) + data[1]);
                    //X = (Int16)((data[2] << 8) + data[3]);
                    //Y = (Int16)((data[4] << 8) + data[5]);
                }
                catch { }
                //------------
                //返回当前值
                byte[] bytes = new byte[6];
                bytes[0] = (byte)(State >> 8);
                bytes[1] = (byte)(State & 0xff);
                bytes[2] = (byte)(X >> 8);
                bytes[3] = (byte)(X & 0xff);
                bytes[4] = (byte)(Y >> 8);
                bytes[5] = (byte)(Y & 0xff);
                return bytes;
            }
            protected override ushort[] Write(ushort[] data)
            {
                //------------
                //改写坐标值
                try
                {
                    //State = (Int16)data[0];
                    //X = (Int16)data[1];
                    //Y = (Int16)data[2];
                }
                catch { }
                //------------
                //返回当前值
                ushort[] Int16s = new ushort[3];
                Int16s[0] = (ushort)State;
                Int16s[1] = (ushort)X;
                Int16s[2] = (ushort)Y;
                return Int16s;
            }
    }
    第二步:编写鼠标应用程序
    为了通用,我封装了一个windowbase基类
    //鼠标事件
            public class MouseEventArgs : EventArgs
            {
                public int X;
                public int Y;
                public int Button;
                public MouseEventArgs()
                {
                    X = 0;
                    Y = 0;
                    Button = 0;
                    State = MouseState.None;
                }
                public MouseEventArgs(int x, int y)
                {
                    X = x;
                    Y = y;
                    Button = 0;
                    State = MouseState.None;
                }
                public MouseEventArgs(int x, int y, int button)
                {
                    X = x;
                    Y = y;
                    Button = button;
                    State = MouseState.None;
                }
            }
           
            //窗体基类
            internal class WindowBase : Window
            {
                protected YFWinApp m_app;
                Thread MouseThread;          
                private ushort state=0, x = 0, y = 0;
                SPI _spi=null;
     
                protected WindowBase(YFWinApp app)
                {
                    m_app = app;
                    this.Visibility = Visibility.Visible;
                    this.Width = SystemMetrics.ScreenWidth;
                    this.Height = SystemMetrics.ScreenHeight;
                    Buttons.Focus(this);
     
                    //SPI的pin定义
                    _spi = new SPI(new SPI.Configuration((Cpu.Pin)127, true, 0, 0, false, false, 4000, SPI.SPI_module.SPI1));
                    x =(ushort)( this.Width/2);
                    y =(ushort)( this.Height/2);
                    MouseThread = new Thread(new ThreadStart(MouseInfo));
                    MouseThread.Start();
                }
               
                protected override void OnButtonDown(ButtonEventArgs e)
                {
                    this.Close();
                    m_app.GoHome();
                }
               
                //获得鼠标信息
                private void MouseInfo()
                {
                    ushort[] bout = new ushort[3];
                    ushort[] bin = new ushort[3];
                    ushort mX, mY, mState;
                    while (true)
                    {
                        //----------------------------------
                        //通过spi通道获取鼠标信息 这部分信息解析和模拟器相对应                   
                        _spi.WriteRead(bout, bin); 
                        mState = bin[0];       //鼠标的状态 1- 按下 0 - 放开
                        mX = bin[1];           //鼠标X坐标
                        mY = bin[2];           //鼠标Y坐标
                        //----------------------------------
     
                        if (x != mX|| y != mY)
                        {
                            x = mX; y = mY;
                            OnMouseMove(new MouseEventArgs(mX, mY, mState));
                        }
                        if (state != mState)
                        {
                            state = mState;
                            if (state == 1)
                            {
                                OnMouseDown(new MouseEventArgs(mX, mY, mState));
                            }
                            else if(state==0)
                            {
                                OnMouseUp(new MouseEventArgs(mX, mY, mState));
                                OnMouseClick(new MouseEventArgs(mX, mY, mState));                          
                            }
                        }
                    }
                }
              
                //鼠标移动
                protected virtual void OnMouseMove(MouseEventArgs e)
                {
                    Debug.Print("MouseMove:" + e.X.ToString() + "," + e.Y.ToString() + "," + e.Button.ToString());
                }
     
                //鼠标单击
                protected virtual void OnMouseClick(MouseEventArgs e)
                {
                    Debug.Print("MouseClick:" + e.X.ToString() + "," + e.Y.ToString() + "," + e.Button.ToString());
                }
     
                //按下
                protected virtual void OnMouseDown(MouseEventArgs e)
                {
                    Debug.Print("MouseDown:" + e.X.ToString() + "," + e.Y.ToString() + "," + e.Button.ToString());
                }
     
                //抬起
                protected virtual void OnMouseUp(MouseEventArgs e)
                {
                    Debug.Print("MouseUp:" + e.X.ToString() + "," + e.Y.ToString() + "," + e.Button.ToString());
                }
                //绘制鼠标
                public override void OnRender(DrawingContext dc)
                {
                    if (state == 1)
                    {
                        Pen pp=new Pen(ColorUtility.ColorFromRGB(255,255,0));
                        dc.DrawLine(pp, x, y - 5, x, y + 5);
                        dc.DrawLine(pp, x-5, y, x+5, y);
                    }
                    int[] points = { x, y, x+10, y+4, x+5,y+5, x+4,y+10};
                    Pen p = new Pen(Color.White, 1);
                    dc.DrawPolygon(null, p, points);
                }
                //窗体刷新
                protected void Refresh()
                {
                    this.Left = this.Left;
                    this.UpdateLayout();  
                }
         }
    下面是我们实际运行的效果图,已经非常完美的支持鼠标了(并且模拟器可两种方式提供鼠标信息,一种是鼠标直接在LCD屏上操作,一种是通过扩展面板上的滑块进行移动)。
    直接用外部鼠标操作。
     通过滑块进行鼠标操作。
     


阅读(1168) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~