Been away from my site for a while. Please bear with me. I’ve had little time to work on my hobbies, but hope to start back up soon. Hopefully much more to come very soon.
I’m needing to decode IR signals for a project I’m working on. I need both the carrier frequency to be known (38kHz, 56kHz, etc) as well as the on/off periods.
The first several codes I read I did it the hard way. I used an IR LED hooked up to an oscilloscope. Essentially with no additional components. Just hook the IR LED straight to the probe. Point the remote control at the IR LED and hit the remote control button. This shows the trasmitted IR signals on the oscilloscope. I zoomed in far enough to see the carrier frequency and calculated the frequency of the carrier. Then I zoomed out to see the on and off bits and used time markers to measure the on/off states.
That got real old real quick.
I have now created a small circuit that allows me to use a Logic Analyzer (I’m using the Saleae Logic16 at 3.6-5.0V = Logic high setting) which outputs the logic that shows the carrier modulation (1/0/1/0 at a certain frequency (i.e. 56kHz)) which the LA software calculates for you. Then you can put a marker at the left of the modulating frequency and right of the modulating frequency to get the time period. I have tried many different sample rates, but if you sample at 500khz, it just shows the time period for on/off bits. If you sample at a higher rate (i.e. 100 mhz) it will show the carrier frequency as well.
It will also show you with a visual indication that it is receiving the IR signal via the LED. It will flash along with the signal of the remote.
The page for the circuit design is here: http://www.controllerprojects.com/ir-decoder-changelog/
I plan on going into more depth in the future about the measurements I do in the software. I also hope to create a program that will parse the exported data from the Logic Analyzer software and automatically calculate the carrier modulation and the timing of the on/off bits. These things will be in a follow up post.
Top view of finished board (The blue thing at the top right next to the power connection is just a jumper to allow you to kill the power via jumper. The 2 open male headers at the bottom left are for the connections to the logic analyzer. I need to label them so I can make sure to hook up the logic analyzer the right way.)
Bottom view of finished board
And the decoder in action (at least the LED flashing… the logic analyzer piece will come soon)
httpv://www.youtube.com/watch?v=nKY_pIFCd8Q
Thanks! As always, comments/suggestions are welcome.
Ok, so I finally had a chance to play with the Logic16 a little more. I have created a circuit with an IR Phototransistor that will allow me to read IR signals from remote controls. At first the way I had the test circuit was ok… it was well above the threshold for 1 and well below for 0. Therefore, it would give the bits needed (but not the carrier modulation). This was all I was really going for. I assumed I would need to use an oscilloscope to check the carrier frequency. I decided to add an LED to pulse the logic, and somehow I lucked out. The modification to my circuit put it at exactly the threshold I needed for the logic levels to be at the carrier frequency levels, so rather than 1 being high, 1 is high-low-high-low-etc etc at the frequency that the IR modulation is at for the duration of the high time. The low time is obviously just low (no modulation). YAY, this means it’s all one package (the tester being less than approximately a couple of inches square… i’m going to design a pcb to etch for it and make it as small as possible).
So, that being said, I was able to sample remote control codes, compare it against a baseline that I measured already with an oscilloscope (and also had used to create an IR signal and confirmed it works), and it matches almost perfectly (close enough to count). I’d say the discrepancy is probably more in my estimations looking at the scope than in the variations with the results of the Logic16.
I want to investigate the SDK to see if there’s a way that i can create a plugin to analyze the IR signal for me. I know you can create analyzer plugins for it, but I’m not sure if I’m smart enough to figure it out and/or if it’s possible to make a “universal” analyzer like I would like to do, or if I have to have the timing already done and just be able to select (for example) “scientific atlanta remote control analyzer” and let it capture the logic and just tell me from that logic which button was pressed. I would prefer it to measure the frequency, then tell me that it had that modulated frequency for X ms, then went low for Y ms, then modulated again for Z ms, etc etc. Another alternative (that may be easier for me) is there’s also an SDK so allow me to write a program that reads from the Logic16 (not using it’s software). That may be an easier way than to write to the analyzer format that Saleae uses.
That’s my brief part 2 review. I will post the schematic for the IR analyzer as soon as I get it in digial format. Please let me know if you have any questions or suggestions.
Thanks!
I just received my OverLoad unit from ITeadStudio (http://iteadstudio.com/store/index.php?main_page=product_info&cPath=29_31&products_id=421).
It can be use as a electronic dummy load , a Voltmeter or an Ammeter. Since I got one of the first ones made, they threw in the Foca (FT232RL breakout) programming adapter (since they are assuming there will be software updates needed while they refine the unit).
I haven’t played with it yet, but here’s some pictures of my unboxing for those of you that want to see what it looks like up close (sorry for the medium quality of the pictures, it’s taken with a cell phone camera). If there’s any particular tests you would like to see, let me know in the comments.
I didn’t realize, until I needed to optimize my code because I was out of RAM, that doing a Serial.print(“this text is in quotes, not a variable, however it takes RAM to store it at runtime”); will load that string into RAM at runtime.
I’ve seen a post about using PROGMEM to optimize your code in regards to things like this, where it uses the program memory (flash memory) rather than RAM to store the variable, but I stumbled across an easier way to handle it in the scenario of doing a Serial.print(“things in quotes);
According to what I read on http://jeelabs.org/2011/05/23/saving-ram-space/
The trick is to place these strings in flash memory, alongside the code, and extract the characters of the string whenever we need them. It’s a great trick, but it will affect our sketch everywhere, unfortunately.
First of all, we need to include this line at the top of our sketch:
#include <avr/pgmspace.h>This header file gives access to a number of preprocessor macros and functions, needed to define strings in the proper way, and to read the character data from flash memory at run time.
The reason for this added complexity, is that flash memory isn’t simply an “address” you can read out. The AVR family uses two separate address spaces for code and data. This is called a Harvard architecture. As far as pointers go in C, there is no access to data in flash memory. Well – there is, because function pointers in C automatically refer to code in flash memory, but there is no way to mix these: data pointers cannot access flash, and function pointers cannot refer to RAM.
So if you add the following function:
void showString (PGM_P s) {
char c;
while ((c = pgm_read_byte(s++)) != 0)
Serial.print(c);
}
You can call that function with showString(PSTR(“String goes in here”)); and it will do a Serial.print(“String goes in here”) without eating up ANY additional RAM.
If you need to do the equivalent of Serial.println(“This is one line”); you can do that with showString(PSTR(“This is one line\r\n”)); and the “\r\n” does a carriage-return.
Unfortunately, I don’t know how (if it’s even possible) to use this construct to avoid using as much ram when dealing with Serial.print() of variables.
Doing a project, I ran into a limitation where I believed that I was using up all 2k of RAM on my Arduino (ATMega328). I stumbled across a post on http://jeelabs.org/2011/05/22/atmega-memory-use/ that gave me what I needed to diagnose that scenario.
The only symptom I had was intermittent jumbled text (with ascii characters mixed in) for my Serial.print() commands and the fact that it would intermittently lock up and/or reboot.
The Arduino IDE shows at compile time how much flash it is using, but it unfortunately doesn’t give any indication for RAM.
As stated on the JeeLabs site:
There are three areas in RAM:
- static data, i.e. global variables and arrays … and strings !
- the “heap”, which gets used if you call malloc() and free()
- the “stack”, which is what gets consumed as one function calls another
The heap grows up, and is used in a fairly unpredictable manner. If you release areas, then they will be lead to unused gaps in the heap, which get re-used by new calls to malloc() if the requested block fits in those gaps.
At any point in time, there is a highest point in RAM occupied by the heap. This value can be found in a system variable called __brkval.
The stack is located at the end of RAM, and expands and contracts down towards the heap area. Stack space gets allocated and released as needed by functions calling other functions. That’s where local variables get stored.
The trick is to keep RAM usage low, because it’s a scarce resource: an ATmega has a mere 2048 bytes of RAM.
So, to use those variables and concepts to show RAM usage, you can utilize the following function:
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
Just call it, not passing any parameters, and it will return the remaining bytes of ram.
i.e.: Serial.println(freeRam());
I ended up (at one point) showing that freeRam() returned 64 then very shortly afterwards the arduino rebooted. That’s a smoking gun that it’s a RAM issue. Time to do some code optimization
I just purchased the new Saleae Logic16 (http://www.saleae.com/logic16/) and will be reviewing it soon. I hope to have the review (or at least part 1) within the next couple of days.
Review Part 1:
This is not a real review piece, but just an FYI. I have attempted to use this to decode UART data (asynchronous serial) on the output of my Arduino in-circuit and it worked flawlessly. Unfortunately, I’ve not had a chance to do much more, but I will have a “real” review as soon as I can.
While I’m preparing to do the review, I’ll leave you with these two links which are a good video review about the hardware and differences between the logic and logic16.
http://thesignalpath.com/blogs/2011/05/31/saleae-logic-and-logic16-product-review/
http://thesignalpath.com/blogs/2011/05/31/saleae-logic-and-logic16-product-teardown/
I created a Win32 Console application in Microsoft Visual C++ to parse out a CSV file in a particular format. It worked GREAT on my computer, but any others i tried to run it on that didn’t have MS Visual C++ 2010 Express wouldn’t run it. It gave the error message: System Error: The program can’t start because MSVCP100D.dll is missing from your computer. Try reinstalling the program to fix this problem”. After a bit of google searches, I came across the solution.
Right click the Project under the Solution Explorer and select Properties
On the left hand side, expand “Configuration Properties” (if not already expanded)
Expand “C/C++”
Select Code Generation
Change Runtime Library to “Multi-threaded (/MT)”
Click OK
Now recompile it and it should work flawlessly.
Your EXE file should be where ever you saved the project, then go into Debug (or Release, or whatever configuration you show in the toolbar at the top of your main C++ window). In my case, it’s under “C:\Users\MyName\Documents\Visual Studio 2010\Projects\modDhctCfgBuilder\Debug\modDhctCfgBuilder.exe”
Ok, so we found that the arduino is fast enough to modulate the signal at 56kHz as long as you do direct port access with a few delayMicroseconds() and assembly code NOPs to pad it slightly. I got the main buttons that we will use decoded into their signals and coded it into the arduino code. For example, IROn1Off1(2); will turn the signal on one cycle, off one cycle, and repeat that twice… IROn1Off3(1); will turn the signal on one cycle and off three cycles only once. an example of the power button’s timing is at http://www.controllerprojects.com/2011/03/13/automatic-audiovideo-channel-checker-part-2-working-on-the-ir-transmitter/ I’m sure there’s a more elegant way to write the code, but here it is. It is currently set up to press 1, wait 1 second, press 2, wait one second, then press 3 and wait one second… then repeat that in the main void loop(
Link to code: http://www.controllerprojects.com/auto-channel-checker-changelog/ The current version is 1.6.5
So we have determined that the smallest increment of on or off that the signal needed was .84 milliseconds. It seems to be in increments of 1, 2, 3, or 4 units of .84 mS blocks as shown by the chart below. This chart reflects the Power button from a Scientific Atlanta remote control. The “on” state needs modulated at 56kHz which we will drive by a 555 timer (more details later).
| State | Length | Units | # of .84 millisecond cycles |
| 1 | 3.36 | milliseconds | 4 |
| 0 | 3.36 | milliseconds | 4 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 0.84 | milliseconds | 1 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
| 1 | 0.84 | milliseconds | 1 |
| 0 | 2.52 | milliseconds | 3 |
Now that we have the on and off (1′s and 0′s) to match the remote control’s states, we need the 56kHz modulation on top of that signal.
Here’s our solution to get the 56kHz modulation on the signal from the arduino (also noting where you can check it with an oscilloscope. 56k_IR_Mod_1_1 (PDF)
























