/* IR Remote Control Detective v5 - see http://www.technoblogy.com/show?24A9 David Johnson-Davies - www.technoblogy.com - 28th January 2024 ATtiny85 @ 1 MHz (internal oscillator; BOD disabled) CC BY 4.0 Licensed under a Creative Commons Attribution 4.0 International license: http://creativecommons.org/licenses/by/4.0/ */ #include // OLED I2C 128 x 32 monochrome display ********************************************** int Scale = 2; const int OLEDAddress = 0x3C; // Initialisation sequence for OLED module int const InitLen = 24; const unsigned char Init[InitLen] PROGMEM = { 0xAE, // Display off 0xD5, // Set display clock 0x80, // Recommended value 0xA8, // Set multiplex 0x1F, 0xD3, // Set display offset 0x00, 0x40, // Zero start line 0x8D, // Charge pump 0x14, 0x20, // Memory mode 0x01, // Vertical addressing 0xA1, // 0xA0/0xA1 flip horizontally 0xC8, // 0xC0/0xC8 flip vertically 0xDA, // Set comp ins 0x02, 0x81, // Set contrast 0x7F, // 0x00 to 0xFF 0xD9, // Set pre charge 0xF1, 0xDB, // Set vcom detect 0x40, 0xA6, // Normal (0xA7=Inverse) 0xAF // Display on }; const int data = 0x40; const int single = 0x80; const int command = 0x00; void InitDisplay () { Wire.beginTransmission(OLEDAddress); Wire.write(command); for (uint8_t c=0; c>8); } } } Wire.endTransmission(); } // Plot text starting at the current plot position void PlotText (PGM_P s, int line, int column) { int p = (int)s; while (1) { char c = pgm_read_byte(p++); if (c == 0) return; PlotChar(c, line, column); column = column + 6 * Scale; } } // Display a 4-digit hexadecimal number starting at line, column void PlotHex (unsigned int hex, int line, int column) { for (unsigned int d=0x1000; d>0; d=d/16) { uint8_t h = (hex/d) % 16; char c = (h < 10) ? h + '0' : h - 10 + 'A'; PlotChar(c, line, column); column = column + Scale*6; } } // NEC ********************************************** void ReceivedCode(char IRtype, unsigned int Address, unsigned int Command) { if (IRtype>32) { PlotChar(IRtype,1,0); Scale = 1; PlotChar(' ',3,0); PlotChar(' ',3,6); Scale = 2; } else { PlotChar('S',1,0); Scale = 1; PlotChar((IRtype/10)+'0',3,0); PlotChar((IRtype%10)+'0',3,6); Scale = 2; } PlotHex(Address, 0, 72); PlotHex(Command, 2, 72); } // Globals volatile unsigned long RecdData; volatile int Bit, Edge; volatile char IRtype; // Protocol timings const int Micros = 64; // Number of microseconds per TCNT1 count const int SonyIntro = 2400/Micros; const int SonyMean = 900/Micros; const int NECIntro = 9000/Micros; const int NECGap = 4500/Micros; const int NECPulse = 562/Micros; const int NECMean = 1125/Micros; const int SamsungIntro = 5000/Micros; const int SamsungGap = 5000/Micros; const int RC5Half = 889/Micros; // 0.889ms const int RC5Full = 1778/Micros; const int RC5Mean = 1334/Micros; // Interrupt service routine - called on Timer/Counter1 overflow ISR(TIMER1_OVF_vect) { ReceivedCode(Bit, RecdData>>7, RecdData & 0x7F); TIMSK = TIMSK & ~(1<>PINB3 & 1)); // Ignore if wrong edge else if (IRtype == 0) { // End of intro pulse if (abs(Time - RC5Half) < 5) { IRtype = 'R'; RecdData = 0x2000; Bit = 12; Edge = 0; Mid = 0; } else if (abs(Time - RC5Full) < 5) { IRtype = 'R'; RecdData = 0x2000; Bit = 11; Edge = 0; Mid = 1; } else if ((abs(Time - SonyIntro) < 5) && (Edge == 1)) { IRtype = 'S'; RecdData = 0; Bit = 0; TIMSK = TIMSK | 1<>6 & 0x1F, (~(RecdData>>6) & 0x40) | (RecdData & 0x3F)); Bit--; } } else if (IRtype == 'S') { if (Time > SonyMean) RecdData = RecdData | ((unsigned long) 1< NECMean && Bit >= 0) RecdData = RecdData | ((unsigned long) 1<>16); } TCNT1 = 0; // Clear counter TIFR = TIFR | 1<