自制电脑红外遥控接收器(PC软解码)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
自制电脑红外遥控接收器(PC软解码) 收藏
网上有很多介绍红外遥控接收器制作的文章,但其中大部分是用单片进行红外解码,然后再通过串口或USB把解码后的按键信息传入到PC的。这样的电路制作起来,不仅造价相对偏高,而且需要对单片编程,这会令大部分软件开发爱好者望而却步。
最近看到一篇仅需要7个简单元器件的红外接收器,只需拿起烙铁,不需硬件编程就可以制作完成,原理图如下:
由原理图我们可知,红外接收头把接收的红外信号转换为高低电平通过串口的D SR管脚传入到PC,PC软件通过对DSR高低电平信号的时间曲线进行分析,从而获得相对应的按键信息。
红外遥控器一般采用脉宽调制的串行码,经38kHz的载频把红外信号发射出去。其编码信息一般由三部分组成:引导码、地址码和数据码。一般信号长度大约1 00ms左右,持续按键则重复发送(中间会有10ms以上的间歇)。
常态下,红外接收头的输出(OUT)都是高电平,引导码信号首先会令红外接收头输出一个大约10ms左右的低电平(不同遥控器有不同的时延),这可令接收设备从容判定信号的到来,而后面的地址码和数据码其电平高低变化就相对较快了,大概在几十或几百个微秒之间。
PC红外遥控软件一般选用Girder,在使用之前需要安装“SFH-56 plugin for Girder”这个插件(文件名"igor SFH-56P lug.dll"),否则不能正常处理我们这种电路的红外接收器信号。可悲的是我至今没找到这个插件,网上提供的很多链接都是坏的。
即使找到了这个插件,要想在我们自己编写的程序中使用也是困难的,因为Gir der并没有为我们开发者提供API接口。
既然Girder能用软件实现红外解码,我们为什么不能呢?凡事都要开动大脑,积极行动才对,下面就是我自己焊接的一个红外接收器(元器件是在中发买的,一共不到10元钱,还富裕好多电阻、电容!)
(图下方的红外遥控器的接收器是基于USB的,仅支持Vista以上版本,并且不支持个人开发,不过今天它终于发挥了它应有的作用。当然用电视或VCD遥控器也是可以的)
硬件有了,但程序该从何编起呢?
1、由于接收到的红外信号在微秒级别中变化,对系统实时性要求较高,所以具备垃圾回收功能,实时性没有保证的C#,似乎完不成这种信号的接收功能,所以我们选择的是VC,由它实现高优先级的线程去进行信号接收。
2、由于红外遥控信号是脉宽调制的串行码,所以我们需要采集信号的宽度,显然采用一般的时钟函数来获取时间间隔是不可行的,因为精度太低,所以我们需用采用多媒体时钟和高精度计时的API函数。
3、一般我们按键持续时间为几秒钟,并且由于按键发出前有一个10ms左右的引导信号,所以我们的程序很容易判断出信号起始点,这样我们一次仅需要接收一定量的原始数据就可以完成初步信号采集工作。
4、对于我们的红外接收程序来说并不需要实际解码出红外信号到底包含了那些具体的信息,只要其能够区分出红外遥控上的各个按键就行。
5、由于红接收器是通过串口RTS管脚供电,且通过DSR传递红外信号的,所以我们的程序即使不接收数据,也要打开串口,不过仅需要处理RTS和DSR管脚的信号即可。
好了,动手去做,下面是用VC实现的一个DLL,其功能就是接收并记录红外信号的持续时间。核心代码如下:
DWORD WINAPI ThreadProc(LPVOID pParam)
{
LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfFreq;
int iTime=0; //微秒
// 获得计数器的时钟频率
QueryPerformanceFrequency(&litmp);
dfFreq = (double)1000000.0/litmp.QuadPart;
DWORD ModemState,oldModemState=MS_DSR_ON;
//EV_BREAK or EV_CTS or EV_DSR or EV_ERR or EV_RING or EV_RL SD or EV_RXCHAR or EV_RXFLAG or EV_TXEMPTY
//SetCommMask(HSC_COM_Handle,EV_DSR);
//DWORD EvtMask,dwError;
//COMSTAT cs;
while(HSC_Thread_RunFlag)
{
//等待DSR信号发生变化
//WaitCommEvent(HSC_COM_Handle,&EvtMask,&HSC_Ovread);
//ClearCommError(HSC_COM_Handle,&dwError,&cs);
//获得DSR的状态
GetCommModemStatus(HSC_COM_Handle,&ModemState); ModemState = (ModemState & MS_DSR_ON);
if(ModemState == oldModemState) continue;
oldModemState=ModemState;
//清计数
InterlockedExchange(&HSC_NUM,0);
//开始接收数据
if(HSC_State == 0 && ModemState == 0)
{
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;
HSC_State=1;
//复位计数
InterlockedExchange(&HSC_NUM,0);
InterlockedExchange(&HSC_Index,0);
//开启定时器
HSC_TimerID = timeSetEvent(10,HSC_Accuracy,MMTi mer,NULL,TIME_PERIODIC);
continue;
}
//接收数据状态
if(HSC_State == 1)
{
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;
//--
if(ModemState == 0)
{
iTime = (int)((QPart2-QPart1)*dfFreq);
}