8

I'm working on a free space optics project to send data wirelessly between two points. To accomplish this I'm using an IR LED connected to an Arduino Uno that pulses with a 56 kHz carrier frequency for the transmitter and a second Arduino with a 56 kHz IR detector module for the receiver.

I tried using delayMicroseconds() between pin high and pin low commands in order to create the carrier frequency. This kind of works, but the frequency isn't always the same and any additional delays for pulsing the signal (i.e. the time required to call the function and decrementing) can change it.

Reading the datasheet for the ATmega328 it appears that there is a way to set a more accurate pulse using the chip's timers. Is that possible, and if so, how do you create a 56 kHz pulse using the timers?

  • What is the accuracy you need for your 56KHz frequency? I.e. what frequency range is acceptable in your project? I ask because using Arduino timers alone, precision has limitations. – jfpoilpret Feb 24 '14 at 9:54
  • 55.5khz to 56.5khz would be ideal in order to maintain a high level of responsiveness in the detector. – jlbnjmn Feb 24 '14 at 15:08
10

It is indeed possible to generate a 56 kHz signal with an Arduino timer.

A timer actually can be seen as a special register, in the MCU, that holds a value (starting at 0) that gets incremented at a frequency that is the MCU clock frequency (16 MHz on Arduino Uno), possibility divided by a factor called prescaler. When that value reaches a limit, called Compare Match, that you specify, then two things happen:

  • The timer register value is reset to 0.
  • One ISR (interrupt service routine) callback function gets called (you can define it to point to your own code).

The idea is to use that ISR to change the output of a logical pin every time it is called (HIGH, then LOW, then HIGH...).

Now, in order to generate a 56 kHz square wave, you'll need your ISR to be called 56000 * 2 times per second (* 2 because you need to change the output value twice per period).

You can choose the prescaler value you want for a timer among the following list:

  • 1 (clock frequency is not divided, hence 16 MHz)
  • 8 (clock frequency is divided by 8, hence 2 MHz)
  • 64
  • 256
  • 1024

There are two sizes of timers/counters on Arduino Uno (they are called timer/counter actually): 8 bits and 16 bits.

On Arduino Uno (ATmega328P), you have three timers overall, but some may be used by the Arduino core library or other libraries used in your sketches (you'll have to check that by yourself):

  • timer0 (8-bit)
  • timer1 (16-bit)
  • timer2 (8-bit): this one has more prescaling options (1, 8, 32, 64, 128, 256, and 1024)

Now you need to generate a 56 kHz wave from 16 MHz, hence, without prescaling, you would need to count to:

16000000 / (56000 * 2) - 1 = 141.857 (- 1 because a timer counts from 0 to this value and resets only after it has been reached)

From this calculation, we can draw two observations:

  1. 141.857 is not an integer and thus you won't be able to generate a wave of exactly 56 kHz.
  2. Without prescaling, you need a 16-bit timer as 285 is not representable as an 8-bit unsigned integer.

From now you have two options:

  1. Use a 16-bit timer (timer1), use prescaler = 1, and select 142 as the Compare Match; that will give you the following frequency: 16000000 / (2 * (142 + 1)) = 55944 Hz
  2. Use an 8-bit timer (timer0), use prescaler = 8, and select 17 as the Compare Match; that will give less precision with the following frequency: 16000000 / (8 * 2 * (17 + 1)) = 55555 Hz which is still within the required range.

Now, regarding how to write your sketch for that, I advise you to check out this instructable which is very complete and very interesting to read.

Of course, the ATmega328P complete datasheet is also important if you want to understand, in the slightest details, what you are doing.

Some important notes:

  • An ISR is executed with disabled interrupts and must thus be as short as possible. In particular, there are several functions from the Arduino library that shall not be called from an ISR.
  • Arduino Uno clock is not very accurate (it uses a ceramic resonator instead of a quartz, which would have been much more accurate), so this means the output frequency will shift further.
  • 2
    Also when the specified limit is reached the hardware can toggle a pin. Thus there is no need to use ISRs at all. There will always be jitter with an ISR because an instruction cannot be interrupted once it starts. However the hardware will always toggle the pin at the desired rate. – Nick Gammon Jul 23 '15 at 7:31
  • It is somewhat surprising that the Arduino Uno uses a ceramic resonator, but a source for it is Arduino UNO FAQ (near "Does the Uno use a resonator or a crystal for the processor clock?"). – Peter Mortensen Feb 15 '18 at 21:36
3

I've found tone() useful for generating high frequency pulses on any pin. It should be able to handle 56 KHz. (Edit: As noted by jfpoilpret, the closest you could actually get on a 16 MHz Arduino is about 55.944 KHz)

The difficulty will obviously be combining it with your data signal. I don't think you could do that in software without resorting to low level code. It should be pretty easy in hardware though, since it's digital.

All you'd need to do is output your data signal on a different pin, and then combine it with the carrier using an AND gate. The combined signal can go straight to your IR transmitter.

If you don't have an AND gate handy then it's quite simple to make your own using a pair of transistors. Just search online for "transistor and gate".

  • Recievers often have active low outputs generally. If you connect the top of the LED to the 56khz, and the bottomto your data pin, when the data pin goes low you get IR output, which should make the reciever go low. No and gate needed, just an led and resistor. Only problem is being limited to whatever current io pins can drive. – EternityForest Apr 7 '14 at 2:31
2

The accepted answer of jfpoilpret is very well written, perfectly valid and in 99% of the cases I will do exactly what he explains. His solutions are well within your defined parameters, so they should work very well. But what is better than "very well"? Perfection! After all, the question is about generating a exact value. As said close enough is good in most cases (arguably all), and even when dealing with something as a clocks when 1 second need to be 1 second, you still have to suffer inherited parts imperfections.

What I will suggest is not always possible. In some cases, it's possible, but with much more hassle and effort than this case. Is it worthy depend on a case-by-case basis. My goal is mostly to show a alternative for future references that is better in somewhat fringe cases. This is written with novice Arduino users in mind that don't have extensive experience in electronics.

For more advanced people this probably will look too verbose and dumbed down. But I believe that, those same people probably already know it and don't need this answer. This is also applicable to every microcontroller and every manufacturer and architecture. But for other microcontrollers you will need to consult the correct datasheet to find out proper registers and prescale names and values.

In your case, you need a specific frequency and the nice thing about it, is that exactly 56 kHz actually can be achieved very easy (not counting practical imperfections of the parts). So this is also a perfect example case.

Generating a signal depends on the timers and clock source of the microcontroller, as explained well by jfpoilpret. His answer deals with the problem of one point of view only and that is fiddling with timers. But you can fiddle with the clock source too, or even better with both for synergy and awesome results. By changing the parameters of the environment, in this case hacking the system and replacing the clock source, we can deal with a specific problem with much, much more ease and simplicity.

First to remind, because of toggling the pin state, you need to execute the ISR two times more than the signal frequency. This is 112,000 times per second. 56,000 and 16,000,000 don't add up very nicely as pointed out already. We need to change either the signal frequency or tact frequency. Let's deal for now with an immutable signal frequency and find a better clock speed.

It would be most straightforward to choose a clock with some order of magnitude bigger than 56 kHz (or 112 kHz, but it is practically the same), as you only add zeros and this kind of math is simplest for most people. Unfortunately everything in this world is some kind of compromise with something. Not every value will work.

The first example is with a too low tact generator speed.

If you choose a 56,000 Hz clock you won't be able to do anything as you will need to call the ISR every cycle and can't do anything else. It is utterly useless. If you choose 10 times faster speed (560 kHz), you will have 9 (10 cycles for the timer to reach its max value - one cycle to call ISR function) microcontroller cycles to do your work and this quite possible can be not enough. You simply often need more computational power.

If you choose a value far too great at other hand, as 56 MHz the microcontroller simply can't work with it. It is way too fast. So, simply choosing the biggest value in the shop won't cut it either.

Original Arduino Uno R3 have a stock clock at 16 MHz, so anything slower that that is guaranteed to work. The next value that is an order of magnitude bigger than 56 and lower than 16 MHz is 5.6 MHz. This will lead to be able to call the ISR every 50 cycles and will create the perfect 112,000 Hz timer frequency. And your signal will be exactly 56 kHz. You will have 49 MCU cycles to execute your program between ISR calls, but it is still around 1/3 of the speed of the original clock. One can use 112 as base and use a 11.2 MHz clock and this will give a about 2/3 of the stock 16 MHz resonator. The ISR function will be called every 100 cycles and still generating a perfect 56 kHz signal.

However two major problems exist with these values.

  • The first problem severely depends on your needs: You sacrifice about 1/3 (with 11.2 MHz) of your maximum computational power to get the exact signal frequency that use an easy-to-find register value (OCR iirc). You may be fine with it or you may not.

  • The second problem is a hard showstopper: It is very easy to find values, but very often they simply do not exist as a manufactured clock source. This is Farnell's resonator web page that simply lack both 5.6 MHz and 11.2 MHz.

To circumvent this we can look at available resonator values and find out something else that can be used to generate exactly desired values. If we divide 56 by 4 we get 14 and luckily there is a 14 MHz resonator. This provides us with much higher speed and more power and with equally easy to find register value. To call the ISR 112,000 times per second we need to put value of decimal 124 or hexadecimal 0x7C in the OCR register, so with counting 124 cycles + 1 for calling the ISR, we get our desired perfect value.

N.B.

  1. ISR - interrupt service routine (this is the code that is executed only on generated interrupts)
  2. How big your program can be depends on the memory size! It has nothing to do with the clock speed and has nothing to do with how often you call the ISR.
  3. When the microcontroller starts with program command a counter is incremented. If an interrupt is generated, the ISR is called and this value is stored in a special register. When the ISR code completes, the value of the program counter is restored from this special register and the program continues from where it was interrupted as if it had never happened.

    I will give an extremely dumbed-down example. If you are a purist, I warn you: Nose and eye bleeding can occur.

    Imagine you have to walk from somewhere to somewhere. The step-by-step route instructions are your main program and its commands. How fast you walk or run, depends on your "clock speed", but not on the route instructions (30 steps forward, 1 turn 90 grad. left, 10 steps forward, 45 grad. right, etc.) They are always the same. Now imagine a little kid or a greedy corrupt local politician untie your shoes now and then. This is the event that generates an interrupt. Then you halt after your last step, kneel and tie your shoe again. This is your ISR program.

    Then you continue from the place you have stopped; you do not start from beginning. When you walk without a care in the world and with all the time, you don't care even if you have to tie your shoe every other step. If you however do it with time constrains, like running in 100 meters on the Olympics (or running from a hungry flesh-eating predator), stopping and tieing your shoes can have dire consequences. The same is with microcontrollers. Even if you execute only one line of code your program will continue, albeit slow. If you don't care about speed at all, it won't be a problem. If you have to do some time related, like using other timer dependent actions, interference can be very unwanted and problematic.

  4. Less is more! A faster clock is not always better. Slower clocked devices use considerably less power. This can be a crucial point in a battery-operated device.

  5. The needed cycles are derived from this formulae:
    (clock speed / (prescaler value * needed ISR calling frequency)) - 1

  • TLDR: Desolder the ceramic 16 MHz oscillator and replace it with another that allows exactly 56 kHz by integer division (e.g. 14 MHz and divide by 250). – Peter Mortensen Mar 7 '18 at 14:00
0

You can turn the carrier on and off simply by toggling the carrier pin mode between output and input. I have used this to control a heat pump through the 37KHz infrared (remote control) port.

0

There is no need to use an ISR to create the carrier. Just set up a timer to produce a 50% PWM output at the required carrier frequency. The ISR is then just in charge of modulating the carrier - typically at 0.5 or 1ms intervals - a far more comfortable rate. In my experience a 5% error in carrier frequency is tolerated by most IR receivers. I used a Freetronics EtherMega 2560 (which has plenty of timers) but I'm sure other CPUs will do just as well.

  • How exactly is the modulation of the carrier implemented then? Changing the mode for the timer output capture pin between input (carrier off) and output (carrier on)? – Peter Mortensen Mar 7 '18 at 14:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.