国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

WinCE下用C++實現掌上電腦遙控TV

2019-11-17 05:30:27
字體:
來源:轉載
供稿:網友
    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_TXABORTPURGE_RXABORT
  PURGE_TXCLEARPURGE_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));
  //每次按鍵設置代碼6次
  for(int x=0;x<6;x++) {
   MakeStream(lValue); //發送代碼
   dwCount=GetTickCount();
   while(GetTickCount()<dwCount+26) //延遲26ms
    i++;
  }
  return true;
}

  注重這個函數調用另外一個函數MakeStream(long)6次,每兩次調用之間停頓26毫秒。我發現該代碼必須發送好幾次才能使接收設備響應,大概是為防止假行為的緣故吧。26毫秒對于接收設備登記該代碼是必需的,在下一個代碼出現之前。

  這個函數MakeStream(long)把字節流寫入IrPort,并根據是否有起始位(1或者0)來確保發送正確的數據包長度。包含數據字節(0xdb)的緩沖區是以一個ByteArray形式存在的。

  函數Close()用于在端口使用后,自然地關閉IrPort。

  這個函數在我的ornada上運行良好。請看下面的討論以進一步確定你要做的可能性改變。

BOOL CIrPulse::MakeStream(DWORD lValue) {
  DWORD dwStreamLength;
  //創建開始脈沖
  dwStreamLength=iHPulse/charWidth;
  ASSERT(Write((const char *)bPulseStream.GetData(),
  dwStreamLength)==dwStreamLength);
  // ************************************
  // ***** 在下一個脈沖到來前延遲一段時間
  // ************************************
  //循環操作代碼中的位來發送脈沖
  for(int i=0;i<iDataLength;i++) {
   if(lValue & 1) {
    //創建一個脈沖1
    dwStreamLength=i1Pulse/charWidth;
    ASSERT(Write((const char *)bPulseStream.GetData(),
    dwStreamLength)==dwStreamLength);
    // *********************************
    // ***在下一個脈沖到來前延遲一段時間
    // *********************************
   }
   else {
    //創建一個脈沖 0
    dwStreamLength=i0Pulse/charWidth;
    ASSERT(Write((const char *)bPulseStream.GetData(),
    dwStreamLength)==dwStreamLength);
    // ********************************
    // **在下一個脈沖到來前延遲一段時間
    // ********************************
   }
   lValue >>= 1;
  }
  return TRUE;
}

  我在所附源代碼中包含了一個簡單的應用程序,它使用CIrPulse來創建一臺索尼TV的遠距離遙控。它具有基本的頻道選擇、音量調整和開/關機的功能。

  4. 非凡注重

  因為該CIrPort類使用一個串行端口連接到該IR端口,所以必須生成一個40KHz的載波信號,這通過從該串行端口發送恰當的字符來實現。幸好,假如我們發送字符0xdb,以115200波特,用8個數據位,2個停止位和奇偶校驗,這樣就能產生一種極接近38.4KHz的載波信號。我們所有的索尼設備接收這種數據是沒有問題的。

  最大的問題是,如何實現間隔每次脈沖的沉默周期。不可能由串行端口來產生該沉默周期,因為就算你發送一個0x0字符,由于存在起始和停止位,你仍然在該IR上得到脈沖。我通過發送不同的字符進行試驗,依據的前提是假如你不以40KHz的頻率發送一個載波信號,這有可能使設備誤把這個當作一個沉默。這樣做的優點是你可以產生一個包含完整的代碼的byteArray,以確保準確計時。但是結果并不一致,所以我拒絕使用這個方法,為的是實現在兩次從串行端口發出成組的0xdb字符之間支持暫停。因為需要的延遲是以550μs的順序;到目前為止,我還沒有找到取得獨立于處理器速度的暫停的方法。在我的Jornada上,是完全不必產生一個延遲的,因為每次調用Write函數看上去都使用了合適的時限。不管怎樣,我擔心的是,你可能胡亂產生一個可以使你的掌上電腦能工作的一個延遲。 WinCE下用C++實現掌上電腦遙控TV[編輯:gigi_miao] [返回首頁]



上一篇:在DBGrid中可選中行而又可進入編輯狀態

下一篇:c++中關于堆內存(heap)的概念和操作方法的教程

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

主站蜘蛛池模板: 江安县| 治多县| 广宁县| 洪江市| 阿拉善右旗| 乌苏市| 武鸣县| 广昌县| 慈溪市| 灯塔市| 广宗县| 乐东| 甘孜县| 安溪县| 科尔| 宝山区| 马龙县| 五峰| 东山县| 五原县| 寿光市| 道孚县| 宜昌市| 辉县市| 梁山县| 遵义县| 南澳县| 余干县| 巴彦淖尔市| 英德市| 博兴县| 辽阳县| 溆浦县| 磐石市| 镇巴县| 靖宇县| 平湖市| 临西县| 大姚县| 阿勒泰市| 淄博市|