IRremote
irSend.cpp
Go to the documentation of this file.
1 #include "IRremote.h"
2 
3 #ifdef SENDING_SUPPORTED
4 //+=============================================================================
5 void IRsend::sendRaw(const unsigned int buf[], unsigned int len, unsigned int hz) {
6  // Set IR carrier frequency
7  enableIROut(hz);
8 
9  for (unsigned int i = 0; i < len; i++) {
10  if (i & 1) {
11  space(buf[i]);
12  } else {
13  mark(buf[i]);
14  }
15  }
16 
17  space(0); // Always end with the LED off
18 }
19 
20 void IRsend::sendRaw_P(const unsigned int buf[], unsigned int len, unsigned int hz) {
21 #if !defined(__AVR__)
22  sendRaw(buf,len,hz); // Let the function work for non AVR platforms
23 #else
24  // Set IR carrier frequency
25  enableIROut(hz);
26 
27  for (unsigned int i = 0; i < len; i++) {
28  uint16_t duration = pgm_read_word_near(buf + sizeof(uint16_t) * i);
29  if (i & 1) {
30  space(duration);
31  } else {
32  mark(duration);
33  }
34  }
35  space(0); // Always end with the LED off
36 #endif
37 
38 }
39 
40 #ifdef USE_SOFT_CARRIER
41 void inline IRsend::sleepMicros(unsigned long us) {
42 #ifdef USE_SPIN_WAIT
43  sleepUntilMicros(micros() + us);
44 #else
45  if (us > 0U) { // Is this necessary? (Official docu https://www.arduino.cc/en/Reference/DelayMicroseconds does not tell.)
46  delayMicroseconds((unsigned int) us);
47  }
48 #endif
49 }
50 
51 void inline IRsend::sleepUntilMicros(unsigned long targetTime) {
52 #ifdef USE_SPIN_WAIT
53  while (micros() < targetTime)
54  ;
55 #else
56  unsigned long now = micros();
57  if (now < targetTime) {
58  sleepMicros(targetTime - now);
59  }
60 #endif
61 }
62 #endif // USE_SOFT_CARRIER
63 
64 //+=============================================================================
65 // Sends an IR mark for the specified number of microseconds.
66 // The mark output is modulated at the PWM frequency.
67 //
68 
69 void IRsend::mark(unsigned int time) {
70 #ifdef USE_SOFT_CARRIER
71  unsigned long start = micros();
72  unsigned long stop = start + time;
73  if (stop + periodTime < start) {
74  // Counter wrap-around, happens very seldomly, but CAN happen.
75  // Just give up instead of possibly damaging the hardware.
76  return;
77  }
78  unsigned long nextPeriodEnding = start;
79  unsigned long now = micros();
80  while (now < stop) {
81  SENDPIN_ON(sendPin);
82  sleepMicros (periodOnTime);
83  SENDPIN_OFF(sendPin);
84  nextPeriodEnding += periodTime;
85  sleepUntilMicros(nextPeriodEnding);
86  now = micros();
87  }
88 #elif defined(USE_NO_CARRIER)
89  digitalWrite(sendPin, LOW); // Set output to active low.
90 #else
91  TIMER_ENABLE_PWM; // Enable pin 3 PWM output
92  if (time > 0) {
93  custom_delay_usec(time);
94  }
95 #endif
96 }
97 
98 //+=============================================================================
99 // Leave pin off for time (given in microseconds)
100 // Sends an IR space for the specified number of microseconds.
101 // A space is no output, so the PWM output is disabled.
102 //
103 void IRsend::space(unsigned int time) {
104 #if defined(USE_NO_CARRIER)
105  digitalWrite(sendPin, HIGH); // Set output to inactive high.
106 #else
107  TIMER_DISABLE_PWM; // Disable pin 3 PWM output
108 #endif
109  if (time > 0) {
111  }
112 }
113 
114 #ifdef USE_DEFAULT_ENABLE_IR_OUT
115 //+=============================================================================
116 // Enables IR output. The khz value controls the modulation frequency in kilohertz.
117 // The IR output will be on pin 3 (OC2B).
118 // This routine is designed for 36-40KHz; if you use it for other values, it's up to you
119 // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
120 // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
121 // controlling the duty cycle.
122 // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
123 // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
124 // A few hours staring at the ATmega documentation and this will all make sense.
125 // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
126 //
127 void IRsend::enableIROut(int khz) {
128 #ifdef USE_SOFT_CARRIER
129  periodTime = (1000U + khz / 2) / khz; // = 1000/khz + 1/2 = round(1000.0/khz)
130  periodOnTime = periodTime * DUTY_CYCLE / 100U - PULSE_CORRECTION;
131 #endif
132 
133 #if defined(USE_NO_CARRIER)
134  pinMode(sendPin, OUTPUT);
135  digitalWrite(sendPin, HIGH); // Set output to inactive high.
136 #else
137  // Disable the Timer2 Interrupt (which is used for receiving IR)
138  TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
139 
140  pinMode(sendPin, OUTPUT);
141 
142  SENDPIN_OFF(sendPin); // When not sending, we want it low
143 
144  // COM2A = 00: disconnect OC2A
145  // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
146  // WGM2 = 101: phase-correct PWM with OCRA as top
147  // CS2 = 000: no prescaling
148  // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A.
149  TIMER_CONFIG_KHZ(khz);
150 #endif
151 }
152 #endif
153 
154 //+=============================================================================
155 // Custom delay function that circumvents Arduino's delayMicroseconds limit
156 
157 void IRsend::custom_delay_usec(unsigned long uSecs) {
158  if (uSecs > 4) {
159  unsigned long start = micros();
160  unsigned long endMicros = start + uSecs - 4;
161  if (endMicros < start) { // Check if overflow
162  while (micros() > start) {
163  } // wait until overflow
164  }
165  while (micros() < endMicros) {
166  } // normal wait
167  }
168  //else {
169  // __asm__("nop\n\t"); // must have or compiler optimizes out
170  //}
171 }
172 
173 #endif // SENDING_SUPPORTED
IRsend::custom_delay_usec
void custom_delay_usec(unsigned long uSecs)
Definition: irSend.cpp:157
IRsend::mark
void mark(unsigned int usec)
Definition: irSend.cpp:69
IRsend::enableIROut
void enableIROut(int khz)
Definition: irSend.cpp:127
IRsend::sendRaw_P
void sendRaw_P(const unsigned int buf[], unsigned int len, unsigned int hz)
Definition: irSend.cpp:20
PULSE_CORRECTION
#define PULSE_CORRECTION
If USE_SOFT_CARRIER or USE_NO_CARRIER, this amount (in micro seconds) is subtracted from the on-time ...
Definition: IRremoteBoardDefs.h:62
SENDPIN_ON
#define SENDPIN_ON(pin)
Board dependent macro to turn on the pin given as argument.
Definition: IRremoteBoardDefs.h:329
IRremote.h
Public API to the library.
IRsend::space
void space(unsigned int usec)
Definition: irSend.cpp:103
SENDPIN_OFF
#define SENDPIN_OFF(pin)
Board dependent macro to turn off the pin given as argument.
Definition: IRremoteBoardDefs.h:336
DUTY_CYCLE
#define DUTY_CYCLE
Duty cycle in percent for sent signals.
Definition: IRremoteBoardDefs.h:55
IRsend::sendRaw
void sendRaw(const unsigned int buf[], unsigned int len, unsigned int hz)
Definition: irSend.cpp:5