Moderators: adafruit_support_bill, adafruit
Serial.print(pulses[i][0] * RESOLUTION, DEC);
Serial.print(" usec, ");
Serial.print(pulses[i][1] * RESOLUTION, DEC);
Serial.println(" usec");
if ((highpulse >= (MAXPULSE/RESOLUTION)) && (currentpulse != 0)) {
if ((lowpulse >= (MAXPULSE/RESOLUTION)) && (currentpulse != 0)) {
dcutler1958 wrote:That's the quickest fix but personally, I prefer incrementing the counter by the number of milliseconds delayed. This also eliminates the need for multiplying the delay counts later when dumping out the data to the serial monitor.
// Raw IR decoder sketch!
//
// This sketch/program uses an Arduno and a GP1UX311QS to decode IR received.
// This can be used to make a IR receiver (by looking for a particular code)
// or transmitter (by pulsing an IR LED at ~38KHz for the durations detected.
//
// Code is public domain, check out www.ladyada.net and adafruit.com
// for more tutorials!
//
// We need to use the 'raw' pin reading methods because timing is
// very important here and the digitalRead() procedure is too slow.
//
// Digital pin #4 is the same as Pin D4 see
// http://arduino.cc/en/Hacking/PinMapping168 for 'raw' pin mapping.
enum { IRpin = 4 } ;
// Maximum number of transitions that can be recorded.
// We will store up to 100 pulse pairs (this is a lot).
enum { MAX_TRANSITIONS = 200 } ;
uint16_t transitions [MAX_TRANSITIONS];
void setup (void) {
Serial.begin (115200);
Serial.println ("Ready to decode IR!");
}
void loop (void) {
uint16_t delays;
int16_t idx = -1;
// Mask to access IR input quickly.
enum { IRpinmask = _BV (IRpin) };
// The maximum transition time we'll listen for. 65 milliseconds is a long time.
enum { MAX_DELAY = 65000 } ; // Milliseconds
// What our timing resolution should be, larger is better as it's
// more 'precise' but too large and you wont get accurate timing.
enum { RESOLUTION = 20 } ; // Milliseconds
for (;;) {
delays = 0;
// Wait for a transition from HIGH to LOW.
while ((PIND & IRpinmask)) { // Using "digitalRead (IRpin)" is too slow.
// Pin is still HIGH, delay.
delayMicroseconds (RESOLUTION);
if ((delays += RESOLUTION) < MAX_DELAY)
continue;
// Pulse is too long, we 'timed out'. NOTHING was received or the transmitted
// code is complete. Print what we've captured so far, and then reset.
printtransitions (idx);
return;
}
// We didn't time out, store the reading.
transitions [idx += 1] = delays;
delays = 0;
// Similar to above, except waiting for a transition HIGH.
while (!(PIND & IRpinmask)) {
// Pin is still LOW, delay.
delayMicroseconds (RESOLUTION);
if ((delays += RESOLUTION) < MAX_DELAY)
continue;
printtransitions (idx);
return;
}
// We read a high-low-high pulse successfully, continue!
transitions [idx += 1] = delays;
}
}
void printtransitions (int16_t idx) {
if (idx < 0)
return;
Serial.println ("\nReceived:\n H->L L->H");
for (uint8_t i = 0; i <= idx; i += 1) {
uint32_t j = transitions [i];
while ((j *= 10) < 100000) // Columnize values nicely
Serial.print (" ");
Serial.print (transitions [i], DEC);
Serial.print (i & 1 ? " usec\n" : " usec "); // Newline after printing duration for L->H transition.
}
}
dcutler1958 wrote:My next thought is to subtract a "fudge factor" to the call to delayMicrosceonds() to compensate for the time elapsed in actual code execution. Something like the equivalent of:
delays += RESOLUTION;
delayMicroseconds (RESOLUTION - 1);
and see how it works.
The code at line 70 of NECremote.cpp to verify that the 4-bytes of data read is valid is
if ((data[0] == (~data[1] & 0xFF)) && (data[2] == (~data[3] & 0xFF))) {
return data[2];
}
and does not work with my remote. The first two bytes sent by my remote are always 0x00 and 0xBF (even before I modified the code.) The third byte sent identifies the key depressed and the last byte is the 1's complement value of that key identifier.
After fixing the first part of the check, I found the one's complement check "(data[2] == (~data[3] & 0xFF))" fails when key 0 is depressed. I've printed out the values for data[2] and (~data[3] & 0xFF)) and they match in the output but the comparison invariably fails.
BTW, you may notice in the code that I prefer declaring an enum to name a literal rather than using a #define. The first reason for doing so is to ensure the literal expression is a static expression at compile-time. The second reason is mainly a habit I've acquired working on large code systems because most modern debuggers can display the value of an enum but none can display the resulting expression value of a #define (except as the raw text of the define body.) The third reason is that enum literals are declared using the C/C++ scoping rules and #defines are not.
if (*x++ = '\0') ..
temp = *x;
x = x + 1;
if (temp == '\0') ...
var [i++] = value;
var [i = i + 1] = value;
i++; // this is actually an expression, not a statement.
var [i] = value;
i += 1;
var [i] = value;
if (maxwaiting < 0)
timedout = true; // timed out waiting
if (timedout)
return -1;
if (maxwaiting < 0) {
timedout = true; // timed out waiting
return -1;
}
#define DO_DELAY \
delayMicroseconds (RESOLUTION);
#if 0
if (timing) { \
maxwaiting -= RESOLUTION; \
if (maxwaiting < 0) \
return -1; \
}
#endif
// Basic timer-less NEC mini-remote library
// banned license
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
// what our timing resolution should be, larger is better
// as its more 'precise' - but too large and you wont get
// accurate timing
#define RESOLUTION 20
class NECremote {
public:
NECremote (uint8_t pin);
int16_t listen (uint16_t maxwaitseconds = 0);
private:
uint8_t _irpin;
uint8_t _irpinport;
uint8_t _irpinmask;
volatile uint8_t* _irpinreg;
uint8_t timing;
int32_t maxwaiting;
// uint16_t measurePulse(boolean state);
// int8_t readNECbit();
};
// Basic timer-less NEC mini-remote library
// banned license
#include "NECremote.h"
#include "pins_arduino.h"
#include "wiring_private.h"
NECremote::NECremote(uint8_t pin) {
_irpin = pin;
_irpinport = digitalPinToPort(_irpin);
_irpinmask = digitalPinToBitMask(_irpin);
_irpinreg = portInputRegister(_irpinport);
timing = 0;
}
#define IN_RANGE(val, lb, ub) (((val) >= (lb)) && ((val) <= (ub)))
#define OUTRANGE(val, lb, ub) (((val) < (lb)) || ((val) > (ub)))
#define DO_DELAY \
delayMicroseconds (RESOLUTION);
#if 0
if (timing) { \
maxwaiting -= RESOLUTION; \
if (maxwaiting < 0) \
return -1; \
}
#endif
#if 0
uint16_t NECremote::measurePulse (uint8_t statemask) {
uint16_t pulse;
// Wait for the state to change.
// while (((IRpin_PIN >> IRpin) & 0x1) != state) {
while ((*_irpinreg & _irpinmask) != statemask) {
DO_DELAY
}
pulse = 0;
// In the proper state, keep track of the pulse duration.
while ((*_irpinreg & _irpinmask) == statemask) {
DO_DELAY
pulse += 1;
}
return pulse;
}
#endif
#define measurePulse(statemask, counter) \
while ((*_irpinreg & _irpinmask) != statemask) { \
DO_DELAY \
} \
counter = 0; \
while ((*_irpinreg & _irpinmask) == statemask) { \
DO_DELAY \
counter += 1; \
}
#if 0
int8_t NECremote::readNECbit (void) {
int16_t p1;
int16_t p2;
#endif
enum { ZERO_MIN_LO = 400 / RESOLUTION } ;
enum { ZERO_MAX_HI = 700 / RESOLUTION } ;
enum { ONE_MIN_LO = 1400 / RESOLUTION } ;
enum { ONE_MAX_HI = 1800 / RESOLUTION } ;
#if 0
measurePulse (0, p1);
if (IN_RANGE (p1, ZERO_MIN_LO, ZERO_MAX_HI)) {
measurePulse (_irpinmask, p2);
if (IN_RANGE (p2, ZERO_MIN_LO, ZERO_MAX_HI))
return 0; // valid 0 bit
if (IN_RANGE (p2, ONE_MIN_LO, ONE_MAX_HI))
return 1; // valid 1 bit
}
return -1;
}
#endif
#define readNECbit(b) \
measurePulse (0, p1); \
if (IN_RANGE (p1, ZERO_MIN_LO, ZERO_MAX_HI)) { \
measurePulse (_irpinmask, p2); \
if (IN_RANGE (p2, ZERO_MIN_LO, ZERO_MAX_HI)) \
b = 0; \
else \
if (IN_RANGE (p2, ONE_MIN_LO, ONE_MAX_HI)) \
b = 1; \
else \
return -1; \
} \
else \
return -1
int16_t NECremote::listen (uint16_t maxwaitseconds) {
uint16_t p1 = 0;
uint16_t p2 = 0;
enum { LONG_PULSE_MIN = 8000 / RESOLUTION } ;
enum { LONG_PULSE_MAX = 10000 / RESOLUTION } ;
enum { SHORT_PULSE_MIN = 4000 / RESOLUTION } ;
enum { SHORT_PULSE_MAX = 5000 / RESOLUTION } ;
if (maxwaitseconds) {
maxwaiting = maxwaitseconds * 1000000; // to microseconds.
timing = 1;
}
// Wait for starting pulses.
while (OUTRANGE (p1, LONG_PULSE_MIN, LONG_PULSE_MAX) &&
OUTRANGE (p2, SHORT_PULSE_MIN, SHORT_PULSE_MAX)) {
measurePulse (0, p1);
measurePulse (_irpinmask, p2);
}
#if 0
Serial.println ("NEC");
#endif
uint8_t data [4] = { 0, 0, 0, 0 } ;
int8_t b;
for (uint8_t i = 0; i < 32; i += 1) {
readNECbit (b);
if (b < 0)
return -1;
data [i / 8] |= b << (i % 8);
}
#if 0
Serial.print ("0x");
Serial.print(data[0], HEX);
Serial.print(" 0x");
Serial.print(data[1], HEX);
Serial.print(" 0x");
Serial.print(data[2], HEX);
Serial.print(" 0x");
Serial.println(data[3], HEX);
#endif
if (((data [0] + data [1]) == 0xBF) && (data [2] == ((~data [3]) & 0xFF)))
return data[2];
return -1;
}
// Example sketch for NEC remote - public domain
#include "NECremote.h"
// Connect a 38KHz remote control sensor to the pin below
#define IRpin 4
NECremote remote(IRpin);
void setup(void) {
Serial.begin(115200);
Serial.println("Ready to decode IR!");
}
void loop(void) {
// You can set the listen() time out to 'n' seconds
// int c = remote.listen(5); // seconds to wait before timing out!
// Or you can wait 'forever' for a valid code
int c = remote.listen(1); // Without a #, it means wait forever
switch (c) {
case -1: Serial.println ("no code"); break;
case 0: Serial.println ("vol-"); break;
case 1: Serial.println ("play/pause"); break;
case 2: Serial.println ("vol+"); break;
case 4: Serial.println ("setup"); break;
case 5: Serial.println ("up"); break;
case 6: Serial.println ("stop"); break;
case 8: Serial.println ("left"); break;
case 9: Serial.println ("enter"); break;
case 10: Serial.println ("right"); break;
case 12: Serial.println ("0"); break;
case 13: Serial.println ("down"); break;
case 14: Serial.println ("undo"); break;
case 16: Serial.println ("1"); break;
case 17: Serial.println ("2"); break;
case 18: Serial.println ("3"); break;
case 20: Serial.println ("4"); break;
case 21: Serial.println ("5"); break;
case 22: Serial.println ("6"); break;
case 24: Serial.println ("7"); break;
case 25: Serial.println ("8"); break;
case 26: Serial.println ("9"); break;
default: Serial.println ("unknown code"); break;
}
}
I'm at the point of thinking that the timing check code is just too long and that using some other timeout method like a hardware defined timer and handler would be a better choice.
#define CHECK_TIME if (!(ticks -= 1)) return -1
#define StartMultiStmtDef do {
#define EndMultiStmtDef } while (false)
#define MYDEFINE(...)
StartMultiStmtDef \
... \
EndMultiStmtDef
if (...)
MYDEFINE(...);
// Basic timer-less NEC mini-remote library
// banned license
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
// what our timing resolution should be, larger is better
// as its more 'precise' - but too large and you wont get
// accurate timing
#define RESOLUTION 20
class NECremote {
public:
NECremote (uint8_t pin);
int8_t listen (uint8_t maxwaitseconds = 0);
private:
uint8_t _irpin;
uint8_t _irpinport;
uint8_t _irpinmask;
volatile uint8_t* _irpinreg;
#if 0
uint16_t measurePulse(boolean state);
int8_t readNECbit();
#endif
// Basic timer-less NEC mini-remote library
// banned license
#include "NECremote.h"
#include "pins_arduino.h"
#include "wiring_private.h"
NECremote::NECremote(uint8_t pin) {
_irpin = pin;
_irpinport = digitalPinToPort(_irpin);
_irpinmask = digitalPinToBitMask(_irpin);
_irpinreg = portInputRegister(_irpinport);
}
#define IN_RANGE(val, lb, ub) (((val) >= (lb)) && ((val) <= (ub)))
#define OUTRANGE(val, lb, ub) (((val) < (lb)) || ((val) > (ub)))
#define CHECK_TIME if (!(ticks -= 1)) return -1
#if 0
uint16_t NECremote::measurePulse (uint8_t statemask) {
uint16_t pulse;
// Wait for the state to change.
// while (((IRpin_PIN >> IRpin) & 0x1) != state) {
while ((*_irpinreg & _irpinmask) != statemask) {
delayMicroseconds (RESOLUTION);
CHECK_TIME;
}
pulse = 0;
// In the proper state, keep track of the pulse duration.
while ((*_irpinreg & _irpinmask) == statemask) {
delayMicroseconds (RESOLUTION);
CHECK_TIME;
pulse += 1;
}
return pulse;
}
#endif
#define measurePulse(statemask, counter) \
while ((*_irpinreg & _irpinmask) != statemask) { \
delayMicroseconds (RESOLUTION); \
CHECK_TIME; \
} \
counter = 0; \
while ((*_irpinreg & _irpinmask) == statemask) { \
delayMicroseconds (RESOLUTION); \
CHECK_TIME; \
counter += 1; \
}
#if 0
int8_t NECremote::readNECbit (void) {
int16_t p1;
int16_t p2;
#endif
enum { ZERO_MIN_LO = 400 / RESOLUTION } ;
enum { ZERO_MAX_HI = 700 / RESOLUTION } ;
enum { ONE_MIN_LO = 1400 / RESOLUTION } ;
enum { ONE_MAX_HI = 1800 / RESOLUTION } ;
#if 0
p1 = measurePulse (0);
if (OUTRANGE (p1, ZERO_MIN_LO, ZERO_MAX_HI))
return -1;
p2 = measurePulse (_irpinmask);
if (IN_RANGE (p2, ZERO_MIN_LO, ZERO_MAX_HI))
return 0; // valid 0 bit
if (IN_RANGE (p2, ONE_MIN_LO, ONE_MAX_HI))
return 1; // valid 1 bit
return -1;
}
#endif
#define readNECbit(b) \
measurePulse (0, p1); \
if (OUTRANGE (p1, ZERO_MIN_LO, ZERO_MAX_HI)) \
return -1; \
measurePulse (_irpinmask, p2); \
if (IN_RANGE (p2, ZERO_MIN_LO, ZERO_MAX_HI)) \
b = 0; \
else \
if (IN_RANGE (p2, ONE_MIN_LO, ONE_MAX_HI)) \
b = 1; \
else \
return -1
int8_t NECremote::listen (uint8_t maxwaitseconds) {
uint16_t p1 = 0;
uint16_t p2 = 0;
uint32_t ticks = maxwaitseconds ?
maxwaitseconds * (1000000 / RESOLUTION) : 0xFFFFFFFF;
enum { LONG_PULSE_MIN = 8000 / RESOLUTION } ;
enum { LONG_PULSE_MAX = 10000 / RESOLUTION } ;
enum { SHORT_PULSE_MIN = 4000 / RESOLUTION } ;
enum { SHORT_PULSE_MAX = 5000 / RESOLUTION } ;
// Wait for starting pulses.
while (OUTRANGE (p1, LONG_PULSE_MIN, LONG_PULSE_MAX) &&
OUTRANGE (p2, SHORT_PULSE_MIN, SHORT_PULSE_MAX)) {
#if 0
p1 = measurePulse (0);
p2 = measurePulse (_irpinmask);
#endif
measurePulse (0, p1);
measurePulse (_irpinmask, p2);
}
#if 0
Serial.println ("NEC");
#endif
uint8_t data [4] = { 0, 0, 0, 0 } ;
int8_t b;
for (uint8_t i = 0; i < 32; i += 1) {
#if 0
b = readNECbit ();
#endif
readNECbit (b);
if (b < 0)
return -1;
data [i / 8] |= b << (i % 8);
}
#if 0
Serial.print ("0x");
Serial.print(data[0], HEX);
Serial.print(" 0x");
Serial.print(data[1], HEX);
Serial.print(" 0x");
Serial.print(data[2], HEX);
Serial.print(" 0x");
Serial.println(data[3], HEX);
#endif
if (((data [0] + data [1]) == 0xBF) && (data [2] == ((~data [3]) & 0xFF)))
return data[2];
return -1;
}
// Example sketch for NEC remote - public domain
#include "NECremote.h"
// Connect a 38KHz remote control sensor to the pin below
#define IRpin 4
NECremote remote(IRpin);
void setup(void) {
Serial.begin(115200);
Serial.println("Ready to decode IR!");
}
void loop(void) {
int c = remote.listen (5); // Without a #, or specifying 0 means wait forever
switch (c) {
case -1: Serial.println ("no code"); break;
case 0: Serial.println ("vol-"); break;
case 1: Serial.println ("play/pause"); break;
case 2: Serial.println ("vol+"); break;
case 4: Serial.println ("setup"); break;
case 5: Serial.println ("up"); break;
case 6: Serial.println ("stop"); break;
case 8: Serial.println ("left"); break;
case 9: Serial.println ("enter"); break;
case 10: Serial.println ("right"); break;
case 12: Serial.println ("0"); break;
case 13: Serial.println ("down"); break;
case 14: Serial.println ("undo"); break;
case 16: Serial.println ("1"); break;
case 17: Serial.println ("2"); break;
case 18: Serial.println ("3"); break;
case 20: Serial.println ("4"); break;
case 21: Serial.println ("5"); break;
case 22: Serial.println ("6"); break;
case 24: Serial.println ("7"); break;
case 25: Serial.println ("8"); break;
case 26: Serial.println ("9"); break;
default: Serial.println ("unknown code"); break;
}
}
readNECbit (b);
if (b < 0)
return -1;
I still remember keying in my first assembler program and debugging it on an 11-10 using just the lights and switches on the front of the CPU (no disk, no paper tape or punched cards, no querty keyboard, no download from another system, just keying in 1's and 0's manually).
Return to Other Adafruit products
Users browsing this forum: No registered users and 5 guests