• «
  • 1
  • 2
  • »
  • Pages: 1/2     Go
主题 : C#开发基于wince SDK的PWM控制软件 复制链接 | 浏览器收藏 | 打印
级别: 新手上路
UID: 3835
精华: 2
发帖: 13
金钱: 155 两
威望: 63 点
贡献值: 11 点
综合积分: 66 分
注册时间: 2009-02-11
最后登录: 2013-12-30
楼主  发表于: 2011-02-04 20:29

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

管理提醒: 本帖被 xoom 执行加亮操作(2011-06-28)
    C#开发基于wince SDK的PWM控制软件

     前些天本人苦于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的系统架构

  2、Windows 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 Function
        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 Function
        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;
            }
        }
    }
}
级别: 新手上路
UID: 31954
精华: 0
发帖: 13
金钱: 65 两
威望: 13 点
贡献值: 0 点
综合积分: 26 分
注册时间: 2010-11-08
最后登录: 2014-02-10
1楼  发表于: 2011-02-24 15:49
好贴必须要顶,LZ辛苦了
级别: 骑士
UID: 14419
精华: 1
发帖: 183
金钱: 995 两
威望: 199 点
贡献值: 1 点
综合积分: 386 分
注册时间: 2010-02-08
最后登录: 2014-04-13
2楼  发表于: 2011-02-26 00:33
谢谢LZ了,我收藏了,对了,不知LZ是否注意到,这样的编写方式仅仅能使用BSP中已提供的驱动,如果BSP中没有提供,要自己开发,这方法就难做了,我之前搞智能家居的时候曾经也尝试过在C#中控制ov9650摄像头,但发现处理采集的数据时候非常麻烦,所以改用C++来做了。
本人认为,一个比较好的方法就是能在C#里头调用C++的函数。
级别: 荣誉会员
UID: 34761
精华: 0
发帖: 1348
金钱: 6835 两
威望: 1367 点
贡献值: 0 点
综合积分: 2696 分
注册时间: 2010-12-21
最后登录: 2017-06-02
3楼  发表于: 2011-02-26 14:40
支持原创,顶。
级别: 新手上路
UID: 32669
精华: 0
发帖: 3
金钱: 15 两
威望: 3 点
贡献值: 0 点
综合积分: 6 分
注册时间: 2010-11-19
最后登录: 2011-05-28
4楼  发表于: 2011-02-26 20:57
顶。。。。
级别: 新手上路
UID: 38365
精华: 0
发帖: 1
金钱: 5 两
威望: 1 点
贡献值: 0 点
综合积分: 2 分
注册时间: 2011-02-24
最后登录: 2011-04-06
5楼  发表于: 2011-02-28 22:16
请问下,怎么测pwm的改变?
级别: 新手上路
UID: 41783
精华: 0
发帖: 5
金钱: 25 两
威望: 5 点
贡献值: 0 点
综合积分: 10 分
注册时间: 2011-04-01
最后登录: 2011-04-06
6楼  发表于: 2011-04-06 15:51
楼主,有没有CMOS摄像头的C#应用程序啊,我这两天搞得头昏脑胀的,资料只有C++,可是我不熟悉C++,崩溃ing。。。
级别: 骑士
UID: 14419
精华: 1
发帖: 183
金钱: 995 两
威望: 199 点
贡献值: 1 点
综合积分: 386 分
注册时间: 2010-02-08
最后登录: 2014-04-13
7楼  发表于: 2011-04-10 01:21

 回 6楼(逝水无痕) 的帖子

我之前在2440上玩过CMOS摄像头,我建议你还是别C#,因为C#在做驱动方面真的不合适。你如果想搞嵌入式,C++是必须熟悉的,否则,等着被炒鱿鱼吧。
级别: 新手上路
UID: 42968
精华: 0
发帖: 4
金钱: 20 两
威望: 4 点
贡献值: 0 点
综合积分: 8 分
注册时间: 2011-04-12
最后登录: 2013-08-06
8楼  发表于: 2011-04-12 19:35

 回 楼主(gaos) 的帖子 偷梁换柱到VS2008

using System;
using System.Runtime.InteropServices;

namespace SmartDeviceProject2
{
    class WinCeApis
    {
        // Constant of Function
        public const UInt32 OPEN_EXISTING = 3;
        public const UInt32 GENERIC_READ = 0x80000000;
        public const UInt32 GENERIC_WRITE = 0x40000000;
        public const Int32 INVALID_HANDLE_VALUE = -1;

        public const UInt32 PWM_STOP = 1;
        public const UInt32 PWM_SET_FEQ = 2;
        public 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);

        //函数:FreqSet 设置PWM频率
        public static void FreqSet(IntPtr hPort, 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);
            }
        }

    }
}

        private void button3_Click(object sender, EventArgs e)
        {
            IntPtr hPort;
            Byte[] sBuf =new Byte[100];

            hPort = WinCeApis.CreateFile("PWM1:", WinCeApis.GENERIC_READ | WinCeApis.GENERIC_WRITE, 0, IntPtr.Zero, WinCeApis.OPEN_EXISTING, 0, IntPtr.Zero);                  //打开设备
            WinCeApis.FreqSet(hPort, 3000);
            
            //WinCeApis.CloseHandle(hPort);                 //关闭PWM

        }
级别: 新手上路
UID: 42968
精华: 0
发帖: 4
金钱: 20 两
威望: 4 点
贡献值: 0 点
综合积分: 8 分
注册时间: 2011-04-12
最后登录: 2013-08-06
9楼  发表于: 2011-04-13 09:06

 回 8楼(tonycjl) 的帖子 LDE 来了

        public static void LedsSet(IntPtr hPort, UInt32 LightId, bool PutOnLed)
        {
            if (PutOnLed == false) LightId += 5;
            if (hPort != (IntPtr)INVALID_HANDLE_VALUE)
            {
                DeviceIoControl(hPort, LightId, null, 0, null, 0, 0, IntPtr.Zero);
            }
            
        }

        private void button3_Click(object sender, EventArgs e)
        {
            

            //hPort = WinCeApis.CreateFile("PWM1:", WinCeApis.GENERIC_READ | WinCeApis.GENERIC_WRITE, 0, IntPtr.Zero, WinCeApis.OPEN_EXISTING, 0, IntPtr.Zero);                  //打开设备
            //WinCeApis.FreqSet(hPort, 3000);
            hPort = WinCeApis.CreateFile("LED1:", WinCeApis.GENERIC_READ | WinCeApis.GENERIC_WRITE, 0, IntPtr.Zero, WinCeApis.OPEN_EXISTING, 0, IntPtr.Zero);                  //打开设备
            WinCeApis.LedsSet(hPort, 1, true);
            WinCeApis.LedsSet(hPort, 2, true);
            WinCeApis.LedsSet(hPort, 3, true);
            WinCeApis.LedsSet(hPort, 4, true);
            //WinCeApis.CloseHandle(hPort);                 //关闭PWM

        }

        private void button4_Click(object sender, EventArgs e)
        {
            WinCeApis.LedsSet(hPort, 5, false );
        }
  • «
  • 1
  • 2
  • »
  • Pages: 1/2     Go