【物联网智能网关-17】.NET Micro Framework之MDK C++二次开发
.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++二次开发的更多相关文章
- 干货分享丨玩转物联网IoTDA服务系列四-智能网关
摘要:该场景主要描述的是设备可以通过MQTT协议与物联网平台进行交互,用户可以在控制台产品详情中自定义Topic,通过应用侧接口或控制台创建数据转发规则,把设备上报的消息转发给其他华为云服务,供应用侧 ...
- 嵌入式的重要平台 .NET Micro Framework
曾经辉煌的巨人PC界渐渐走向下坡路,而智能手机圈则没完没了般地争个你死我活.随着智能手机的广泛普及,不少商家为了不坐以待毙而纷纷开始涉足与穿戴式设备--智能手表(具体参见智能手表时代还有多远). 我们 ...
- 迅为4412开发平台Zigbee模块在物联网智能家居中的应用
物联网智能家居的发展物联网随着互联网的发展,可以通过互联网实现物和物的互联,就有了物联网的概念.传统家居电器 有了物联网之后,在家居电器范围中,就是通过物联网技术将家中的各种设备连接到一起,家居中 ...
- 【.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 ...
- 浅谈.NET Micro Framework性能优化 转自 软件中国
.NET Micro Framework的可剪裁性,高定执行,和天生对硬件高集成度都让它的前途一片光明.当然,它现在还很年轻,就发布的SDK v3.0来看,它还有很长的路要走. 废话不说,就这几个月我 ...
- 报表工具ActiveReports开发实例——物联网智能供水云平台
一.公司简介 山西汾西电子科技股份有限公司(以下简称:汾西电子)是经中国船舶重工集团批准,在原汾西重工电子科技公司基础上重组的专业从事智能电能表.水表.热量表及电动汽车充电设备研发生产的高科技公司. ...
- .NET Micro Framework 4.2 beta 源码探析
.NET Micro Framework 4.2 beta发布已经有一段时间了,一直没有腾出时间研究,昨天因为LWIP协议栈的原因(感觉上一个版本有点问题)刚 下了代码,所以抽空研究了一下. ...
- 如何重置电信悦 me 智能网关
如何重置电信悦 me 智能网关 重置电信网关密码 电信悦 me 智能网关密码忘记了怎么办? 首先,得要知道默认终端配置地址和默认终端配置密码. 可以从无线路由器背面标签得知. 如果不知道密码了,可以通 ...
- 电信悦 me 智能网关
电信悦 me 智能网关 悦 me 智能网关 Q1:什么是电信悦 me 智能网关? 悦me网关是智慧家庭的核心终端,作为"光猫+智能路由器"的集合体, 采用了全新的硬件.外观及智能操 ...
随机推荐
- .Net Excel操作之NPOI(一)简介
一.NPOI简介 NPOI是一个开源项目,可以读/写xls,doc,ppt文件,有着广泛的应用. 使用NPOI能够帮助开发者在没有安装微软Office的情况下读写Office 97-2003的文件,支 ...
- [转]php rsa加密解密实例
转自:http://blog.csdn.net/clh604/article/details/20224735 php服务端与客户端交互.提供开放api时,通常需要对敏感的部分api数据传输进行数据加 ...
- 用Eclipse开发Androd应用程序时,自带虚机模拟器太慢了,怎么办
问:用Eclipse开发Androd应用程序时,系统自带模拟器太慢了,怎么办? 答:用Genymotin
- webrequest HttpWebRequest webclient/HttpClient
webrequest(abstract类,不可直接用) <--- (继承)---- HttpWebRequest(更好的控制请求) <--- (继承)---- webclient (简单快 ...
- 【deep learning学习笔记】注释yusugomori的DA代码 --- dA.h
DA就是“Denoising Autoencoders”的缩写.继续给yusugomori做注释,边注释边学习.看了一些DA的材料,基本上都在前面“转载”了.学习中间总有个疑问:DA和RBM到底啥区别 ...
- 命令行调用dubbo远程服务
命令行调用dubbo远程服务 telnet远程连接到dubbo telnet 127.0.0.1 20880 查看提供服务的接口 dubbo>ls com.test.service.TestIn ...
- 关于使用rem单位、css函数calc()进行自适应布局
一.关于css中的单位 大家都知道在css中的单位,一般都包括有px,%,em等单位,另外css3新增加一个单位rem. 其中px,%等单位平时在传统布局当中使用的比较频繁,大家也比较熟悉,不过px单 ...
- O2O、C2C、B2B、B2C
一.O2O.C2C.B2B.B2C的区别在哪里? O2O是Online to offline 分为四种运营模式 1.Online to offline 是线上交易到线下消费体验 2.Offline t ...
- [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 ...
- Java程序猿的JavaScript学习笔记(1——理念)
计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...