wince 控制 数码管 显示系统时间 控制流水灯

来源:互联网 发布:淘宝更改所在地 编辑:程序博客网 时间:2024/05/01 06:06

先看几个函数

 

Windows CE提供了VirtualAlloc()VirtualCopy()函数,VirtualAlloc负责在虚拟内存空间内保留一段虚拟内存,而VirtualCopy负责把一段物理内存和虚拟内存绑定,这样,最终对物理内存的访问还是通过虚拟地址进行。
 
VirtualCopy()负责将硬件设备寄存器的物理地址与VirtualAlloc()分配的虚拟地址做一个映射关系,这样驱动程序访问虚拟地址即是访问对应的物理地址处的第一个寄存器);

BOOL VirtualCopy(

  LPVOID lpvDest,   // 虚拟内存的目标地址

  LPVOID lpvSrc,   // 物理内存地址

  DWORD cbSize,   // 要绑定的大小

  DWORD fdwProtect   // 访问权限

);
 

VirtualAlloc()函数用于分配一块内存空间。如果要映射一硬件寄存器,必然要将其映射到一块确定的内存空间。

LPVOID VirtualAlloc(

 LPVOID lpAddress,    // 希望的虚拟内存起始地址

 DWORD dwSize,       // 以字节为单位的大小

 DWORD flAllocationType, // 申请类型,ReserveCommit

 DWORD flProtect  // 访问权限

);

例: VirtualAlloc(0,0x1000,MEM_RESERVE,PAGE_READWRITE)

 

VirtualCopy((PVOID)pLightReg,(PVOID)(pLightIoBaseAddress>>8),0x1000,PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL)

    这里的pLightReg即前面分配的虚拟地址空间,而pLightIoBaseAddress为实际的硬件地址,需要将它右移8位,因为在函数中存储器分配是以256位为单位的。而后面的选项则指定了映射地址的属性——可读写、不缓冲以及硬件物理地址。

 

由于Visual Studio 2005里没有提供没有VirtualCopy()的头文件和库文件(这些是由Platform Builder提供的),因此需要将它们作为外部函数调用导入。如下:

extern "C" __declspec(dllimport) BOOL VirtualCopy(LPVOID lpvDest, LPVOID lpvSrc, DWORD cbSize, DWORD fdwProtect );

 

释放虚拟空间

   BOOL VirtualFree(

 LPVOID lpAddress,  // 虚拟内存的地址

 DWORD dwSize,  // 释放的地址空间区域的大小

 DWORD dwFreeType  // 释放内存类型

);

如果参数dwFreeType指定了MEM_RELEASE标志,则将dwSize设置为0,由系统计算在特定内存地址上的待释放区域的大小。

VirtualFree((PVOID) pLightReg,0,MEM_RELEASE);

 

释放虚拟空间

   BOOL VirtualFree(

 LPVOID lpAddress,  // 虚拟内存的地址

 DWORD dwSize,  // 释放的地址空间区域的大小

 DWORD dwFreeType  // 释放内存类型

);

如果参数dwFreeType指定了MEM_RELEASE标志,则将dwSize设置为0,由系统计算在特定内存地址上的待释放区域的大小。

VirtualFree((PVOID) pLightReg,0,MEM_RELEASE);

 

 

    我们通过VirtualAlloc得到所分配的空间的首地址,通过VirtualCopy函数使得物理内存和虚拟内存进行绑定,这时我们通过返回的地址空间的首地址,就可以对物理地址进行读写,即控制小灯的状态。

     假设pLightReg为虚拟空间首地址,当我们作如下操作时

     *pLightReg = 0X7e;

     小灯的状态相应发生变化。* pLightReg的每一位控制一个小灯的状态,* pLightReg从低位到高位依次控制H1~H8,并且低电平有效。

     此时* pLightReg = 0111 1110B,所以只有H1H8被点亮。

 

  

 

1控制数码管显示系统时间

 

 

在本实验箱中七段数码管是共阳极的,所以每一段是由低电平触发。数码管的a~g段的状态对应着控制数据低位到高位的电平,且数据位的最高位为七段数码管的选通位,当其为0时,七段数码管才工作。

 

   dp   g   f   e  d  b  c  b  a

        0     0   0  0  0  0  0  1  0 

*v_pLEDBaseAddr1 = 0X02 时,

七段数码管如右图显示

 

和小灯不同的是,八个小灯的状态由一个字节的数据控制,

而八个字节的数据只能控制一个7段数码管。

     LED_CS2 = 0x10300000LED_CS3 = 0x10400000分别控制两个7段数码管,所以控制数码管时,注意自定义变量的类型和个数。

说的够多了:看代码:

 

#include <Windows.h>

WORD *pLightReg1 = NULL;//于物理内存相对应的虚拟内存地址的指针
WORD *pLightReg2 = NULL;
#define pLightIoBaseAddress1 0x10300000
#define pLightIoBaseAddress2 0x10400000
#define m_ShiftTime 1000

const int led[10] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//大家可以自己算一下 各个数字对应的数码管的代码值

extern "C" __declspec(dllimport) BOOL VirtualCopy(LPVOID lpvDest, LPVOID lpvSrc, DWORD cbSize, DWORD fdwProtect );

BOOL alloc();
DWORD WINAPI sevenlight(LPVOID lpParameter);//对下面用到的函数进行先声明

int _tmain(int argc, _TCHAR* argv[])//主函数
{
 HANDLE h;
 if(alloc())
 {
 h= (HANDLE)::CreateThread(NULL,0,LPTHREAD_START_ROUTINE(sevenlight),NULL,0,NULL);//创建一个以sevenlight为入口函数的主函数
 ::WaitForSingleObject(h,INFINITE);//等待线程结束 这行代码很关键 第一次就是因为没有写这个代码怎么也出不来,如果不等待线程结束二十直接CLOSEHANDLE大家可以想一下后果 那必须是直接结束没商量啊
 ::CloseHandle(h);
 }

 

 
 return 0;
}

BOOL alloc()
{

 pLightReg1=(WORD*)VirtualAlloc(0,0x100,MEM_RESERVE,PAGE_READWRITE);//在本机上开辟一块内存
 pLightReg2=(WORD*)VirtualAlloc(0,0x100,MEM_RESERVE,PAGE_READWRITE);

 if(!pLightReg1 || !pLightReg2)
  return FALSE;

 if(!VirtualCopy((PVOID)pLightReg1,(PVOID)(pLightIoBaseAddress1>>8),0x100,PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL))//把对应的物理地址和当前本机上分配的地址进行绑定 这样对本机分配地址的指针进行操作就可以控制 物理机上的设备
 {
  VirtualFree((PVOID)pLightReg1,0,MEM_RELEASE);
  pLightReg1 = NULL;
  return FALSE;
 }
 if(!VirtualCopy((PVOID)pLightReg2,(PVOID)(pLightIoBaseAddress2>>8),0x100,PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL))
 {
  VirtualFree((PVOID)pLightReg2,0,MEM_RELEASE);
  pLightReg2 = NULL;
  return FALSE;
 }
 return TRUE;
}
DWORD WINAPI sevenlight(LPVOID lpParameter)
{
 WORD tmp1;
    WORD tmp2;
 while(1){
 SYSTEMTIME time;
 ::GetLocalTime(&time);
 int a,b;
 a = time.wSecond%10;
 b = (time.wSecond-a)/10;
 
 tmp1=led[b];

 tmp2=led[a];

 *pLightReg2=(tmp2<<8)+tmp1;//这一步很关键 大家想想为什么 WOED是16位的 它控制的是两个八位的数码管 所以要是控制这个数码管显示出两个十进制数 可以这样做 先声明两个16进制数 都赋给两个八位的数 然后让一个往右移八位加上另一个 补上空位 这样不就实现了么
 a = time.wMinute%10;
 b = (time.wMinute-a)/10;

 tmp1=led[b];

 tmp2=led[a];

 *pLightReg1=(tmp2<<8)+tmp1;
 Sleep(1000);
 }

 


 return 0;

}

控制流水灯

// demo1.cpp : 定义控制台应用程序的入口点。
//
#include <Windows.h>

#include "stdafx.h"


char *pLightReg = NULL;
#define pLightIoBaseAddress 0x10500000
#define m_ShiftTime 500
CRITICAL_SECTION g_cs;

extern "C" __declspec(dllimport) BOOL VirtualCopy(LPVOID lpvDest, LPVOID lpvSrc, DWORD cbSize, DWORD fdwProtect );

BOOL alloc();
DWORD WINAPI LeftShift(LPVOID lpParameter);
DWORD WINAPI RightShift(LPVOID lpParameter);
DWORD WINAPI MidShift(LPVOID lpParameter);
DWORD WINAPI LoopShift(LPVOID lpParameter);

int _tmain(int argc, _TCHAR* argv[])
{
 HANDLE h[2];
 if(alloc())
 {
  ::InitializeCriticalSection(&g_cs);

  h[0] = (HANDLE)::CreateThread(NULL,0,LPTHREAD_START_ROUTINE(LeftShift),NULL,0,NULL);

  h[1] = (HANDLE)::CreateThread(NULL,0,LPTHREAD_START_ROUTINE(RightShift),NULL,0,NULL);
  ::WaitForSingleObject( h[0], INFINITE );
  ::WaitForSingleObject( h[1], INFINITE );
  ::CloseHandle(h[0]);
  ::CloseHandle(h[1]);

  ::DeleteCriticalSection(&g_cs);


 }


 

 return 0;
}


BOOL alloc()
{

 pLightReg=(char*)VirtualAlloc(0,0x100,MEM_RESERVE,PAGE_READWRITE);
 if(!pLightReg)
  return FALSE;

 if(!VirtualCopy((PVOID)pLightReg,(PVOID)(pLightIoBaseAddress>>8),0x100,PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL))
 {
  VirtualFree((PVOID)pLightReg,0,MEM_RELEASE);
  pLightReg = NULL;
  return FALSE;
 }
 return TRUE;
}

DWORD WINAPI LeftShift(LPVOID lpParameter)
{
 unsigned char tmp;
 tmp=0x01;

 while(1)
 {
  
  for(int i=0;i<8;i++)
  {
   ::EnterCriticalSection(&g_cs);
   *pLightReg=~tmp;
   Sleep(m_ShiftTime);
   tmp=tmp<<1;
   ::LeaveCriticalSection(&g_cs);
  }
  
  tmp=0x01;
 }

 return 0;

}

DWORD WINAPI RightShift(LPVOID lpParameter)
{
 unsigned char tmp;
 tmp=0x80;
 while(1)
 {
  
  for(int i=0;i<8;i++)
  {
   ::EnterCriticalSection(&g_cs);
   *pLightReg=~tmp;
   Sleep(m_ShiftTime);
   tmp=tmp>>1;
   ::LeaveCriticalSection(&g_cs);
  }
  
  tmp=0x80;
 }

 return 0;
}
DWORD WINAPI MidShift(LPVOID lpParameter)
{
 unsigned char tmp1;
 unsigned char tmp2;
 tmp1 = 0x01;
 tmp2 = 0x80;
 unsigned char tmp=tmp1|tmp2;
 while(1)
 {
  for(int i=0;i<8;i++)
  {

   *pLightReg=~tmp;
   Sleep(m_ShiftTime);
   tmp1=tmp1<<1;
   tmp2=tmp2>>1;
   tmp=tmp1|tmp2;
  }
  tmp1 = 0x01;
  tmp2 = 0x80;
  tmp=tmp1|tmp2;
 }
 return 0;
}


DWORD WINAPI LoopShift(LPVOID lpParameter)
{
 unsigned char tmp1;
 unsigned char tmp2;
 tmp1 = 0x01;
 tmp2 = 0x80;
 while(1)
 {
  for(int i=0;i<8;i++)
  {
   *pLightReg=~tmp1;
   Sleep(m_ShiftTime);
   tmp1=tmp1<<1;
  }
  for(int i=0;i<8;i++)
  {
   *pLightReg=~tmp2;
   Sleep(m_ShiftTime);
   tmp2=tmp2>>1;
  }
  tmp1 = 0x01;
  tmp2 = 0x80;
 }

 return 0;

}

原创粉丝点击