The microcontroller (uC) firmware was based primarily on how to maintain the serial communication channel while carrying out other functions. Since the boat was going to receive a lot of commands over the serial channel, it is important that the channel be very responsive and not prone to errors.
The first iteration of the firmware utilized an if statement in the main loop which checked if there was any data in the serial receive buffer. If there was any data, the byte would be read and verified if it is equal to '$'. Otherwise, the loop proceeds. Since the first byte is '$' it is probable that a command is being sent to the uC from the phone. The subsequent character bytes from the serial buffer are read until a '#' character is read. Next, a switch-case statement is used to decide what the command is, based on the first character of the message. The command is carried out, and the main loop continues.
Other than the if statement for checking the serial receive buffer, there was nothing else that ran in the main loop. There was no need to run any other command continuously. Instead, the valves, pumps and sensors were all commanded within the switch-case structure described previously.
This system worked effectively until we had to replace the solenoid valves with the pinch valves that we had designed. The key concern was that the RC servos that we were using needed commands to be sent to it continuosly. If the commands were not sent to it, the servos would not hold position, and the valves would open.
Thus, we changed the firmware to use an interrupt based architecture. Interrupts give the uC the ability to halt whatever it is doing and respond to changes immediately. We made the serial communications peripheral, the USART, trigger an interrupt whenever a byte was received. Within the interrupt itself, we insert the entirety of the algorithm described earlier to read the other characters and trigger commands. However, the commands were modified to be more like tripping flags, rather than performing anything substantial. For instance, one command would be to change the variable which described the position of the turret.
Now, within the main loop, the other commands are run. The time intensive signals to run the three RC servo motors are run continuosly, only broken whenever the interrupts trip.
Since the PWM module is a peripheral, it can operate independently of the main uC processor. Therefore, when the speed of the pumps need to be changed, a command is issued which changes the duty of the PWM signal. Nothing else needs to be done to keep the PWM signal running.
Development of the uC firmware was done entirely using MPLAB. The MPLAB development environment's rich debugging features like the MPSIM simulator, and integration with the Pickit 2 programmer/debugger made it indespensable. One of the major quirks we had the debug was why using a polling technique would not work when we wanted to do many slow things within our main loop. We found that the receive buffers were overflowing and just losing bytes. It was exciting to step through code while debugging, knowing that we were stepping through code on a tiny uC.
Full source code can be found here