-
-
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.