.NET Micro Framework虽然好学易用,但是在一些需要实时,需要高性能的应用领域,却有些勉为其难。毕竟.NET Micro Framework上层应用程序由底层CLR(TinyCLR)解释执行,执行效率被打个折扣是在所难免的。

美国GHI公司(国外.NET Micro Framework硬件产品主要生厂商)为此提供了一个称为RLP方案(https://www.ghielectronics.com/docs/50/rlp-enhanced)。可以让.NET Micro Framework的应用程序调用MDK编写的C++程序,主要是解决性能问题,把一些比较运行比较耗时的代码采用C++完成,功能相对简单。

而我们所提供的方案和他们不同,我们是通过流式驱动的方式用MDK开发C++程序。用户程序采用标准的流式驱动接口进行相关调用。并且流式驱动提供事件机制,底层和上层可以通过事件进行交互。

另外就是为MDK C++程序提供了丰富的.NET Micro Framework PAL层接口,可以让用户随心所欲地开发出功能强大的程序。

在此之前我已经写过两篇相关的文章,用户可以先行了解一下:《.NET Micro Framework动态调用C/C++底层代码(原理篇)》和《【物联网智能网关-11】流式驱动之用户驱动(MDK C++开发)》。

和上一篇文章介绍的功能函数相比,又扩展了一些比较实用的功能,比如I2C、SPI接口,底层中断打开关闭,HAL_COMPLETION、HAL_CONTINUATION类似底层多线程支持和中断程序用户态执行,功能函数由原来的61个扩展到了80个。具体功能接口如下:

struct IGeneralStream_Function

{

  INT32  iParam1;

  LPCSTR sParam1;

  //---

  void (*Notice_GenerateEvent)(UINT32 data1, UINT32 data2);

  void (*lcd_printf)(char const * format,...);

  void (*debug_printf)(char const* format, ... );

  void (*HAL_Time_Sleep_MicroSeconds_InterruptEnabled)(UINT32 uSec);

  UINT32 (*Events_WaitForEvents)(UINT32 WakeupSystemEvents, UINT32 Timeout_Milliseconds);

  void (*disable_interrupts)();

  void (*enable_interrupts)();

  void* (*private_malloc)(size_t len);

  void  (*private_free)( void*  ptr);

  //--- lock ---

  BOOL (*DISABLE_INTERRUPTS)(void* context);

  BOOL (*ENABLE_INTERRUPTS)(void* context);

  //HAL_COMPLETION/HAL_CONTINUATION

  UINT32 (*HAL_COMPLETION_Initialize)(HAL_CALLBACK_FPN EntryPoint,void* Argument);

  void (*HAL_COMPLETION_Uninitialize)(UINT32 handle);

  void (*HAL_COMPLETION_EnqueueDelta)(UINT32 handle,UINT32 uSec);

  UINT32 (*HAL_CONTINUATION_Initialize)(HAL_CALLBACK_FPN EntryPoint,void* Argument);

  void (*HAL_CONTINUATION_Uninitialize)(UINT32 handle);

  void (*HAL_CONTINUATION_Enqueue)(UINT32 handle);

  //--- mem ---

  int (*hal_snprintf)( char* buffer, size_t len, const char* format, ... );

  int (*hal_stricmp)( const char * dst, const char * src );

  int (*hal_strncmp_s)( const char* str1, const char* str2, size_t num );

  size_t (*hal_strlen_s)(const char * str);          

  void *(*memcpy)(void * dst, const void * src, size_t len);

  void *(*memset)( void * dst, int value, size_t len );  

  //--- Flash ---

  INT32 (*YFSoft_Flash_Erase)( UINT32 address, UINT32 count);

  INT32 (*YFSoft_Flash_Read)( UINT32 address, UINT32 count,UINT8 *buffer);

  INT32 (*YFSoft_Flash_Write)( UINT32 address, UINT32 count,UINT8 *buffer);

  //--- GPIO ---

  void (*CPU_GPIO_DisablePin)(GPIO_PIN Pin, GPIO_RESISTOR ResistorState, UINT32 Direction, GPIO_ALT_MODE AltFunction);

  BOOL (*CPU_GPIO_EnableInputPin)(GPIO_PIN Pin, BOOL GlitchFilterEnable, GPIO_INTERRUPT_SERVICE_ROUTINE ISR, GPIO_INT_EDGE IntEdge, GPIO_RESISTOR ResistorState);

  void (*CPU_GPIO_EnableOutputPin)(GPIO_PIN Pin, BOOL InitialState);

  BOOL (*CPU_GPIO_GetPinState)(GPIO_PIN Pin);

  void (*CPU_GPIO_SetPinState)(GPIO_PIN Pin, BOOL PinState);

  //--- TIMER ---

  BOOL (*CPU_TIMER_Initialize)(UINT32 timer, UINT32 ARR,UINT16 PSC,HAL_CALLBACK_FPN ISR, void* ISR_Param );

  BOOL (*CPU_TIMER_Uninitialize)(UINT32 timer );

  void (*CPU_TIMER_Start)(UINT32 timer);

  void (*CPU_TIMER_Stop)(UINT32 timer);  

  UINT32 (*CPU_TIMER_GetState)(UINT32 timer);

  void (*CPU_TIMER_SetState)(UINT32 timer,UINT32 state);

  //--- USART ---  

  BOOL (*USART_Initialize)( int ComPortNum, int BaudRate, int Parity, int DataBits, int StopBits, int FlowValue );

  BOOL (*USART_Uninitialize)( int ComPortNum );

  int  (*USART_Write)( int ComPortNum, const char* Data, size_t size );

  int  (*USART_Read)( int ComPortNum, char* Data, size_t size );

  BOOL (*USART_Flush)( int ComPortNum );

  int  (*USART_BytesInBuffer)( int ComPortNum, BOOL fRx );

  void (*USART_DiscardBuffer)( int ComPortNum, BOOL fRx );

  //--- AD/DA ---

  BOOL (*DA_Initialize)( ANALOG_CHANNEL channel, INT32 precisionInBits );

  void (*DA_Write)( ANALOG_CHANNEL channel, INT32 level );

  BOOL (*AD_Initialize)( ANALOG_CHANNEL channel, INT32 precisionInBits );

  INT32 (*AD_Read)( ANALOG_CHANNEL channel );

  //--- PWM ----

  BOOL (*PWM_Initialize)( PWM_CHANNEL channel );

  BOOL (*PWM_Uninitialize)( PWM_CHANNEL channel );

  BOOL (*PWM_ApplyConfiguration)( PWM_CHANNEL channel, GPIO_PIN pin, UINT32& period, UINT32& duration, PWM_SCALE_FACTOR &scale, BOOL invert );

  BOOL (*PWM_Start)( PWM_CHANNEL channel, GPIO_PIN pin );

  void (*PWM_Stop)( PWM_CHANNEL channel, GPIO_PIN pin );

  GPIO_PIN (*PWM_GetPinForChannel)( PWM_CHANNEL channel );

  //--- SPI ----

  BOOL (*CPU_SPI_nWrite16_nRead16)( const SPI_CONFIGURATION& Configuration, UINT16* Write16, INT32 WriteCount, UINT16* Read16, INT32 ReadCount, INT32 ReadStartOffset );

  BOOL (*CPU_SPI_nWrite8_nRead8)( const SPI_CONFIGURATION& Configuration, UINT8* Write8, INT32 WriteCount, UINT8* Read8, INT32 ReadCount, INT32 ReadStartOffset );

  //--- I2C ----

  BOOL (*I2C_Initialize)();

  BOOL (*I2C_Uninitialize)();

  BOOL (*I2C_Execute)(UINT16 address,UINT8 *inBuffer,int inCount,UINT8 *outBuffer,int outCount,UINT32 clockRateKhz,int timeout);

  //--- TinyGUI ----

  void (*LCD_ClearEx)(UINT32 color);   

  void (*LCD_SetPixel)(INT32 x,INT32 y,UINT32 color);

  UINT32 (*LCD_GetPixel)(INT32 x,INT32 y);

  void (*LCD_DrawLine)(INT32 x1,INT32 y1,INT32 x2,INT32 y2,UINT32 color);

  void (*LCD_DrawRectangle)(INT32 x,INT32 y,INT32 width,INT32 height,UINT32 color);

  void (*LCD_DrawEllipse)(INT32 x,INT32 y,INT32 width,INT32 height,UINT32 color);

  void (*LCD_DrawImage)(INT32 x,INT32 y,UINT8 *bytData);

  void (*LCD_DrawImageEx)(INT32 x,INT32 y,UINT8 *bytData,UINT32 MaskColor);

  void (*LCD_DrawString)(INT32 x,INT32 y,LPCSTR s,UINT32 color);

  void (*LCD_DrawStringEx)(INT32 x,INT32 y,UINT32 color,UINT8 *fontdata,int width,int height,int count); //2012-08-06

  void (*LCD_FillRectangle)(INT32 x,INT32 y,INT32 width,INT32 height,UINT32 color);

  void (*LCD_FillEllipse)(INT32 x,INT32 y,INT32 width,INT32 height,UINT32 color);

  void (*LCD_GetFrameBufferEx)(UINT8 *bytData,UINT32 offset,UINT32 size);

  void (*LCD_SuspendLayout)();

  void (*LCD_ResumeLayout)();  

};

下面简单介绍一下驱动开发步骤。

1、  在MDK 4.xx版本创建一个新项目,添加generalstream.h头文件,然后再添加模板文件UserDriver.cpp。如下图所示:

2、  选定MCU类型,可以根据实际硬件选择STM32F103/STM32F207/STM32F407/STM32F405。

(凌霄智能终端采用的芯片就是STM32F405RG)

3、  输入对应的平台宏定义

4、  配置针对具体硬件所设置的离散加载配置文件

凌霄智能终端的离散加载文件的内容如下:

LR_IROM1 0x08010000 0x00010000  {    ; load region size_region

ER_IROM1 0x08010000 0x00010000  {    ; load address = execution address

.ANY (+RO)

}

RW_IRAM1 0x20000400 0x00002000  {  ; RW data

.ANY (+RW +ZI)

}

}

表示程序加载的位置在0x08010000,大小为64K,RAM空间为0x20000400起始的8K空间。

注:用户驱动除了这部分RAM可用外,还可以直接通过接口提供的内存操作函数,分配堆上的内存。

5、  编写用户驱动(C/C++),下面是一个综合示例,用到了GPIO操作、显示操作、时钟中断操作和事件通知。

#include "GeneralStream.h"
//--//
#if defined(YF_Campsis103) || defined(YF_Campsis405)
#define COM_PORT COM1
#else
#define COM_PORT COM3
#endif volatile UINT32 Num;
void TIMER_ISR(void* param)
{
#if defined(YF_Campsis103) || defined(YF_Campsis405)
MF->CPU_GPIO_SetPinState(PC0,!MF->CPU_GPIO_GetPinState(PC0));
#else
MF->CPU_GPIO_SetPinState(PF6,!MF->CPU_GPIO_GetPinState(PF6));
#endif
MF->CPU_TIMER_SetState(TIM3,); if(Num++>)
{
Num=;
//触发事件
MF->Notice_GenerateEvent(UserDriver_Hander,);
}
} //--//
//Open1永远也不会被调用
int GeneralStream_Open1_UserDriver(LPCSTR config)
{
return ;
} int GeneralStream_Open2_UserDriver(int config)
{
//获取系统函数的指针
MF = (IGeneralStream_Function*)config; //C#下传的参数
//MF->lcd_printf("%d,%s\r\n",MF->iParam1,MF->sParam1);
MF->debug_printf("%d,%s\r\n",MF->iParam1,MF->sParam1); //初始化LED灯
#if defined(YF_Campsis103) || defined(YF_Campsis405)
MF->CPU_GPIO_EnableOutputPin(PC0,TRUE);
#else
MF->CPU_GPIO_EnableOutputPin(PF6,TRUE);
MF->CPU_GPIO_EnableOutputPin(PF7,TRUE);
MF->CPU_GPIO_EnableOutputPin(PF8,TRUE);
#endif //时钟定时
Num = ;
MF->CPU_TIMER_Initialize(TIM3,,(SYSTEM_TIM_CLOCK_HZ/-),TIMER_ISR,NULL);
MF->CPU_TIMER_Start(TIM3); //初始化串口
MF->USART_Initialize(COM_PORT,,USART_PARITY_NONE,,USART_STOP_BITS_ONE,USART_FLOW_NONE); //显示界面
MF->LCD_ClearEx(Color_Black);
MF->LCD_DrawString(,,"UserDriver Test",Color_Blue); return ;
} int GeneralStream_Close_UserDriver()
{
return ;
} int GeneralStream_IOControl1_UserDriver(int code, BYTE *inBuffer, int inCount, BYTE *outBuffer, int outCount)
{
return -;
} int GeneralStream_IOControl2_UserDriver(int code,int parameter)
{
char data[]={,,};
MF->USART_Write(COM_PORT, data, ); MF->lcd_printf("[4]%d-%d\r\n",code,parameter);
MF->debug_printf("[4]%d-%d\r\n",code,parameter); char str[];
MF->hal_snprintf(str,,"%d-%d",code,parameter);
MF->LCD_FillRectangle(,,,,Color_Black);
MF->LCD_DrawString(,,str,Color_Red); #if defined(YF_Wisteria207) || defined(YF_Wisteria407)
MF->CPU_GPIO_SetPinState(PF7,! MF->CPU_GPIO_GetPinState(PF7));
MF->CPU_GPIO_SetPinState(PF8,! MF->CPU_GPIO_GetPinState(PF8));
#endif
return code+parameter;
} int GeneralStream_Read_UserDriver(BYTE *buffer, int offset, int count)
{
return -;
} int GeneralStream_Write_UserDriver(BYTE *buffer, int offset, int count)
{
return -;
} //--//
//该函数无用,主要是为了编译成功而写
int main(void)
{
//空
} //--//
const IGeneralStream_Function *MF=NULL;
const IGeneralStream g_GeneralStream_UserDriver __attribute__ ((at(IGeneralStream_Address))) =
{
UserDriver_Flag,
&GeneralStream_Open1_UserDriver,
&GeneralStream_Open2_UserDriver,
&GeneralStream_Close_UserDriver,
&GeneralStream_IOControl1_UserDriver,
&GeneralStream_IOControl2_UserDriver,
&GeneralStream_Read_UserDriver,
&GeneralStream_Write_UserDriver,
};

6、  编译用户驱动,生成UserDriver.bin文件。

7、  采用YFAccessFlash部署UserDriver.bin文件。

选定UserDriver.bin文件然后直接部署即可。

注:如果这不是初次部署运行用户驱动,需要先终止当前程序的执行,否则部署会出现问题(凌霄103的设备需要先部署应用,然后再部署用户驱动)。

8、  用户程序编写(C#)

   public class Program

    {   

        public static void Main()

        {

            Debug.Print("UserDriver Test ...");

            GeneralStream gs = new GeneralStream();

            if (gs.Open("UserDriver") <= 0)

            {

                Debug.Print("Open UserDriver failed!");

                return;

            }

            gs.Notice += new GeneralStreamEventHandler(gs_Notice);

            Debug.Print("Open UserDriver OK!");

            int e = 0;

            byte[] bytData= new byte[8];

            while (true)

            {

                Debug.Print(gs.IOControl(100, e++).ToString());

                gs.Read(bytData, e, 10);

                System.Threading.Thread.Sleep(1000);

            }

        }

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

        {

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

        }

    }

  

9、  用户程序写好后,直接在VS 2010中编译执行。

硬件运行效果图(如下):

-------------------------------------------------------

MF简介:http://blog.csdn.net/yefanqiu/article/details/5711770

MF资料:http://www.yfiot.com/DownloadList.asp?Id=2&page=1

【物联网智能网关-17】.NET Micro Framework之MDK C++二次开发的更多相关文章

  1. 干货分享丨玩转物联网IoTDA服务系列四-智能网关

    摘要:该场景主要描述的是设备可以通过MQTT协议与物联网平台进行交互,用户可以在控制台产品详情中自定义Topic,通过应用侧接口或控制台创建数据转发规则,把设备上报的消息转发给其他华为云服务,供应用侧 ...

  2. 嵌入式的重要平台 .NET Micro Framework

    曾经辉煌的巨人PC界渐渐走向下坡路,而智能手机圈则没完没了般地争个你死我活.随着智能手机的广泛普及,不少商家为了不坐以待毙而纷纷开始涉足与穿戴式设备--智能手表(具体参见智能手表时代还有多远). 我们 ...

  3. 迅为4412开发平台Zigbee模块在物联网智能家居中的应用

      物联网智能家居的发展物联网随着互联网的发展,可以通过互联网实现物和物的互联,就有了物联网的概念.传统家居电器 有了物联网之后,在家居电器范围中,就是通过物联网技术将家中的各种设备连接到一起,家居中 ...

  4. 【.NET MF】.NET Micro Framework USB移植

    1.开发环境 windows 7  32位 MDK 4.54 .Net Micro Framework Porting Kit 4.2(RTM QFE2) .Net Micro Framework   ...

  5. 浅谈.NET Micro Framework性能优化 转自 软件中国

    .NET Micro Framework的可剪裁性,高定执行,和天生对硬件高集成度都让它的前途一片光明.当然,它现在还很年轻,就发布的SDK v3.0来看,它还有很长的路要走. 废话不说,就这几个月我 ...

  6. 报表工具ActiveReports开发实例——物联网智能供水云平台

    一.公司简介 山西汾西电子科技股份有限公司(以下简称:汾西电子)是经中国船舶重工集团批准,在原汾西重工电子科技公司基础上重组的专业从事智能电能表.水表.热量表及电动汽车充电设备研发生产的高科技公司. ...

  7. .NET Micro Framework 4.2 beta 源码探析

    .NET Micro Framework 4.2 beta发布已经有一段时间了,一直没有腾出时间研究,昨天因为LWIP协议栈的原因(感觉上一个版本有点问题)刚 下了代码,所以抽空研究了一下.      ...

  8. 如何重置电信悦 me 智能网关

    如何重置电信悦 me 智能网关 重置电信网关密码 电信悦 me 智能网关密码忘记了怎么办? 首先,得要知道默认终端配置地址和默认终端配置密码. 可以从无线路由器背面标签得知. 如果不知道密码了,可以通 ...

  9. 电信悦 me 智能网关

    电信悦 me 智能网关 悦 me 智能网关 Q1:什么是电信悦 me 智能网关? 悦me网关是智慧家庭的核心终端,作为"光猫+智能路由器"的集合体, 采用了全新的硬件.外观及智能操 ...

随机推荐

  1. .Net Excel操作之NPOI(一)简介

    一.NPOI简介 NPOI是一个开源项目,可以读/写xls,doc,ppt文件,有着广泛的应用. 使用NPOI能够帮助开发者在没有安装微软Office的情况下读写Office 97-2003的文件,支 ...

  2. [转]php rsa加密解密实例

    转自:http://blog.csdn.net/clh604/article/details/20224735 php服务端与客户端交互.提供开放api时,通常需要对敏感的部分api数据传输进行数据加 ...

  3. 用Eclipse开发Androd应用程序时,自带虚机模拟器太慢了,怎么办

    问:用Eclipse开发Androd应用程序时,系统自带模拟器太慢了,怎么办? 答:用Genymotin

  4. webrequest HttpWebRequest webclient/HttpClient

    webrequest(abstract类,不可直接用) <--- (继承)---- HttpWebRequest(更好的控制请求) <--- (继承)---- webclient (简单快 ...

  5. 【deep learning学习笔记】注释yusugomori的DA代码 --- dA.h

    DA就是“Denoising Autoencoders”的缩写.继续给yusugomori做注释,边注释边学习.看了一些DA的材料,基本上都在前面“转载”了.学习中间总有个疑问:DA和RBM到底啥区别 ...

  6. 命令行调用dubbo远程服务

    命令行调用dubbo远程服务 telnet远程连接到dubbo telnet 127.0.0.1 20880 查看提供服务的接口 dubbo>ls com.test.service.TestIn ...

  7. 关于使用rem单位、css函数calc()进行自适应布局

    一.关于css中的单位 大家都知道在css中的单位,一般都包括有px,%,em等单位,另外css3新增加一个单位rem. 其中px,%等单位平时在传统布局当中使用的比较频繁,大家也比较熟悉,不过px单 ...

  8. O2O、C2C、B2B、B2C

    一.O2O.C2C.B2B.B2C的区别在哪里? O2O是Online to offline 分为四种运营模式 1.Online to offline 是线上交易到线下消费体验 2.Offline t ...

  9. [Git] Undo a commit that has already been pushed to the remote repository

    If we pushed our changes already to the remote repository we have to pay attention to not change the ...

  10. Java程序猿的JavaScript学习笔记(1——理念)

    计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...