/************************************************************************* IRrecorder_Raw_TeensyLC.ino V1.0 Pin 3 is usually the input interrupt pin Pin 4 is set to GND Pin 5 is set to VCC (5V or 3V3 depending on the board Plug the TMPS58000 IR receiver into pins 3,4,5 (looking from the front of the IR reveiver, VCC is on the right, plug it into pin 5) #define RAW // sets Raw() ascii output. Other wise AnalysIR binary output is produced see IRrecoder_AnalysIR_Teensy.ino The entire Raw ():, ... can be copied and pasted into AnalysIR's ImportIR window for decoding OR you can add the frequency (rounded to nearest kHZ to the front of the data and use it directly in IR_Remote_TX e.g. v add freq in kHZ here in front of the raw data unsigned int panasonic_tv_av[] = {38, 3440, 1764, 408, 460, 408, 1320, 412, 456, 408, 460, 404, 460, 408, 456, 408, 460, 408, 456, 408, 460, 404, 460, 408, 460, 404, 460, 404, 464, 404, 1324, 408, 460, 404, 460, 416, 448, 408, 460, 408, 456, 408, 460, 408, 456, 408, 460, 408, 456, 408, 1324, 416, 452, 404, 460, 404, 460, 408, 460, 404, 460, 408, 460, 404, 460, 408, 460, 404, 1324, 408, 460, 404, 1324, 408, 460, 408, 456, 408, 460, 408, 456, 408, 460, 408, 1320, 412, 456, 408, 1324, 408, 460, 404, 460, 404, 460, 408, 456, 408, 1324 408}; then add this code to the cmd IR_DATA struct {.data = (uint8_t*)&panasonic_tv_av, .len = sizeof(panasonic_tv_av), .repeatInterval = 0, .codeType = RAW_code, .cmd = 'a'} // no repeat for this button see IR_Remote_TX.ino and www.forward.com.au/pfod/HomeAutomation/WiFi_IR_Remote/index.html for more details. If copying directly into IR_Remote_TX.ino press and release the remote button very quickly and choose the output with the shortest data len to avoid repeats. Also check for an unusually large number in the output which will be the gap between the sends Try to confirm this by holding the remote's button down to force a repeat and then compare the two lines of data. If #define RAW is commented out then the output is in binary and can be feed directly into AnalysIR via its Arduino source COM port. and the the result exported from there in a number of formats. IRrecorder_Raw_Teensy is modified from Poor Maker's Infrared receiver V1.0 Author: AnalysIR Copyright: AnalysIR Free to use, provided AnalysIR is credited and a link to http://www.AnalysIR.com/blog is included in the source and any related article or publication. Contact: via our blog at http://www.analysir.com/blog/contact/ Get your own copy of AnalysIR >>>: http://www.analysir.com/blog/get-analysir/ Modified by Matthew Ford Modifications Copyright: Forward Computing and Control Pty. Ltd. (www.forward.com.au) Free to use, provided, in addition to above creditation, Forward Computing and Control Pty. Ltd. is credited and a link to www.forward.com.au/pfod/HomeAutomation/WiFi_IR_Remote/index.html is included in the source and any related article or publication. The modification by Forward -- customized code for TeensyLC memory size -- improve the estimatation of the modulation frequency -- improved reject invalid signals -- added ASCII output format the output so that it can be copied and pasted into AnalysIR ImportIR screen for decoding The following boards should work using Pin 3 i.e. digitalPinToInterrupt(3) is valid. but need to check available memory for pulseIR[] i.e. set maxPULSE to a suitable size depending on available RAM Arduino328, UNO, Yun, Leonardo, Mega1280, Mega2560, TeensyLC etc ************************************************************************ */ #define RAW // sets Raw() ascii output. Other wise AnalysIR binary output is produced see IRrecoder_AnalysIR_Teensy.ino // this pin seems to work for most boards. If not check which pin returns digitalPinToInterrupt(INTERRUPT_PIN) != -1 #define INTERRUPT_PIN 3 volatile unsigned long spaceLen = 0; unsigned long lastSpaceLen = 0; volatile unsigned long markLen = 0; volatile unsigned long thisChange = 0; volatile unsigned long lastChange = 0; volatile unsigned long lastChangeSafe = 0; //avoids changes by ISR volatile unsigned long spaceStart = 0; volatile unsigned long markStart = 0; volatile unsigned long pulseCount = 0; unsigned long dataCount = 0; unsigned long firstPulseCount = 0; unsigned long firstMarkLen = 0; unsigned long freq = 0; bool invalid = false; // set to true if freq not valid // range of valid frequencies unsigned long validFreqUpper = 100; unsigned long validFreqLower = 20; bool newIR = true; const size_t maxPULSES = 1024; // uses 4K, set for TeensyLC with 8K Ram size_t pulseIdx = 0; uint16_t pulseIR[maxPULSES]; //temp store for pulse durations (demodulated) pulse lengths > 0xffff are split across multiple entries unsigned long usLoop; uint16_t timingAdjustment = 64; // add to mark subtract from space to adjust for delay in interrupt method detecting end of mark i.e. >50 #define SIGNALGAP 125000 //determines gap between signals (typical range 100000->125000) size_t outputIdx = 0; //Serial Tx buffer - uses Serial.write for faster execution byte txBuffer[4]; //Key(+-)/1,count/1,value/2 <= format of packet sent to AnalysIR over serial void setup() { pinMode(3, INPUT_PULLUP); // add a pullup for TSMP58000 input pinMode(4, OUTPUT); pinMode(5, OUTPUT); digitalWrite(4, LOW); // GND for TSMP58000 digitalWrite(5, HIGH); // VCC for TSMP58000 Serial.begin(115200); while (!Serial); // enable interrupts attachInterrupt(digitalPinToInterrupt(3), rxIR_Interrupt_Handler, FALLING); //set up interrupt handler for IR rx on pin 3 - raw signal newIR = true; usLoop = micros(); pulseCount = 0; //reset values for next signal markLen = 0; markStart = usLoop; spaceStart = usLoop; lastChange = usLoop; pulseIdx = 0; lastChange = usLoop; #ifndef RAW Serial.println(F("!AnalysIR!")); // HELLO STRING - ALL COMMENTS SENT IN !....! FORMAT #else inputKeyName(); #endif } void inputKeyName() { // clear input while (Serial.available()) { Serial.read(); } Serial.println(" Enter next button name: "); } void loop() { while (true) { //endless loop, wait for the action! #ifdef RAW if (Serial.available()) { Serial.print((char)Serial.read()); } #endif if (markLen > 0) { //High markLen += timingAdjustment; if (newIR) { outputIdx = 0; newIR = false; invalid = false; firstPulseCount = pulseCount; firstMarkLen = markLen; // check first freq if <20kHz or >= 100kHz skip this one freq = ((firstPulseCount * 1000) / firstMarkLen); if ((freq < validFreqLower) || (freq > validFreqUpper) || (markLen < 1000)) { // first mark has to be > 1000uS == 1mS == 20 to 100 pulses min // wait for next space gap #ifdef DEBUG Serial.print("Invalid signal freq : "); Serial.print(freq); Serial.print(" firstPulseCount:"); Serial.print(firstPulseCount); Serial.print(" firstMarkLen:"); Serial.print(firstMarkLen); Serial.println(" "); #endif invalid = true; firstPulseCount = 0; firstMarkLen = 0; pulseCount = 0; markLen = 0; pulseCount = 0; } if (!invalid) { dataCount = 0; pulseIdx = 0; } } else { if (!invalid) { } } if (!invalid) { while (markLen > 0xFFFF) { //this allows for a mark/space of greater than 65535 uSecs (0xFFFF), ignore first signal markLen -= 65535; //this assumes the length is not longer than 131070 if (pulseIdx < maxPULSES) { pulseIR[pulseIdx++] = 65535 | 0x0001; } } if (pulseIdx < maxPULSES) { pulseIR[pulseIdx++] = markLen | 0x0001; } dataCount++; // number of unsplit marks / spaces } markLen = 0; if ((spaceLen < SIGNALGAP) && (spaceLen > 0)) { //LOW spaceLen -= timingAdjustment; if (!invalid) { while (spaceLen > 0xFFFF) { //this allows for a mark/space of greater than 65535 uSecs (0xFFFF), ignore first signal spaceLen -= 65535; if (pulseIdx < maxPULSES) { pulseIR[pulseIdx++] = 65535 & 0xFFFE; } } if (pulseIdx < maxPULSES) { pulseIR[pulseIdx++] = spaceLen & 0xFFFE; } dataCount++; // number of unsplit marks / spaces } } spaceLen = 0; lastChangeSafe = spaceStart; // prevents update of value by ISR } usLoop = micros(); if ((pulseIdx > 0) && ((usLoop - lastChangeSafe) > SIGNALGAP) && (markLen == 0) && (spaceLen == 0)) { //last mark in sequence markLen = spaceStart - markStart; // final markLen markLen += timingAdjustment; if (!invalid) { while (markLen > 0xFFFF) { //this allows for a mark/space of greater than 65535 uSecs (0xFFFF), ignore first signal markLen -= 65535;//this assumes the length is not longer than 131070 if (pulseIdx < maxPULSES) { pulseIR[pulseIdx++] = 65535 | 0x0001; } } if (pulseIdx < maxPULSES) { pulseIR[pulseIdx++] = markLen | 0x0001; } dataCount++; // number of unsplit marks / spaces size_t idxEnd = pulseIdx; #ifndef RAW Serial.println(F("!AnalysIR!")); // HELLO STRING - ALL COMMENTS SENT IN !....! FORMAT // output in AnalysIR binary format for direct connection to AnalysIR com input // add a leading space to match what AnalysIR displays for the Raw format output size_t counter = 0; unsigned long zeroSpace = 1000; txBuffer[0] = '-'; txBuffer[1] = (byte) (counter & 0xFF); //count txBuffer[3] = zeroSpace >> 8; //byte 1 txBuffer[2] = zeroSpace & 0xFE; //LSB 0 ..remove lat bit as it was State Serial.write(txBuffer, 4); for (size_t i = 0; i < idxEnd; i++) { counter++; if (pulseIR[i] & 0x01) { txBuffer[0] = '+'; } else { txBuffer[0] = '-'; } txBuffer[1] = (byte) (counter & 0xFF); //count txBuffer[3] = pulseIR[i] >> 8; //byte 1 txBuffer[2] = pulseIR[i] & 0xFE; //LSB 0 ..remove lat bit as it was State Serial.write(txBuffer, 4); } unsigned long nanoSecPeriod = firstMarkLen * 1000 / firstPulseCount; //get it in nano secs // // now send over serial using buffer txBuffer[0] = 'M'; //Modulation report is sent as 'M' txBuffer[1] = firstPulseCount; //number of samples used txBuffer[3] = nanoSecPeriod >> 8 & 0xFF; //byte Period MSB txBuffer[2] = nanoSecPeriod & 0xFF; //byte Period LSB Serial.write(txBuffer, 4); Serial.println(); #ifdef DEBUG Serial.print("!!M "); Serial.print(firstPulseCount); Serial.print(" "); Serial.print(nanoSecPeriod); Seral.println("!!") #endif #else Serial.print("Raw ("); Serial.print(dataCount); Serial.print("):"); // collect first pulse bool markPulse = true; if (pulseIR[0] & 0x01) { markPulse = true; } else { markPulse = false; } bool currentMarkPulse = markPulse; unsigned long pulseWidth = pulseIR[0] & 0xFFFE; bool firstMark = true; // process the following pulses // add together sequential marks or sequential spaces // and output once sequence stops for (size_t i = 1; i < idxEnd; i++) { if (pulseIR[i] & 0x01) { markPulse = true; } else { markPulse = false; } if (markPulse != currentMarkPulse) { // switched from mark/space // output current total if (!firstMark) { Serial.print(','); } else { // skip first , firstMark = false; } if (currentMarkPulse) { Serial.print('+'); } else { Serial.print('-'); } Serial.print(pulseWidth); pulseWidth = (pulseIR[i] & 0xFFFE); //LSB 0 ..remove last bit as it was State currentMarkPulse = markPulse; } else { pulseWidth += (pulseIR[i] & 0xFFFE); } } // output final one Serial.print(','); if (currentMarkPulse) { Serial.print('+'); } else { Serial.print('-'); } Serial.print(pulseWidth & 0xFFFE); //LSB 0 ..remove lat bit as it was State Serial.println(); Serial.print("Modulation Frequency: "); Serial.print((firstPulseCount * 1000000) / firstMarkLen); Serial.print(" (Hz)"); Serial.println(""); Serial.println(); inputKeyName(); #endif } newIR = true; pulseCount = 0; //reset values for next signal markLen = 0; spaceLen = 0; markStart = usLoop; spaceStart = usLoop; lastChange = usLoop; pulseIdx = 0; } } } void rxIR_Interrupt_Handler(void) { //ISR for IR signals //on falling edge so pin 3 will always be LOW here // _________|||||||||______________||||||||||||||_______________||||||||||||||||||___________|||||||||||||||| etc thisChange = micros(); //capture timestamp only once in ISR if ((thisChange - lastChange) > 50) {//start of mark / end of space works for carriers down to ~20kHz //so calculate previous space & mark lengths spaceLen = thisChange - spaceStart ; markLen = thisChange - markStart - spaceLen; markStart = thisChange; //spaceStart=0; } else { //repeatedly update this bit until last modulation of mark spaceStart = thisChange; } pulseCount++; lastChange = thisChange; }