Here is a project I did for making an Arduino a Power Functions remote for the NXT. I took advantage of my NXTI2C library, as well as my PFIR library (more info, and download links for both here).
I setup the I2C register of the Arduino system as follows:
0x00-0x07 - version number - "V1.0" - read only 0x08-0x0F - manuf. name - "Mt Allen" - read only 0x10-0x17 - device type - "PFIR" - read only 0x41 - Command - write only 0x42 - Nibble 1 - write/read 0x43 - Nibble 2 - write/read 0x44 - Nibble 3 - write/read 0x45 - ActiveChannel - write/read
If you write, starting at Nibble 1, and going through at least Nibble 3, the Arduino will load the data into the appropriate (PF channel specific) buffers, and automatically enable sending messages on that channel. You can optionally write to the ActiveChannel buffer, to remote control the permissions bits (either by writing to 0x45, or by writing a 4th byte, starting at 0x42).
There is a fairly extensive list of commands you can issue to the command register. In order to issue a command, you must write it to 0x41 (e.g. you can’t write 2 bytes starting at 0x40, and have the command take effect).
Here are the supported commands, as defined in the program:
#define COMMAND_E_STOP 0x73 // s Command to float all motors immediately. Applies only to active channels. #define COMMAND_E_STOP_ALL 0x53 // S Command to float all motors immediately. Applies to all channels. Takes control of all channels. #define COMMAND_DIS_ASS 0x64 // d Disassociate from all IR channels. #define COMMAND_DIS_ASS_CC 0x44 // D Disassociate from all IR channels, and completely clear the ActiveChannel byte. #define COMMAND_DISABLE 0x4E // N Disable messages. #define COMMAND_ENABLE 0x45 // E Enable messages. #define COMMAND_LOAD_DATA 0x6C // l (L) Load data as if it was sent directly to REG_NIBBLE_1. #define COMMAND_DISABLE_TO 0x4F // O Disable timeout. #define COMMAND_ENABLE_TO 0x54 // T Enable timeout. (default when booted). #define COMMAND_COMP_CON 0x43 // C Enable complete control of IR. #define COMMAND_COMP_CON_O 0x63 // c Disable complete control of IR. #define COMMAND_FAST_OFF 0x46 // F Enable really short blank messages. #define COMMAND_FAST_OFF_O 0x66 // f Disable really short blank messages.
You will need to give the user-program running on the Arduino some time to respond to any messages sent (commands or PF control messages). With the simple loop I made, 10ms between sending messages seems to be more than enough. If I integrated the two libraries into one, specific for this purpose, it would probably eliminate this potential drawback (although 10ms really isn’t much of a wait).
Here’s the schematic of the circuit I’m using:
I used a transistor to increase the current for the IR LED. The IR LED I’m using is rated 1.6v forward drop, up to 100ma continuous current, and 940nm wavelength.
For R3, I used a 47 ohm resistor, but the appropriate value is specific to the LED you use.
For R4, I just used a common value of 330, but 220 to 1k should work just fine.