Hardware/Software Design
- Hardware
For details on the hardware circuitry and wiring see the schematics in Appendix B. The hardest part of the hardware was soldering the components onto the small surface mount board. We chose the XFILT and YFILT capacitor values of 0.1uF to give us a 50Hz bandwidth output on each channel and a 1MOhm resistor for a 10ms duty cycle. The actual interfacing with the MCU was performed using standard copper bell wire. The switches on the output board were connected to ground and pull-up resistors were used. Also, the LED’s were connected with an active-low configuration using pull-up resistors. The LCD was connected to the MCU easily using standard copper bell wire and a potentiometer was used to control the contrast on the screen. Again, for more detail, please refer to the schematics section of the report and the pictures in Appendix F.
- Software
The software is structured using the same mult-tasking design that we have been using all semester. In order to create concurrency we set have several functions that need to run concurrently (the tasks) and they are each triggered by a counter that counts down at a fixed rate. By presetting the counter values we can controll the frequency at which each of the tasks is executed. So long as all the tasks can run in succession without exceeding the period of any one task, no bottlenecking will be encountered. Our software is divided into three major tasks: polling the accelerometers, polling the buttons, and updating the LCD display. The code which can be found in the Program Listing section is well commented and most of the code is rather straight forward. However, there is a key portion of code in the poll_accelerometers task that deserves further explanation.
The goal is to determine if the Digi-Lev is off level to the greatest degree of accuracy possible. Thus we cannot afford to ignore any of the bits of data we have coming from the accelerometer. After summing up over many values, we want to take the average value and determine if it is less than or greater than 1/2 (ideally zero is the only perfectly level value but half a bit is pretty good for the real world). The big snag is that we can't afford floating point computations because we want to poll the accelerometers as fast as possible and floating point is slow. Here's what we do...
The following is our 16 bit sum of acceleration values:
[15..0]
Assume without loss of generality that we are taking an average of 16 values (all our averages are powers of 2 for this purpose). Then we look at the 16 bit value as follows:
[15..4|3..0]
The bits to the left of the division form a truncated value of our sum divided by 16. The rightmost bits [3..0] are the remainder. If the value on the left is greater than or equal to one then surely our value is greater than one. If not we compare the value on the right to the binary value 1000 or 1/2 the maximum possible value four bits can take on. Thus we are able to determine the average value to within one bit without resorting to the built in floating point libraries which take orders of magnitude more clock cycles.