wince下用c++实现掌上电脑遥控tv - 网易学院·教程.htm
来自「WinCE下串口编程应用实例」· HTM 代码 · 共 515 行 · 第 1/3 页
HTM
515 行
<LI><A href="http://tech.163.com/special/v/000915SN/videostu.html"
target=_self>视频中心</A> </LI>
<LI><A href="http://tech.163.com/special/A/00091593/Arts1.html"
target=_self>艺术设计</A></LI>
<LI><A href="http://tech.163.com/special/S/000915AH/S_InterView.html"
target=_self>教授视点</A> </LI>
<LI><A href="http://tech.163.com/special/s/000915AS/softnews.html"
target=_self>软件新闻</A> </LI>
<LI><A
href="http://tech.163.com/special/s/00091KUI/securitynews.html">病毒安全新闻</A>
</LI>
<LI><A href="http://tech.163.com/special/s/000917D5/schoolbbs.html">论坛</A>
</LI>
<LI><A href="http://tech.163.com/special/s/00091589/schoolroll.html">滚动更新</A>
</LI></UL></DIV>
<DIV id=MyPosition>你现在的位置是: <A href="http://www.163.com/">网易</A> > <A
href="http://tech.163.com/">网易科技</A> > <A
href="http://tech.163.com/school">网易学院·教程</A> </DIV>
<DIV id=TextTitle>
<H1>WinCE下用C++实现掌上电脑遥控TV</H1>http://tech.163.com/school · 2005-10-10 15:07:53 ·
来源: 天极网</DIV>
<DIV id=TextContent>
<P></P> <STRONG> 1.
简介</STRONG><BR><BR> 你是否曾想过通过你的掌上电脑上的IR端口控制你的TV、Hi-Fi或者其它视频?本文将介绍怎样使用掌上电脑中的IR端口来编程控制一台TV。<BR><BR><STRONG> 2.
背景</STRONG><BR><BR> 我近些日子丢失了我的老式索尼TV的遥控器。这本身没有什么问题,因为我买了个新的遥控器作为代替。然而,当电视失去了它的设定的颜色时,我遇到了问题,因为它只能显示黑白色了,而新的遥控器没有颜色调整按钮。我决定在我的老式的Jornada
525掌上电脑上写一个程序使用IR端口把正确的代码发送给TV。<BR><BR> 共有三个主要协议可以用于发送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’协议的设备写出相似的类。<BR><BR> 我曾使用嵌入式C++写过一个类CirPulse,它封装了从一台运行Windows CE
3.0的Jornada 525
PC上控制索尼及其相匹配设备的功能。估计它能够与其它相匹配设备和操作系统一起工作,但是你需要试验才行!<BR><BR><STRONG> 3.
实现过程分析</STRONG><BR><BR> 这个CIrPulse类暴露了几个函数,它们使得发送IR代码尽可能容易。在声明CIrPulse类时,你应该调用一次FindIrPort(),它返回一个描述IrDA端口的端口号的UINT,这通过搜索注册表得到。这个端口号用于后面的调用来打开IrDA端口进行串行通讯。<BR><BR><CODE>UINT
CIrPulse::FindIrPort()<BR>{<BR> // 查询注册表中的IR端口号<BR> HKEY hKey = NULL;<BR>
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("Comm\\IrDA"),0, 0, &hKey) ==
ERROR_SUCCESS)<BR> {<BR> DWORD dwType = 0;<BR> DWORD dwData = 0;<BR>
DWORD dwSize = sizeof(dwData);<BR> if (RegQueryValueEx(hKey, _T("Port"), NULL,
&dwType, (LPBYTE) &dwData, &dwSize) == ERROR_SUCCESS)<BR> {<BR>
if (dwType == REG_DWORD && dwSize == sizeof(dwData))<BR> {<BR>
RegCloseKey(hKey);<BR> return (UINT) dwData;<BR> }<BR> }<BR>
RegCloseKey(hKey);<BR> }<BR> return
0;<BR>}</CODE><BR> 得到端口号后,你可以调用Open(UINT)函数,把通过调用FindIrPort()得到的端口号传递过去。这打开该端口并设置串口参数,如果成功返回true。该端口被设置为115200波特,8个数据位,2个停止位和奇偶校验位。关于如何产生载波以及为什么我使用这些设置将在本文后面介绍。<BR><BR><CODE>BOOL
CIrPulse::Open(UINT uiPort)<BR>{<BR> ASSERT(uiPort > 0 && uiPort
<= 255);<BR> Close(); <BR> //打开IRDA端口<BR> CString strPort;<BR>
strPort.Format(_T("COM%d:"), uiPort);<BR> m_irPort = CreateFile((LPCTSTR)
strPort, GENERIC_READ | GENERIC_WRITE,0, NULL, OPEN_EXISTING, 0, NULL);<BR> if
(m_irPort == INVALID_HANDLE_VALUE)<BR> {<BR> return FALSE;<BR> }<BR>
//设置输入和输出缓冲区的大小<BR> VERIFY(SetupComm(m_irPort, 2048, 2048));<BR>
//清除读和写缓冲区<BR> VERIFY(PurgeComm(m_irPort,PURGE_TXABORT|PURGE_RXABORT|<BR>
PURGE_TXCLEAR|PURGE_RXCLEAR));<BR> //重新初始化所有的IRDA端口设置<BR> DCB dcb;<BR>
dcb.DCBlength = sizeof(DCB);<BR> VERIFY(GetCommState(m_irPort, &dcb));<BR>
dcb.BaudRate = CBR_115200;<BR> dcb.fBinary = TRUE;<BR> dcb.fParity =
TRUE;<BR> dcb.fOutxCtsFlow = FALSE;<BR> dcb.fOutxDsrFlow = FALSE;<BR>
dcb.fDtrControl = DTR_CONTROL_DISABLE;<BR> dcb.fDsrSensitivity = FALSE;<BR>
dcb.fTXContinueOnXoff = FALSE;<BR> dcb.fOutX = FALSE;<BR> dcb.fInX =
FALSE;<BR> dcb.fErrorChar = FALSE; <BR> dcb.fNull = FALSE;<BR>
dcb.fRtsControl = RTS_CONTROL_DISABLE;<BR> dcb.fAbortOnError = FALSE;<BR>
dcb.ByteSize = 8; <BR> dcb.Parity = EVENPARITY; <BR> dcb.StopBits =
TWOSTOPBITS;<BR> VERIFY(SetCommState(m_irPort, &dcb));<BR>
//为所有的读和写操作设置超时值<BR> COMMTIMEOUTS timeouts;<BR>
VERIFY(GetCommTimeouts(m_irPort, &timeouts));<BR>
timeouts.ReadIntervalTimeout = MAXDWORD;<BR>
timeouts.ReadTotalTimeoutMultiplier = 0;<BR> timeouts.ReadTotalTimeoutConstant
= 0;<BR> timeouts.WriteTotalTimeoutMultiplier = 0;<BR>
timeouts.WriteTotalTimeoutConstant = 0;<BR> VERIFY(SetCommTimeouts(m_irPort,
&timeouts));<BR> DWORD dwEvent=EV_TXEMPTY;<BR>
SetCommMask(m_irPort,dwEvent);<BR> return
TRUE;<BR>}</CODE><BR> 调用函数SetCodeSize(DWORD)来设置要传送的位数(如12位)。这可以在任何时候完成且只需要做一次。它一直保持有效,直到后面的调用改变它为止。<BR><BR> 最后调用SendCode(long),传递实际要发送的代码。<BR><BR><CODE>BOOL
CIrPulse::SendCode(DWORD lValue)<BR>{<BR> DWORD dwCount;<BR> int i=0;<BR>
ASSERT(iDataLength>0);<BR> //清除传送缓冲区<BR>
VERIFY(PurgeComm(m_irPort,PURGE_TXABORT| PURGE_RXABORT |PURGE_TXCLEAR |
PURGE_RXCLEAR));<BR> //每次按键设置代码6次<BR> for(int x=0;x<6;x++) {<BR>
MakeStream(lValue); //发送代码<BR> dwCount=GetTickCount();<BR>
while(GetTickCount()<dwCount+26) //延迟26ms<BR> i++;<BR> }<BR> return
true;<BR>}</CODE><BR> 注意这个函数调用另外一个函数MakeStream(long)6次,每两次调用之间停顿26毫秒。我发现该代码必须发送好几次才能使接收设备响应,大概是为防止假行为的缘故吧。26毫秒对于接收设备登记该代码是必需的,在下一个代码出现之前。<BR><BR> 这个函数MakeStream(long)把字节流写入IrPort,并根据是否有起始位(1或者0)来确保发送正确的数据包长度。包含数据字节(0xdb)的缓冲区是以一个ByteArray形式存在的。<BR><BR> 函数Close()用于在端口使用后,自然地关闭IrPort。<BR><BR> 这个函数在我的ornada上运行良好。请看下面的讨论以进一步确定你要做的可能性改变。<BR><BR><CODE>BOOL
CIrPulse::MakeStream(DWORD lValue) {<BR> DWORD dwStreamLength;<BR>
//创建开始脉冲<BR> dwStreamLength=iHPulse/charWidth;<BR> ASSERT(Write((const char
*)bPulseStream.GetData(),<BR> dwStreamLength)==dwStreamLength);<BR> //
************************************<BR> // ***** 在下一个脉冲到来前延迟一段时间<BR> //
************************************<BR> //循环操作代码中的位来发送脉冲<BR> for(int
i=0;i<iDataLength;i++) {<BR> if(lValue & 1) {<BR> //创建一个脉冲1<BR>
dwStreamLength=i1Pulse/charWidth;<BR> ASSERT(Write((const char
*)bPulseStream.GetData(),<BR> dwStreamLength)==dwStreamLength);<BR> //
*********************************<BR> // ***在下一个脉冲到来前延迟一段时间<BR> //
*********************************<BR> }<BR> else {<BR> //创建一个脉冲 0 <BR>
dwStreamLength=i0Pulse/charWidth;<BR> ASSERT(Write((const char
*)bPulseStream.GetData(),<BR> dwStreamLength)==dwStreamLength);<BR> //
********************************<BR> // **在下一个脉冲到来前延迟一段时间<BR> //
********************************<BR> }<BR> lValue >>= 1;<BR> }<BR>
return
TRUE;<BR>}</CODE><BR> 我在所附源代码中包含了一个简单的应用程序,它使用CIrPulse来创建一台索尼TV的远距离遥控。它具有基本的频道选择、音量调整和开/关机的功能。<BR><BR> <STRONG> 4.
特别注意</STRONG><BR><BR> 因为该CIrPort类使用一个串行端口连接到该IR端口,所以必须生成一个40KHz的载波信号,这通过从该串行端口发送恰当的字符来实现。幸好,如果我们发送字符0xdb,以115200波特,用8个数据位,2个停止位和奇偶校验,这样就能产生一种极接近38.4KHz的载波信号。我们所有的索尼设备接收这种数据是没有问题的。<BR><BR> 最大的问题是,如何实现间隔每次脉冲的沉默周期。不可能由串行端口来产生该沉默周期,因为就算你发送一个0x0字符,由于存在起始和停止位,你仍然在该IR上得到脉冲。我通过发送不同的字符进行试验,依据的前提是如果你不以40KHz的频率发送一个载波信号,这有可能使设备误把这个当作一个沉默。这样做的优点是你可以产生一个包含完整的代码的byteArray,以确保准确计时。但是结果并不一致,所以我拒绝使用这个方法,为的是实现在两次从串行端口发出成组的0xdb字符之间支持暂停。因为需要的延迟是以550μs的顺序;到目前为止,我还没有找到取得独立于处理器速度的暂停的方法。在我的Jornada上,是完全不必产生一个延迟的,因为每次调用Write函数看上去都使用了合适的时限。不管怎样,我担心的是,你可能胡乱产生一个可以使你的掌上电脑能工作的一个延迟。
<CENTER><A href="http://tech.163.com/school" target=_blank><IMG
src="WinCE下用C++实现掌上电脑遥控TV - 网易学院·教程.files/20051009160245d41d8.gif"
border=0></A></CENTER>
<P style="TEXT-ALIGN: left"><IMG alt=gigi_miao
src="WinCE下用C++实现掌上电脑遥控TV - 网易学院·教程.files/Editor.gif"
align=absMiddle>[编辑:gigi_miao] <A class=goback
href="http://tech.163.com/">[返回首页]</A></P></DIV>
<P class=prenext></P></DIV>
<DIV id=OtherNews><STRONG>相关文章:</STRONG>
<UL></UL></DIV>
<DIV class=Othercomment>
<P style="BORDER-BOTTOM: #ccc 1px solid"><STRONG>推荐文章:</STRONG>·<A
href="http://tech.163.com/05/0916/09/1TOSFO2M000915AS.html">IE 7 最新清晰截图</A> ·<A
href="http://tech.163.com/05/0824/12/1RTV7736000915BF.html">GoogleTalk学院独家试用</A>
·<A href="http://tech.163.com/05/0824/10/1RTQLTLP00091589.html">抽出滤镜抠发法</A> ·<A
href="http://tech.163.com/05/0824/11/1RTSK6MA00091589.html">高级:抠取颜色相近的头发</A>
</P>
<P>
<MARQUEE id=idMarquee onmouseover="document.all('idMarquee').stop();"
onmouseout="document.all('idMarquee').start();" scrollAmount=2>·<A
href="http://tech.163.com/05/1012/16/1VSKS5KH00091589.html">Photoshop
CS镜头模糊滤镜:轻松实现背景虚化</A> ·<A
href="http://tech.163.com/05/1012/16/1VSKI06H00091589.html">图解Photoshop绘制金属风格XP主题桌面壁纸</A>
·<A
href="http://tech.163.com/05/1012/16/1VSK9GAE00091589.html">ASP程序中提供在线文章翻译功能</A>
·<A href="http://tech.163.com/05/1012/15/1VSHN9P700091589.html">一些奇特的 JavaScript
功能</A> ·<A
href="http://tech.163.com/05/1012/15/1VSH86H400091589.html">PS初级技巧:Photoshop抠图的技巧</A>
·<A
href="http://tech.163.com/05/1012/15/1VSH3MSD00091589.html">Photoshop抠图之毛茸茸的牧羊犬</A>
·<A href="http://tech.163.com/05/1012/15/1VSGKOM3000917IO.html">学院艺术:Medusateam
平面设计</A> ·<A
href="http://tech.163.com/05/1012/15/1VSG630V00091589.html">代号Kahuna
MSN邮件服务beta版预览</A> ·<A
href="http://tech.163.com/05/1012/15/1VSG4DF300091589.html">Flash图文教程:flash文字跳动(教程)</A>
·<A
href="http://tech.163.com/05/1012/15/1VSFNA4I00091589.html">Photoshop打造火焰字+光照效果</A>
·<A
href="http://tech.163.com/05/1012/15/1VSEOKMK00091589.html">Photoshop图文教程:一种简单的数码照片后期润饰</A>
·<A
href="http://tech.163.com/05/1012/15/1VSEHFLL00091589.html">[激辩]哪个是适用的桌面操作系统?</A>
·<A
href="http://tech.163.com/05/1012/14/1VSDKBOF00091589.html">Foxmail自动分拣并删除垃圾邮件</A>
·<A
href="http://tech.163.com/05/1012/14/1VSDGFAU00091589.html">巧用Photoshop滤镜绘制仿真水纹效果</A>
·<A href="http://tech.163.com/05/1012/14/1VSCOT9T00091589.html">巧妙施招
手机瞬间变无线猫</A> ·<A
href="http://tech.163.com/05/1012/14/1VSCHJOO00091589.html">RealOne在线播放不畅解决办法</A>
·<A href="http://tech.163.com/05/1012/14/1VSB5SJV00091589.html">PS CS2视频教程:138
图层的编辑操作6</A> ·<A
href="http://tech.163.com/05/1012/14/1VSB5ECN00091589.html">PS CS2视频教程:137
图层的编辑操作5</A> ·<A
href="http://tech.163.com/05/1012/14/1VSB4OO100091589.html">PS CS2视频教程:136
图层的编辑操作4</A> ·<A
href="http://tech.163.com/05/1012/14/1VSB4DDK00091589.html">PS CS2视频教程:135
图层的编辑操作3</A></MARQUEE></P></DIV>
<DIV style="MARGIN: 0px auto; WIDTH: 750px"><A name=0></A>
<TABLE cellSpacing=0 cellPadding=0 width="100%">
<TBODY>
<TR>
<TD align=middle bgColor=#15477c height=23><FONT style="FONT-SIZE: 14px"
color=#ffffff>最新评论</FONT></TD></TR></TBODY></TABLE><SPAN
id=firstcomment></SPAN><A name=rightnow></A>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD width=173><A
href="http://comment.news.163.com/reply/post.jsp?board=tech_bbs&threadid=1VNA328M00091589"><IMG
height=63 src="WinCE下用C++实现掌上电脑遥控TV - 网易学院·教程.files/arc_b1.gif"
border=0></A></TD>
<TD background="WinCE下用C++实现掌上电脑遥控TV - 网易学院·教程.files/arc_b5.gif"> </TD>
<TD width=180
background="WinCE下用C++实现掌上电脑遥控TV - 网易学院·教程.files/arc_b6.gif"><IMG
height=13 src="WinCE下用C++实现掌上电脑遥控TV - 网易学院·教程.files/arc_i3.gif" width=16>
<STRONG><A
href="http://comment.news.163.com/reply/post.jsp?type=re&board=tech_bbs&threadid=1VNA328M00091589">更多评论</A></STRONG>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?