设为首页 加入收藏

TOP

WinCE下用C++实现掌上电脑遥控TV(一)
2014-11-23 19:56:29 】 浏览:499
Tags:WinCE 下用 实现 掌上电脑 遥控
1. 简介

  你是否曾想过通过你的掌上电脑上的IR端口控制你的TV、Hi-Fi或者其它视频 本文将介绍怎样使用掌上电脑中的IR端口来 编程控制一台TV。

  2. 背景

  我近些日子丢失了我的老式索尼TV的遥控器。这本身没有什么问题,因为我买了个新的遥控器作为代替。然而,当电视失去了它的设定的颜色时,我遇到了问题,因为它只能显示黑白色了,而新的遥控器没有颜色调整按钮。我决定在我的老式的Jornada 525掌上电脑上写一个程序使用IR端口把正确的代码发送给TV。

  共有三个主要协议可以用于发送IR代码到设备上。索尼TV使用 ’Pulse Coded’ 方法,它需要发送一个包含头(header)位的以空格隔开的’1’位和’0’位的数据流。这些位被调制成一种40KHz的载波信号。其中,头长度为2200 μs,’1’位为110 μs,’0’位为550 μs,而空格是550μs的沉默(silence)。大多数索尼设备使用12位数据,它被分离成6位的地址(设备类型)和6位命令。因此数据看起来象这个样子:hxxxxxxyyyyyy,其中h是头位,xxxxxx是6位的命令(msb first),yyyyyy是6位的地址。对此我不再细述,因为网上有很多资源描述这种协议,并列举了针对不同设备的代码。一些新的索尼设备使用19位代码,我相信另外的制造商也使用和我描述的相同的格式。还有可能为使用’Space Coded’或’Shift Coded’协议的设备写出相似的类。

  我曾使用嵌入式C++写过一个类CirPulse,它封装了从一台运行Windows CE 3.0的Jornada 525 PC上控制索尼及其相匹配设备的功能。估计它能够与其它相匹配设备和操作 系统一起工作,但是你需要试验才行!

  3. 实现过程分析

  这个CIrPulse类暴露了几个函数,它们使得发送IR代码尽可能容易。在声明CIrPulse类时,你应该调用一次FindIrPort(),它返回一个描述IrDA端口的端口号的UINT,这通过搜索注册表得到。这个端口号用于后面的调用来打开IrDA端口进行串行通讯。

UINT CIrPulse::FindIrPort()
{
  // 查询注册表中的IR端口号
  HKEY hKey = NULL;
  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("Comm\IrDA"),0, 0, &hKey) == ERROR_SUCCESS)
  {
   DWORD dwType = 0;
   DWORD dwData = 0;
   DWORD dwSize = sizeof(dwData);
   if (RegQueryValueEx(hKey, _T("Port"), NULL, &dwType, (LPBYTE) &dwData, &dwSize) == ERROR_SUCCESS)
   {
    if (dwType == REG_DWORD && dwSize == sizeof(dwData))
    {
     RegCloseKey(hKey);
     return (UINT) dwData;
    }
   }
   RegCloseKey(hKey);
  }
  return 0;
}

  得到端口号后,你可以调用Open(UINT)函数,把通过调用FindIrPort()得到的端口号传递过去。这打开该端口并设置串口参数,如果成功返回true。该端口被设置为115200波特,8个数据位,2个停止位和奇偶校验位。关于如何产生载波以及为什么我使用这些设置将在本文后面介绍。

BOOL CIrPulse::Open(UINT uiPort)
{
  ASSERT(uiPort > 0 && uiPort <= 255);
  Close();
  //打开IRDA端口
  CString strPort;
  strPort.Format(_T("COM%d:"), uiPort);
  m_irPort = CreateFile((LPCTSTR) strPort, GENERIC_READ | GENERIC_WRITE,0, NULL, OPEN_EXISTING, 0, NULL);
  if (m_irPort == INVALID_HANDLE_VALUE)
  {
   return FALSE;
  }
  //设置输入和输出缓冲区的大小
  VERIFY(SetupComm(m_irPort, 2048, 2048));
  //清除读和写缓冲区
  VERIFY(PurgeComm(m_irPort,PURGE_TXABORT|PURGE_RXABORT|
  PURGE_TXCLEAR|PURGE_RXCLEAR));
  //重新初始化所有的IRDA端口设置
  DCB dcb;
  dcb.DCBlength = sizeof(DCB);
  VERIFY(GetCommState(m_irPort, &dcb));
  dcb.BaudRate = CBR_115200;
  dcb.fBinary = TRUE;
  dcb.fParity = TRUE;
  dcb.fOutxCtsFlow = FALSE;
  dcb.fOutxDsrFlow = FALSE;
  dcb.fDtrControl = DTR_CONTROL_DISABLE;
  dcb.fDsrSensitivity = FALSE;
  dcb.fTXContinueOnXoff = FALSE;
  dcb.fOutX = FALSE;
  dcb.fInX = FALSE;
  dcb.fErrorChar = FALSE;
  dcb.fNull = FALSE;
  dcb.fRtsControl = RTS_CONTROL_DISABLE;
  dcb.fAbortOnError = FALSE;
  dcb.ByteSize = 8;
  dcb.Parity = EVENPARITY;
  dcb.StopBits = TWOSTOPBITS;
  VERIFY(SetCommState(m_irPort, &dcb));
  //为所有的读和写操作设置超时值
  COMMTIMEOUTS timeouts;
  VERIFY(GetCommTimeouts(m_irPort, &timeouts));
  timeouts.ReadIntervalTimeout = MAXDWORD;
  timeouts.ReadTotalTimeoutMultiplier = 0;
  timeouts.ReadTotalTimeoutConstant = 0;
  timeouts.WriteTotalTimeoutMultiplier = 0;
  timeouts.WriteTotalTimeoutConstant = 0;
  VERIFY(SetCommTimeouts(m_irPort, &timeouts));
  DWORD dwEvent=EV_TXEMPTY;
  SetCommMask(m_irPort,dwEvent);
  return TRUE;
}

  调用函数SetCodeSize(DWORD)来设置要传送的位数(如12位)。这可以在任何时候完成且只需要做一次。它一直保持有效,直到后面的调用改变它为止。

  最后调用SendCode(long),传递实际要发送的代码。

BOOL CIrPulse::SendCode(DWORD lValue)
{
  DWORD dwCount;
  int i=0;
  ASSERT(iDataLength>0);
  //清除传送缓冲区
  VERIFY(PurgeComm(m_irPort,PURGE_TXABORT| PURGE_RXABORT |PURGE_TXCLEAR | PURGE_RXCLEAR));
  //每次按键设置
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇VC++动态链接库编程之MFC扩展 DLL 下一篇Visual C++中DDB与DIB位图编程全..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目