C#开发基于wince SDK的PWM控制软件

来源:互联网 发布:吴克群 知乎 编辑:程序博客网 时间:2024/05/21 23:00

在网上看到一片文章,很好,转了过来。

 

     前些天本人苦于vs2005下开发pwm的控制软件,经过几天的努力,现已成功写出了pwm的控制软件,现总结如下

      开发环境:mini2440+vs2005+vs2005 sp1+mini2440 SDK

                没有安装wince6.0及PB    

 

   一、学习相关的知识

     1、流驱动的相关知识

1.1 流驱动的主要接口

Wince流驱动方式与c++中开发dll很相相似,主要有以下几个接口:

     

流接口函数

功能描述

调用流接口对象

XXX_Init()

初始化设备

系统设备管理器

XXX_Denit()

卸载设备

系统设备管理器

XXX_Open()

打开设备进行读写操作

文件API函数CreateFile()

XXX_Close()

关闭设备

文件API函数CloseHandle()

XXX_Read()

读取设备数据

文件API函数ReadFile()

XXX_Write()

向设备写数据

文件API函数WriteFile()

XXX_IOControl()

对设备进行各种操作

文件API函数DeviceIOControl()

XXX_Seek()

移动设备数据的指针位置

文件API函数SetFilePointer()

XXX_PowerDown()

使设备休眠

系统电源管理器

XXX_PowerUp()

恢复设备电源

系统电源管理器

                                            图1 流驱动主要接口

 

1.2  流驱动工作及调用过程

1)加载驱动。在当系统启动时,设备管理器搜寻注册表的HKEY_LOCAL_MACHINE\Driver\BuiltIn键下面的子键,并逐一加载子键下的每个驱动,此过程叫BusEnum。

2)设备管理器从注册表的dll键值中获取驱动程序所在的DLL文件名。

3)设备管理器调用LoadDriver()函数把DLL加载到自己的虚拟地址空间内。

4)设备管理器在注册表的HKEY_LOCAL_MACHINE\Driver\Active下面,记录所有已经加载的驱动程序。

5)设备管理器调用驱动中的XXX_Init()函数。

6)在XXX_Init()中,通常对硬件进行一些基本的初始化操作。通过以上6步,流接口驱动被成功加载。

7)应用程序使用该设备。首先它调用CreateFile()打开设备。CreateFile()是在FileSys.exe中实现的。但是FileSys.exe只作简单判断,如果发现打开的设备驱动程序而不是一个文件,那么就重新把主动权交还给设备管理器。

8)设备管理器调用驱动程序中的XXX_Open()函数打开设备。在XXX_Open()中,驱动程序可能会对硬件进行一些额外的初始化工作,使硬件进入工作状态。

9)XXX_Open()函数把打开设备的结果返回给设备管理器。

10)设备管理器把XXX_Open()返回的结果,再返回给应用程序的CreateFile()函数调用。通过7-10步,设备已被成功打开,至此就可以对设备进行读写和控制操作。

11)应用程序使用第7步CreateFile()函数返回的句柄作为 ReadFile() / WriteFile()的第一个参数,向设备发送读请求。同样ReadFile() / WriteFile()要经过FileSys.exe转发给设备管理器。

12)设备管理器调用驱动程序中的XXX_Read() / XXX_Write() 函数,读取设备的数据信息或向设备写信息。

13)在流驱动程序中,XXX_Read() / XXX_Write() 函数可与硬件交互,从硬件中读取必要的信息或向硬件写必要的信息。然后返回给设备管理器,再返回给应用程序。

当应用程序不再使用该设备时,它可调用CloseHandle()将设备关闭。当系统不再使用设备时,应用程序可调用DeactivateDevice()函数把该驱动程序卸载

   通过以上的过程我们已知道了流驱动相关函数的调用过程及wince的一些硬件控制知识

下面我们再了解一下 wince的系统架构

 

  2Windows Embedded CE 6.0的系统架构的模块组成

                                                                           图2 WINCE6.0 系统架构

 

   从这个架构图可以发现wince的应用程序(windows CE Application)及其他的一些服务都是通过win32 CE API函数来支持,通过API函数与内核空间对话,达到控制硬件的目的。

我们发现win32 CE APIS,中有coredll,winsock,commctrl ,commdlg,其中coredll就是我们驱动PWM及一些其他的硬件所要用到的。

 

 

3、了解coredll.dll的相关知识

Coredll对于wince来说,就相当于win32中的kernel32.dll,我们要调用驱动中的一些:函数,就得通过他来调用。

 

 

Coredll有很多函数,但我们驱动PWM只用以下几个:

coredll接口函数

功能描述

CreateFile()

打开设备进行读写操作

CloseHandle()

关闭设备

ReadFile()

读取设备数据

WriteFile()

向设备写数据

DeviceIOControl()

对设备进行各种操作

SetFilePointer()

移动设备数据的指针位置

    图3 coredll中的API函数

 

  4、综合分析

         通过以上3部分学习,我们知道了设备是通过流驱动来操作,而流驱动测通过调用coredll中的一些函数来操作,主要操作就是图3中的一些函数。


二、c#中编写PWM操作程序

1、程序流程

1.1声明coredll中的相关函数

[DllImport("coredll.dll")]

        public static extern IntPtr CreateFile(

            String lpFileName,

            UInt32 dwDesiredAccess,

            UInt32 dwShareMode,

            IntPtr lpSecurityAttributes,

            UInt32 dwCreationDisposition,

            UInt32 dwFlagsAndAttributes,

            IntPtr hTemplateFile);

        [DllImport("coredll.dll")]

        public static extern bool DeviceIoControl(

            IntPtr hDevice,

            UInt32 dwIoControlCode,

            Byte[] lpInBuffer,

            UInt32 nInBufferSize,

            Byte[] lpOutBuffer,

            UInt32 nOutBufferSize,

            UInt32 lpBytesReturned,

            IntPtr lpOverlapped);

        [DllImport("coredll.dll")]

        public static extern bool CloseHandle(IntPtr hDevice);

 

      

以上声明了CreateFile,DeviceIoControl,CloseHandle三个函数,注意要用coredll还要声明引用空间

using System.Runtime.InteropServices;

还有一些常数

// Constant of

        const UInt32 OPEN_EXISTING = 3;

        const UInt32 GENERIC_READ = 0x80000000;

        const UInt32 GENERIC_WRITE = 0x40000000;

        const Int32 INVALID_HANDLE_VALUE = -1;

还有一些操作的指令,这些指令可查看c:\WINCE600\platform\mini2440\src\driver\pwm\pwm.h,这是BSP中的源程序文件

        const UInt32 PWM_STOP = 1;     

        const UInt32 PWM_SET_FEQ = 2;

 

1.2应用以上函数来控制PWM

private IntPtr hPort;

hPort = CreateFile("PWM1:", GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);                //打开设备

DeviceIoControl(hPort, PWM_SET_FEQ, sBuf, 4, null, 0, 0, IntPtr.Zero);  //设置PWM频率

CloseHandle(hPort);                  //关闭PWM

 用以上3个函数就可以进行PWM的常规操作了

 

2、完整的程序

2.1程序功能说明

  本程序是一个可设置PWM频率,可控制PWM开关时间程序

2.2程序界面

  

2.3程序

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Runtime.InteropServices;

using System.Threading;

 

namespace pwm_test

{

    public partial class Form1 : Form

    {

      

 

        private IntPtr hPort;

        // Constant from PWM Driver

        //查看c:\WINCE600\platform\mini2440\src\driver\pwm\pwm.h

        const UInt32 PWM_STOP = 1;     

        const UInt32 PWM_SET_FEQ = 2;

        const UInt32 PWM_SET_DUTY = 3;

 

        [DllImport("coredll.dll")]

        public static extern IntPtr CreateFile(

            String lpFileName,

            UInt32 dwDesiredAccess,

            UInt32 dwShareMode,

            IntPtr lpSecurityAttributes,

            UInt32 dwCreationDisposition,

            UInt32 dwFlagsAndAttributes,

            IntPtr hTemplateFile);

        [DllImport("coredll.dll")]

        public static extern bool DeviceIoControl(

            IntPtr hDevice,

            UInt32 dwIoControlCode,

            Byte[] lpInBuffer,

            UInt32 nInBufferSize,

            Byte[] lpOutBuffer,

            UInt32 nOutBufferSize,

            UInt32 lpBytesReturned,

            IntPtr lpOverlapped);

        [DllImport("coredll.dll")]

        public static extern bool CloseHandle(IntPtr hDevice);

 

        // Constant of

        const UInt32 OPEN_EXISTING = 3;

        const UInt32 GENERIC_READ = 0x80000000;

        const UInt32 GENERIC_WRITE = 0x40000000;

        const Int32 INVALID_HANDLE_VALUE = -1;

 

        public bool pwm_ena = true;

        public int   tpwmon;

        public int   tpwmoff;

        public bool pwm_level=false ;

        //函数:FreqSet 设置PWM频率

        private void FreqSet(UInt32 value)

        {

            byte[] sBuf = new byte[4];

            UInt32 sInput;

 

            // Check Open Device already

            if (hPort != (IntPtr)INVALID_HANDLE_VALUE)

            {

                sInput = 50;

                // Convert sInput(UInt32) to sBuf(Array of Byte)

                BitConverter.GetBytes(sInput).CopyTo(sBuf, 0);

                // Set Duty[0-99] to PWM Device

                DeviceIoControl(hPort, PWM_SET_DUTY, sBuf, 4, null, 0, 0, IntPtr.Zero);

                sInput = value;

                // Convert sInput(UInt32) to sBuf(Array of Byte)

                BitConverter.GetBytes(sInput).CopyTo(sBuf, 0);

                // Set Freq to PWM Device

                DeviceIoControl(hPort, PWM_SET_FEQ, sBuf, 4, null, 0, 0, IntPtr.Zero);

            }

        }

 

        public Form1()

        {

           InitializeComponent();

       

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            if (pwm_ena)

            {            

                button1.Text = "Stop";

                pwm_ena = false;

                tpwmoff =Convert .ToInt32  (offtime.Value);

                tpwmon =Convert .ToInt32 ( ontime.Value);

                timer1.Interval = tpwmon;

                timer1.Enabled = true;

                 FreqSet(Convert.ToUInt32(pwm_freq.Value ));

                pwm_level = true;

            }

            else

            {

                button1.Text = "Start";

                FreqSet (Convert .ToUInt32 (0));

                timer1 .Enabled =false ;

                pwm_ena =true ;

            }

        }

 

        private void Form1_Closed(object sender, EventArgs e)

        {

            if (hPort != (IntPtr)INVALID_HANDLE_VALUE)

                // Close PWM Device

                CloseHandle(hPort);

        }

 

        private void Form1_Load(object sender, EventArgs e)

        {

            // Open PWM Device

            hPort = CreateFile("PWM1:", GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

            if (hPort == (IntPtr)INVALID_HANDLE_VALUE)

            {

                MessageBox.Show("Open PWM1 Driver Fail");

            }

        }

        private void timer1_Tick(object sender, EventArgs e)

        {

            timer1.Enabled = false;

            if (pwm_level)

            {

                pwm_level = false;

                 FreqSet(Convert.ToUInt32(0 ));

                 timer1.Interval = tpwmoff  ;

                 timer1.Enabled = true;

            }

            else

            {

                pwm_level = true;

                FreqSet(Convert.ToUInt32(pwm_freq.Value ));

                timer1.Interval = tpwmon  ;

                timer1.Enabled = true;

            }

        }

    }

}


原创粉丝点击