NEC红外遥控协议理解与实现

news/2024/11/8 11:58:32/

NEC红外遥控协议理解与实现

在上个链接里转载了NEC标准的远程控制协议,家电的遥控器基本遵守这个标准。

红外发射管有2个管脚,发送的是经过38KHz时钟调制过的信号。例如下图使用PWM产生一个等占空时钟信号用于调制。


接收管收下来的信号已经经过了解调,可以直接连接系统的外部中断脚。


 

下面通过逻辑分析仪来实际测量一下。

随便找了个红外遥控器,测量power键按下后的波形。首先是信号发送侧。


可以看到,0秒开始是一个按键动作,0.11秒后的那个波形是一个repeat,展开:


把波形重叠的部分展开,就可以看到这个38KHz的调制时钟


如果持续按下遥控器上的按键,那么就会发送连续的repeat信号,发送的间隔也基本满足协议上指出的110ms

下面是接收侧


可以看到信号被解调了,也就是说重叠的部分变成了低电平。

 

最后通过编写协议分析插件的方式,来描述如何通过程序来理解上面的波形。

我使用的逻辑分析软件是 Saleae Logic 1.1.15 编译环境是Microsoft Visual Studio 2008,编译时需要SaleaeAnalyzerSdk-1.1.14。完整的代码从这里下载。

 

分析的方法是测量两个信号下降沿之间的时间长度,这里先定义一些时间参数。

/* Timing define , unit : ms*/

#defineSTART_LOW_TIMING         9000

#defineSTART_HIGH_TIMING        4500

#defineREPEAT_HIGH_TIMING       2250

#defineLOGIC_ONE_TIMING         (562*3)

#defineLOGIC_ZERO_TIMING        (562*1)

#defineDATA_LOW_TIMING     (562*1)

从逻辑分析仪测量的结果,可以发现发射器给出的信号并不是非常的精确,所以我们需要定义误差范围。

/* Timing Margin , unit : ms*/

#definedelta                        20

在下面代码里,通过API函数AdvanceToNextEdge来获取下一个信号发生变化的采样点,如果对应的采样点是低电平,则表示下跳沿,这时和前一个下跳沿采样点的时间做差,按照采样频率换算成时间间隔。再根据上面定义的时间常量来判断这是一个START标记、REPEAT标记、逻辑1、逻辑0还是无效的信号。对于逻辑1和0的情况,需要通过移位来整理成32bits的有效数据,这里要特别注意协议里规定,先发送的是LSB,后发送的MSB。

voidIRNECAnalyzer::WorkerThread()

{

     U64per_sample = 0;

     U64cur_sample = 0;

     U64starting_sample = 0;

     U64differ = 0;

     char action = state_down;

     U8fail = 0;

     U64data = 0;

     U32code = 0;

     U8count = 0;

     U8data_f = 0;

    

     mResults.reset(new IRNECAnalyzerResults( this, mSettings.get() ) );

     SetAnalyzerResults(mResults.get() );

     mResults->AddChannelBubblesWillAppearOn(mSettings->mInputChannel );

     mSampleRateHz= GetSampleRate();

     mSerial= GetAnalyzerChannelData( mSettings->mInputChannel );

 

     if( mSerial->GetBitState() == BIT_LOW )

         mSerial->AdvanceToNextEdge();

 

     for(;;){

         mSerial->AdvanceToNextEdge();

         cur_sample= mSerial->GetSampleNumber();

//只处理时钟的下跳沿

         if(mSerial->GetBitState() == BIT_LOW){

              differ= (cur_sample - per_sample)*1000000/mSampleRateHz;

//判断是否是REPEAT信号           if(((START_LOW_TIMING+REPEAT_HIGH_TIMING-delta*6)<differ)&&((differ)<(START_LOW_TIMING+REPEAT_HIGH_TIMING+delta*6))){

                   action=state_repeat;

                   fail=0;

              }else //判断是否是START信号

if(((START_LOW_TIMING+START_HIGH_TIMING-delta*6)<differ)&&((differ)<(START_LOW_TIMING+START_HIGH_TIMING+delta*6))){

                  action=state_start;

                  fail=0;

             }else//判断是否是逻辑1if(((LOGIC_ONE_TIMING+DATA_LOW_TIMING-delta*2)<differ)&&((differ)<(LOGIC_ONE_TIMING+DATA_LOW_TIMING+delta*2))){

                   action=state_data;

                   data_f=1;

                   fail=0;

              }else  //判断是否是逻辑0if(((LOGIC_ZERO_TIMING+DATA_LOW_TIMING-delta*2)<differ)&&((differ)<(LOGIC_ZERO_TIMING+DATA_LOW_TIMING+delta*2))){

                   action=state_data;

                   data_f=0;

                   fail=0;

              }else{//否则为错误信号

                  fail=1;

             }

              if(fail==0){

                   switch (action){

                   case state_start:

                       code= 0;

                       count= 0;

                       starting_sample= cur_sample;

                       AddFrame(per_sample,cur_sample, 0, FStart);

                            break;

 

                   case state_data:

                       data_f= data_f << count;

                       code= code | data_f;

                       count++;

                       if(count == 8){

                            count= 0;        

                            AddFrame(starting_sample,cur_sample, code, FData);

                            code= 0;

                            starting_sample= cur_sample;

                       }

                       break;

 

                   case state_repeat:

                       AddFrame(per_sample,cur_sample, data, FRepeat);

                       break;

                      

                   default:

                       break;

                   }

              }

              per_sample= cur_sample;

         }

     }

}

加载上面的插件后,可以看到分析的结果


所以如果将这份代码放在板卡上运行,首先应该将接收器的信号接到处理器的外部中断管脚,然后注册一个下跳沿触发的快速中断。然后最通常的情况你需要再注册一个标准的输入设备,映射一下遥控器码字和按键事件的对应关系就可以了。



http://www.ppmy.cn/news/468873.html

相关文章

红外遥控器快速编码解码(NEC)

红外遥控器快速编码解码 NEC编解码模块 红外遥控简介NEC编码红外编解码模块接线说明串口查看数据数据验证总结 原文链接&#xff1a;https://www.yourcee.com/newsinfo/2923957.html 红外遥控简介 红外遥控由发射部分和接收部分两部分组成&#xff0c;发射部分通过控制控制红…

NEC协议——红外遥控的使用

NEC协议是众多红外遥控协议的其中一种&#xff0c;下面以蓝桥杯的单片机开发板实现红外解码。 相关芯片与元器件介绍 此图为跳线帽的解法&#xff0c;在做红外通信时应接3,5&#xff1b;4,6。 此图左为红外发射装置和HX1838集成芯片&#xff0c;放大与接受于一体&#xff0c;…

NEC红外遥控解码

单片机AVR atmel16,将事件和键值通过串口发送出去,注意熔丝位配置时钟。 #include <iom16v.h> #include <macros.h>#define KEY_CUSTOM_CODE 0x22f5 /* 遥控器用户识别码 */ #define KEY_PRESS_EVENT 0x1 /* PRESS按键事件 */ #define KEY_REPEAT_EVEN…

NEC900C服务器系统,nec gdc学习nec900c结构图2018 3 3 nec900c放映机安装.pdf

目录 ▐ 安装前须知 ▐ 如何选择合适的放映机 ▐ 拆箱前检查及准备 ▐ NC900C的安装 ▐ NC900C的维护使用 Page 2 © NEC Corpo at o 2010 NEC Confidential 安装前须知 Page 3 © NEC Corporation 2010 EC Confidential 1 安装前须知 放映机安装前须知 1. 在操作之前应…

NEC协议红外解码

载波Carrier 占空比1/3 频率38kHz(由445kHz产生37.91kHz) Lead code Custom code Custom code Data code Data code Stop Bit 引导码 用户码 用户码 数据码 数据反码 停止位 Lead code引导码 : 载波9ms 没有…

NEC格式红外解码程序

好久没折腾过单片机的东西了&#xff0c;最近在折腾着自己DIY一个APE播放机&#xff0c;要用到红外控制&#xff0c;复习了下51的东西&#xff0c;用AT89C2051写了个红外解码程序&#xff0c;丢在这里吧&#xff0c;供以后参考&#xff1b; #ifndef _IR_H#define _IR_H#define …

CentOS 7远程登录jupyter lab

使用cat /etc/redhat-release看到操作系统是CentOS Linux 7.6&#xff0c;使用uname -r看到内核是3.10.0-957.el7.x86_64。 python3 --version看一下python的版本&#xff0c;pip3 --version看一下pip的版本&#xff0c;这是我CentOS 7默认安装好的。 pip3 install jupyterla…

一次完整的Loadrunner基本流程操作

目录 一.生成脚本&#xff1a; 二.回放脚本&#xff1a; 三.创建场景&#xff1a; 四.生成报告&#xff1a; Loadrunner基本流程操作 准备条件&#xff1a; 一.安装loadrunner 二.破解loadrunner &#xff08;注&#xff1a;本次使用lr11版本可以兼容的IE浏览器版本为I…