WINCE6.0 简单LED驱动程序的编写

本文档详细介绍了在WINCE6.0环境下编写简单LED驱动程序的过程,包括驱动的目的、所需设备、原理、步骤和实验结果。通过理解流驱动结构,利用BSP提供的映射函数和GPIO寄存器操作,实现了LED的点亮和熄灭功能。实验涉及的函数包括地址映射、LED上下文结构体、GPIO寄存器操作等,还展示了如何导出驱动接口并配置平台文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

把它写成了实验报告的样子! 在此BLOG中的有些函数是针对特定的BSP, 比如:地址的映射函数, 在每一个BSP中它的地址映射函数都不同, 但是都是地址映射(废话当然是地址映射了)。其实里面有很多的东西都还可以添加:比如添加读取LED信息状态, 优化地址映射(不必把全部的GPIO都映射, 可以自定义一个小的结构体来实现)。

 

一. 实验目的

a)         掌握流驱动的结构

b)        掌握一般流驱动的编写方法

 

二. 实验设备

a)         S3C6410 开发板一台

b)        PC 机一台, VS2005, CE6.0 环境

 

三. 实验内容

a)         进行简单 LED 驱动的编写。

 

四. 实验原理

a)         硬件原理图

                                                    i.             

                      ii.             

                    iii.              从原理图可以知道如果我们要点亮 LEDx 只需要 GPMx 输出高电平, 如果要熄灭 LEDx 只需要 GPMx 输出低电平即可。

 

b)        软件原理设计

                        i.              由于在 WINCE 中使用都是虚拟的地址, 所以需要将实际的物理地址转换为虚拟地址来使用。 在系统提供的 BSP 中提供了一个函数来实现从物理地址到虚拟地址的映射。

1.         void *DrvLib_MapIoSpace (UINT32 PhysicalAddress , UINT32 NumberOfBytes , BOOL CacheEnable )

2.         把物理地址转换为虚拟地址。(其实它就是在地址映射表中查找相应的物理地址,然后返回对应的虚拟地址加上它的偏移。)

3.         UINT32 PhysicalAddress :要实现映射的物理地址的起始地址。

4.         UINT32 NumberOfBytes : 要映射物理地址的长度。

5.         BOOL CacheEnable :该物理地址是否使用了CACHE.( 具体参照地址映射表) 。

                      ii.              LED 上下文结构体的定义

1.         定义了一个 LED 驱动的上下文, 用来保存 LED 驱动的信息。 但是只是简单的 LED 驱动, 没有包含多的数据。

typedef struct

{

                volatile S3C6410_GPIO_REG    *pGPIOReg ;

}LED_PUBLIC_CONTEXT , *PLED_PUBLIC_CONTEXT ;

2 S3C6410_GPIO_REG 是BSP 预先定义的一个GPIO 使用的数据结构。

                    iii.              GPIO 寄存器的使用。 GPIO 寄存器的地址都映射到了虚拟的地址上。 BSP 提供了一个结构体方便 GPIO 寄存器的使用。

1.         typedef struct

{     ……………..

                                            UINT32 GPMCON;            // 820

                                            UINT32 GPMDAT;            // 824

UINT32 GPMPUD;            // 828

………………..

} S3C6410_GPIO_REG, *PS3C6410_GPIO_REG;

2.         在使用这个结构全的时候把 GPIO 的虚拟地址的基地址映射到此结构的开始即可以操作此结构体的数据来操作实际的寄存器。

3.         进行GPIO 物理地址到虚拟地址的映射:        pLedContext ->pGPIOReg = (volatile S3C6410_GPIO_REG *)DrvLib_MapIoSpace (S3C6410_BASE_REG_PA_GPIO , sizeof (S3C6410_GPIO_REG ), FALSE )

                     iv.              实现 LED 灯状态的操作。

1.         获得了 GPIO 的虚拟地址就可以像实际的物理地址那样实现寄存器的操作。

2.          

a)         // 使能上拉

b)        pLedContext ->pGPIOReg ->GPMPUD |= 0x0ff;

c)         // 设置为输出

d)        pLedContext ->pGPIOReg ->GPMCON = 0x111111;

e)         // 关闭所有的LED

f)         LED_ALL_OFF (pLedContext ->pGPIOReg ->GPMDAT );

3.         为了方便进行操作,定义了一组宏。

// 打开或关闭LED0

#define LED0_ON (x )   (x |= 0x00000001)

#define LED0_OFF (x )  (x &= 0xfffffffe)

// 打开或关闭LED1

#define LED1_ON (x )   (x |= 0x00000002)

#define LED1_OFF (x )  (x &= 0xfffffffd)

// 打开或关闭LED2

#define LED2_ON (x )   (x |= 0x00000004)

#define LED2_OFF (x )  (x &= 0xfffffffb)

// 打开或关闭LED3

#define LED3_ON (x )   (x |= 0x00000008)

#define LED3_OFF (x )  (x &= 0xfffffff7)

// 打开或关闭所有的LED

#define LED_ALL_ON (x )    (x |= 0x0000000f)

#define LED_ALL_OFF (x )   (x &= 0xfffffff0)

五. 实验步骤

a)         Xxx_Init 函数的原型:

                        i.              DWORD XXX_Init( LPCTSTR pContext , DWORD dwBusContext );

                      ii.              pContext: Pointer to a string containing the registry path to the active key for the stream interface driver.

                    iii.              lpvBusContext: Potentially process-mapped pointer passed as the fourth parameter to ActivateDeviceEx . If this driver was loaded through legacy mechanisms, then dwBusContext is zero. This pointer, if used, has only been mapped again as it passes through the protected server library (PSL). The XXX _Init function is responsible for performing all protection checking

                     iv.              返回值 Returns a handle to the device context created if successful. Returns zero if not successful. This handle is passed to the XXX_Open (Device Manager) , XXX_PowerDown (Device Manager) , XXX_PowerUp (Device Manager) , and XXX_Deinit (Device Manager) functions

                       v.              注意:当调用 设备管理程序当调用 ActivateDeviceEx 函数的时候会间接调用到此函数, ActivateDeviceEx 的作用就是加载设备

                     vi.              LED_Init 函数的编写。 LED_Init 最主要的功能就是进行硬件的初使化。

                   vii.              LED_Init 函数的实现:

DWORD Led_Init (LPCTSTR pContext )

{

    volatile PLED_PUBLIC_CONTEXT     pLedContext ;

 

    RETAILMSG (DEBUG_LED ,(TEXT ("Led_Init Function!/n" )));

 

    // 申请LED 的CONTEXT

    pLedContext = (PLED_PUBLIC_CONTEXT )LocalAlloc (LPTR , sizeof (pContext ));

    if (!pLedContext )

    {

       RETAILMSG (DEBUG_LED , (TEXT ("Can't alloc memory for led context!/n" )));

       return NULL ;

    }

 

    // 得到GPIO 寄存器的地址

    pLedContext ->pGPIOReg = (volatile S3C6410_GPIO_REG *)DrvLib_MapIoSpace (S3C6410_BASE_REG_PA_GPIO , sizeof (S3C6410_GPIO_REG ), FALSE );

    if (pLedContext ->pGPIOReg == NULL )

    {

       RETAILMSG (DEBUG_LED , (TEXT ("LED for pGPIORges: DrvLib_MapIoSpace failed!/n" )));

       LocalFree (pLedContext );

       return NULL ;

    }

 

    // 使能上拉

    pLedContext ->pGPIOReg ->GPMPUD |= 0x0ff;

    // 设置为输出

    pLedContext ->pGPIOReg ->GPMCON = 0x111111;

    // 关闭所有的LED

    LED_ALL_OFF (pLedContext ->pGPIOReg ->GPMDAT );

    RETAILMSG (DEBUG_LED , (TEXT ("Led0 on! %d!/n" ), (pLedContext ->pGPIOReg ->GPMDAT )));

 

    return pLedContext ;

`   }

a)         Xxx_Write 函数原型:

DWORD XXX_Write(DWORD 
hOpenContext
, LPCVOID 
pBuffer
, DWORD 
Count 
);


                        i.              hOpenContext Handle to the open context of the device. The call to the XXX_Open (Device Manager) function returns this identifier

                      ii.              pBuffer Pointer to the buffer that contains the data to write.

                    iii.              Count: Number of bytes to write from the pBuffer buffer into the device.

                     iv.              返回值: The number of bytes written indicates success. A value of –1 indicates failure.

                       v.              LED_Write 函数的作用只是进行对 LED 状态的写入。

自定义结构体:

typedef struct

{

    unsigned char cLedNum ;

    unsigned char fLedStatue ;

}LED_DATA , *PLED_DATA ;

cLedNum :LED 的标号。0 对应第一个LED, 1 对应第2 个LED 4 表示全部熄灭(因为它只有4 个LED )

fLegStatue :将要实现的操作。 0 熄灭, 1 点亮。

                     vi.              LED_Write 函数的实现。

DWORD Led_Write (DWORD hOpenContext ,

              DWORD pBuffer ,

              DWORD Count )

{

    PLED_DATA pLedData = (PLED_DATA )pBuffer ;

    RETAILMSG (DEBUG_LED , (TEXT ("Current hOpenContext %d  /n" )), hOpenContext );

    RETAILMSG (DEBUG_LED , (TEXT ("Corrent GPMDATA %d!/n" ), (((PLED_PUBLIC_CONTEXT )hOpenContext )->pGPIOReg ->GPMDAT )));

 

    switch (pLedData ->cLedNum )

    {

    case 0:

       if (pLedData ->fLedStatue )

       {

           LED0_ON (((PLED_PUBLIC_CONTEXT )hOpenContext )->pGPIOReg ->GPMDAT );

           RETAILMSG (DEBUG_LED , (TEXT ("Led0 on! %d/n!" ), ((PLED_PUBLIC_CONTEXT )hOpenContext )->pGPIOReg ->GPMDAT ));

       }

       else

       {

           LED0_OFF (((PLED_PUBLIC_CONTEXT )hOpenContext )->pGPIOReg ->GPMDAT );

           RETAILMSG (DEBUG_LED , (TEXT ("Led0 off!/n!" )));

       }

       break ;

    case 1:

       。。。。。。

       break ;

    case 2:

       。。。。。。

       break ;

    case 3:

       。。。。。。

    case 4:

       if (pLedData ->fLedStatue )

       {                                LED_ALL_ON (((PLED_PUBLIC_CONTEXT )hOpenContext )->pGPIOReg ->GPMDAT );

       }

       else

       {          LED_ALL_OFF (((PLED_PUBLIC_CONTEXT )hOpenContext )->pGPIOReg ->GPMDAT );

       }

    default :

       break ;

    }

 

    return (Count );

}

 

b)        其它流接口函数的编写:其它的流接口函数并没有实现函数过程, 它们一般就直接返回。在Led_Deinit 函数中进行了申请内存的释放, 也调用了一个放弃映射的函数DrvLib_UnmapIoSpace , 其实这个函数在6.0 之中没有作用, 它是直接返回结果的函数。

c)         LED 的配置:

设备管理器要使用LED 流驱动的接口, 就必须将LED 提供的接口函数导出。在Led.def 文件中添加如下代码:

LIBRARY     LED

 

EXPORTS Led_Init

    Led_Deinit

    Led_Open

    Led_Close

    Led_Read

    Led_Write

  Led_Seek

    Led_PowerDown

    Led_PowerUp

Led_IOControl

 

导出了LED 的接口函数,要把Led.dll 添加到镜像文件中去还要修改platform.bib 文件。

MODULES 节中添加代码如图:

 

最后修改注册表 platform.reg

HKEY_LOCAL_MACHINE/Drives/BuildIn 下添加注册表项 LED( 任意名字都可 )

注册表项中的内容:

六. 实验结果及分析

a)         按照上述步骤进行 LED 流驱动的编写, 再编写一个简单的应用程序即可进行 LED 灯的控制。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值