技术开发 频道

C++实现用掌上电脑遥控电视


【IT168技术文档】

  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; }
0
相关文章