设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

树莓派+.NET MF打造视频监控智能车 遥控篇

2014-2-8 14:47| 发布者: 红黑魂| 查看: 4696| 评论: 0|来自: 博客园

摘要: 树莓派是最近比较火热的开源硬件,其设备只有信用卡大小,运行着Linux系统,专为学生编程教育而设计。我十多年的技术路线基本以学习微软的技术为主,中间也曾试图学习过linux,但是相对陡峭的学习曲线,只好让我放弃 ...

用户驱动开发

虽然接口类似SPI,但是实际用SPI接口去通信,设置各种模式(A/B/C/D四种模式),通信都不正常(返回0xFF等系列值)。所以我们采用用户驱动,用C++进行开发。

用户驱动我已经写过几篇文章了,请网友自行参考《.NET Micro Framework之MDK C++二次开发》。

我们直接从Arduino相关驱动进行修改移植,包含两个文件:ps2x_lib.h和ps2x_lib.cpp。

我们需要修改和GPIO操作、时钟操作相关的部分。

在config_gamepad函数中我们添加GPIO初始化相关代码

复制代码
MF->CPU_GPIO_EnableOutputPin(att,FALSE);

MF->CPU_GPIO_EnableOutputPin(cmd,FALSE);

MF->CPU_GPIO_EnableInputPin(dat,FALSE,NULL,GPIO_INT_NONE,RESISTOR_PULLUP);

MF->CPU_GPIO_EnableOutputPin(clk,FALSE);
复制代码

原GPIO操作代码:

复制代码
inline void  PS2X::CMD_SET(void) {

         *_cmd_lport_set |= _cmd_mask;

}

inline void  PS2X::CMD_CLR(void) {

         *_cmd_lport_clr |= _cmd_mask;

}

inline void  PS2X::ATT_SET(void) {

         *_att_lport_set |= _att_mask;

}

inline void PS2X::ATT_CLR(void) {

         *_att_lport_clr |= _att_mask;

}

inline bool PS2X::DAT_CHK(void) {

         return (*_dat_lport & _dat_mask)? true : false;

}
复制代码

改为:

复制代码
// On pic32, use the set/clr registers to make them atomic...

inline void  PS2X::CLK_SET(void) {

     MF->CPU_GPIO_SetPinState(SPI_CLK_Pin,TRUE);

}

inline void  PS2X::CLK_CLR(void) {

    MF->CPU_GPIO_SetPinState(SPI_CLK_Pin,FALSE);

}

inline void  PS2X::CMD_SET(void) {

         MF->CPU_GPIO_SetPinState(SPI_MO_Pin,TRUE);

}

inline void  PS2X::CMD_CLR(void) {

         MF->CPU_GPIO_SetPinState(SPI_MO_Pin,FALSE);

}

inline void  PS2X::ATT_SET(void) {

    MF->CPU_GPIO_SetPinState(SPI_CS_Pin,TRUE);

}

inline void PS2X::ATT_CLR(void) {

         MF->CPU_GPIO_SetPinState(SPI_CS_Pin,FALSE);

}

inline bool PS2X::DAT_CHK(void) {

         return MF->CPU_GPIO_GetPinState(SPI_MI_Pin);

}

 
复制代码

定义几个宏:

#define delayMicroseconds    MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled

#define millis()                   (MF->HAL_Time_CurrentTime()/1000)

#define delay(x)                      MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled(1000*x)

由于没有map函数,需要我们自己实现:

复制代码
int map(INT32 x, int in_min, int in_max, int out_min, int out_max)

{

  return(x -in_min)*(out_max -out_min)/(in_max -in_min)+out_min;

}
复制代码

另外就是重定义一些变量类型了,这里就不详述了。

 

下面说一下用户驱动接口的编程:

我们通过GeneralStream_Open2_UserDriver接口传递一个32位整型数,传入四个GPIO的值。

复制代码
int GeneralStream_Open2_UserDriver(int config)

{

   //必须第一个执行

   InitUserDriver();

   //获取系统函数的指针

   MF = (IGeneralStream_Function*)config;      

 

   //配置IO

   att = (UINT8)(MF->iParam1>>24 & 0xFF);

   cmd=  (UINT8)(MF->iParam1>>16 & 0xFF);

   dat=  (UINT8)(MF->iParam1>>8 & 0xFF);

   clk = (UINT8)(MF->iParam1>>0 & 0xFF);

   ……

}
复制代码

这里我们用到一个.NET Micro Framework PAL底层特有的一个功能函数:HAL_COMPLETION。可以定时去执行一个函数,类似一种多线程机制(可以定义多个)。

我们定义一个20ms执行的扫描函数,用来扫描键值:

    hcHander = MF->HAL_COMPLETION_Initialize(ScanKey,NULL);

    MF->HAL_COMPLETION_EnqueueDelta(hcHander,20000);  //20ms执行一次 

完整的扫描函数代码如下:

复制代码
void ScanKey(void *arg)

{   

    if(error == 1 || type == 2)        

    {

           InitPS2();

           MF->HAL_COMPLETION_EnqueueDelta(hcHander,1000000);  //1s执行一次

      if(error == 1 || type == 2)return;

    }

 

         //读状态

    ps2x.read_gamepad(false, vibrate);

         UINT8 button = 0;

         for(int i=0;i<16;i++)

         {

            if(ps2x.NewButtonState(Buttons[i]))

            {

                button = ps2x.Button(Buttons[i]);

                      //MF->debug_printf("%s:%d\r\n",ButtonNames[i],button);

                      //MF->lcd_printf("%s:%d             \r\n",ButtonNames[i],button);

                      if(button) ButtonState |= 1<<i;

                      else  ButtonState &= ~(1<<i);

                      //触发事件

                MF->Notice_GenerateEvent(UserDriver_Hander,(byte)i<<16 | button );

            }

    } 

         UINT8 lx=ps2x.Analog(PSS_LX);

    UINT8 ly=ps2x.Analog(PSS_LY);

    UINT8 rx=ps2x.Analog(PSS_RX);

    UINT8 ry=ps2x.Analog(PSS_RY);

         ButtonAnalog = lx<<24 | ly<<16 | rx<<8 | ry;

         if(frist!=1)

         {

             if(lx!=olx || ly!=oly)

                   {

                       //MF->lcd_printf("lx:%d ly:%d     \r\n",lx,ly);

                       //触发事件

                 MF->Notice_GenerateEvent(UserDriver_Hander,(byte)16<<16 | lx<<8 | ly );

                   }

                   if(rx!=orx || ry!=ory)

                   {

                       //MF->lcd_printf("rx:%d ry:%d     \r\n",rx,ry);

                            //触发事件

                 MF->Notice_GenerateEvent(UserDriver_Hander,(byte)17<<16 | rx<<8 | ry );

                   }

         }

         olx=lx;oly=ly;orx=rx;ory=ry;frist=0;

    MF->HAL_COMPLETION_EnqueueDelta(hcHander,20000);       //20ms执行一次

}
复制代码

为了便于同时获取键值和摇杆值,我们还封装了一个接口,代码如下:

复制代码
int GeneralStream_IOControl2_UserDriver(int code,int parameter)

{ 

   //获取当前按键状态 

   if(code == 0) return ButtonState;

   else if(code == 1) return ButtonAnalog;

   return -1;

}
复制代码

以上代码编译成bin文件,通过YFAccessFlash直接部署到设备中即可。

 

下面我们介绍一下,用户C#代码

我们先做一个简单的封装:

复制代码
public PS2(Cpu.Pin clk,Cpu.Pin cmd,Cpu.Pin att,Cpu.Pin dat )

     {

            gs = new GeneralStream();

            if (gs.Open("UserDriver", (int)((int)clk << 24 | (int)cmd << 16 | (int)att << 8 | (int)dat)) <= 0)

            {

                throw  new Exception("Open UserDriver failed!");

            }

            gs.Notice += new GeneralStreamEventHandler(gs_Notice); 

     }

 

     void gs_Notice(uint hander, uint data, DateTime timestamp)

     {

            //Debug.Print(hander.ToString() + " - " + data.ToString());

            if (hander == 1)

            {

                Key key = (Key)(data >> 16 & 0xFF);

                int state = 0,x=0,y=0;

                if (key == Key.LRocker || key == Key.RRocker)

                {

                    x = (int)(data >> 8 & 0xFF);

                    y = (int)(data & 0xFF);

                }

                else

                {

                    state = (int)(data & 0xFF);

                }

                if (Click != null) Click(this, new ButtonArgs(key, state, x, y));

            }

}

 

    public class Program

    {

        public static void Main()

        {

            PS2 ps2 = new PS2(Mainboard.SubPort.Pin12, Mainboard.SubPort.Pin10, Mainboard.SubPort.Pin8, Mainboard.SubPort.Pin14

);

            ps2.Click += new PS2.ClickHandle(ps2_Click);

            Thread.Sleep(Timeout.Infinite);

        }

 

        static void ps2_Click(object sender, PS2.ButtonArgs e)

        {

            Debug.Print(e.ToString());

        }      

    }
复制代码

 

D用户应用程序功能测试

接上设备,把以上的程序运行,操作游戏机手柄,我们就可以看到按键信息了。

文章导航:

1、【树莓派+.NET MF打造视频监控智能车】遥控篇

2、【树莓派+.NET MF打造视频监控智能车】控制篇(.NET MF)

3、【树莓派+.NET MF打造视频监控智能车】控制篇(树莓派)

4、【树莓派+.NET MF打造视频监控智能车】视频篇

小结:

1、 有了用户驱动C/C++二次开发接口,很容易移植相关C/C++代码。

2、 .NET Micro Framework的封装性能,让用户程序仅关注业务逻辑即可,显得非常的简单易用。

3、 VS2010/VS2012可以在线调试.NET Micro Framework(加断点、单步执行等等),便于问题诊断和调试。


本文地址:http://www.cnblogs.com/yefanqiu/p/3533454.html


酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部