Я пытаюсь создать систему ответов учеников для игры, подобной Jeopardy, с использованием дешевых телевизионных пультов дистанционного управления. Они инфракрасные, протокол NEC. Последовательный монитор отображает нажатие кнопок от студентов в порядке их ответа.
Я использую приемник TSOP 4838, подключенный к Arduino Uno с конденсатором, и пока только последовательный монитор, который поставляется с программным обеспечением Arduino IDE. Мой код отображается ниже.
Все работает хорошо, если 2 или более ученика не нажимают кнопки в течение полсекунды друг от друга. Если это произойдет, я не получу вывод на последовательный монитор. Я надеюсь, что есть некоторые изменения, которые я могу внести в мой эскиз или в файлы IRremote.h или IRremoteInt.h, чтобы быстрее различать сигналы, чтобы мои списки отображения отображались первыми.
IRremote.h:
*/
* IRremote v1.1
* By Chris Targett
* November 2011
*
* Based on Ken Shirriff's Version 0.11 of his IR-Remote library August, 2009
* https://github.com/shirriff/Arduino-IRremote
*/
#ifndef IRremote_h
#define IRremote_h
// The following are compile-time library options.
// If you change them, recompile the library.
// If DEBUG is defined, a lot of debugging output will be printed during decoding.
// TEST must be defined for the IRtest unittests to work. It will make some
// methods virtual, which will be slightly slower, which is why it is optional.
// #define DEBUG
// #define TEST
// Results returned from the decoder
class decode_results {
public:
int decode_type; // NEC, SONY, RC5, RC6, DISH, SHARP, SAMSUNG, JVC, UNKNOWN
unsigned long value; // Decoded value
unsigned long address; // address for panasonic codes
int bits; // Number of bits in decoded value
volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks
int rawlen; // Number of records in rawbuf.
};
// Values for decode_type
#define NEC 1
#define SONY 2
#define RC5 3
#define RC6 4
#define DISH 5
#define SHARP 6
#define SAMSUNG 7
#define JVC 8
#define PANASONIC 9
#define UNKNOWN -1
// Decoded value for NEC when a repeat code is received
#define REPEAT 0xffffffff
// main class for receiving IR
class IRrecv
{
public:
IRrecv(int recvpin);
void blink13(int blinkflag);
int decode(decode_results *results);
void enableIRIn();
void resume();
private:
// These are called by decode
int getRClevel(decode_results *results, int *offset, int *used, int t1);
long decodeNEC(decode_results *results);
long decodeSony(decode_results *results);
long decodeSamsung(decode_results *results);
long decodeRC5(decode_results *results);
long decodeRC6(decode_results *results);
long decodeJVC(decode_results *results);
long decodeHash(decode_results *results);
long decodePanasonic(decode_results *results);
int compare(unsigned int oldval, unsigned int newval);
}
;
// Only used for testing; can remove virtual for shorter code
#ifdef TEST
#define VIRTUAL virtual
#else
#define VIRTUAL
#endif
class IRsend
{
public:
IRsend() {}
void sendNEC(unsigned long data, int nbits);
void sendSony(unsigned long data, int nbits);
void sendSamsung(unsigned long data, int nbits);
void sendRaw(unsigned int buf[], int len, int hz);
void sendRC5(unsigned long data, int nbits);
void sendRC6(unsigned long long data, int nbits);
void sendDISH(unsigned long data, int nbits);
void sendSharp(unsigned long data, int nbits);
void sendJVC(unsigned long data, int nbits, int repeat);
void sendPanasonic(unsigned long address, unsigned long data);
// private:
void enableIROut(int khz);
VIRTUAL void mark(int usec);
VIRTUAL void space(int usec);
}
;
// Some useful constants
#define USECPERTICK 50
#define RAWBUF 76
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 100
#endif
Вот IRremoteInt.h
/*
* IRremote v1.1
* By Chris Targett
* November 2011
*
* Based on Ken Shirriff's Version 0.11 of his IR-Remote library August, 2009
* https://github.com/shirriff/Arduino-IRremote
*/
#ifndef IRremoteint_h
#define IRremoteint_h
#include <Arduino.h>
#define CLKFUDGE 5 // fudge factor for clock interrupt overhead
#define CLK 256 // max value for clock (timer 2)
#define PRESCALE 8 // timer2 clock prescale
#define SYSCLOCK 16000000 // main Arduino clock
#define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000) // timer clocks per microsecond
#define ERR 0
#define DECODED 1
#define BLINKLED 13
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// clock timer reset value
#define INIT_TIMER_COUNT2 (CLK - USECPERTICK*CLKSPERUSEC + CLKFUDGE)
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT2
// pulse parameters in usec
#define NEC_HDR_MARK 9000
#define NEC_HDR_SPACE 4500
#define NEC_BIT_MARK 560
#define NEC_ONE_SPACE 1600
#define NEC_ZERO_SPACE 560
#define NEC_RPT_SPACE 2250
#define SONY_HDR_MARK 2400
#define SONY_HDR_SPACE 600
#define SONY_ONE_MARK 1200
#define SONY_ZERO_MARK 600
#define SONY_RPT_LENGTH 45000
#define RC5_T1 889
#define RC5_RPT_LENGTH 46000
#define RC6_HDR_MARK 2666
#define RC6_HDR_SPACE 889
#define RC6_T1 444
#define RC6_RPT_LENGTH 46000
#define SAMSUNG_HDR_MARK 4500
#define SAMSUNG_BITS 32
#define SAMSUNG_HDR_SPACE 4500
#define SAMSUNG_BIT_MARK 560
#define SAMSUNG_ONE_SPACE 1600
#define SAMSUNG_ZERO_SPACE 600
#define SHARP_BIT_MARK 245
#define SHARP_ONE_SPACE 1805
#define SHARP_ZERO_SPACE 795
#define SHARP_GAP 600000
#define SHARP_TOGGLE_MASK 0x3FF
#define SHARP_RPT_SPACE 3000
#define DISH_HDR_MARK 400
#define DISH_HDR_SPACE 6100
#define DISH_BIT_MARK 400
#define DISH_ONE_SPACE 1700
#define DISH_ZERO_SPACE 2800
#define DISH_RPT_SPACE 6200
#define DISH_TOP_BIT 0x8000
#define SHARP_BITS 15
#define DISH_BITS 16
#define JVC_HDR_MARK 8000
#define JVC_HDR_SPACE 4000
#define JVC_BIT_MARK 600
#define JVC_ONE_SPACE 1600
#define JVC_ZERO_SPACE 550
#define JVC_RPT_LENGTH 60000
#define PANASONIC_HDR_MARK 3502
#define PANASONIC_HDR_SPACE 1750
#define PANASONIC_BIT_MARK 502
#define PANASONIC_ONE_SPACE 1244
#define PANASONIC_ZERO_SPACE 370
#define TOLERANCE 25 // percent tolerance in measurements
#define LTOL (1.0 - TOLERANCE/100.)
#define UTOL (1.0 + TOLERANCE/100.)
#define _GAP 5000 // Minimum map between transmissions
#define GAP_TICKS (_GAP/USECPERTICK)
#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1))
#ifndef DEBUG
#define MATCH(measured_ticks, desired_us) ((measured_ticks) >= TICKS_LOW(desired_us) && (measured_ticks) <= TICKS_HIGH(desired_us))
#define MATCH_MARK(measured_ticks, desired_us) MATCH(measured_ticks, (desired_us) + MARK_EXCESS)
#define MATCH_SPACE(measured_ticks, desired_us) MATCH((measured_ticks), (desired_us) - MARK_EXCESS)
// Debugging versions are in IRremote.cpp
#endif
// receiver states
#define STATE_IDLE 2
#define STATE_MARK 3
#define STATE_SPACE 4
#define STATE_STOP 5
// information for the interrupt handler
typedef struct {
uint8_t recvpin; // pin for IR data from detector
uint8_t rcvstate; // state machine
uint8_t blinkflag; // TRUE to enable blinking of pin 13 on IR processing
unsigned int timer; // state timer, counts 50uS ticks.
unsigned int rawbuf[RAWBUF]; // raw data
uint8_t rawlen; // counter of entries in rawbuf
}
irparams_t;
// Defined in IRremote.cpp
extern volatile irparams_t irparams;
// IR detector output is active low
#define MARK 0
#define SPACE 1
#define TOPBIT 0x80000000
#define NEC_BITS 32
#define SONY_BITS 12
#define JVC_BITS 32
#define MIN_RC5_SAMPLES 11
#define MIN_RC6_SAMPLES 1
#endif
и вот мой эскиз:
#include <IRremote.h>
#include <IRremoteInt.h>
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
}
void loop()
{
if (irrecv.decode(&results))
{
if (results.value == 551520375) { //1
Serial.println("Team 1");
}
if (results.value == 551504055) { //2
Serial.println("Team 2");
}
if (results.value == 551536695) { //3
Serial.println("Team 3");
}
if (results.value == 551495895) { //4
Serial.println("Team 4");
}
if (results.value == 551528535) { //5
Serial.println("Team 5");
}
if (results.value == 551512215) { //6
Serial.println("Team 6");
}
if (results.value == 551544855) { //7
Serial.println("Team 7");
}
if (results.value == 551491815) { //8
Serial.println("Team 8");
}
if (results.value == 551524455) { //9
Serial.println("Team 9");
}
if (results.value == 551487735) { //10
Serial.println("Team 10");
}
// Serial.println(results.value);
irrecv.resume(); // Receive the next value
}
}
Короче говоря — не совсем и не надежно. Проблема заключается в том, что ваша система эффективно поддерживает несколько каналов. Приемник видит сумму обоих передатчиков. Где модуляция и кодированный сигнал суммируются и, таким образом, искажаются.
У меня есть ИК игрушечные волшебные палочки, для дуэли у меня есть победитель, продолжающий передавать относительно JAM более слабый последний сигнал.
Вы можете попробовать использовать две разные частоты модуляции. Один пульт на 36К, а другой на 60К. 38K является типичным и имеет значительное совпадение. Я видел, как 36 и 40 услышали или испортили 38K. Так что я бы добрался до самых дальних концов доступных чипов демодулятора; быть 36K и 60K. Тем не менее, я подозреваю, что вы используете предоставленные передатчики, которые не могут быть изменены. Таким образом, вам придется найти или построить один.
Кроме того, используя готовые, вы зависите от его поведения. Вы заявили 1/2 секунды. Это вероятно, потому что они повторно передают повторные попытки и имеют задержки запуска и паузы, превышающие время отправки кадра NEC.
Вы также можете реализовать пары RX / TX с различной длиной волны ИК. Тем не менее, большинство приобретаемых ИС демодулятора находятся на стандартной длине волны. Я также рекомендую не создавать дискретный RX, когда это возможно, поскольку в них интегрированы RX / демодуляторы с функцией Auto GAIN, и тому подобное.