【物聯網智能網關-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,0);

   if(Num++>30)
   {
      Num=0;
      //觸發事件
      MF->Notice_GenerateEvent(UserDriver_Hander,123);
   }
}

//--// 
//Open1永遠也不會被調用
int GeneralStream_Open1_UserDriver(LPCSTR config) 
{ 
  return 0;
}    

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 = 0;
  MF->CPU_TIMER_Initialize(TIM3,200,(SYSTEM_TIM_CLOCK_HZ/2000-1),TIMER_ISR,NULL);
  MF->CPU_TIMER_Start(TIM3);

  //初始化串口
  MF->USART_Initialize(COM_PORT,115200,USART_PARITY_NONE,8,USART_STOP_BITS_ONE,USART_FLOW_NONE);

  //顯示界面
  MF->LCD_ClearEx(Color_Black);
  MF->LCD_DrawString(10,10,"UserDriver Test",Color_Blue);

  return 0;
}

int GeneralStream_Close_UserDriver()
{
   return 0;
}

int GeneralStream_IOControl1_UserDriver(int code, BYTE *inBuffer, int inCount, BYTE *outBuffer, int outCount)
{
   return -1;
}

int GeneralStream_IOControl2_UserDriver(int code,int parameter)
{
    char data[3]={65,66,67};
    MF->USART_Write(COM_PORT, data, 3);

    MF->lcd_printf("[4]%d-%d\r\n",code,parameter);
    MF->debug_printf("[4]%d-%d\r\n",code,parameter);
    
    char str[32];
    MF->hal_snprintf(str,32,"%d-%d",code,parameter);
    MF->LCD_FillRectangle(100,80,100,20,Color_Black);    
    MF->LCD_DrawString(100,80,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 -1;
}

int GeneralStream_Write_UserDriver(BYTE *buffer, int offset, int count)
{
   return -1;
}

//--//
//該函數無用,主要是為了編譯成功而寫  
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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM