The "best" software for me is the free Visual Studio Express for Desktops.
Using C#, I would add a SerialPort component to the form, configure it for the same COM port as the Arduino/FTDI, then send commands to it.
Visual Studio is "stupid simple" (I'm not implying anything :D). Double-click Button in the toolbox(1) and it creates one. Double click the button(2), and it outlines the code and attaches the Click event to it for you. Double click Components>SerialPort(3) to create one. My code is highlighted in blue to the right and this took all of 1 minute to create.
To point you in the right direction on the Arduino side, here is the structure of the "command" I sent in the screenshot:
XXXYYYZZ
Where:
XXX = 000b for "turn off", 001b for "turn on", 010b for "toggle", 011b for "read pin"
YYY = Pin number //Max = 111b = 7 (+ 0) = 8 uniquely addressable pins (using 3 bits)
//Pin number does not have to match the MCU port/pin designations
//MCU will convert logical pin #'s 0-7 into the correct physical port+pin
//For more pins, steal another bit from ZZ; Max for YYYY = 1111b = 15
ZZ = Spare bits //Tell the Arduino whether to acknowledge or not, etc.
00100100b = "Set pin 1 high"
01001000b = "Toggle pin 2"
10000000b + 0xAA (two byte command) = "Reply with contents of register 0xAA"
Additional commands can be created to tell the Arduino to reply with a specific variable or status.
bool isRegisterRead = false;
bool isMultiByte = false;
while (true)
if (wasByteReceived) //This flag is set in the RX interrupt and the byte is saved to byteReceived
if (isMultiByte) //Second byte received
{
if (isRegisterRead)
{
//We need to read and send the value of the register at the address in byteReceived
ReadAndSendRegisterValueAtAddress(byteReceived);
isRegisterRead = false;
}
else DoSomethingWith(byteReceived);
isMultiByte = false; //Start over
}
else //First or only byte received
{
//Consider using a ZZ bit to indicate more data instead of listing them explicitly
if (byteReceived == 0x80) //A multi-byte "read register" command
{
isMultiByte = true; //Next byte received is money
//For my example we need to set a flag somewhere to indicate that we are reading a register
//isRegisterRead should be set to true by DoSomethingWith
}
//Is there any processing for the "command" byte? (i.e. extract and save the pin number)
DoSomethingWith(byteReceived); //Process one-byte command or first of two-byte command
}