-
-
Save christer-watson/5efc1ea7bd8d7c4f74cd8a00bfdc69b6 to your computer and use it in GitHub Desktop.
| /* | |
| * tiny_IRremote | |
| * Version 0.2 July, 2016 | |
| * Christian D'Abrera | |
| * Fixed what was originally rather broken code from http://www.gammon.com.au/Arduino/ | |
| * ...itself based on work by Ken Shirriff. | |
| * | |
| * This code was tested for both sending and receiving IR on an ATtiny85 DIP-8 chip. | |
| * IMPORTANT: IRsend only works from PB4 ("pin 4" according to Arduino). You will need to | |
| * determine which physical pin this corresponds to for your chip, and connect your transmitter | |
| * LED there. | |
| * | |
| * Copyright 2009 Ken Shirriff | |
| * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html | |
| * | |
| * Interrupt code based on NECIRrcv by Joe Knapp | |
| * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 | |
| * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ | |
| */ | |
| #include "tiny_IRremote.h" | |
| #include "tiny_IRremoteInt.h" | |
| // Provides ISR | |
| #include <avr/interrupt.h> | |
| volatile irparams_t irparams; | |
| void IRsend::sendNEC(unsigned long data, int nbits) | |
| { | |
| enableIROut(38); | |
| mark(NEC_HDR_MARK); | |
| space(NEC_HDR_SPACE); | |
| for (int i = 0; i < nbits; i++) { | |
| if (data & TOPBIT) { | |
| mark(NEC_BIT_MARK); | |
| space(NEC_ONE_SPACE); | |
| } | |
| else { | |
| mark(NEC_BIT_MARK); | |
| space(NEC_ZERO_SPACE); | |
| } | |
| data <<= 1; | |
| } | |
| mark(NEC_BIT_MARK); | |
| space(0); | |
| } | |
| void IRsend::mark(int time) { | |
| // Sends an IR mark for the specified number of microseconds. | |
| // The mark output is modulated at the PWM frequency. | |
| TCCR1 |= _BV(COM1A1); // Enable pin PWM output (PB1 - Arduino D4) | |
| delayMicroseconds(time); | |
| } | |
| /* Leave pin off for time (given in microseconds) */ | |
| void IRsend::space(int time) { | |
| // Sends an IR space for the specified number of microseconds. | |
| // A space is no output, so the PWM output is disabled. | |
| TCCR1 &= ~(_BV(COM1A1)); // Disable pin PWM output (PB1 - Arduino D4) | |
| delayMicroseconds(time); | |
| } | |
| void IRsend::enableIROut(int khz) { | |
| // Enables IR output. The khz value controls the modulation frequency in kilohertz. | |
| // The IR output will be on pin (PB1 - Arduino D) (OC1A). | |
| // This routine is designed for 36-40KHz; if you use it for other values, it's up to you | |
| // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.) | |
| // TIMER1 is used in fast PWM mode, with OCR1Ccontrolling the frequency and OCR1A | |
| // controlling the duty cycle. | |
| // There is no prescaling, so the output frequency is 8MHz / (2 * OCR1C) | |
| // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin. | |
| // A few hours staring at the ATmega documentation and this will all make sense. | |
| // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details. | |
| // Disable the Timer1 Interrupt (which is used for receiving IR) | |
| TIMSK &= ~_BV(TOIE1); //Timer1 Overflow Interrupt | |
| pinMode(1, OUTPUT); // (PBA - Arduino D - physical pin ) | |
| digitalWrite(1, LOW); // When not sending PWM, we want it low | |
| // CTC1 = 1: TOP value set to OCR1C | |
| // CS = 0001: No Prescaling | |
| // TCCR1 = _BV(CTC1) | _BV(CS10); | |
| // PWM1A = 1: Enable PWM for OCR1A | |
| // GTCCR = _BV(PWM1A); | |
| // perhaps this should be instead...? | |
| // TCCR1 = _BV(PWM1A); | |
| //or... | |
| TCCR1 = _BV(PWM1A) | _BV(CTC1) | _BV(CS10); | |
| //or... | |
| //TCCR1 = _BV(PWM1A) | 3<<COM1A0 | _BV(CS10); | |
| // The top value for the timer. The modulation frequency will be SYSCLOCK / OCR1C. | |
| OCR1C = SYSCLOCK / khz / 1000; | |
| OCR1A = OCR1C / 3; // 33% duty cycle | |
| } |
| /* | |
| * tiny_IRremote | |
| * Version 0.2 July, 2016 | |
| * Christian D'Abrera | |
| * Fixed what was originally rather broken code from http://www.gammon.com.au/Arduino/ | |
| * ...itself based on work by Ken Shirriff. | |
| * | |
| * This code was tested for both sending and receiving IR on an ATtiny85 DIP-8 chip. | |
| * IMPORTANT: IRsend only works from PB4 ("pin 4" according to Arduino). You will need to | |
| * determine which physical pin this corresponds to for your chip, and connect your transmitter | |
| * LED there. | |
| * | |
| * Copyright 2009 Ken Shirriff | |
| * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com | |
| * | |
| * Interrupt code based on NECIRrcv by Joe Knapp | |
| * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 | |
| * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ | |
| */ | |
| #ifndef tiny_IRremote_h | |
| #define tiny_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, UNKNOWN | |
| unsigned long value; // Decoded value | |
| 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 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); | |
| 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 decodeRC5(decode_results *results); | |
| long decodeRC6(decode_results *results); | |
| } | |
| ; | |
| // 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 sendRaw(unsigned int buf[], int len, int hz); | |
| void sendRC5(unsigned long data, int nbits); | |
| void sendRC6(unsigned long data, int nbits); | |
| // private: | |
| void enableIROut(int khz); | |
| VIRTUAL void mark(int usec); | |
| VIRTUAL void space(int usec); | |
| } | |
| ; | |
| // Some useful constants | |
| #define USECPERTICK 50 // microseconds per clock interrupt tick | |
| #define RAWBUF 76 // Length of raw duration buffer | |
| // Marks tend to be 100us too long, and spaces 100us too short | |
| // when received due to sensor lag. | |
| #define MARK_EXCESS 100 | |
| #endif |
| /* | |
| * tiny_IRremote | |
| * Version 0.2 July, 2016 | |
| * Christian D'Abrera | |
| * Fixed what was originally rather broken code from http://www.gammon.com.au/Arduino/ | |
| * ...itself based on work by Ken Shirriff. | |
| * | |
| * This code was tested for both sending and receiving IR on an ATtiny85 DIP-8 chip. | |
| * IMPORTANT: IRsend only works from PB4 ("pin 4" according to Arduino). You will need to | |
| * determine which physical pin this corresponds to for your chip, and connect your transmitter | |
| * LED there. | |
| * | |
| * Copyright 2009 Ken Shirriff | |
| * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html | |
| * | |
| * Interrupt code based on NECIRrcv by Joe Knapp | |
| * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 | |
| * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ | |
| */ | |
| #ifndef tiny_IRremoteint_h | |
| #define tiny_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 4 // TIMER1 clock prescale | |
| #if defined (F_CPU) | |
| #define SYSCLOCK F_CPU // main Arduino clock | |
| #else | |
| #define SYSCLOCK 8000000 // default ATtiny clock | |
| #endif | |
| #define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000) // timer clocks per microsecond | |
| #define ERR 0 | |
| #define DECODED 1 | |
| // 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_COUNT1 (CLK - USECPERTICK*CLKSPERUSEC + CLKFUDGE) | |
| #define RESET_TIMER1 TCNT1 = INIT_TIMER_COUNT1 | |
| // 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 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 tiny_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 | |
| 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 tiny_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 MIN_RC5_SAMPLES 11 | |
| #define MIN_RC6_SAMPLES 1 | |
| #endif | |
I think this is the code I used for sending NEC IR codes from a home-built remote control, so a lot of the code is dealing with looking for button pushes
`/* IR Remote Wand v2 - see http://www.technoblogy.com/show?25TN
David Johnson-Davies - www.technoblogy.com - 13th May 2018
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 <avr/sleep.h>
#include <tiny_IRremote.h>
#include <tiny_IRremoteInt.h>
IRsend irsend;
// IR transmitter **********************************************
// Buttons
const int S1 = 4;
const int S2 = 3;
const int S3 = 5; // Reset
const int S4 = 2;
const int S5 = 0;
const int LED = 1; // IR LED output
// Pin change interrupt service routine
ISR (PCINT0_vect) {
int in = PINB;
if ((in & 1<<S1) == 0)
{
irsend.sendNEC(0x61A00AF5,32); // HDMI toggle
}
else if ((in & 1<<S2) == 0)
{
irsend.sendNEC(0x61A0B04F,32); // vol down
delay(300);
while ((PINB & 1<<S2) == 0)
{
irsend.sendNECrepeat(); // repeat
}
}
else if ((in & 1<<S4) == 0)
{
irsend.sendNEC(0x61A030CF,32); // vol up
delay(300);
while ((PINB & 1<<S4) == 0)
{
irsend.sendNECrepeat(); // repeat
delay(200);
}
}
else if ((in & 1<<S5) == 0)
{
irsend.sendNEC(0x61A0F00F,32); // powerup
}
}
// Setup demo **********************************************
void setup() {
// pinMode(LED, OUTPUT);
pinMode(S1, INPUT_PULLUP);
pinMode(S2, INPUT_PULLUP);
pinMode(S4, INPUT_PULLUP);
pinMode(S5, INPUT_PULLUP);
// Configure pin change interrupts to wake on button presses
PCMSK = 1<<S1 | 1<<S2 | 1<<S4 | 1<<S5;
GIMSK = 1<<PCIE; // Enable interrupts
GIFR = 1<<PCIF; // Clear interrupt flag
// Disable what we don't need to save power
ADCSRA &= ~(1<<ADEN); // Disable ADC
PRR = 1<<PRUSI | 1<<PRADC; // Turn off clocks to unused peripherals
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
// Send S3 code on reset
// Send('R', 0x0013, 0x000C);
}
// Stay asleep and just respond to interrupts
void loop() {
sleep_enable();
sleep_cpu();
}`
Thanks ill check it out.
Any chance of adding some examples?
Im looking to receive a NEC code and send a different NEC code using an ATTiny85.
New Google Chromecast (CCWGTV) doesnt list all TVs.