arduino 的红外遥控解码

 

测试发现   遥控器的角度不一样  或者有反射  导致解析的码也不一样 

 

 

 

 

 

 

 

 

程序 

/*
 * IRrecvDemo-LED
 * =====================功能说明=====================
 * 演示如何利用Arduino开发板接收红外遥控器控制信号,
 * 并利用接受到的信号遥控Arduino开发板上的红外LED。
 * Arduino所接收到的红外遥控器信号内容也将通过串口监视器显示出来。
 * 
 * 本程序基于Ken Shirriff开发的IRremote库。如需获得该库文件
 * 可前往以下网址获得:
 * http://arcfn.com (Ken Shirriff个人博客)                              
 * http://www.taichi-maker.com/homepage/download/  (太极创客官网)
 * 
 * =====================电路连接======================
 *   红外接收器 1838B OUT 引脚 ---  Arduino Uno 11  引脚 
 *   红外接收器 1838B VCC 引脚 ---  Arduino Uno +5V 引脚 
 *   红外接收器 1838B GND 引脚 ---  Arduino Uno GND 引脚 
 *         
 *  如需获得详细电路连接说明图,请参阅太极创客网站:
 *  http://WWW.TAICHI-MAKER.COM
 * 
 * 此示例程序为配合太极创客制作的
 * 《零基础入门学用ARDUINO教程-智能应用篇》使用
 * 
 */
 
#include <IRremote.h>
#define  RECV_PIN 11
 
IRrecv irrecv(RECV_PIN);   // 红外遥控初始化
decode_results results;   // 储存接收到的红外遥控信息
 
void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);     
  Serial.begin(9600);
  Serial.println("Enabling IRin");
  irrecv.enableIRIn();     // 启动红外接收
  Serial.println("Enabled IRin");
}
 
void loop() {
  /* 
  decode()库函数用于判断红外接收器所接收到的红外信号是否可以被解析。
  如可以成功解析,则返回非零数值。并将解析结果存储于results中。
  如无法成功解析,则返回零。
  
  每一次解析完成,都需要调用resume()函数从而让Arduino开始准备接收下一个红外
  遥控指令。
  */
  if (irrecv.decode(&results)) {  
    Serial.println(results.value, HEX);  // results.value为红外遥控信号的具体数值
 
    if(results.value == 0xF7C03F) //如果控制信息数值为F7C03F
    {          
        Serial.println("Command Received: Turn On LED.");
        digitalWrite(LED_BUILTIN, HIGH); 
    } 
    
    if(results.value == 0xF740BF) //如果控制信息数值为F740BF
    {          
        Serial.println("Command Received: Turn Off LED.");
        digitalWrite(LED_BUILTIN, LOW); 
    }
    
    irrecv.resume(); // 恢复接收下一个红外遥控信号
  }
  delay(100);
}

 

 

 

 

 

 

 

买的一个红外解码模块    接受的数据   00 FF 45

发送数据  

A2 F1 00 FF 49 

arduino  接受 红外解码模块发送红外 数据     FF926D

arduino  接受 按键发送红外 数据                   FF00926D

 

 

 

电视遥控器测试1

红外遥控解码器能读出数据    40 BF 04

 

arduino 能读出数据    2FD20DF

 

利用红外遥控解码器发送得到的16进制数据     A2 F1 40 BF 04   arduino能解码出 原始码   2FD20DF

 遥控器2     红外解码模块不能读出数据

 

arduino 能读出红外数据    6A68351E

 

 经过以上阶段的测试    遥控器的编码  不一致  

具体的协议类型 大家可以百度  

https://wenku.baidu.com/view/edd46df9c77da26925c5b05c.html

NEC

SONY

PANASONIC

JVC

RC5  RC6 .....

最恶心的就是自定义的协议  比如 下面这个遥控器   TCL

 

 

于是我又在网上找资料   

重新写了一个程序进行解码  

/*
 * 学霸型红外遥控器 
 * 太极创客 http://www.taichi-maker.com/
 * Ver. 1.2 - 01/07/2017
 * =====================功能说明=====================
 * 利用Arduino开发板记录并“重放”红外遥控信号
 * 用户可以使用家中控制电器用的红外遥控器对准本装置的
 * 红外接收器,本装置可将接收到的红外遥控信号记录至EEPROM。
 * 当用户按下"发射"按键时,红外LED会发射记录的红外遥控信号
 * 从而控制家中电器。
 * 
 * 本示例程序主要内容借鉴Ken Shirriff 的 IRremote 库示例程序IRrecord。
 * 
 * 本程序基于Ken Shirriff开发的IRremote库。如需获得该库文件
 * 可前往以下网址获得:
 * http://arcfn.com   (Ken Shirriff个人博客)
 * http://www.taichi-maker.com/   (太极创客官网)
 * 
 * =====================电路连接======================
 * 红外接收器 1838B OUT 引脚 --- Arduino Uno 引脚 11
 *     红外发射 LED 正极     --- Arduino Uno 引脚  3
 *         按键开关          --- Arduino Uno 引脚 12
 *         
 *  如需获得详细电路连接说明图,请参阅太极创客网站:
 *  http://WWW.TAICHI-MAKER.COM
 * 
 * 此示例程序为配合太极创客制作的
 * 《零基础入门学用ARDUINO教程-智能应用篇》使用
 * 版本更新说明
 * V1.1 使用put get来 进行EEPROM存取
 * V1.2 针对IRrecord代码进行优化
 */
 
#include <IRremote.h>
#include <EEPROM.h>
 
#define codeTypeEAddr     0  // 存放红外信号编码类型EEPROM地址
#define codeLenEAddr      1  // 存放红外信号编码长度EEPROM地址
#define toggleEAddr       2  // 存放红外信号RC5/RC6类型EEPROM地址
#define codeValueEAddr    3  // 存放红外信号数值EEPROM地址  
#define RECV_PIN 11          // 红外接收器 OUT 引脚 --- Arduino 引脚11
#define BUTTON_PIN 12               // 按键开关 --- Arduino 引脚12
#define STATUS_PIN LED_BUILTIN      // 状态显示LED --- 开发板内置LED
 
IRrecv irrecv(RECV_PIN);   // 红外遥控接收器对象
IRsend irsend;             // 红外遥控发射对象
 
decode_results results;    // 储存接收到的红外遥控信息
 
void setup() {
  Serial.begin(9600);
  irrecv.enableIRIn(); // 启动红外接收
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(STATUS_PIN, OUTPUT);
  delay(10);
  loadEepromValues();  // 从EEPROM中读取红外信号信息(具体信息请见函数部分)
}
 
// 红外信号存储变量
int codeType; // 红外信号编码类型
unsigned long codeValue; // 存放红外信号数值(如果不是raw型)
unsigned int rawCodes[RAWBUF]; // raw型信号
int codeLen;    // 红外信号编码长度
int toggle;     // 红外信号RC5/RC6类型
 
// 记录收到的红外信号
void storeCode(decode_results *results) {
  codeType = results->decode_type;
  int count = results->rawlen;
  if (codeType == UNKNOWN) {    //如果收到的信号是无法识别的协议,则存储为raw型数据
    Serial.println("Received unknown code, saving as raw");  
    codeLen = results->rawlen - 1;
    // 存储raw型信号:
    // 将首个数值放弃(间隙)
    // 将信号转化为毫秒
    // 细微调整信号内容,将信息变短将空档间隙变长从而取消红外接收信号的扰动
    for (int i = 1; i <= codeLen; i++) {
      if (i % 2) {
        // 信号
        rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS;
        Serial.print(" m");
      } 
      else {
        // 空档间隙
        rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS;
        Serial.print(" s");
      }
      Serial.print(rawCodes[i - 1], DEC);
    }
    Serial.println("");
  }
  else {
    if (codeType == NEC) {  //如果是NEC协议类型
      Serial.print("Received NEC: ");
      if (results->value == REPEAT) {
        // Don't record a NEC repeat value as that's useless.
        Serial.println("repeat; ignoring.");
        return;
      }
    } 
    else if (codeType == SONY) {  //如果是SONY协议类型
      Serial.print("Received SONY: ");
    } 
    else if (codeType == PANASONIC) {  //如果是PANASONIC协议类型
      Serial.print("Received PANASONIC: ");
    }
    else if (codeType == JVC) {  //如果是JVC协议类型
      Serial.print("Received JVC: ");
    }
    else if (codeType == RC5) {  //如果是RC5协议类型
      Serial.print("Received RC5: ");
    } 
    else if (codeType == RC6) {  //如果是RC6协议类型
      Serial.print("Received RC6: ");
    } 
    else {
      Serial.print("Unexpected codeType "); //无法识别信号
      Serial.print(codeType, DEC);
      Serial.println("");
    }
    Serial.println(results->value, HEX); //输出信号数值
    codeValue = results->value;
    codeLen = results->bits;
  }
  writeEepromVal();  //将收到的信号信息储存于eeprom
}
 
// 发射红外信号
void sendCode(int repeat) {
  if (codeType == NEC) {  //如果是NEC协议信号
    if (repeat) {         //且如果是发射重复信号
      irsend.sendNEC(REPEAT, codeLen);     //发射NEC协议的重复信号
      Serial.println("Sent NEC repeat");
    } 
    else {
      irsend.sendNEC(codeValue, codeLen);  //否则发射NEC协议红外指令信号
      Serial.print("Sent NEC ");
      Serial.println(codeValue, HEX);      //串口监视器输出红外指令信号数值
    }
  } 
  else if (codeType == SONY) {             // 发射的信号是SONY协议
    irsend.sendSony(codeValue, codeLen);   // 发射SONY协议红外指令信号
    Serial.print("Sent Sony ");
    Serial.println(codeValue, HEX);
  } 
  else if (codeType == PANASONIC) {            // 发射的信号是PANASONIC协议
    irsend.sendPanasonic(codeValue, codeLen);  // 发射PANASONIC协议红外指令信号
    Serial.print("Sent Panasonic");
    Serial.println(codeValue, HEX);
  }
  else if (codeType == JVC) {                    // 发射的信号是JVC协议
    irsend.sendJVC(codeValue, codeLen, false);   // 发射JVC协议红外指令信号
    Serial.print("Sent JVC");
    Serial.println(codeValue, HEX);
  }
  else if (codeType == RC5 || codeType == RC6) {  // 发射的信号是RC5或RC6协议
    if (!repeat) {
      // 新按键按下后反转toggle位
      toggle = 1 - toggle;
    }
    // 将toggle位放入信号代码中发送
    codeValue = codeValue & ~(1 << (codeLen - 1));
    codeValue = codeValue | (toggle << (codeLen - 1));
    if (codeType == RC5) {       // 发射的信号是RC5协议
      Serial.print("Sent RC5 ");
      Serial.println(codeValue, HEX);
      irsend.sendRC5(codeValue, codeLen);
    } 
    else {   // 发射的信号是RC6协议
      irsend.sendRC6(codeValue, codeLen);
      Serial.print("Sent RC6 ");
      Serial.println(codeValue, HEX);
    }
  } 
  else if (codeType == UNKNOWN /* i.e. raw */) {
    // 假设信号频率 38 KHz
    irsend.sendRaw(rawCodes, codeLen, 38);
    Serial.println("Sent raw");
  }
}
 
int lastButtonState;   // 此变量用于判断发射红外信号的按键开关所处的状态
 
void loop() {
  
  int buttonState = !digitalRead(BUTTON_PIN);           // 读取当前的按键开关状态(检查用户是否按下了按键开关)
  if (lastButtonState == HIGH && buttonState == LOW) {  // 如果按键开关是被按下后再抬起的
    
    Serial.println("Released");                         // 通过串口监视器输出"按键抬起"
    irrecv.enableIRIn();                                // 启动红外接收器信号接收
  }                                                     
 
  if (buttonState) {                                    // 如果按键开关处于被按下的状态
    
    Serial.println("Pressed, sending");                 // 通过串口监视器输出"按键按下"
    digitalWrite(STATUS_PIN, HIGH);                     // 闪烁状态显示红外LED告知用户当前"学霸遥控器"正在发射红外信号(点亮LED)
    sendCode(lastButtonState == buttonState);           // 更新按键开关状态变量
    digitalWrite(STATUS_PIN, LOW);                      // 闪烁状态显示红外LED告知用户当前"学霸遥控器"正在发射红外信号(熄灭LED)
    delay(50);                                          // 信号发射间歇
    
  } else if (irrecv.decode(&results)) {                 // 如果按键开关处于没有被按下的状态,则实时检查红外接收器并对接收到的信号进行解码
                                                        // 如果接收到的红外信号可以通过decode函数成功解码
    digitalWrite(STATUS_PIN, HIGH);                     // 闪烁状态显示红外LED告知用户当前"学霸遥控器"正在发射红外信号(点亮LED)
    storeCode(&results);                                // 将解码的红外信号信息进行储存(非EEPROM储存)
    irrecv.resume();                                    // 恢复红外接收器
    digitalWrite(STATUS_PIN, LOW);                      // 闪烁状态显示红外LED告知用户当前"学霸遥控器"正在发射红外信号(熄灭LED)
  }
  lastButtonState = buttonState;                        // 更新按键开关状态变量
}
 
// 通过EEPROM读取红外信号信息
// 每次Arduino通电后,都会从EEPROM中读取存储的红外信号信息。
// 从而确保"学霸遥控器"在断电后依然可以保持上一次运行时所存储的
// 红外信号信息。
void loadEepromValues(){
  codeType = EEPROM.read(codeTypeEAddr);
  delay(10);
  codeLen = EEPROM.read(codeLenEAddr);
  delay(10);
  toggle = EEPROM.read(toggleEAddr);  
  delay(10);
  toggle = EEPROM.read(toggleEAddr);  
  delay(10);
  EEPROM.get(codeValueEAddr, codeValue);
}
 
// 将红外信号信息储存于EEPROM
// 每一次"学霸遥控器"接收到新的红外遥控信号
// 都将最新接收的红外遥控器储存于EEPROM
// 从而确保信号信息不会因为Arduino断电而丢失
void writeEepromVal(){
   EEPROM.write(codeTypeEAddr, codeType);
   delay(10);
   EEPROM.write(codeLenEAddr, codeLen);
   delay(10);
   EEPROM.write(toggleEAddr, toggleEAddr);
   delay(10);
   EEPROM.put(codeValueEAddr, codeValue);
   delay(10);
}

按键 接3.3v 拉高

于是下载查看现象

发现了恶心的一项  

遥控器什么玩意

 

 

 

 

 

 

 

  • 2
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值