首页 文章 精选 留言 我的

精选列表

搜索[数据库语义网关],共10000篇文章
优秀的个人博客,低调大师

【物联网智能网关-15】WAV播放器(WinForm+WavPlay库实例)

2002年在首钢实施焦炉四大机车自动化项目的时候,为了使系统更加友好,便增加了语音提示功能。不过控制设备是PLC,所以语音模块是通过IO进行控制的。接触WAV解码,是在2009年,为TI DM355平台移植.NET Micro Framework系统,同事进行驱动移植,我封装上层C#接口,不过那时候技术有限,封装的接口只能同步播放。 当前市场上的语音模块一般分两种,一种是可录音的模块,录上音,触发一下,就可以播放。另外一种就是烧录WAV文件(或其它自定义格式的语音数据)。前者往往很难做到分段录音分段播放,而后一种,由于是部署文件,所以相对容易的分段控制。控制方式一种是IO方式,另一种就是串口发命令控制。 最近和一个朋友合作开发一个医疗上的上肢康复设备,需要用到语音提示功能。最初想到的也是采用语音模块控制,便花了一百多元购买了两个语音模块进行研究,语音模块虽然有些小贵,但是价格和音质还可以,既可以用IO控制,也可以通过RS485发指令控制。不过朋友感觉外接一个模块的方式不大好,建议加一个解码芯片或PWM驱动控制。 因此便开始研究语音控制技术,由于.NET Micro Framework已经支持了DA输出功能,而STM32芯片时钟中断功能也比较强大,所以就尝试做WAV解码。没有想到实际做出的效果竟然非常好,特别是用外接音箱播放的时候,几乎可以媲美一些播放器的音质。 系统直接支持语音播放,可以非常方便实现各种功能,比如做一个报时功能,由于可能在任一个时间要求报时,所以不可能像整点报时一样,做20多个语音文件到时播放即可。更好的做法就是把各个语音分成单元,到时候用程序控制拟合播放。不仅仅是报时,如电子秤称重报数、计算器语音报时、智能家居控制中的智能提示,都需要语音。并且由文件系统支持,100多兆字节的存储空间,可以存放很多语音文件。不像一些语音模块,存储空间都是比较有限的,比如我采购的那款价格相对较高的语音模块,存储空间才8M。 下面我以一个WAV播放器为实例,介绍WAV播放类库的使用。 第一步:准备WAV声音文件 我们可以借助一些声音转换工具,把常见的MP3格式的文件转换为WAV格式的文件。比如GoldWave软件,声音文件最好重新采样,建议速率为16000Hz(最好不要大于44100Hz),如下图所示: 保存的格式,建议为:PCM unsigned 8bit,mono。16位、双声道播放(需要两路DA),WavPlay函数也是支持的,不过感觉没有必要,一是文件会增大几倍,但是音质改善并不大。 第二步:把WAV声音文件下载到文件系统 如果WAV文件不大,把WAV文件作为资源文件(WAV文件添加资源的时候,要修改扩展名,以二进制资源的方式加入)也是可以的,WavPlay函数可直接播放字节数组数据。但是对一些比较大的WAV文件,如一首歌曲,一般就得3M Byte左右的大小了,是不能添加到资源中去的。 我们还是用在博文《Html5:Canvas+WebSocket实现远程实时通信》中介绍的YFFileViewer工具,参见下图。 第三步:设计播放界面 我们采用YFSoft.WinForm库进行界面编写(WinForm相关博文,请参见《WinForm for .NET MF 功能一览》)。界面设计,我们还是先用桌面版的程序进行设计,设计好后,把代码加入.NET Micro Framework工程。 第四步:播放代码编写 (1) 枚举文件系统根目录下所有的WAV文件 string[] files = Directory.GetFiles("\\ROOT"); foreach (string file in files) { if (file.Substring(file.Length - 3, 3).ToLower() == "wav") { listBox1.Items.Add(file); } } (2) 播放和停止播放 private void button1_Click(object sender, EventArgs e) { WavPlay.Play(listBox1.Text,true); tm.Enabled = true; progressBar1.Value = 0; button1.Enabled = false; button2.Enabled = true; } private void button2_Click(object sender, EventArgs e) { WavPlay.Stop(); tm.Enabled = false; button1.Enabled = true; button2.Enabled = false; } WavPlay库下载:http://www.sky-walker.com.cn/MFRelease/library/v42/YFSoft.WavPlay.rar 示例源码下载:http://www.sky-walker.com.cn/MFRelease/Sample/YFWavPlay.rar 程序运行后界面如下: 注:DA输出可以接音箱,也可以接耳机,不过直接驱动扬声器,则声音有些小,需要加一个功放模块(可以单击这里,购买功放+喇叭套件)。 目前紫藤207平台已经支持屏幕横竖屏切换了,系统启动的时候,先检查是不是竖屏,如果不是,则自动切换(YFAccessFlash工具也可以配置横竖屏模式),相关代码如下: //检查LCD是否竖屏显示模式 YFStream.Utility.LCD_ViewMode mode = YFStream.Utility.Instance.GetLcdMode(); if (mode != YFStream.Utility.LCD_ViewMode.Portrait) { YFStream.Utility.Instance.SetLcdMode(YFStream.Utility.LCD_ViewMode.Portrait); //重启系统 Microsoft.SPOT.Hardware.PowerState.RebootDevice(false); Thread.Sleep(Timeout.Infinite); } 实际的运行效果如何,请看相关视频: 播放链接:http://v.youku.com/v_show/id_XNDgwODgyOTky.html ----------------------------------------------------------------- MF简介:http://blog.csdn.net/yefanqiu/article/details/5711770 MF资料:http://www.sky-walker.com.cn/News.asp?Id=25 相关硬件:http://www.sky-walker.com.cn/Products.asp?Id=24 本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/1073543,如需转载请自行联系原作者

优秀的个人博客,低调大师

【物联网智能网关-10】构建.NET MF平台下的流式驱动模型

无论是做linux下的驱动开发,还是Windows CE平台下的驱动开发,对流式驱动模型一定非常熟悉。在此架构下,把所有的硬件设备都看成文件,和设备的交互其实就是读写文件,也就是数据流动。这样开发驱动不仅简单实用,并且用户也用一致的接口访问硬件,大大降低了学习代价。但是在.NET Micro Framework平台下,却没有提供这样的驱动开发接口,用户如果想在应用层操作硬件,必须要做一个专门的接口库(Interop),如果有n个设备,对应的驱动接口库文件也必须n个,如果一个应用程序和n个设备通信,那就必须引用n个库了。另外如果库接口有更改,那么上层和底层代码还必须重新编译才能使用。 正是基于流式驱动的一些优点和Interop驱动接口开发的繁杂,所以我在.NET Micro Framework系统上构建了一套流式驱动架构。尤为值得一提的是,在流式驱动架构的基础上,还实现了的用户可以在MDK IDE环境下,采用C++开发流式驱动(参见相关文章《.NET Micro Framework动态调用C/C++底层代码》)。 流式驱动应用层的C#接口代码如下: public sealed class GeneralStream { publicGeneralStream(); public event GeneralStreamEventHandlerNotice; public int Close(); public int IOControl(intcode); public int IOControl(intcode, int parameter); public int IOControl(intcode, byte[] inBuffer, intinCount, byte[] outBuffer, int outCount); public int Open(stringname); public int Open(string name,int config); public int Open(string name,string config); public int Read(byte[]buffer, int offset, intcount); public int Write(byte[]buffer, int offset, intcount); } 以上接口其实和WinCE平台下的流式接口非常类似了,但是比较有特色的是,还提供了一个事件通知接口,这样就为各种硬件驱动开发提供了更灵活的支持。有了这个流式接口,一般情况下,为上层C#语言提供专有的硬件底层功能,就不需要再编写接口相关的代码了,直接写相关的C/C++代码,然后编译链接即可。 当前已经基于流式驱动接口,实现了10个设备和功能模块的驱动,下面先简单介绍一下,后续将详细写文章一一介绍。 序号 名称 说明 备注 000 UserDriver 用户流式驱动开发接口 MDK下的C++开发 001 Watchdog 看门狗驱动 002 Ultrasonic 超声波模块驱动 测距 003 DHT11 温湿度模块驱动 004 GPIO GPIO特殊功能驱动 比如可以配置开漏 005 Counter 高速计数器 006 ADIS16227 ADIS16227模块驱动 基于特殊的SPI接口 007 MAX7219 MAX71219芯片驱动 LED和点阵控制 008 PCD8544 Norkia5110显示模块驱动 009 LCD1602 LCD1602模块驱动 在开发ADIS16227、Norkia5110和LCD1602模块驱动的过程中,深切感受到,给用户留一个C++驱动开发接口非常重要,因为这类驱动,上层应用一是没有现成的接口,二是直接用C#是不能实现的,所以必须底层移植,如果没有现成用户接口,就必须依赖厂商了,这很大层度上限制了用户的开发的主动性和灵活性,还有对产品及项目的把控性。 关于这部分内容,我在用户流式驱动开发接口(UserDriver)的文章中会详细介绍。 ----------------------------------------------------------- MF简介:http://blog.csdn.net/yefanqiu/article/details/5711770 MF资料:http://www.sky-walker.com.cn/News.asp?Id=25 本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/1004388,如需转载请自行联系原作者

优秀的个人博客,低调大师

【物联网智能网关-11】流式驱动之用户驱动(MDK C++开发)

微软体系的产品给人的感觉一直是易学易用,但是其执行性能却屡受诟病。所以一些对性能要求相对较高的硬件产品研发,一般都是采用linux体系的技术,或者是无操作系统开发,其开发语言也绝大数是C/C++(启动代码或中断部分的代码有时会用汇编代码实现)。但是对工控集成类的项目开发来说,由于项目开发周期比较短,对稳定性要求比较高,如果全部采用C/C++开发,不仅对开发人员的能力要求比较高,并且开发和调试的代价非常大。所以PC平台的,大都是用组态系统搭建,嵌入式系统则是采用嵌入式组态软件,其定制化的软件则采用WinCE等易用的嵌入式系统来开发了,但是对再小型的嵌入式系统,由于选择目前比较少,也只有选用传统的C/C++来开发了。 2001年.NET Micro Framework的开始研发,其实就是基于比尔盖茨所谓的.NET战略,上至服务器大型系统,下至嵌入式领域的芯片都希望是.NET系统,都可以用C#等.NET开发语言进行开发。所以最开始.NET Micro Framework系统就是开发硬件产品的,MSN Direct产品、SideShow,还有一些高端遥控器,键盘,都是采用.NET Micro Framework系统开发(相关介绍,请参见《MSN Direct项目简介》),虽然用.NET Micro Framework系统开发比较容易,但是要达到同样的性能,必须要求系统的主频更快,RAM更大,这对批量生产的硬件产品来说,长远发展来看,不是一个好选择。 我个人认为微软官方的.NET Micro Framework产品类开发的定位是错误的,这一点我可以看到微软在Windows领域的开发也是放弃了全用.NET托管代码实现的诉求,大部分底层或对性能要求很高的代码,依然采用原生C/C++实现(目前iOS和安卓系统的开发,基于性能的考虑,很多开发人员都开始用原生C/C++进行开发)。 用.NET Micro Framework开发用户需求变化少,不需要二次开发接口的产品来说,是非常不适合的,特别是销售量数量非常大的产品,因为随着产品的销量不断增加,前期开发成本所占的成本比重将越来越小。但是对用户需求变化大,用户需要有二次开发,或者是销量比较少的产品来说,用.NET Micro Framework优势就比较明显了。特别是工控集成类的产品,.NET Micro Framework系统有天然的优势(这是我7年工控领域的工作经历深切感受到的)。 PC领域的组态化技术已经非常成熟了,目前已经在向组态软件的第二代或第三代进行发展。但是在嵌入式领域,特别是低端MCU方面,这方面做得远远不够,我工作的定位就是致力于嵌入式领域组态化,并且我认为.NET Micro Framework系统是实现这个愿景的最好的一种技术支撑。 .NET Micro Framework的平台的C#(或VB.NET)开发虽然开发比较简单,但是其执行性能却是一个必须面对的问题(2009年我在微软总部和MSN Direct开发人员交流的时候,他们对.NET Micro Framework的执行性能颇有微词)。 我的解决方案就是:.NET Micro Framework必须尽可能的封装,C#语言执行的不是大段功能代码,而只是一些工艺流程代码即可,那些功能性的代码尽可能用C/C++实现。C#起到粘连串接的作用即可,这一点和网页开发中的脚本语言的角色非常类似。 目前这类封装,必须是porting开发人员完成,是.NET Micro Framework TinyCLR的不可分的部分,普通用户是不能进行C/C++开发的。而我这篇文章所介绍的重点,就是为普通的开发用户,开启C/C++ 基于.NET Micro Framework编程之门。在《.NET Micro Framework动态调用C/C++底层代码》文章中我介绍了这种技术的实现原理,本篇文章就是基于应用的角度,介绍如果用MDK进行.NET Micro Framework用户驱动开发。 在进行用户流式驱动开发介绍之前,我先比较一下C#和C++开发的性能,让大家有一个直观的感受。 上图C#代码如下: OutputPort io = new OutputPort((Cpu.Pin)GPIO_NAMES.PA6,false); while (true) { io.Write(true); io.Write(false); } C++的代码如下(NativeSample下运行) CPU_GPIO_EnableOutputPin(STM32F20x_GPIO_Driver::PA6,FALSE); while(TRUE) { CPU_GPIO_SetPinState(STM32F20x_GPIO_Driver::PA6,FALSE); CPU_GPIO_SetPinState(STM32F20x_GPIO_Driver::PA6,TRUE); } 硬件平台采用紫藤207(STM32F207 主频120M),通过示波器检查PA6管脚。 从示波器的显示结果来看,二者相差近60倍,所以说在C#层很难实现微秒级别的控制。 另外我也比较了一下C#和C++的for循环的执行效率。 代码很简单,就是:for(x=0;x<1000;x++); 执行次数 C# C++ 倍数 10 316us - - 100 2.5ms 3.5us 714 1000 24ms 33us 727 10000 - 333us - C#层提供的Sleep延时也是毫秒级别的,我做了一个简单的测试,结果如下: Sleep参数 0 1 10 执行时间 176-184 us 1.3ms 10.4ms 注:由于底层时钟中断不断触发,Sleep的时间是不确定的。 相信以上的测试结果,对大家的印象是深刻的。所以说,不考虑C#的封装优点,而是非要用C#和C++实现同样的功能,只能是让大家越来越远离.NET Micro Framework。 -------- 分割线 --------- 在《.NET Micro Framework动态调用C/C++底层代码》这篇文章中,我介绍g_GeneralStream_Function的时候,其支持的函数才15个,并且主要是GPIO和时钟类的函数,这次调整以后,已经扩展支持61个了,并且也可以传递初始化函数的字符串或整型变量参数了,新的g_GeneralStream_Function定义如下: IGeneralStream_Function g_GeneralStream_Function = { -1, NULL, //-- &Notice_GenerateEvent, &lcd_printf, &debug_printf, &HAL_Time_Sleep_MicroSeconds_InterruptEnabled, &Events_WaitForEvents, &disable_interrupts, &enable_interrupts, &private_malloc, &private_free, //mem &hal_snprintf, &hal_stricmp, &hal_strncmp_s, &hal_strlen_s, &memcpy, &memset, //Flash &YFSoft_Flash_Erase, &YFSoft_Flash_Read, &YFSoft_Flash_Write, //GPIO &CPU_GPIO_DisablePin, &CPU_GPIO_EnableInputPin, &CPU_GPIO_EnableOutputPin, &CPU_GPIO_GetPinState, &CPU_GPIO_SetPinState, //TIMER &CPU_TIMER_Initialize, &CPU_TIMER_Uninitialize, &CPU_TIMER_Start, &CPU_TIMER_Stop, &CPU_TIMER_GetState, &CPU_TIMER_SetState, //USART &USART_Initialize, &USART_Uninitialize, &USART_Write, &USART_Read, &USART_Flush, &USART_BytesInBuffer, &USART_DiscardBuffer, //DA/AD &DA_Initialize, &DA_Write, &AD_Initialize, &AD_Read, //PWM &PWM_Initialize, &PWM_Uninitialize, &PWM_ApplyConfiguration, &PWM_Start, &PWM_Stop, &PWM_GetPinForChannel, //TinyGUI &LCD_ClearEx, &LCD_SetPixel, &LCD_GetPixel, &LCD_DrawLine, &LCD_DrawRectangle, &LCD_DrawEllipse, &LCD_DrawImage, &LCD_DrawImageEx, &LCD_DrawString, &LCD_DrawStringEx, &LCD_FillRectangle, &LCD_FillEllipse, &LCD_GetFrameBufferEx, &LCD_SuspendLayout, &LCD_ResumeLayout, }; 有了这些函数支持,就可以在MDK中独立编写 MF的用户流驱动了。当然,你也可以不用这些函数,也可以调用MDK相关的库或STM32提供的库,直接通过寄存器对硬件进行操作(前提是和已有的功能不要冲突就行)。 为了便于在MDK 4.x中开发用户流式驱动,我提供了yfmflib.h和grenralstream.h头文件,也提供了一个UserDriver.cpp模板,用户只要简单修改一下即可。 UserDriver.cpp模板中的代码如下: //说明:代码空间 0x08010000 - 0x08020000 64K // 内存空间 0x20002000 - 0x20004000 8K #include "YFMFLib.h" #include "GeneralStream.h" #define UserDriver_Flag "UserDriver" #define UserDriver_Hander 1 const IGeneralStream_Function *MF=NULL; int GeneralStream_Open1_UserDriver(LPCSTR config) { return 0;} //Open1永远也不会被调用 //int GeneralStream_Open2_UserDriver(int config) { 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){return -1;} 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 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); } extern const IGeneralStream g_GeneralStream_UserDriver; const IGeneralStream g_GeneralStream_UserDriver = { UserDriver_Flag, &GeneralStream_Open1_UserDriver, &GeneralStream_Open2_UserDriver, &GeneralStream_Close_UserDriver, &GeneralStream_IOControl1_UserDriver, &GeneralStream_IOControl2_UserDriver, &GeneralStream_Read_UserDriver, &GeneralStream_Write_UserDriver, }; 为了让大家印象深刻,我们以LCD1602的驱动为示例,进行用户驱动编写(我已经为其专门开发了一个流式驱动,以其为例只是便于说明,后续还将详细介绍LCD1602)。 其实LCD1602的显示就是IO操作,其实理论上在C#层也可以实现,但是通过我以上的性能测试,估计大家会鲜有尝试了。LCD1602的驱动,通过上网搜索,无论是C51、STM32还是Arduino都提供了相关的源码,我们只要把相关的IO操作的函数,转换为我们MF的IO操作函数即可。 主要代码如下: void LCD1602_Write_byte(BYTE data) { MF->CPU_GPIO_SetPinState(LCD1602_E_Pin,TRUE); MF->CPU_GPIO_SetPinState(LCD1602_D7_Pin,(data & 0x80)>0); MF->CPU_GPIO_SetPinState(LCD1602_D6_Pin,(data & 0x40)>0); MF->CPU_GPIO_SetPinState(LCD1602_D5_Pin,(data & 0x20)>0); MF->CPU_GPIO_SetPinState(LCD1602_D4_Pin,(data & 0x10)>0); MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled(1); MF->CPU_GPIO_SetPinState(LCD1602_E_Pin,FALSE); MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled(1); MF->CPU_GPIO_SetPinState(LCD1602_E_Pin,TRUE); MF->CPU_GPIO_SetPinState(LCD1602_D7_Pin,(data & 0x08)>0); MF->CPU_GPIO_SetPinState(LCD1602_D6_Pin,(data & 0x04)>0); MF->CPU_GPIO_SetPinState(LCD1602_D5_Pin,(data & 0x02)>0); MF->CPU_GPIO_SetPinState(LCD1602_D4_Pin,(data & 0x01)>0); MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled(1); MF->CPU_GPIO_SetPinState(LCD1602_E_Pin,FALSE); } void LCD1602_Write_Command(BYTE cmd) { MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled(100); MF->CPU_GPIO_SetPinState(LCD1602_RS_Pin,FALSE); LCD1602_Write_byte(cmd); } void LCD1602_Write_Data(BYTE data) { MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled(100); MF->CPU_GPIO_SetPinState(LCD1602_RS_Pin,TRUE); LCD1602_Write_byte(data); } void LCD1602_SetXY(BYTE x,BYTE y)//x:0~15,y:0~1 { if(y) LCD1602_Write_Command(0xc0+x);//第二行显示 else LCD1602_Write_Command(0x80+x);//第一行显示 } void LCD1602_Write_Char(BYTE x,BYTE y,char data) { LCD1602_SetXY( x, y); //写地址 LCD1602_Write_Data(data); } void LCD1602_Print(BYTE x,BYTE y,char *s) { if(x>15)x=15; LCD1602_SetXY( x, y ); //写地址 int i=0; while (*s && (x+i++)<16) //写显示字符 { LCD1602_Write_Data( *s++ ); } } void LCD1602_Init() { MF->CPU_GPIO_SetPinState(LCD1602_RW_Pin,FALSE); //只写 MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled(100000); LCD1602_Write_Command(0x33); MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled(20000); LCD1602_Write_Command(0x32); MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled(20000); LCD1602_Write_Command(0x28); LCD1602_Write_Command(0x0C); //显示开 LCD1602_Write_Command(0x01); //清屏 MF->HAL_Time_Sleep_MicroSeconds_InterruptEnabled(20000); } 以上就是LCD驱动相关的代码,下面我们填写接口代码 int GeneralStream_Open2_UserDriver(int obj) { //获取系统函数的指针 MF = (IGeneralStream_Function*)obj; //-- LPCSTR config = MF->sParam1; //不能有空格 // 012345678901234567890123456789012345678901234567890123 //格式RS=PC08,RW=PC09,E=PB06,D4=PB07,D5=PC00,D6=PC02,D7=PC03 if(config[3]!='P' || config[11]!='P' || config[18]!='P' || config[26]!='P' || config[34]!='P' || config[42]!='P' || config[50]!='P') { return -1; } LCD1602_RS_Pin =(GPIO_PIN)((config[4]-'A') * 16 + (config[5]-'0') * 10+ (config[6] - '0')); LCD1602_RW_Pin =(GPIO_PIN)((config[12]-'A') * 16 + (config[13]-'0') * 10+ (config[14] - '0')); LCD1602_E_Pin =(GPIO_PIN)((config[19]-'A') * 16 + (config[20]-'0') * 10+ (config[21] - '0')); LCD1602_D4_Pin =(GPIO_PIN)((config[27]-'A') * 16 + (config[28]-'0') * 10+ (config[29] - '0')); LCD1602_D5_Pin =(GPIO_PIN)((config[35]-'A') * 16 + (config[36]-'0') * 10+ (config[37] - '0')); LCD1602_D6_Pin =(GPIO_PIN)((config[43]-'A') * 16 + (config[44]-'0') * 10+ (config[45] - '0')); LCD1602_D7_Pin =(GPIO_PIN)((config[51]-'A') * 16 + (config[52]-'0') * 10+ (config[53] - '0')); MF->CPU_GPIO_EnableOutputPin(LCD1602_RS_Pin,FALSE); MF->CPU_GPIO_EnableOutputPin(LCD1602_RW_Pin,FALSE); MF->CPU_GPIO_EnableOutputPin(LCD1602_E_Pin,FALSE); MF->CPU_GPIO_EnableOutputPin(LCD1602_D4_Pin,FALSE); MF->CPU_GPIO_EnableOutputPin(LCD1602_D5_Pin,FALSE); MF->CPU_GPIO_EnableOutputPin(LCD1602_D6_Pin,FALSE); MF->CPU_GPIO_EnableOutputPin(LCD1602_D7_Pin,FALSE); LCD1602_Init(); //初始化液晶 return 0; } int GeneralStream_Write_UserDriver(BYTE *buffer, int offset, int count) { UINT8 x = (BYTE)((offset>>8) & 0xFF); UINT8 y = (BYTE)(offset & 0xFF); buffer[count]=0; if(x>15 || y>1 ) return -1; LCD1602_Print(x,y,(char *)buffer); return 0; } 以上代码在MDK中直接编译,编译后的bin文件,经过转换适当转换,变为MF部署工具所支持的Hex文件,用MFDeploy或YFAccessFlash工具直接部署即可,如下图所示: 基于C++的代码我们已经完成,下一步我们开始写C#代码,以便调用我们写好的C++代码。 代码如下: using System; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using YFSoft.IO; namespace UserDriverTest { public class Program { public static void Main() { Debug.Print("UserDriver Test ..."); LCD1602 lcd = new LCD1602(); lcd.Print(0, 0, "Hello .NET MF!!!"); lcd.Print(0, 1, "YFSoft 20120920"); while (true) { System.Threading.Thread.Sleep(500); } } } //Width = 16 Height = 2 public class LCD1602 { GeneralStream gs = null; public LCD1602() { gs = new GeneralStream(); int ret = 0; if ((ret = gs.Open("UserDriver", "RS=PC08,RW=PC09,E=PB06,D4=PB07,D5=PC00,D6=PC02,D7=PC03")) <= 0) { Debug.Print("ERR=" + ret.ToString()); gs = null; } } public void Print(byte x, byte y, string s) { if (gs == null) return; byte[] temp = System.Text.UTF8Encoding.UTF8.GetBytes(s); byte[] buff = new byte[temp.Length + 1]; Array.Copy(temp, buff, temp.Length); buff[buff.Length - 1] = 0; gs.Write(buff, x << 8 | y, temp.Length); } } } 代码执行后,其运行效果如下图所示: ------------------------------------------------- MF简介:http://blog.csdn.net/yefanqiu/article/details/5711770 MF资料:http://www.sky-walker.com.cn/News.asp?Id=25 本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/1031101,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册