After some research, I decided to use the Arduino Nano for this project, and got a half dozen units along with some miscellaneous components. They were bizarrely cheap - something like $3 / per on average. So far things are working fine. The clone Nanos I bought came with the CH340 USB to Serial chip so it required a driver installation from the vendor, but otherwise worked fine once I set the IDE to the right COM port.
Think I'm sold on Arduinos in general - the in-circuit code update makes it so easy to prototype and debug. And now I'm thinking of buying a cheap laptop for future projects, so that I'm not tethered to my desktop.
My setup here uses a transistor to power the infrared LED. An Arduino can source up to 40 mA per pin, but the Infrared LED I'm using takes 70 - 100 mA in pulsed mode. It can probably work well enough with that, but I was planning to use several LEDs in the final device, so that meant using a different power source. The circuit was supposed to use an NPN transistor, but I used an N-channel MOSFET I had laying around, the IRFD120.
The dominant infrared library for Arduino is IRremote and there are tons of tutorials and examples about it. It seems to have used parts of the LIRC project as a way to shape its code. That's where I ran into a snag.
IRremote's sendSharp() function doesn't work for all devices.
The Sharp-manufacturer codes from the LIRC listing didn't seem to work at all: volume up / mute / down codes were supposed to be 0x40a2, 0x43a2 and 0x42a2. I verified that the infrared LED was sending something by looking at it through a smartphone camera, but I didn't have an oscilloscope to compare original and constructed signals, and nothing was happening.
Troubleshooting with LIRC
Last year I bought the Vero 2, a Linux-based streaming device running OSMC and Kodi, and though it came with a radio remote controller it also had an infrared receiver and ran LIRC. After ssh'ing into the device, I killed the lircd daemon and ran irrecord -d /dev/lirc0 myconf.conf to inspect what my TV's remote controller was sending.
Using irrecord, I recorded the actual Sharp remote and my breadboard prototype's signals. The two conf files irrecord generated should have been identical, but they weren't. Something was wrong.
begin remote name sharp.conf bits 15 flags SPACE_ENC|CONST_LENGTH eps 30 aeps 100 one 250 1828 zero 250 790 ptrail 249 gap 66772 toggle_bit_mask 0x0 begin codes volup 0x40A2 0x435D voldown 0x42A2 0x415D mute 0x43A2 0x405D pwr 0x41A2 0x425D end codes end remote
begin remote name dinotest5-arduino.conf bits 15 flags SPACE_ENC eps 30 aeps 100 one 211 1844 zero 211 837 ptrail 206 gap 40808 toggle_bit_mask 0x0 begin codes a 0x7442 0x77BD b 0x7442 0x77BD c 0x3842 0x3BBD end codes end remote
Irrecord verified that I was looking at the correct sharp codes as per LIRC documentation of a similar device. However, my prototype was off in a bunch of places. The gap value difference made me think that my nano's timing might be off (wrong oscillator, configuration error?), but a separate blinking LED test confirmed my stopwatch matched count of 1 second blinks after ten minutes. So that wasn't it.
I started suspecting the IRremote library's version of sendSharp(). First thing I noticed from looking at the generated LIRC configuration file of my actual remote is that the toggle bit mask was different than expected in the documentation.
IRrecord and raw signals to the rescue
Not having an oscilloscope, I ordered a 38 KHz infrared receiver that I originally thought I wouldn't need. Once I connected it and ran the IRrecord example to spy on the raw IR signals, everything started working. Well, almost. The serial monitor in the Arduino IDE showed activity and that was encouraging. Arduino's serial monitor and overall interface is so incredibly useful for development.
With my setup, I had to make a couple of alterations to the sample program - replace pin numbers, change input mode to INPUT_PULLUP, and tweak the buttonState logic to flip LOW and HIGH. But it worked, and worked great. The program could record some of my other devices and emit their signals, and those worked. All except for the Sharp TV, because I believe the signal has to be inverted as per their protocol, so that'll take an additional step or two.
Next steps: power management and button matrix
Specifically, I want to put the Nano to sleep and connect a pushbutton matrix circuit that can wake it up via interrupt pin. Most examples of the button matrix circuit I've seen weren't designed with an interrupt in mind. There are dedicated integrated circuits that can send an interrupt signal, but I figured the Nano has plenty of I/O pins available in my circuit to allow for 25 - 30 buttons, and I'm thinking I'll need 20 (4 + 5 I/O pins.)
Before I wrote any code to send meaningful signals, I tested the infrared LED with my smartphone camera and recorded this. It's startling how bright infrared LEDs are, since we can't see at that wavelength.
Being a nerd, I found this oddly satisfying to watch, and it gave me some hints as to how to position the IR LEDs in the remote.