Portable Heads Up Display ECET 396 – Prof. Barnett Bill Bai 4/18/2011

Keywords: Heads Up Display, 3 Axis Accelerometer, Infrared Range Finder, Ambient Light Sensor, CdS Photocell, Vacuum Fluorescent Display, Atmel Microcontroller, Serial Peripheral Interface Network, SPI Network, I hereby submit this report and the accompanying project as my own work and give my permission to have this report made available to other students for reference. ___________________________________________________

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

Abstract The purpose of this project was to create a portable heads up display that could be used in a vehicle, such as a car or small private airplane, to display various pieces of relevant information to the operator. The device gathers the information from three sources: a ±3.6g three axis accelerometer, an infrared range finder, and a GPS module. A CdS photocell allows the device to detect the ambient light level, and adjust the display brightness accordingly. The collated information is then presented in a ‘heads up display’ manner using a vacuum fluorescent display (VFD). All of the internal communications between modules are conducted over a Serial Peripheral Interface (SPI) network. Overall, the project has not achieved the portability that was originally desired due to cost considerations, but functionality is fully proved.

Page 1 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

Table of Contents Abstract ........................................................................................................................................... 1 1.

Introduction ............................................................................................................................. 4

2.

Detailed Description ............................................................................................................... 5 2.1.

Photograph ....................................................................................................................... 5

2.2.

Specifications for Overall Performance ........................................................................... 6

2.3.

Operating Instructions ...................................................................................................... 7

2.3.1.

For End User ............................................................................................................. 7

2.3.2.

For Installation .......................................................................................................... 7

2.3.3.

For Connections ........................................................................................................ 7

2.3.4.

For Calibration .......................................................................................................... 7

3.

Overall Hardware Description ................................................................................................ 8

4.

Block by Block Technical Description ................................................................................... 9

5.

4.1.

GPS Block ........................................................................................................................ 9

4.2.

Accelerometer Block ...................................................................................................... 11

4.3.

Range Finder Block ........................................................................................................ 13

4.4.

Ambient Light Detection Block ..................................................................................... 15

4.5.

Display Controller Block ............................................................................................... 17

4.6.

Main Controller Block ................................................................................................... 19

Overall Software Description and Flowchart ....................................................................... 21

Page 2 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

6.

Overall Schematic ................................................................................................................. 23

7.

Testing Methods, Results, and Evaluation ............................................................................ 24 7.1.

Accelerometer Testing ................................................................................................... 24

7.2.

Range Finder Testing ..................................................................................................... 25

7.3.

GPS Testing.................................................................................................................... 27

7.4.

Ambient Light Testing ................................................................................................... 27

7.5.

Display Testing .............................................................................................................. 29

7.6.

Main Controller/SPI Network Testing ........................................................................... 29

8.

Conclusions and Recommendations ..................................................................................... 30

9.

References ............................................................................................................................. 32

10.

Appendices ......................................................................................................................... 35

10.1.

Budget ......................................................................................................................... 35

10.2.

Tracking Gantt Chart .................................................................................................. 36

10.3.

Software Listings ........................................................................................................ 37

10.4.

Datasheets ................................................................................................................... 53

Page 3 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

1. Introduction In a world that delivers increasing amounts of information to our fingertips at every moment, it is very difficult not to bury our heads in our cell phones and ignore the outside world. This however, is a serious safety issue when the distracted person is operating a moving vehicle such as a bike, car or airplane. One method for increasing safety and situational awareness for a vehicle operator is to decrease the amount of heads down time. Heads down time is a vital part of operating the vehicle correctly, but it also reduces the operator’s situational awareness and ability to respond to quickly developing situations in the immediate area. The best way to decrease the amount of heads down time for a vehicle operator is to provide a heads up display (HUD). A heads up display is a special kind of display that superimposes important data into the operator’s normal field of view. Military combat aircraft and their pilots, who have always had the greatest need for situational awareness in their operating environment, have had and used heads up displays since the early 1940’s. Military aircraft are still the most commonly heads up display equipped aircraft; but recently the technology has expanded to include high-tech commercial airliners and luxury cars. The problem is that the vast majority of the consumer population has no access to an effective and affordable heads up display. This project shows the viability of such a display. Existing market solutions fall in to one of two categories: custom displays and novelty displays. The custom displays include the HUD’s built into the BMW 5 series (BMW HUD information page for 5 Series Sedan) or Chevrolet Camaro cars (Chevrolet Camero HUD in Action Video); whilst the novelty displays include apps such as iHUD (iHud Multifunction Glass Display) made for the iPhone that can be used as a HUD. The custom display’s main drawback is that they are a custom solution; they are specifically designed to fit and work in a specific car (in this case, the

Page 4 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

BMW 5 and the Camaro), they are very difficult if not impossible to move and install into another vehicle. The novelty display’s main drawback is that it is a novelty; it is not designed to be utilized as a true HUD, but simply as an interesting app that can be shown off to friends. Thus this project brings the element of portability to a true heads up display.

2. Detailed Description 2.1.

Photograph

Figure 1: Photograph of the Heads Up Display Demonstration Unit

Page 5 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

2.2. 

ECET 396 Prof. Barnett

Bill Bai

Specifications for Overall Performance

Portability o Weight:

6 lbs

o Size:

10.5” x 10.5” x 8”

o Powered by 12VDC from car cigarette lighter 

Information displayed: o GPS module: 

Speed in KPH from 0.0 KPH to 1800.0 KPH



Altitude in Meters from -9999.9 meters to 17,999.9 meters



Time in HH:MM:SS

o Accelerometer module 

Acceleration in three axes from -3.6g to +3.6g

o Rangefinder module 

Range to object from 30cm to 180cm

o Ambient Light module 

Ambient light level from 0 (very bright) to 255 (very dark)

Page 6 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

2.3.

ECET 396 Prof. Barnett

Bill Bai

Operating Instructions

2.3.1. For End User 

Install HUD onto dashboard where the display can project onto the windshield at a convenient spot (adjustments may be made after the HUD is turned on)



Connect the power cord to the 12VDC cigarette lighter power port



Turn the power switch on



Adjust position of HUD to allow best viewing angle 2.3.2. For Installation



Utilize non-slip sticky tack to securely anchor unit to the dashboard



Make sure display projects correctly onto the windshield



Adjust unit for best viewing angle 2.3.3. For Connections



Connect the power cord to the 12VDC cigarette lighter jack



Turn the power switch on 2.3.4. For Calibration



Adjust position of the unit on the dashboard for best viewing angle and display

Page 7 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

3. Overall Hardware Description

Heads Up Display

Display Controller

Microcontroller Network

GPS

Accelerometer

Range Finder

Main Controller

Ambient Light Detection

12VDC

Power Supply

Figure 2: Overall Block Diagram

Figure 2 shows the overall block diagram for the entire project. The power supply provides power for all of the sensors, microcontrollers, and display for the system. The power supply runs off of the 12VDC cigarette lighter power available in cars. There are four blocks involved in

Page 8 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

collecting information for the system from the outside world: the GPS, accelerometer, range finder, and ambient light sensors. Each of these collects the relevant information and makes it available to the main controller via the Serial Peripheral Interface (SPI) network. The display controller communicates with the main controller via the SPI network to determine how bright the display should be and what information needs to be displayed. Finally, the heads up display projects the information onto the glass combiner, where the operator can see it.

4. Block by Block Technical Description GPS Block Time Data

GPS Decoder Micro GPS Reciever

Speed Data

GPS Data Stream Altitude Data

Microcontroller Network

4.1.

Figure 3: GPS Block – Sub-block Functional Decomposition

Figure 3 shows the sub-block functional decomposition diagram for the GPS block. The GPS block is responsible for receiving and decoding the GPS NMEA 0183(National Marine Electronics Association) messages.

The microcontroller then extracts the time, speed and

altitude data from the GPS data stream and encodes them again. The time, speed and altitude data is then made available to the main controller via the microcontroller network. Figure 4 shows the GPS block schematic. The GPS receiver obtains the GPS information from the array of GPS satellites orbiting the earth. The GPS receiver then outputs the data according to the NMEA 0183 standard via UART at 9600BPS, 8 data bits, no parity, 1 stop bit. The

Page 9 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

ATTiny4313 (same footprint and pinout as the 2313 with 4K rather than 2K of memory) IC1 reads the data output by the GPS receiver U$25 via the UART on pins 2 and 3, and parses the relevant data from the NMEA sentences. This data is then output to the SPI network on pins 19, 18, 17 and 16.

Figure 4: GPS Block Schematic

Page 10 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

Bill Bai

Accelerometer Block X-Axis 0-3.3VDC

Accelerometer

Y-Axis 0-3.3VDC

X-Axis Data

Acceleration Encoder Microcontroller

Z-Axis 0-3.3VDC

Y-Axis Data

Z-Axis Data

Microcontroller Network

4.2.

ECET 396 Prof. Barnett

Figure 5: Accelerometer Block – Sub-block Functional Decomposition Diagram

Figure 5 shows the sub-block functional decomposition diagram for the accelerometer block. The accelerometer block measures the amount of acceleration being experienced in all three axes of movement. The accelerometer itself outputs a 0V to 3.3V scaled voltage proportional to the acceleration on that axis. An acceleration of 0G will produce a 1.65V output, this allows both positive and negative accelerations to be measured. The accelerometer microcontroller measures the output of each axis and then encodes the data. This acceleration data for each axis is then made available to the main controller via the microcontroller network. Figure 6 shows the accelerometer block schematic. The three axis ADXL335 accelerometer U2 is connected to the ATTiny44 microcontroller U$4 on pins 13, 12, and 11 of the microcontroller. The ATTiny44 microcontroller measures the value of each axis by incrementing through the three single ended ADC’s (ADC0, ADC1, and ADC2) located on the corresponding pins. After the value of each axis is measured, the data is output to the SPI network on pins 9, 8, 7, and 6 on the ATTiny44.

Page 11 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

Figure 6: Accelerometer Block Schematic

Page 12 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

Bill Bai

Range Finder Block

Range Finder Sensor

Range 0-3.3VDC

Range Encoder Microcontroller

Range Data

Microcontroller Network

4.3.

ECET 396 Prof. Barnett

Figure 7: Range Finder Block – Sub-block Functional Decomposition Diagram

Figure 7 shows the sub-block functional decomposition of the range finder block. The range finder block is responsible for determining the distance from the HUD unit to the next object ahead of the vehicle. The range finder sensor will output a 0 to 3.3V scaled signal indicating the distance to the object. The range encoder microcontroller will read this signal and calculate the corresponding distance. This range data is then made available to the main controller via the microcontroller network. Figure 8 shows the range finder block schematic. The Sharp GP2Y0A02YK0F range finder is connected to a single ended ADC (ADC2) on pin 3 of the ATTiny45 U$2 microcontroller. The ATTiny45 measures the value of the range finder with the ADC and then outputs the range data to the SPI network on pins 7, 6, 5, and 2 of the microcontroller.

Page 13 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

Figure 8: Range Finder Block Schematic

Page 14 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

Bill Bai

Ambient Light Detection Block

Ambient Light Sensor

Light Level 0-3.3VDC

Ambient Light Encoder Microcontroller

Ambient Light Data

Microcontroller Network

4.4.

ECET 396 Prof. Barnett

Figure 9: Ambient Light Detection Block – Sub-block Functional Decomposition

Figure 9 shows the sub-block functional decomposition of the ambient light detection block. The ambient light detection block is responsible for determining the amount of ambient light. This is important because the brightness output by the HUD will depend on the amount of ambient light. When there is little ambient light, such as at night, the HUD will not need to be bright because it is dim outside. However, when it is bright out, such as during the day, the HUD brightness will need to increase so that the operator can still see the image projected by the HUD. The light sensor will output a 0 to 3.3V scaled signal indicating the ambient brightness. The ambient light encoder microcontroller will interpret this signal and make the ambient light data available to the main controller via the microcontroller network. Figure 10 shows the ambient light block schematic. A CdS photocell is used to measure the amount of ambient light. The CdS photocell has a very large resistance (~1MΩ) when it is dark, and a very low resistance (~100Ω) when it is bright). A 4.7kΩ resistor is added in series to limit the current, and the ambient light value is measured from the CdS cell to ground. This value is read by the ATTiny45 U$7’s ADC (ADC2) at pin 3. The ambient light level read by the ADC is then output to the SPI network on the microcontroller’s pins 7, 6, 5, and 2.

Page 15 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

Figure 10: Ambient Light Block Schematic

Page 16 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

Bill Bai

Display Controller Block Microcontroller Network

4.5.

ECET 396 Prof. Barnett

Display Data

Display Controller

UART Control

Heads Up Display

Figure 11: Display Controller Block – Sub-block Functional Decomposition

Figure 11 shows the sub-block functional decomposition of the display controller block. This block is responsible for controlling the image projected by the heads up display. The main controller tells the display controller what information needs to be displayed on the display via the microcontroller network. The display controller then parses this information to create the image that needs to be projected by the heads up display. Finally, the display controller tells the heads up display what to project via UART commands to the display. Figure 12 shows the display controller block schematic.

The display controller block

microcontroller, an ATMega168 IC2 receives display data from the SPI network on pins 14, 15, 16, and 17. After processing and parsing, the data is sent to the display. The VFD is controlled with RS232 commands, so a RS232 transceiver is used to convert the voltage level from TTL to true RS232. The transceiver utilized is the MAX3233, it is a 3.3V powered transceiver which does not need any external capacitors. The transceiver is connected to the microcontroller on pins 4 and 6 to pins 31 and 30 respectively. This allows the display controller to send the relevant commands and data to the VFD.

Page 17 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

Figure 12: Display Controller Block Schematic

Page 18 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

4.6.

ECET 396 Prof. Barnett

Bill Bai

Main Controller Block GPS Speed Data

GPS Altitude Data

X-Axis Acceleration Data Main Microcontroller

Display Data

Y-Axis Acceleration Data

Microcontroller Network

Microcontroller Network

GPS Time Data

Z-Axis Acceleration Data

Range Data

Ambient Light Data

Figure 13: Main Controller Block – Sub-block Functional Decomposition

Figure 13 shows the main controller sub-block functional decomposition. The main controller is responsible for coordinating the transfer of information between the various sensor inputs and the display controller. All of this is done via the microcontroller network. The main controller will retrieve the data from the GPS, accelerometer, range finder, and ambient light sensor. This data will then be parsed and the display data is output to the display controller via the microcontroller network. Figure 14 shows the main controller block schematic. The main controller block is responsible for controlling all traffic on the SPI network. It utilizes pins 14, 15, 16, and 17 to interface to the SPI network. The main controller also utilizes pins 1, 2, 9, 10, and 11 to control the various

Page 19 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

slave select lines corresponding to each slave block. Without these slave select lines, many instances of bus contention would occur, causing a large amount of problems. With this master controller these issues are avoided.

Figure 14: Main Controller Block Schematic

Page 20 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

5. Overall Software Description and Flowchart

Gather Sensor Data

Yes

Wait for SPI Command

Interrupt

No

Save Data

Wait for next interrupt

No

Correct Command?

Yes

Figure 15: Basic Sensor Flowchart Respond with corresponding data

Figure 16: Basic SPI Flowchart

Figure 15 and Figure 16 show the basic and generalized flowcharts for the sensor blocks (accelerometer, range, ambient light, GPS). These blocks utilize an interrupt controlled to gather data from their associated sensors and a looping, polling process to send that data out via the SPI network. The reason that these two independent loops are implemented is so that neither will interfere with the other. The sensor blocks either use an ADC (in the range, ambient light, and accelerometer blocks) or a UART (GPS block) to gather data. In both cases, an interrupt is available to utilize on Atmel microcontrollers. However, not all Atmel microcontrollers have an interrupt available for the SPI communication bus, it is for this reason that the SPI communications are conducted in a polling, looping manner rather than being interrupt based.

Page 21 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

The sensor interrupt quickly stores the received data into a descriptive and appropriate global variable so that the data may be retrieved by the SPI loop later. When the SPI network interface receives a command character that it recognizes, it will put the relevant data onto the SPI bus; otherwise, the interface will ignore the command and continue to gather sensor data.

Poll Sensors for data

Send data to Display Controller

Figure 17: Main Controller Flowchart

Figure 17 shows the flowchart for the main controller block. The main controller is the master on the SPI network, and thus controls all of the data moving on the SPI bus. The main controller loops through each sensor block, activating the corresponding slave select and querying the block for the requisite information. After the sensor data has been retrieved from all the sensor blocks, the main controller activates the slave select for the display controller and sends out all the gathered information to the display controller block.

Page 22 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

Wait for SPI command

No

Correct Command?

Yes

Receive data from Main Controller

Update VFD with new data

Figure 18: Display Controller Flowchart

Figure 18 shows the display controller block flowchart. The display controller waits for the main controller to send it the appropriate commands and data. After receiving those commands and data, the display controller updates the display with the new values. This method of updating the display is fast enough that the refresh rate is indiscernible to the human eye.

6. Overall Schematic See attached schematics. (8 pages)

Page 23 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

7. Testing Methods, Results, and Evaluation 7.1.

Accelerometer Testing

Testing of the accelerometer was done by utilizing the constant 1g force exerted by the Earth. By rotating the accelerometer so that a different axis is oriented down, a 1g force can be applied independently to each axis. The first set of tests utilized a SPI bus analyzer and tester (a Bus Pirate) to interrogate the accelerometer block with various bytes and testing the response. Any byte other than an ‘X’, ‘Y’, or ‘Z’ (decimal values 88, 89, and 90, respectively), should be ignored, and the sent byte should be returned. If an ‘X’, ‘Y’ or ‘Z’ is received, the value corresponding to that axis should be returned. The calculated value for the corresponding axis is included in the ‘Expected Value’ column. Table 1: Accelerometer Bus Pirate Testing Results

Axis force X+0g X+0g X+1g X+1g X-1g X-1g X+1g X+1g Y+0g Y+0g Y+1g Y+1g Y-1g Y-1g Y-1g Y-1g Z+0g Z+0g Z+1g Z+1g Z-1g

Sent Byte (ASCII) 40 88 (x) 50 88 (x) 60 88 (x) 89 (y) 90 (z) 70 89 (y) 80 89 (y) 100 89 (y) 88 (x) 90 (z) 110 90 (z) 120 90 (z) 130

Expected Value 40 128 50 105 60 151 128 128 70 128 80 105 100 151 128 128 110 128 120 105 130

Received Byte 40 127 50 101 60 152 128 127 70 127 80 101 100 152 127 125 110 127 120 101 130

Ok? √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √

Page 24 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Z-1g 90 (z) Z-1g 88 (x) Z-1g 89 (y) (All g forces utilize gravity)

151 128 128

Bill Bai

√ √ √

153 126 126

The second set of tests involved checking the expected output against the value displayed on the display. The complete device was rotated to achieve the desired g force on each axis. The value displayed on the VFD was then recorded and compared to the expected value. This test was conducted for each axis. Table 2: Accelerometer Display Testing Results

Axis force Expected Value X+0g X+0.00g X+1g X+1.00g X-1g X-1.00g Y+0g Y+0.00g Y+1g Y+1.00g Y-1g Y-1.00g Z+0g Z+0.00g Z+1g Z+1.00g Z-1g Z-1.00g (All g forces utilize gravity)

Displayed Value X-0.04g X+0.96g X-1.04g Y+0.00g Y+1.04g Y-1.00g Z-0.04g Z+1.00g Z-1.04g

Ok? √ √ √ √ √ √ √ √ √

These two tests clearly show that the accelerometer block is working correctly. The first test in Table 1 shows that the interface between the accelerometer values being measured and the data being transmitted over the SPI network correspond correctly. The second tests in Table 2 show that this data is successfully transmitted across the SPI network to the display and is being interpreted and projected correctly onto the display.

7.2.

Range Finder Testing

Testing of the range finder was done by placing an object at a known distance from the sensor and checking that the output value matched the expected value. The first set of tests involved

Page 25 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

using a SPI bus analyzer and tester (a Bus Pirate) to interrogate the range finder block with various bytes and testing the response. Any byte other than an ‘R’ (decimal value 82), should be ignored, and the sent byte should be returned. If an ‘R’ is received, the value corresponding to the input voltage should be returned. The calculated value for the corresponding voltage is included in the ‘Expected Value’ column. Table 3: Range Finder Bus Pirate Testing Results

Voltage (VDC) Sent Byte (ASCII) Expected Value 0.023 45 (-) 45 0.023 82 (R) 2 1.00 120 (x) 120 1.00 82 (R) 78 1.50 97 (a) 97 2.00 75 (k) 75 2.00 82 (R) 116 2.50 43 (+) 43 2.50 82 (R) 193 3.00 -------(Range finder voltage maxed out at 2.54VDC)

Received Byte 45 2 120 90 97 75 117 43 196 ----

Ok? √ √ √ Marginal √ √ √ √ √ ----

The second set of tests involves checking the expected output on the VFD against the output from the range finder block. Again, this test places an item at a known distance from the range finder sensor. This time, the measured distance will be checked against the displayed distance value on the display. Table 4: Range Finder Display Testing Results

Measured Distance Expected Value 000cm 000cm 000cm 000cm 000cm 000cm (incomplete at time of draft)

Displayed Value 000cm 000cm 000cm

Ok?

The tests show that the range finder value is working correctly (tentative). Table 3 shows that the microcontroller is able to correctly gather the relevant data from the range finder sensor and

Page 26 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

convey that data to the SPI network. Table 4 shows the transmission of the range finder data from the microcontroller, across the SPI network, to the display controller, and that it is being correctly interpreted and displayed. (tentative)

7.3.

GPS Testing

Testing of the GPS block would be done by checking the output values against the values measured by another GPS device. However, it was discovered that the GPS module being used had issues locking on to satellites. The most reliable way currently known to get this GPS module to lock on is to leave it powered on for a very long time, overnight if possible. An opportunity to test this method has not come up yet. However, the clock built into the GPS module still works. It does not synchronize to the time on the satellites, but instead resets to 12:00:00 every time the module is powered on. This indicates minimal but verifiable operation of the GPS block as a whole. Furthermore, this time information is transmitted across the SPI network and is displayed correctly on the VFD. If this faulty GPS module were to be replaced with a correctly operating GPS module, this block would likely have a much higher level of functionality. But again, this display of the time does indicate a minimal but verifiable level of operation in the GPS block.

7.4.

Ambient Light Testing

Testing of the ambient light block was done by exposing the CdS photocell to various light conditions. The first set of tests involved using a SPI bus analyzer and tester (a Bus Pirate) to interrogate the range finder block with various bytes and testing the response. Any byte other than an ‘L’ (decimal value 76), should be ignored, and the sent byte should be returned. If an ‘L’ is received, the value corresponding to the input voltage should be returned. Because the CdS

Page 27 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

cell is not a particularly accurate sensor, and because no preset output curve is available, the expected value shows an estimation of the output value. Table 5: Ambient Light Sensor Bus Pirate Testing

Light Level Sent Byte (ASCII) Expected Value Received Byte Low (covered sensor) 10 10 10 Low (covered sensor) 76 (L) High value 96 High (flashlight) 20 20 20 High (flashlight) 76 (L) Low value 0 Dim room 30 30 30 Dim room 76 (L) Medium high value 54 Medium room 40 40 40 Medium room 76 (L) Medium value 34 Bright room 50 50 50 Bright room 76 (L) Medium low value 17 (Dim room – daytime, no lights; Medium room – one light on; Bright room – all lights on)

Ok? √ √ √ √ √ √ √ √ √ √

The second test involves the brightness control on the display. The display being used has four levels of brightness available. To test this, the light sensor will either be covered up or lit up with a flashlight. When the light sensor detects a low ambient light level, the display should dim. Conversely, when the sensor detects a high ambient light level, the display should brighten. Table 6: Ambient Light Display Testing

Light Level Low (covered sensor) High (flashlight)

Expected Reaction Dim Brighten

Actual Reaction Dim Brighten

Ok? √ √

The tests in Table 5 and Table 6 show that the ambient light block is working correctly. The first test shows that the ambient light block microcontroller is correctly able to detect the ambient light value and send it over the SPI network. The second test shows that the system is able to utilize the ambient light value to adjust the brightness of the display.

Page 28 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

7.5.

ECET 396 Prof. Barnett

Bill Bai

Display Testing

Testing of the display was done by verifying that the data being updated on the display corresponded to the data being collected by the sensors. See the second tests conducted for the accelerometer, range finder, ambient light, and GPS blocks.

7.6.

Main Controller/SPI Network Testing

Testing of the main controller and SPI network was done by utilizing a logic analyzer. The logic analyzer was used to sniff the packets being transferred on the SPI network. This testing was done to validate the proper execution of slave select activation and command character transfer.

Figure 19: Main Controller/SPI Network Logic Analyzer Capture

Figure 19 shows a logic analyzer capture for the SPI network that the main controller is the master for. The top three lines are the Serial ClocK, Master In-Slave Out, and Master Out-Slave In lines. The remaining five lines are the slave select lines for the various blocks; accelerometer, range finder, GPS, ambient light, and display, respectively. The bubbles on the MISO and MOSI lines indicate that an SPI byte was correctly decoded from the data. The main point of this logic analyzer capture is to show that the main controller is pulling each slave select line down, activating that slave, in succession. Furthermore, a transfer of command

Page 29 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

and data bytes between the main controller and the various slaves on the network is indicated by the correctly decoded SPI bytes. The final validation of the successful transfer of bytes across the SPI network is the correct display of data on the display, as shown in the testing for the acceleration, ambient light, range and GPS block tests. Overall, the main controller is working very well.

8. Conclusions and Recommendations Overall, this project was generally successful as a proof of concept. The original idea was to create a truly portable heads up display unit that could be useful. However, the cost of such a prototype exceeded the available funds. The main roadblocks that were encountered were the display and range finder. To be effective as a heads up display, the display unit being used must be exceptionally bright with extremely high contrast and clarity. The most affordable technology meeting these requirements was the vacuum fluorescent display. Yet even VFD’s are fairly expensive. Luckily, the ECET department was kindly able to grant the use of a spare VFD. Unfortunately, this VFD was not suitable at all to the application. It was much too large and heavy, in addition to requiring a massive amount of power to operate. This forced the project to proceed down the proof of concept route rather than trying to create a working prototype. Another hurdle was the range finder. The original idea was to have a range finder capable of detecting the range to an object a reasonable distance away (several hundred feet). However, the only easily portable system for that range of detection is a laser based system. Again, the issue is the price. Laser based range finders for golf players run in the $200 range. This simply would not fit into the budget for a project of this caliber. It was therefore decided to utilize a much less

Page 30 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

expensive infrared range finder. Although the effective range is limited to about 150cm, this is still enough to serve as a proof of concept. In conclusion, I believe that this project was an overall success. I think that if this idea were developed further, a more appropriate display and range finder could be found and utilized. With the types of consumer electronics being developed nowadays, a truly portable heads up display unit is more than possible. I have certainly learned a lot about product development and project management, which are both skills I will continue to grow and develop as I progress through my career.

Page 31 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

9. References 1. Analog Devices MEMS. (n.d.). Retrieved 11 8, 2010, from Analog Devices: http://www.analog.com/en/mems/products/index.html 2. Atmel AVR Microcontrollers. (n.d.). Retrieved 11 8, 2010, from atmel.com: http://www.atmel.com/products/avr/default.asp?family_id=607&source=redirect 3. Avionic CRT HUD. (n.d.). Retrieved 11 8, 2010, from thomaselectronics.com: http://www.thomaselectronics.com/avionics/04m302_head_up_display.php 4. Bartlett, C. (2004, April). A Laser Illuminated Head Up Display. (D. Hopper, Ed.) Defense, Security, and Cockpit Displays, 5443, 156-164. 5. BMW HUD information page for 5 Series Sedan. (n.d.). Retrieved 10 23, 2010, from BMW.com: http://www.bmw.com/com/en/newvehicles/5series/sedan/2007/allfacts/ergonomics/hud.h tml 6. Brown, R., Modro, D., & Greer, M. (2001). High Resolution LCD Projection Based Color Head-Up Display. (D. Hopper, Ed.) Cockpit Displays VIII: Displays for Defense Applications, 4362, 183-193. 7. Chevrolet Camero HUD in Action Video. (n.d.). Retrieved 10 20, 2010, from camaroblog.com:

http://www.camaroblog.com/blog/1044318_first-video-of-2011-

camaro-hud-display-in-action 8. Cyclone

III

FPGA.

(n.d.).

Retrieved

11

8,

2010,

from

altera.com:

http://www.altera.com/products/devices/cyclone3/cy3-index.jsp 9. Doshi, A., Cheng, S., & Trivedi, M. (2009, February). A Novel Active Heads-Up Display for Driver Assistance. IEEE Transactions on Systems, Man, and Cybernetics, 39(1), 8593. 10. GPS Information. (n.d.). Retrieved 11 8, 2010, from GPS.gov: http://www.gps.gov/

Page 32 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

11. I2C

ECET 396 Prof. Barnett

Specification.

(n.d.).

Retrieved

Bill Bai

11

8,

2010,

from

nxp.com:

http://www.nxp.com/acrobat_download2/literature/9398/39340011.pdf 12. iHud Multifunction Glass Display. (n.d.). Retrieved 10 20, 2010, from i-hud.com: http://ihud.com/ 13. Kalinsky, D., & Kalinsky, R. (n.d.). Introduction to SPI. Retrieved 11 8, 2010, from eetimes.com: http://www.eetimes.com/discussion/other/4023908/Introduction-to-SerialPeripheral-Interface 14. Laser

HUD.

(n.d.).

Retrieved

11

8,

2010,

from

microvision.com:

http://www.microvision.com/vehicle_displays/index.html 15. Laser

Range

Finder.

(n.d.).

Retrieved

11

8,

2010,

from

Wikipedia:

http://en.wikipedia.org/wiki/Laser_rangefinder 16. MAX 6921/6932 Serial Interfaced VFD Tube Drivers. (n.d.). Retrieved 11 8, 2010, from maxim.com: http://www.maxim-ic.com/datasheet/index.mvp/id/4097 17. Microcontroller UART Tutorial. (n.d.). Retrieved 11 8, 2010, from societyofrobots.com: http://www.societyofrobots.com/microcontroller_uart.shtml 18. Millimeter Wave Radar Distance Sensor. (n.d.). Retrieved 11 8, 2010, from Elva 1: http://www.elva-1.com/products/industrial/FMCW_Distance_Sensor.html 19. Photodiodes.

(n.d.).

Retrieved

11

8,

2010,

from

hamamatsu.com:

http://sales.hamamatsu.com/assets/html/ssd/si-photodiode/index.htm 20. Piezoelectric Sensors. (n.d.). Retrieved 11 8, 2010, from Piezocryst Sensors: http://www.piezocryst.com/piezoelectric_sensors.php 21. Review of the Jumpstart HUD App. (n.d.). Retrieved 10 20, 2010, from navigationapps.com: http://navigationapps.com/jumpstart-hud-iphone-app-review/ 22. Rohm Ambient Light Sensors. (n.d.). Retrieved 11 8, 2010, from rohm.com: http://www.rohm.com/products/lsi/sensor/ambient_light_sensor/selection/

Page 33 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai

23. Sharp IR Rangers Info. (n.d.). Retrieved 11 8, 2010, from Acroname Robotics: http://www.acroname.com/robotics/info/articles/sharp/sharp.html 24. Strain Gauge Tutorial. (n.d.). Retrieved 11 9, 2010, from Society of Robots: http://www.societyofrobots.com/sensors_forcetorque.shtml 25. TI

DLP

PicoProjector.

(n.d.).

Retrieved

11

8,

2010,

from

ti.com:

http://focus.ti.com/general/docs/gencontent.tsp?contentId=52770 26. Vernier

Light

Sensor.

(n.d.).

Retrieved

11

8,

2010,

from

vernier.com:

http://www.vernier.com/probes/ls-bta.html 27. VFD Technology. (n.d.). Retrieved 11 8, 2010, from Noritake Electronics: http://www.noritake-elec.com/vfd_technology_an.htm

Page 34 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

10. 10.1.

Bill Bai

Appendices

Budget Table 7: Planned Portable Heads Up Display Project Budget

Item GPS Reciever 3 Axis Accelerometer Microcontroller Heads Up Display Range Finder Light Detector NiMH AA Battery Misc. Ics PCBs Enclosure Misc. Supplies

Unit Cost $ 60.00 $ 30.00 $ 5.00 $ 200.00 $ 100.00 $ 5.00 $ 3.00 $ 2.00 $ 50.00 $ 20.00 $ 50.00

Grand Total: Quantity 1 1 6 1 1 1 4 10 4 1 1

$ Total $ $ $ $ $ $ $ $ $ $ $

727.00 Cost 60.00 30.00 30.00 200.00 100.00 5.00 12.00 20.00 200.00 20.00 50.00

The final cost of the project was significantly reduced by utilizing a VFD provided by the ECET department. Also, a much more inexpensive infrared rangefinder was used instead of a laser range finder. The final cost of the project is shown below. Table 8: Actual Portable Heads Up Display Project Budget

Item GPS Reciever 3 Axis Accelerometer Microcontroller Heads Up Display Range Finder Light Detector NiMH AA Battery Misc. Ics PCBs Enclosure Misc. Supplies

Unit Cost $ 60.00 $ 30.00 $ 5.00 $ 0.00 $ 15.00 $ 5.00 $ 3.00 $ 2.00 $ 50.00 $ 20.00 $ 50.00

Grand Total: Quantity 1 1 6 1 1 1 4 10 4 1 1

$ 442.00 Total Cost $ 60.00 $ 30.00 $ 30.00 $ 0.00 $ 15.00 $ 5.00 $ 12.00 $ 20.00 $ 200.00 $ 20.00 $ 50.00

Page 35 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

10.2.

ECET 396 Prof. Barnett

Bill Bai

Tracking Gantt Chart

Page 36 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

10.3.

ECET 396 Prof. Barnett

Bill Bai

Software Listings

/*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display

ADMUX = (ADMUX & ~0x3F) | 2;

/* switch

to ADC2 */ } else {

Block:

Accelerometer Microcontroller

Module:

Project header

Desc.:

This file contains information useful to all modules in this block, namely

global variables and include files **********************************************************/ #ifndef PROJ_HDR_H #define PROJ_HDR_H /* Include Files */ #include #include #include /* Module Includes */ #include "adc.h" #include "usi.h"

/* any other ADC selected */

X_AXIS = ADCH; /* Read the Z-axis accelerometer measurement */ ADMUX = (ADMUX & ~0x3F) | 0; /* switch back to ADC0 */ } ADC_START; /* Start next ADC conversion */ } /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Accelerometer Microcontroller

Module:

Universal Serial Interface header

Desc.:

This file contains the global variables for the USI functions. This code

is originally from the AVR Appnote AVR319 - Using the USI

/* ADC extern extern extern

Global Variables */ volatile char X_AXIS; volatile char Y_AXIS; volatile char Z_AXIS;

module for SPI communications. the code over to the WinAVR compiler. **********************************************************/

#endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display

#ifndef USI_H #define USI_H /* Set SPI bus mode */ #define SPI_MODE 0 /* Sample on leading _rising_ edge, setup on trailing _falling_ edge. */ //#define SPI_MODE 1 /* Sample on leading _falling_ edge, setup on trailing _rising_ edge. */

Block:

Accelerometer Microcontroller

Module:

Analog to Digital converter header

Desc.:

This file contains the function prototypes and variable definitions for the ADC

functions **********************************************************/ #ifndef ADC_H #define ADC_H /* ADC function prototypes */ void adc_init(void); /* Initialize ADC functionality */ ISR(ADC_vect); /* ADC finished conversion interrupt */ /* ADC Macros */ #define ADC_START (ADCSRA |= (1<
Module:

Analog to Digital converter Functions

Desc.:

This file contains the source code for the ADC functions **********************************************************/ #include "proj_hdr.h" /* Initialize ADC functionality */ void adc_init(void) { ADMUX |= (0<
} /* ADC finished conversion interrupt */ ISR(ADC_vect) { if( (ADMUX & 0x3F) == 0 ) */ { Z_AXIS = ADCH; accelerometer measurement */ ADMUX = (ADMUX & ~0x3F) to ADC1 */ } else if ( (ADMUX & 0x3F) == 1 ) */ { Y_AXIS = ADCH; accelerometer measurement */

/* if ADC0 is selected /* Read the Z-axis | 1;

/* USI port and pin definitions. */ #define USI_OUT_REG PORTA port output register. #define USI_IN_REG PINA port input register. #define USI_DIR_REG DDRA port direction register. #define USI_CLOCK_PIN 4 clock I/O pin. #define USI_SELECT_PIN 7 #define USI_DATAIN_PIN 6 data input pin. #define USI_DATAOUT_PIN 5 data output pin.

//!< USI //!< USI //!< USI //!< USI //!< USI //!< USI

/* USI slave select input */ #define USI_SS ((USI_IN_REG & (1<> USI_SELECT_PIN)

Block:

ADC_START;

I

have ported

/* switch

/* if ADC1 is selected

/* Speed configuration: * Bits per second = CPUSPEED / PRESCALER / (COMPAREVALUE+1) / 2. * Maximum = CPUSPEED / 64. * 8MHz / 64 = 125kHz * 125kHz = 8MHz / 8 / (3+1) / 2 * Prescaler = 8 * Compare Value = 3 */ #define TC0_PRESCALER_VALUE 8 //!< Must be 1, 8, 64, 256 or 1024. #define TC0_COMPARE_VALUE 3 //!< Must be 0 to 255. Minimum 31 with prescaler CLK/1. /* Prescaler value converted to bit settings. */ #if TC0_PRESCALER_VALUE == 1 #define TC0_PS_SETTING (1<
Accelerometer Microcontroller

Module:

Universal Serial Interface functions

/* Read the Y-axis

Page 37 of 57

Date: April 18, 2011 Lab Section: Monday 1:30 Desc.:

ECET 396 Prof. Barnett

Bill Bai

TCCR0A = (1<
This file contains the source code for the USI functions. This code is originally

from the

// Init Output Compare Register. OCR0A = TC0_COMPARE_VALUE;

AVR Appnote AVR319 - Using the USI module for SPI communications.

I have ported

// Init driver status register. USI_SPI_status.masterMode = 1; USI_SPI_status.transferComplete = 0; USI_SPI_status.writeCollision = 0;

the code over to the WinAVR compiler. **********************************************************/ #include "proj_hdr.h"

storedUSIDR = 0; }

/*! \brief Data input register buffer. * * Incoming bytes are stored in this byte until the next transfer is complete. * This byte can be used the same way as the SPI data register in the native * SPI module, which means that the byte must be read before the next transfer * completes and overwrites the current value. */ unsigned char storedUSIDR; /*! \brief Driver status bit structure. * * This struct contains status flags for the driver. * The flags have the same meaning as the corresponding status flags * for the native SPI module. The flags should not be changed by the user. * The driver takes care of updating the flags when required. */ struct usidriverStatus_t { unsigned char masterMode : 1; //!< True if in master mode. unsigned char transferComplete : 1; //!< True when transfer completed. unsigned char writeCollision : 1; //!< True if put attempted during transfer. };

/*! \brief Initialize USI as SPI slave. * * This function sets up all pin directions and module configurations. * Use this function initially or when changing from master to slave mode. * Note that the stored USIDR value is cleared. * * \param spi_mode Required SPI mode, must be 0 or 1. */ void USI_SPI_initslave(void) { // Configure port directions. //USI_DIR_REG |= (1<
volatile struct usidriverStatus_t USI_SPI_status; //!< The driver status bits.

storedUSIDR = 0; }

/*! \brief Timer/Counter 0 Compare Match Interrupt handler. * * This interrupt handler is only enabled when transferring data * in master mode. It toggles the USI clock pin, i.e. two interrupts * results in one clock period on the clock pin and for the USI counter. */ /*#pragma vector=TIMER0_COMP_vect */ /* Compiler specific directive */ /*__interrupt void timer0comp_handler()*/ ISR(TIM0_COMPA_vect) { USICR |= (1<
/* Changes USI MISO between input and output when slave is selected or not */ void USI_SPI_SSn(unsigned char mode) { if( mode == 0 ) /* Slave is selected */ { USI_DIR_REG |= (1<
// Configure USI to 3-wire master mode with overflow

}

USICR = (1<
/*! \brief Get one byte from bus. * * This function only returns the previous stored USIDR value. * The transfer complete flag is not checked. Use this function * like you would read from the SPDR register in the native SPI module.

interrupt.

// Enable 'Clear Timer on Compare match' and init prescaler.

Page 34 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett #include /* Module Includes */ #include "adc.h" #include "usi.h"

*/ unsigned char USI_SPI_getc(void) { return storedUSIDR; } /*! \brief Wait for transfer to complete. * * This function waits until the transfer complete flag is set. * Use this function like you would wait for the native SPI interrupt flag. */ void USI_SPI_wait(void) { do {} while( USI_SPI_status.transferComplete == 0 ); } /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Accelerometer Microcontroller

Module:

Main program

Desc.:

This is the main program section of the Accelerometer microcontroller **********************************************************/ #include "proj_hdr.h"

Bill Bai

/* Include project header file */

/* Global Variables for ADC readings */ volatile char X_AXIS = 10; /* X-axis accelerometer reading */ volatile char Y_AXIS = 20; /* Y-axis accelerometer reading */ volatile char Z_AXIS = 30; /* Z-axis accelerometer reading */ int main(void) { /* Local Variables */ unsigned char cmd = 0;

/* ADC Global Variables */ extern volatile char LIGHT; #endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Ambient Light

Module:

Analog to Digital converter header

Desc.:

This file contains the function prototypes and variable definitions for the ADC functions **********************************************************/ #ifndef ADC_H #define ADC_H /* ADC function prototypes */ void adc_init(void); /* Initialize ADC functionality */ ISR(ADC_vect); /* ADC finished conversion interrupt */ /* ADC Macros */ #define ADC_START (ADCSRA |= (1<
Ambient Light

Module:

Analog to Digital converter Functions

/* Initialize software modules */ adc_init(); /* Initialize ADC */ //USI_SPI_initmaster(); USI_SPI_initslave(); /* Initialize SPI as slave */

This file contains the source code for the ADC functions **********************************************************/

sei();

#include "proj_hdr.h"

/* Enable global interrupts */

while(1) { if( !USI_SS )

/* if this SPI slave is

selected */ { USI_SPI_SSn(0); /* Active low slave selected */ cmd = USI_SPI_getc(); if( cmd == 'X' ) /* if the X axis is requested */ { USI_SPI_putc(X_AXIS); /* Send X-axis value */ USI_SPI_wait(); /* wait for transmission to finish */ } else if( cmd == 'Y' ) /* if the Y axis is requested */ { USI_SPI_putc(Y_AXIS); /* Send Y-axis value */ USI_SPI_wait(); /* wait for transmission to finish */ } else if( cmd == 'Z' ) /* if the Z axis is requested */ { USI_SPI_putc(Z_AXIS); /* Send X-axis value */ USI_SPI_wait(); /* wait for transmission to finish */ } else{} /* all other requests, do nothing */ } else /* if not selected, do nothing */ { USI_SPI_SSn(1); /* Active low slave not selected */ }/* End of if */ }/* End of while */ return 0; }/* End of main */ /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Ambient Light

Module:

Project header

Desc.:

This file contains information useful to all modules in this block, namely

global variables and include files **********************************************************/ #ifndef PROJ_HDR_H #define PROJ_HDR_H /* Include Files */ #include #include

Desc.:

/* Initialize ADC functionality */ void adc_init(void) { ADMUX |= (0<
/* Start ADC Conversion */

} /* ADC finished conversion interrupt */ ISR(ADC_vect) { LIGHT = ADCH; /* Read ADC value into Range variable */ ADC_START; /* Start next ADC conversion */ } /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Ambient Light

Module:

Universal Serial Interface header

Desc.:

This file contains the global variables for the USI functions. This code

is originally from the AVR Appnote AVR319 - Using the USI module for SPI communications.

I

have ported the code over to the WinAVR compiler. **********************************************************/ #ifndef USI_H #define USI_H /* Set SPI bus mode */ #define SPI_MODE 0 /* Sample on leading _rising_ edge, setup on trailing _falling_ edge. */ //#define SPI_MODE 1 /* Sample on leading _falling_ edge, setup on trailing _rising_ edge. */ /* USI port and pin definitions. */ #define USI_OUT_REG PORTB port output register. #define USI_IN_REG PINB port input register. #define USI_DIR_REG DDRB port direction register. #define USI_CLOCK_PIN 2 clock I/O pin.

//!< USI //!< USI //!< USI //!< USI

Page 35 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

#define USI_SELECT_PIN 3 #define USI_DATAIN_PIN 0 data input pin. #define USI_DATAOUT_PIN 1 data output pin.

//!< USI //!< USI

Bill Bai

ISR(TIMER0_COMPA_vect) { USICR |= (1<
// Toggle clock output pin.

/* USI SPI start condition interrupt */ ISR(USI_START_vect) { /* not enabled */ }

/* USI slave select input */ #define USI_SS ((USI_IN_REG & (1<> USI_SELECT_PIN) /* Speed configuration: * Bits per second = CPUSPEED / PRESCALER / (COMPAREVALUE+1) / 2. * Maximum = CPUSPEED / 64. * 8MHz / 64 = 125kHz * 125kHz = 8MHz / 8 / (3+1) / 2 * Prescaler = 8 * Compare Value = 3 */ #define TC0_PRESCALER_VALUE 8 //!< Must be 1, 8, 64, 256 or 1024. #define TC0_COMPARE_VALUE 3 //!< Must be 0 to 255. Minimum 31 with prescaler CLK/1. /* Prescaler value converted to bit settings. */ #if TC0_PRESCALER_VALUE == 1 #define TC0_PS_SETTING (1<
Ambient Light

Module:

Universal Serial Interface functions

Desc.:

This file contains the source code for the USI functions. This code is originally

/*! \brief USI Timer Overflow Interrupt handler. * * This handler disables the compare match interrupt if in master mode. * When the USI counter overflows, a byte has been transferred, and we * have to stop the timer tick. * For all modes the USIDR contents are stored and flags are updated. */ /*#pragma vector=USI_OVF_vect*/ /* Compiler specific directive */ /*__interrupt void usiovf_handler()*/ ISR(USI_OVF_vect) { // Master must now disable the compare match interrupt // to prevent more USI counter clocks. if( USI_SPI_status.masterMode == 1 ) { TIMSK &= ~(1<
from the // Enable 'Clear Timer on Compare match' and init

AVR Appnote AVR319 - Using the USI prescaler.

module for SPI communications.

TCCR0A = (1<
I have ported

the code over to the WinAVR compiler. **********************************************************/

// Init Output Compare Register. OCR0A = TC0_COMPARE_VALUE;

#include "proj_hdr.h" /*! \brief Data input register buffer. * * Incoming bytes are stored in this byte until the next transfer is complete. * This byte can be used the same way as the SPI data register in the native * SPI module, which means that the byte must be read before the next transfer * completes and overwrites the current value. */ unsigned char storedUSIDR; /*! \brief Driver status bit structure. * * This struct contains status flags for the driver. * The flags have the same meaning as the corresponding status flags * for the native SPI module. The flags should not be changed by the user. * The driver takes care of updating the flags when required. */ struct usidriverStatus_t { unsigned char masterMode : 1; //!< True if in master mode. unsigned char transferComplete : 1; //!< True when transfer completed. unsigned char writeCollision : 1; //!< True if put attempted during transfer. };

// Init driver status register. USI_SPI_status.masterMode = 1; USI_SPI_status.transferComplete = 0; USI_SPI_status.writeCollision = 0; storedUSIDR = 0; } /*! \brief Initialize USI as SPI slave. * * This function sets up all pin directions and module configurations. * Use this function initially or when changing from master to slave mode. * Note that the stored USIDR value is cleared. * * \param spi_mode Required SPI mode, must be 0 or 1. */ void USI_SPI_initslave(void) { // Configure port directions. //USI_DIR_REG |= (1<
volatile struct usidriverStatus_t USI_SPI_status; //!< The driver status bits. /*! \brief Timer/Counter 0 Compare Match Interrupt handler. * * This interrupt handler is only enabled when transferring data * in master mode. It toggles the USI clock pin, i.e. two interrupts * results in one clock period on the clock pin and for the USI counter. */ /*#pragma vector=TIMER0_COMP_vect */ /* Compiler specific directive */ /*__interrupt void timer0comp_handler()*/

// Init driver status register. USI_SPI_status.masterMode = 0; USI_SPI_status.transferComplete = 0; USI_SPI_status.writeCollision = 0; storedUSIDR = 0; } /* Changes USI MISO between input and output when slave is selected or not */ void USI_SPI_SSn(unsigned char mode)

Page 36 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

{ if( mode == 0 ) /* Slave is selected */ { USI_DIR_REG |= (1<
// Master should now enable compare match interrupts. if( USI_SPI_status.masterMode == 1 ) { TIFR |= (1<
Module:

{ USI_SPI_SSn(0); /* Active low slave selected */ cmd = USI_SPI_getc(); if( cmd == 'L' ) /* if the X axis is requested */ { USI_SPI_putc(LIGHT); // Send temp value to SPI and increment USI_SPI_wait(); // wait for transmission to finish } else{} /* all other requests, do nothing */ } else /* if not selected, do nothing */ { USI_SPI_SSn(1); /* Active low slave not selected */ }/* End of if */ } /* End of while */ return 0; } /* End of main */ /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Display Controller

Module:

Project header

Desc.:

This file contains information useful to all modules in this block, namely

global variables and include files **********************************************************/ #ifndef PROJ_HDR_H #define PROJ_HDR_H

// Put data in USI data register. USIDR = val;

Block:

Bill Bai

/* Include Files */ #include #include #include #include /* Module Includes */ #include "spi.h" #include "uart.h" #include "vfd.h" #include "disp.h" /* Global Variables */ extern volatile unsigned char X_AXIS; /* X-axis acceleration */ extern volatile unsigned char Y_AXIS; /* Y-axis acceleration */ extern volatile unsigned char Z_AXIS; /* Z-axis acceleration */ extern volatile unsigned char RANGE; /* Range finder distance */ extern volatile unsigned char LIGHT; /* Ambient light level */ extern volatile int ALTITUDE; /* Altitude in meters */ extern volatile unsigned int SPEED; /* Speed in kilometers per hour */ extern volatile unsigned char BEARING; /* Heading of the vehicle */ extern volatile unsigned char HOURS; /* Hour of the current time */ extern volatile unsigned char MINUTES; /* Minutes of the current hour */ extern volatile unsigned char SECONDS; /* Seconds of the current hour */ #endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Display Controller

Module:

SPI bus header

Ambient Light Main program Desc.:

Desc.:

This is the main program section of the Ambient Light microcontroller **********************************************************/ #include "proj_hdr.h"

/* Include project header file */

/* Global Variables for ADC readings */ volatile char LIGHT = 0; /* Ambient Light value */ int main(void) { /* Local Variables */ unsigned char cmd = 0; /* Initialize software modules */ adc_init(); /* Initialize ADC */ USI_SPI_initslave(); /* Initialize SPI as slave */ sei();

#ifndef SPI_H #define SPI_H /* SPI Defines */ #define DDR_SPI #define DD_MOSI #define DD_MISO #define DD_SCK #define DD_SSN

DDRB 3 4 5 2

/* SPI Function Prototypes */ void SPI_MasterInit(void); void SPI_putc(char cData); void SPI_SlaveInit(void); char SPI_getc(void); ISR(SPI_STC_vect);

/* Enable global interrupts */

while(1) { if( !USI_SS ) selected */

This file contains the function prototype and variable definitions for the SPI bus functions **********************************************************/

/* if this SPI slave is

/* SPI Macros */ #define SPI_SS ((DDR_SPI & (1<> DD_SSN) #endif /***********************************************************

Page 37 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Bill Bai

{ cnt = 2; type = 8; } else if( rcv == 'h' )

Display Controller

/* if the Hours are

sent */ {

Module:

SPI bus functions

This file contains the source code for the SPI bus functions **********************************************************/

cnt = 1; type = 9; } else if( rcv == 'm' )

Desc.:

/* if the Minutes are

sent */ {

#include "proj_hdr.h" /* Initialize SPI for master mode */ void SPI_MasterInit(void) { /* Cofigure SSn, MOSI, and SCK as output */ DDR_SPI = (1<
cnt = 1; type = 10; } else if( rcv == 's' )

/* if the Hours are

sent */ { cnt = 1; type = 11; } else

/* all other requests, do nothing

*/ { cnt = 0; type = 0; }

/* Transmit a byte of data via the SPI bus in master mode */ void SPI_putc(char cData) { /* Start transmission */ SPDR = cData; /* Wait for transmission complete */ while(!(SPSR & (1<
/* Recieve byte counter /* Type of byte recieved */

rcv = SPDR; /* Get SPI Data Register value */ if( cnt == 0 ) { if( rcv == 'x' ) /* if the X-axis is sent */ { cnt = 1; type = 1; } else if( rcv == 'y' )

/* if the Y-axis is

sent */ { cnt = 1; type = 2; } else if( rcv == 'z' )

/* if the Z-axis is

sent */ { cnt = 1; type = 3; } else if( rcv == 'l' )

/* if the Ambient Light

level is sent */ { cnt = 1; type = 4; } else if( rcv == 'r' )

/* if the Range

distance is sent */ { cnt = 1; type = 5; } else if( rcv == 'a' )

/* if the Altitude is

sent */ { cnt = 2; type = 6; } else if( rcv == 'v' )

/* if the Speed is sent

*/ { cnt = 2; type = 7; } else if( rcv == 'b' ) sent */

/* if the Bearing is

} else if( cnt == 1 ) { if( type == 1 ) /* if the X-axis is sent */ { X_AXIS = SPDR; /* Get X-axis value from the Main Controller */ cnt = 0; type = 0; } else if( type == 2 ) /* if the Y-axis is sent */ { Y_AXIS = SPDR; /* Get Y-axis value from the Main Controller */ cnt = 0; type = 0; } else if( type == 3 ) /* if the Z-axis is sent */ { Z_AXIS = SPDR; /* Get Z-axis value from the Main Controller */ cnt = 0; type = 0; } else if( type == 4 ) /* if the Ambient Light level is sent */ { LIGHT = SPDR; /* Get Ambient Light value from the Main Controller */ cnt = 0; type = 0; } else if( type == 5 ) /* if the Range distance is sent */ { RANGE = SPDR; /* Get Range value from the Main Controller */ cnt = 0; type = 0; } else if( type == 6 ) /* if the Altitude is sent */ { ALTITUDE += SPDR; /* Low byte of Altitude */ cnt = 0; type = 0; } else if( type == 7 ) /* if the Speed is sent */ { SPEED += SPDR; /* Low byte of Speed */ cnt = 0; type = 0; } else if( type == 8 ) /* if the Bearing is sent */ { BEARING += SPDR; /* Low byte of Bearing */ cnt = 0; type = 0; } else if( type == 9 ) /* if the Hours are sent */ { HOURS = SPDR; /* Get Hours value from the Main Controller */ cnt = 0; type = 0; } else if( type == 10 ) /* if the Minutes are sent */ { MINUTES = SPDR; /* Get Minutes value from the Main Controller */ cnt = 0; type = 0; } else if( type == 11 ) /* if the Seconds are sent */ {

Page 38 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

SECONDS = SPDR; /* Get Seconds value from the Main Controller */ cnt = 0; type = 0; } else /* all other requests, do nothing */ { cnt = 0; type = 0; } } else if( cnt == 2 ) { if( type == 6 )

/* if the Altitude is

sent */ { ALTITUDE = 0;

/* reset

ALTITUDE += (SPDR<<8);

/* High

Altitude */

Bill Bai

volatile unsigned char UART_BUF_CNT = 0; /* UART Buffer position counter */ volatile unsigned char UART_FLAGS = 0; UART status */

/* "Register" to store

/* Initialize UART module, from datasheet */ void UART_init( unsigned int ubrr ) { /* Set baud rate */ UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char)ubrr; /* Enable receiver and transmitter */ UCSR0B = (1<
byte of Altitude */ cnt = 1; type = 6; } else if( type == 7 )

/* if the Speed is sent

*/ { SPEED = 0; /* reset SPEED */ SPEED += (SPDR<<8) ; /* High

/* Send a byte via UART, from datasheet */ void UART_putc( unsigned char data ) { /* Wait for empty transmit buffer */ while ( !( UCSR0A & (1<
byte of Speed */ cnt = 1; type = 7; } else if( type == 8 )

/* if the Bearing is

sent */ { BEARING = 0;

/* reset

BEARING += (SPDR<<8);

/* High

BEARING */ byte of Bearing */ cnt = 1; type = 8; } else {

/* Send a string via UART */ void UART_puts(unsigned char * string ) { unsigned char n = 0; while( n < strlen(string) ) /* while not at the end of the string */ { UART_putc(string[n++]); /* putc the next character */ }/* end while */ } /* Get a byte via UART, from datasheet */ unsigned char UART_getc( void ) { /* Wait for data to be received */ while ( !(UCSR0A & (1<
cnt = 0; type = 0; } } else { cnt = 0; type = 0; } } /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display

/* Flush out the UART receive buffer, from datasheet */ void UART_flush( void ) { unsigned char dummy; while ( UCSR0A & (1<
Block:

Display Controller

Module:

UART header

Block:

Display Controller

Desc.:

This file contains the global variables and function prototypes for the UART

Module:

VFD Commands header

module. **********************************************************/ #ifndef UART_H #define UART_H /* Function prototypes */ void UART_init( unsigned int baud ); void UART_putc( unsigned char data ); void UART_puts( unsigned char * string ); unsigned char UART_getc( void ); void UART_flush( void );

Desc.:

This file contains the global variables and function prototypes for the VFD Commands module. **********************************************************/ #ifndef VFD_H #define VFD_H /* Function prototypes */ void cursor_home(void); void cursor_up(unsigned char lines); void cursor_down(unsigned char lines); void cursor_right(unsigned char cols); void cursor_left(unsigned char cols); void cursor_position(unsigned char row, unsigned char col); void save_cursor(void); void restore_cursor(void); void request_cursor(void); void auto_linefeed_on(void); void auto_linefeed_off(void); void reverse_video_on(void); void reverse_video_off(void); void blinking_on(void); void blinking_off(void); void reset(void); void single_single(void); void double_double(void); void dpmm(unsigned char a, unsigned char b, unsigned char

/* Global Variables */ extern volatile unsigned char UART_BUFFER[]; /* Defines */ #define UART_BUFFER_SIZE 8

/* Set max buffer size

*/ //#define UART_RXC 0 /* UART finished receiving byte flag */ //#define UART_TXC 1 /* UART finished transmitting byte flag */ #endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Display Controller

Module:

UART functions

Desc.:

This file contains the source code for the functions for the UART module.

Much of the code for this module is taken from the ATTiny2313 datasheet. **********************************************************/ #include "proj_hdr.h" /* Global Variables */ volatile unsigned char UART_BUFFER[UART_BUFFER_SIZE]; /* Set size of UART buffer */

c, unsigned char d, unsigned char e, unsigned char f, void void void void void

unsigned char g, unsigned char h); brightness(unsigned char level); self_test(void); rcvd_data_test(void); rcvd_data_test_exit(void); cancel(void);

#endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Display Controller

Page 39 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

Module:

VFD Command functions

Desc.:

This file contains the source code for the functions for the VFD commands

module. WARNING: Functions are not protected for invalid inputs **********************************************************/ #include "proj_hdr.h" /* Global Variables */ volatile unsigned char row_report = 0; volatile unsigned char col_report = 0; volatile unsigned char cursor_responded = 0; /* Moves cursor to home position */ void cursor_home(void) /* works */ { UART_putc(0x1B); /* ESC */ UART_putc(0x5B); /* [ */ UART_putc(0x48); /* H */ } /* Moves the cursor up 1-6 lines in */ void cursor_up(unsigned char lines) { UART_putc(0x1B); UART_putc(0x5B); UART_putc(0x30+lines); UART_putc(0x41); }

the same column, stops at the top /* unknown */ /* /* /* /*

ESC */ [ */ number of lines */ A */

/* Moves the cursor down 1-6 lines in the same column, stops at the bottom */ void cursor_down(unsigned char lines) /* unknown */ { UART_putc(0x1B); /* ESC */ UART_putc(0x5B); /* [ */ UART_putc(0x30+lines); /* number of lines */ UART_putc(0x42); /* B */ } /* Moves the cursor right 1-9 columns, void cursor_right(unsigned char cols) { UART_putc(0x1B); /* UART_putc(0x5B); /* UART_putc(0x30+cols); /* UART_putc(0x43); /* }

stops at the right margin */ /* unknown */ ESC */ [ */ number of lines */ C */

/* Moves the cursor left 1-9 columns, stops at the left margin */ void cursor_left(unsigned char cols) /* unknown */ { UART_putc(0x1B); /* ESC */ UART_putc(0x5B); /* [ */ UART_putc(0x30+cols); /* number of lines */ UART_putc(0x44); /* D */ } /* Moves the cursor to an arbitrary position */ void cursor_position(unsigned char row, unsigned char col) /* DOES NOT work */ { UART_putc(0x1B); /* ESC */ UART_putc(0x5B); /* [ */ UART_putc(0x30+(row/10)); /* Row, 10's digit */ UART_putc(0x30+(row%10)); /* Row, 1's digit */ UART_putc(0x3B); /* ; */ UART_putc(0x30+(col/100)); /* Column, 100's digit */ UART_putc(0x30+((col/10)%10)); /* Column, 10's digit */ UART_putc(0x30+(col%10)); /* Column, 1's digit */ UART_putc(0x52); /* R */ } /* Saves the present value of the cursor location, character attribute, and character set selection, moves to home if none were saved */ void save_cursor(void) /* unknown */ { UART_putc(0x1B); /* ESC */ UART_putc(0x37); /* 7 */ } /* Restores the previously saved cursor position */ void restore_cursor(void) /* unknown */ { UART_putc(0x1B); /* ESC */ UART_putc(0x38); /* 8 */ } /* Request cursor position */ void request_cursor(void) /* unknown, probably doesnt work */ { row_report = 0; col_report = 0; UART_putc(0x1B); /* ESC */ UART_putc(0x5B); /* [ */ UART_putc(0x36); /* 6 */ UART_putc(0x6E); /* n */ UART_getc(); /* ESC */ UART_getc(); /* [ */ row_report += (UART_getc() - 0x30) * 10; /* Row, 10's digit */ row_report += UART_getc() - 0x30; /* Row, 1's digit */ UART_getc(); /* ; */ col_report += (UART_getc() - 0x30) * 100; /* Column, 100's digit */ col_report += (UART_getc() - 0x30) * 10; /* Column,

Bill Bai

10's digit */ col_report += UART_getc() - 0x30; /* Column, 1's digit */ if( UART_getc() == 'R' ) { cursor_responded = 1; flag */ } else { cursor_responded = 0; } }

/* Put up cursor valid

/* With Auto Linefeed on, LF, CR, FF, and vertical tab commands cause cursor to move to first column on the next line */ void auto_linefeed_on(void) /* unknown */ { UART_putc(0x1B); /* ESC */ UART_putc(0x5B); /* [ */ UART_putc(0x32); /* 2 */ UART_putc(0x30); /* 0 */ UART_putc(0x68); /* h */ } void auto_linefeed_off(void) /* unknown */ { UART_putc(0x1B); /* ESC */ UART_putc(0x5B); /* [ */ UART_putc(0x32); /* 2 */ UART_putc(0x30); /* 0 */ UART_putc(0x6C); /* l */ } /* Clear all character and graphic attributes */ void clear_all_attributes(void) /* unknown */ { UART_putc(0x1B); /* ESC */ UART_putc(0x5B); /* [ */ UART_putc(0x30); /* 0 */ UART_putc(0x6D); /* m */ } /* Reverse Video */ void reverse_video_on(void) { UART_putc(0x1B); UART_putc(0x5B); UART_putc(0x37); UART_putc(0x6D); } void reverse_video_off(void) { UART_putc(0x1B); UART_putc(0x5B); UART_putc(0x32); UART_putc(0x37); UART_putc(0x6D); }

/* works */ /* /* /* /*

ESC */ [ */ 7 */ m */

/* works, tested by Barnett */ /* /* /* /* /*

ESC */ [ */ 2 */ 7 */ m */

/* Blinking */ void blinking_on(void) /* works */ { UART_putc(0x1B); /* ESC */ UART_putc(0x5B); /* [ */ UART_putc(0x35); /* 5 */ UART_putc(0x6D); /* m */ } void blinking_off(void) /* works, tested by Barnett */ { UART_putc(0x1B); /* ESC */ UART_putc(0x5B); /* [ */ UART_putc(0x32); /* 2 */ UART_putc(0x35); /* 5 */ UART_putc(0x6D); /* m */ } /* Reset */ /* Initialized the VFD, clears the input buffer, the screen and all communication parameters, and character attributes teturn to their defaults. No characters can be sent for 900ms after the reset. */ void reset(void) /* works */ { UART_putc(0x1B); /* ESC */ UART_putc(0x43); /* C */ } /* Character Sizes */ void single_single(void) { UART_putc(0x1B); UART_putc(0x23); UART_putc(0x35); } void double_double(void) { UART_putc(0x1B); UART_putc(0x23); UART_putc(0x33); }

/* works */ /* ESC */ /* # */ /* 5 */ /* works */ /* ESC */ /* # */ /* 3 */

/* Digital Panel Meter Mode */ /* Display the characters to be displayed in 32x48 cell 8/ /* Example: ESC/4;+123,+010,g Display: +123 +10 */ void dpmm(unsigned char a, unsigned char b, unsigned char c, unsigned char d, unsigned char e, unsigned char f, unsigned char g, unsigned char h) /* works, tested by Barnett */ { UART_putc(0x1B); /* ESC */ UART_putc(0x2F); /* / */ UART_putc(0x34); /* 4 */ UART_putc(0x30+a);

Page 40 of 57

Date: April 18, 2011 Lab Section: Monday 1:30 UART_putc(0x30+b); UART_putc(0x30+c); UART_putc(0x30+d); UART_putc(0x2C); UART_putc(0x30+e); UART_putc(0x30+f); UART_putc(0x30+g); UART_putc(0x30+h); UART_putc(0x2C); UART_putc(0x67);

ECET 396 Prof. Barnett

/* , */

/* , */ /* g */

} /* Brightness, 4 levels */ void brightness(unsigned char level) /* works, tested by Barnett */ { UART_putc(0x1B); /* ESC */ UART_putc(0x23); /* # */ if( level == 1 ) /* Dimmest */ { UART_putc(0x61); /* a */ } else if( level == 2 ) { UART_putc(0x62); /* b */ } else if( level == 3 ) { UART_putc(0x63); /* c */ } else if( level == 4 ) /* Brightest */ { UART_putc(0x64); /* d */ } else /* Default to Brightness */ { UART_putc(0x64); /* d */ } } /* Self-test mode */ void self_test(void) /* works */ { UART_putc(0x1B); /* ESC */ UART_putc(0x42); /* B */ } /* Recieved data test mode */ /* All bytes recieved will be displayed in HEX rather than ASCII. */ void rcvd_data_test(void) /* works */ { UART_putc(0x1B); /* ESC */ UART_putc(0x44); /* D */ } void rcvd_data_test_exit(void) /* unknown */ { UART_putc(0x1B); /* ESC */ UART_putc(0x45); /* E */ } /* Cancel */ void cancel(void) /* unknown */ { UART_putc(0x18); /* CAN */ } /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Display Controller

Module:

Display Output header

Desc.: This file contains the global variables and function prototypes for the Display Output module. **********************************************************/

/* /* /* /*

Bill Bai

0.00G is 127 */ Max is 127-(3.6*24), Min is 127+(3.6*24) */ Max value is 214 (-3.6G) */ Min value is 40 (+3.6G) */

/* Print the X-axis Accelerometer value to the VFD */ void display_x(void) { /* Local Variables */ unsigned char sign = 0; /* + or - */ unsigned int accel = 0; /* 000 to 360 for 0.00G to 3.60G*/ /* Set cursor position */ UART_puts("\n\r\t X= "); information */ if( X_AXIS == 0 )

/* Print

/* if X-axis value is still at

default */ { UART_puts("NO VAL");

/* Print error message

*/ return;

/* exit function */

} else if( X_AXIS > 214 ) /* if X-axis value is >max value */ { UART_putc('>'); /* Print the greater than sign */ sign = '-'; /* Set sign to negative */ accel = 360; /* Set acceleration value to absolute maximum */ } else if( X_AXIS < 40 ) /* if X-axis value is = 128 ) /* if X-axis has negative g */ { sign = '-'; /* Set sign to negative */ accel = (((float)(X_AXIS-128)/24)*100); /* Calculate Acceleration */ } else /* else Xaxis has positive g */ { sign = '+'; /* Set sign to positive */ accel = (((float)(128-X_AXIS)/24)*100); /* Calculate Acceleration */ }/* end if */ /* Print X-axis sign and value */ UART_putc(sign); /* Print the + or - sign */ UART_putc( (accel/100)+0x30 ); /* Print the 100's digit */ UART_putc('.'); /* Print the decimal point */ UART_putc( ((accel/10)%10)+0x30 ); /* Print the 10's digit */ UART_putc( (accel%10)+0x30 ); /* Print the 1's digit */ UART_puts("G "); /* Append the units */ } /* Print the Y-axis Accelerometer value to the VFD */ void display_y(void) { /* Local Variables */ unsigned char sign = 0; /* + or - */ unsigned int accel = 0; /* 000 to 360 for 0.00G to 3.60G*/ /* Set cursor position */ UART_puts("\n\r\t Y= "); information */

#ifndef DISP_H #define DISP_H /* Function prototypes */ void display_x(void); void display_y(void); void display_z(void); void display_r(void); void display_l(void); void display_a(void); void display_v(void); void display_b(void); void display_time(void); void display_counter(void); #endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Display Controller

Module:

Display Output functions

Desc.:

This file contains the source code for the functions for the Display Outputs module. **********************************************************/ #include "proj_hdr.h" /* 24 per G (ADXL335 is ratiometric) */

if( Y_AXIS == 0 )

/* Print

/* if Y-axis value is still at

default */ { UART_puts("NO VAL");

/* Print error message

*/ return;

/* exit function */

} else if( Y_AXIS > 214 ) /* if Y-axis value is >max value */ { UART_putc('>'); /* Print the greater than sign */ sign = '-'; /* Set sign to negative */ accel = 360; /* Set acceleration value to absolute maximum */ } else if( Y_AXIS < 40 ) /* if Y-axis value is = 128 ) /* if Y-axis has negative g */ { sign = '-'; /* Set sign to negative */

Page 41 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

accel = (((float)(Y_AXIS-128)/24)*100); /* Calculate Acceleration */ } else /* else Yaxis has positive g */ { sign = '+'; /* Set sign to positive */ accel = (((float)(128-Y_AXIS)/24)*100); /* Calculate Acceleration */ }/* end if */ /* Print Y-axis sign and value */ UART_putc(sign); /* Print the + or - sign */ UART_putc( (accel/100)+0x30 ); /* Print the 100's digit */ UART_putc('.'); /* Print the decimal point */ UART_putc( ((accel/10)%10)+0x30 ); /* Print the 10's digit */ UART_putc( (accel%10)+0x30 ); /* Print the 1's digit */ UART_puts("G "); /* Append the units */ } /* Print the Z-axis Accelerometer value to the VFD */ void display_z(void) { /* Local Variables */ unsigned char sign = 0; /* + or - */ unsigned int accel = 0; /* 000 to 360 for 0.00G to 3.60G*/ /* Set cursor position */ UART_puts("\n\r\t Z= "); information */ if( Z_AXIS == 0 )

dist = 180 - RANGE;//(float)(RANGE*65)-12.5; UART_putc( (dist/100)+0x30 ); /* Print the 100's digit */ UART_putc( ((dist/10)%10)+0x30 ); /* Print the 10's digit */ UART_putc( (dist%10)+0x30 ); /* Print the 1's digit */ UART_puts("cm "); } /* Print the Ambient Light value */ void display_l(void) { /* Set cursor position */ UART_puts("\n\r\t L= "); information */ if( LIGHT == 0 )

/* Print

/* if Light value is still at

default */ { UART_puts("NO VAL");

/* Print error message

*/ return;

/* quit function */

} else if( LIGHT > 200 ) /* if it's dark */ { brightness(1); /* dimmest display level */ } else if( LIGHT > 150 ) { brightness(2); } else if( LIGHT > 100 ) { brightness(3); } else { brightness(4);

/* Print

/* if Z-axis value is still at

default */ {

Bill Bai

/* brightest display

level */ UART_puts("NO VAL");

/* Print error message

}

*/ return; /* exit function */ } else if( Z_AXIS > 214 ) /* if Z-axis value is >max value */ { UART_putc('>'); /* Print the greater than sign */ sign = '-'; /* Set sign to negative */ accel = 360; /* Set acceleration value to absolute maximum */ } else if( Z_AXIS < 40 ) /* if Z-axis value is = 128 ) /* if Z-axis has negative g */ { sign = '-'; /* Set sign to negative */ accel = (((float)(Z_AXIS-128)/24)*100); /* Calculate Acceleration */ } else /* else Zaxis has positive g */ { sign = '+'; /* Set sign to positive */ accel = (((float)(128-Z_AXIS)/24)*100); /* Calculate Acceleration */ }/* end if */ /* Print Z-axis sign and value */ UART_putc(sign); /* Print the + or - sign */ UART_putc( (accel/100)+0x30 ); /* Print the 100's digit */ UART_putc('.'); /* Print the decimal point */ UART_putc( ((accel/10)%10)+0x30 ); /* Print the 10's digit */ UART_putc( (accel%10)+0x30 ); /* Print the 1's digit */ UART_puts("G "); /* Append the units */ } /* Print the Range Finder value */ void display_r(void) { /* Local Variables */ unsigned char dist = 0; /* Set cursor position */ UART_puts("\n\r\t R= "); information */ if( RANGE == 0 )

/* Print

/* Print the Altitude value */ void display_a(void) { /* Set cursor position */ UART_puts("\n\r\t\t\t A= ");

/* Print /* Print the 10's digit /* Print

/* Print information */

if( ALTITUDE < 0 ) /* if Altitude is negative */ { UART_putc('-'); /* Print a negative sign */ } /* Display Altitude value */ UART_putc( (ALTITUDE/10000)%10+0x30 ); /* Print the 10000's digit */ UART_putc( (ALTITUDE/1000)%10+0x30 ); /* Print the 1000's digit */ UART_putc( (ALTITUDE/100)%10+0x30 ); /* Print the 100's digit */ UART_putc( (ALTITUDE/10)%10+0x30 ); /* Print the 10's digit */ UART_putc( (ALTITUDE%10)+0x30 ); /* Print the 1's digit */ UART_puts("m "); } /* Print the Speed value */ void display_v(void) { /* Set cursor position */ UART_puts("\n\r\t\t\t S= ");

/* Print information */

/* Display Speed value */ UART_putc( (SPEED/10000)%10+0x30 ); /* Print the 1000's digit */ UART_putc( (SPEED/1000)%10+0x30 ); /* Print the 100's digit */ UART_putc( (SPEED/100)%10+0x30 ); /* Print the 10's digit */ UART_putc( (SPEED/10)%10+0x30 ); /* Print the 1's digit */ UART_putc( '.' ); /* Print decimal point */ UART_putc( SPEED%10+0x30 ); /* Print the tenthes digit */ UART_puts("kmh "); } /* Print the Bearing */ void display_b(void) { /* Set cursor position */ UART_puts("\n\r\t\t\t B= ");

/* Print information */

/* if Range vale is still at

default */ { UART_puts("NO VAL");

/* Print error message

*/ return;

/* Display Ambient Light value */ UART_putc( (LIGHT/100)+0x30 ); the 100's digit */ UART_putc( ((LIGHT/10)%10)+0x30 ); */ UART_putc( (LIGHT%10)+0x30 ); the 1's digit */ UART_puts(" "); }

/* quit function */

} /* Display Range value */

/* Display Bearing value */ UART_putc( (BEARING/1000)%10+0x30 ); /* Print the 100's digit */ UART_putc( (BEARING/100)%10+0x30 ); /* Print the 10's digit */ UART_putc( (BEARING/10)%10+0x30 ); /* Print the 1's digit */ UART_putc( '.' ); /* Print decimal point */

Page 42 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

UART_putc( (BEARING)%10+0x30 ); /* Print the tenthes digit */ UART_puts("deg");

Bill Bai

*/ UART_puts("\n\r\tAmbient Light"); display_l(); /* Display Ambient

}

Light value */

/* Print the Time */ void display_time(void) { /* Set cursor position */ UART_puts("\n\r\t\t\t "); /* Print information */ /* Display Time */ UART_putc( ((HOURS/10)%10)+0x30 ); /* Print the 10's digit */ UART_putc( (HOURS%10)+0x30 ); /* Print the 1's digit */ UART_putc(':'); UART_putc( ((MINUTES/10)%10)+0x30 ); /* Print the 10's digit */ UART_putc( (MINUTES%10)+0x30 ); /* Print the 1's digit */ UART_putc(':'); UART_putc( ((SECONDS/10)%10)+0x30 ); /* Print the 10's digit */ UART_putc( (SECONDS%10)+0x30 ); /* Print the 1's digit */ } volatile unsigned char COUNT = 0; /* Print a simple counter */ void display_counter(void) {

cursor_home(); UART_puts("\t\t\tGPS Data"); display_a(); display_v(); display_b(); UART_puts("\n\n\r\t\t\tGPS Time"); display_time(); _delay_ms(100); /* End of while */

} return 0; } /* End of main */ /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

GPS

Module:

Project header

Desc.:

This file contains information useful to all modules in this block, namely

global variables and include files **********************************************************/

UART_putc( (COUNT/100)%10+0x30 ); /* Print the 100's digit */ UART_putc( (COUNT/10)%10+0x30 ); /* Print the 10's digit */ UART_putc( (COUNT%10)+0x30 ); /* Print the 1's digit */ COUNT++; } /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display

#ifndef PROJ_HDR_H #define PROJ_HDR_H /* Include Files */ #include #include #include #include #include /* Module Includes */ #include "usi.h" #include "uart.h" #include "nmea.h" /* Global Variables */

Block:

Display Controller

Module:

Main program

Desc.:

This is the main program section of the Display microcontroller **********************************************************/ #include "proj_hdr.h"

/* Include project header file */

#endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display

/* Calculation for UART baud rate */ #define FOSC 8000000 // Clock Speed #define BAUD 9600 #define MYUBRR FOSC/16/BAUD-1 /* Global Variables */ volatile unsigned char X_AXIS = 100; */ volatile unsigned char Y_AXIS = 128; */ volatile unsigned char Z_AXIS = 156; */ volatile unsigned char RANGE = 10; /* volatile unsigned char LIGHT = 10; /* volatile int ALTITUDE = 12345; in meters */ volatile unsigned int SPEED = 1234; /* volatile unsigned char BEARING = 123; vehicle */ volatile unsigned char HOURS = 12; /* volatile unsigned char MINUTES = 34; current hour */ volatile unsigned char SECONDS = 56; current hour */

/* X-axis acceleration /* Y-axis acceleration /* Z-axis acceleration Range finder distance */ Ambient light level */ /* Altitude Speed in kilometers per hour */ /* Heading of the Hour of the current time */ /* Minutes of the /* Seconds of the

int main(void) { /* Local Variables */ unsigned char cmd = 0x20; /* Initialize software modules */ SPI_SlaveInit(); /* Initialize SPI */ UART_init(MYUBRR); /* Initialize UART */ sei();

/* Enable global interrupts */

_delay_ms(200); reset(); /* Wait 200ms for display to boot up */ _delay_ms(500);

GPS

Module:

Universal Serial Interface header

Desc.:

This file contains the global variables for the USI functions. This code

is originally from the AVR Appnote AVR319 - Using the USI module for SPI communications.

I

have ported the code over to the WinAVR compiler. **********************************************************/ #ifndef USI_H #define USI_H /* Set SPI bus mode */ #define SPI_MODE 0 /* Sample on leading _rising_ edge, setup on trailing _falling_ edge. */ //#define SPI_MODE 1 /* Sample on leading _falling_ edge, setup on trailing _rising_ edge. */ /* USI port and pin definitions. */ #define USI_OUT_REG PORTB port output register. #define USI_IN_REG PINB port input register. #define USI_DIR_REG DDRB port direction register. #define USI_CLOCK_PIN 7 clock I/O pin. #define USI_SELECT_PIN 4 #define USI_DATAIN_PIN 5 data input pin. #define USI_DATAOUT_PIN 6 data output pin.

//!< USI //!< USI //!< USI //!< USI //!< USI //!< USI

/* USI slave select input */ #define USI_SS ((USI_IN_REG & (1<> USI_SELECT_PIN)

while(1) { cursor_home(); display_counter(); //cursor_position(0,0); /* Set cursor row 0, column 0 */ cursor_home(); UART_puts("\tAccelerometer");

Block:

/* Print

information */ display_x();

/* Display X-axis value

display_y();

/* Display Y-axis value

display_z();

/* Display Z-axis value

*/ */ */ UART_puts("\n\r\tRange Finder"); display_r(); /* Display Range value

/* Speed configuration: * Bits per second = CPUSPEED / PRESCALER / (COMPAREVALUE+1) / 2. * Maximum = CPUSPEED / 64. * 8MHz / 64 = 125kHz * 125kHz = 8MHz / 8 / (3+1) / 2 * Prescaler = 8 * Compare Value = 3 */ #define TC0_PRESCALER_VALUE 8 //!< Must be 1, 8, 64, 256 or 1024. #define TC0_COMPARE_VALUE 3 //!< Must be 0 to 255. Minimum 31 with prescaler CLK/1. /* Prescaler value converted to bit settings. */ #if TC0_PRESCALER_VALUE == 1 #define TC0_PS_SETTING (1<
Page 43 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

#elif TC0_PRESCALER_VALUE == 8 #define TC0_PS_SETTING (1<
GPS

Module:

Universal Serial Interface functions

Desc.:

This file contains the source code for the USI functions. This code is originally

Bill Bai

} // Update flags and clear USI counter USISR = (1<
from the // Enable 'Clear Timer on Compare match' and init

AVR Appnote AVR319 - Using the USI prescaler.

module for SPI communications.

TCCR0A = (1<
I have ported

the code over to the WinAVR compiler. **********************************************************/

// Init Output Compare Register. OCR0A = TC0_COMPARE_VALUE;

#include "proj_hdr.h" /*! \brief Data input register buffer. * * Incoming bytes are stored in this byte until the next transfer is complete. * This byte can be used the same way as the SPI data register in the native * SPI module, which means that the byte must be read before the next transfer * completes and overwrites the current value. */ unsigned char storedUSIDR; /*! \brief Driver status bit structure. * * This struct contains status flags for the driver. * The flags have the same meaning as the corresponding status flags * for the native SPI module. The flags should not be changed by the user. * The driver takes care of updating the flags when required. */ struct usidriverStatus_t { unsigned char masterMode : 1; //!< True if in master mode. unsigned char transferComplete : 1; //!< True when transfer completed. unsigned char writeCollision : 1; //!< True if put attempted during transfer. };

// Init driver status register. USI_SPI_status.masterMode = 1; USI_SPI_status.transferComplete = 0; USI_SPI_status.writeCollision = 0; storedUSIDR = 0; } /*! \brief Initialize USI as SPI slave. * * This function sets up all pin directions and module configurations. * Use this function initially or when changing from master to slave mode. * Note that the stored USIDR value is cleared. * * \param spi_mode Required SPI mode, must be 0 or 1. */ void USI_SPI_initslave(void) { // Configure port directions. USI_DIR_REG |= (1<
volatile struct usidriverStatus_t USI_SPI_status; //!< The driver status bits. /*! \brief Timer/Counter 0 Compare Match Interrupt handler. * * This interrupt handler is only enabled when transferring data * in master mode. It toggles the USI clock pin, i.e. two interrupts * results in one clock period on the clock pin and for the USI counter. */ /*#pragma vector=TIMER0_COMP_vect */ /* Compiler specific directive */ /*__interrupt void timer0comp_handler()*/ ISR(TIMER0_COMPA_vect) { USICR |= (1<
// Init driver status register. USI_SPI_status.masterMode = 0; USI_SPI_status.transferComplete = 0; USI_SPI_status.writeCollision = 0; storedUSIDR = 0; } /*! \brief Put one byte on bus. * * Use this function like you would write to the SPDR register in the native SPI module. * Calling this function in master mode starts a transfer, while in slave mode, a * byte will be prepared for the next transfer initiated by the master device. * If a transfer is in progress, this function will set the write collision flag * and return without altering the data registers. * * \returns 0 if a write collision occurred, 1 otherwise. */ char USI_SPI_putc( unsigned char val ) { // Check if transmission in progress, // i.e. USI counter unequal to zero. if( (USISR & 0x0F) != 0 ) { // Indicate write collision and return. USI_SPI_status.writeCollision = 1; return; } // Reinit flags. USI_SPI_status.transferComplete = 0; USI_SPI_status.writeCollision = 0; // Put data in USI data register. USIDR = val;

Page 44 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

// Master should now enable compare match interrupts. if( USI_SPI_status.masterMode == 1 ) { TIFR |= (1<
Bill Bai

//volatile char UART_BUFFER[UART_BUFFER_SIZE]; /* Set size of UART buffer */ //volatile char UART_BUF_CNT = 0; /* UART Buffer position counter */ //volatile char UART_FLAGS = 0; /* "Register" to store UART status */

interrupt. } if( USI_SPI_status.writeCollision == 0 ) return 1; return 0; } /*! \brief Get one byte from bus. * * This function only returns the previous stored USIDR value. * The transfer complete flag is not checked. Use this function * like you would read from the SPDR register in the native SPI module. */ unsigned char USI_SPI_getc(void) { return storedUSIDR; } /*! \brief Wait for transfer to complete. * * This function waits until the transfer complete flag is set. * Use this function like you would wait for the native SPI interrupt flag. */ void USI_SPI_wait(void) { do {} while( USI_SPI_status.transferComplete == 0 ); } /* Changes USI MISO between input and output when slave is selected or not */ void USI_SPI_SSn(unsigned char mode) { if( mode == 0 ) /* Slave is selected */ { USI_DIR_REG |= (1<
GPS

Module:

UART header

/* Initialize UART module, from datasheet */ void UART_init( void ) { /* UBRR = (fosc/16/baud)-1 = (8MHz/16/9600bps)-1 = 51.083 = 51 */ unsigned int ubrr = 51; /* Set baud rate */ UBRRH = (unsigned char)(ubrr>>8); UBRRL = (unsigned char)ubrr; /* Enable receiver and transmitter */ UCSRB = (1<
/* Read UART Data Register into local variable

*/ if( rx == '$' ) /* if start new sentence */ { COUNT = 0; /* reset count */ NMEA_TYPE = 0; /* reset NMEA type */ }

Desc.: This file contains the global variables and function prototypes for the UART module. **********************************************************/ #ifndef UART_H #define UART_H

if( COUNT == 1 )

/* first character should always be

G */ {

/* Includes */ //#include /* Function prototypes */ void UART_init( void ); void UART_putc( unsigned char data ); unsigned char UART_getc( void ); void UART_flush( void ); ISR( USART_RX_vect );

if( rx != 'G' ) /* if it's not a G */ { COUNT = 83; /* set count to higher than max */ } } if( COUNT == 2 )

/* second character should always

be P */ {

/* Global Variables */ extern volatile char UART_BUFFER[]; /* Defines */ #define UART_BUFFER_SIZE 82 /* Set max buffer size as max NMEA sentence size */ #define UART_RXC 0 /* UART finished receiving byte flag */ #define UART_TXC 1 /* UART finished transmitting byte flag */ #endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

GPS

Module:

UART functions

Desc.:

This file contains the source code for the functions for the UART module.

if( rx != 'P' ) /* if it's not a G */ { COUNT = 83; /* set count to higher than max */ } } if( COUNT == 3 ) /* third char should be V or G */ { if( rx == 'V' ) /* if it's a V */ { NMEA_TYPE = 6; /* set VTG type */ } else if( rx == 'G' ) /* if it's a G */ { NMEA_TYPE = 1; /* set GGA type */

Much of the code for this module is taken from the

} else { NMEA_TYPE = 0;

COUNT = 83; /* set count higher than max */ }

ATTiny2313 datasheet. **********************************************************/ #include "proj_hdr.h" /* Global Variables */

/* set no

type */

} if( COUNT == 4 )

/* continue checking for VTG or GGA

type */ {

Page 45 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

if( rx == 'T' && NMEA_TYPE == 6 )

Bill Bai

/* if VTG

{

is still valid */ {

TEMP += (rx-48);

/* ones

MINUTES = TEMP;

/* set

digit of minutes */ NMEA_TYPE = 6;

/* keep VTG

type */

MINUTES to temp */ } else if( rx == 'G' && NMEA_TYPE == 1 ) /* if GGA is still valid */ { NMEA_TYPE = 1; /* keep GGA

} else if( NMEA_TYPE == 6 ) { if( rx == '.' )

/* GPVTG */ /* should

be a decimal point */

type */

{ } else {

NMEA_TYPE = 6; /* keep GPVTG */ NMEA_TYPE = 0;

} else {

/* no type

*/ COUNT = 83; /* > max */

/* oopsie */ NMEA_TYPE = 0; COUNT = 83;

} }

}

if( COUNT == 5 )

} else {

/* continue checking for VTG or GGA

type */ { if( rx == 'G' && NMEA_TYPE == 6 )

/* if VTG

NMEA_TYPE = 0;

/* reset

COUNT = 83;

/* reset

type */

is still valid */ {

/* oopsie state */

count */ NMEA_TYPE = 6;

/* keep VTG

type */

} }

} else if( rx == 'A' && NMEA_TYPE == 1 ) /* if GGA is still valid */ { NMEA_TYPE = 1; /* keep GGA type */ } else { NMEA_TYPE = 0;

/* no type

*/ COUNT = 83; /* > max */ } } if( COUNT == 7 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { TEMP = 0; TEMP += (rx-48)*10; digit of hours */ } else if( NMEA_TYPE == 6 ) { TEMP = 0; TEMP += (rx-48)*1000; thousands digit of course */ } else /* oopsie state */ { NMEA_TYPE = 0; type */ COUNT = 83; count */ } }

/* tens /* GPVTG */ /*

/* reset /* reset

if( COUNT == 8 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { TEMP += (rx-48); /* ones digit of hours */ HOURS = TEMP; /* set HOURS to temp */ } else if( NMEA_TYPE == 6 ) /* GPVTG */ { TEMP += (rx-48)*100; /* hundreds digit of course */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 9 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { TEMP = 0; TEMP += (rx-48)*10; /* tens digit of minutes */ } else if( NMEA_TYPE == 6 ) /* GPVTG */ { TEMP += (rx-48)*10; /* tens digit of course */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 10 ) { if( NMEA_TYPE == 1 )

/* GPGGA */

if( COUNT == 11 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { TEMP = 0; TEMP += (rx-48)*10; /* tens digit of seconds */ } else if( NMEA_TYPE == 6 ) /* GPVTG */ { TEMP += (rx-48); /* ones digit of course */ BEARING = TEMP; /* set BEARING to temp */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 12 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { TEMP += (rx-48); /* ones digit of seconds */ SECONDS = TEMP; /* set SECONDS to temp */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } /* Parse out speed */ if( COUNT == 25 ) { if( NMEA_TYPE == 6 ) /* GPVTG */ { TEMP = 0; /* reset temp */ TEMP += (rx-48)*10000; /* ten thousands digit of speed */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 26 ) { if( NMEA_TYPE == 6 ) /* GPVTG */ { TEMP += (rx-48)*1000; /* thousands digit of speed */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 27 ) { if( NMEA_TYPE == 6 ) /* GPVTG */ { TEMP += (rx-48)*100; /* hundreds digit of speed */ } else /* oopsie state */ {

Page 46 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett NMEA_TYPE = 0;

/* reset

COUNT = 83;

/* reset

type */ count */ }

Bill Bai

TEMP += (rx-48)*100; thousands digit of altitude */ } else {

}

/*

/* oopsie state */ NMEA_TYPE = 0;

/* reset

COUNT = 83;

/* reset

type */ if( COUNT == 28 ) { if( NMEA_TYPE == 6 ) /* GPVTG */ { TEMP += (rx-48)*10; /* tens digit of speed */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 29 ) { if( NMEA_TYPE == 6 ) /* GPVTG */ { if( rx == '.' ) /* should be a decimal point */ { NMEA_TYPE = 6; /* keep GPVTG */ } else /* oopsie */ { NMEA_TYPE = 0; COUNT = 83; } } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 30 ) { if( NMEA_TYPE == 6 ) /* GPVTG */ { TEMP += (rx-48); /* ones digit of speed */ SPEED = TEMP; /* set SPEED to temp */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } /* end of speed parser */ /* start altitude parser */ if( COUNT == 51 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { TEMP = 0; if( rx == '-' ) /* if altitude is negative */ { /* do nothing for now */ } else { TEMP += (rx-48)*100000; /* hundred thousands digit of altitude */ } } else /* oopsie state */ { NMEA_TYPE = 0; /* reset

count */ } } if( COUNT == 54 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { TEMP += (rx-48)*100; /* hundreds digit of altitude */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 55 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { TEMP += (rx-48)*10; /* tens digit of altitude */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 56 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { if( rx == '.' ) /* should be a decimal point */ { NMEA_TYPE = 6; /* keep GPVTG */ } else /* oopsie */ { NMEA_TYPE = 0; COUNT = 83; } } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 57 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { TEMP += (rx-48); /* ones digit of altitude */ ALTITUDE = TEMP; /* set ALTITUDE to temp */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } /* end of altitude parser */

type */ COUNT = 83;

/* reset

count */ } } if( COUNT == 52 ) { if( NMEA_TYPE == 1 ) /* GPGGA */ { TEMP += (rx-48)*10000; /* ten thousands digit of altitude */ } else /* oopsie state */ { NMEA_TYPE = 0; /* reset type */ COUNT = 83; /* reset count */ } } if( COUNT == 53 ) { if( NMEA_TYPE == 1 ) {

/* GPGGA */

COUNT++; /* increment count */ } /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

GPS

Module:

NMEA Parser header

Desc.:

This file contains the global variables and function prototypes for the NMEA Parser module. **********************************************************/ #ifndef NMEA_H #define NMEA_H /* Function prototypes */ unsigned char GPVTG_parser( unsigned char * ); unsigned char GPGGA_parser( unsigned char * ); /* NMEA Flag definitiongs */

Page 47 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

#define NMEA_RXC 1 #define NMEA_START 2 #define NMEA_ERROR 3 /* NMEA Global Variables extern volatile unsigned extern volatile unsigned extern volatile unsigned extern volatile unsigned extern volatile unsigned extern volatile unsigned extern volatile extern volatile Sentence pointer */ extern volatile Sentence Flags */ extern volatile

USI_SPI_initslave(); UART_init(); Initialize UART for 9600, 8N1 */ */ int ALTITUDE; int BEARING; int SPEED; char HOURS; char MINUTES; char SECONDS;

sei();

if( !USI_SS )

/* NMEA /* NMEA

unsigned char NMEA_TYPE;

GPS NMEA Parser functions

Desc.:

This file contains the source code for the functions for the NMEA Parser module. **********************************************************/ #include "proj_hdr.h" /* Global Variables */ /* NMEA sentence buffer of max size 82 chars */ //volatile unsigned char NMEA_SENTENCE[82]; //volatile unsigned char NMEA_SENT_ptr = 0; /* NMEA Sentence pointer */ //volatile unsigned char NMEA_FLAGS = 0; /* NMEA Sentence Flags */ volatile unsigned char NMEA_TYPE = 0; /* NMEA Types: 0 - No type 1 - GPGGA, Global Position System Fix Data 2 - GPGLL, Latitude/Longitude 3 - GPGSA, GNSS DOP and Active Satellites 4 - GPGSV, GNSS Satellites in View 5 - GPRMC, Recommended Minimum Specific GNSS Data 6 - GPVTG, Course Over Ground and Ground Speed */ unsigned unsigned unsigned unsigned unsigned unsigned

int ALTITUDE = 0;//13579; int BEARING = 2436; int SPEED = 0;//12345; char HOURS = 12; char MINUTES = 30; char SECONDS = 45;

/* GPS data parser for the GPVTG sentence */ /* Parses for Bearing and Speed in kmh */ //unsigned char GPVTG_parser( unsigned char * sentence ) //{ // /* Local Variables */ // unsigned char ack = 0; // // /* Parser */ // ack = sscanf(sentence, "$GPVTG,%f,T,,M,%*f,n,%f,k,%*c*%*2c\r\n", &BEARING, &SPEED); // // return ack; //} // ///* GPS data parser for the GPGGA sentence */ ///* Parses for Hours, Minutes, Seconds, and Altitude in meters */ //unsigned char GPGGA_parser( unsigned char * sentence ) //{ // /* Local Variables */ // unsigned char ack = 0; // // /* Parser */ // ack = sscanf(sentence, "$GPGGA,%2d%2d%2d.%*3d,%*f,%*c,%*f,%*c,%*d,%8d,%*f,%f,M,,,,%*d*%*2c\r\n ", // &HOURS, &MINUTES, &SECONDS, &ALTITUDE); // // return ack; //} /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

GPS

Module:

Main program

USI_SPI_SSn(0); /* Active low slave selected */ cmd = USI_SPI_getc(); if( cmd == 'B' ) /* Heading requested */ { USI_SPI_putc( (unsigned char)(BEARING>>8) ); /* send high byte of Bearing */ USI_SPI_wait(); USI_SPI_putc( (unsigned char)BEARING ); /* send low byte of Bearing */ USI_SPI_wait(); } else if( cmd == 'V' ) /* Speed requested (Velocity) */ { USI_SPI_putc( (unsigned char)(SPEED>>8) ); /* send high byte of Speed */ USI_SPI_wait(); USI_SPI_putc( (unsigned char)SPEED ); /* send low byte of Speed */ USI_SPI_wait(); } else if( cmd == 'A' ) /* Altitude requested */ { USI_SPI_putc( (unsigned char)(ALTITUDE>>8) ); /* send high byte of Altitude */ USI_SPI_wait(); USI_SPI_putc( (unsigned char)ALTITUDE ); /* send low byte of Altitude */ USI_SPI_wait(); } else if( cmd == 'H' ) /* Hours requested */ { USI_SPI_putc( HOURS ); /* send Hours */ USI_SPI_wait(); } else if( cmd == 'M' ) /* Minutes requested */ { USI_SPI_putc( MINUTES );

/* send Minutes */ USI_SPI_wait(); } else if( cmd == 'S' ) /* Seconds

requested */ { USI_SPI_putc( SECONDS );

/* send Seconds */ USI_SPI_wait(); } else /* Ignore all other requests */ {} /* End of if */ } else /* if not selected, do nothing */ { USI_SPI_SSn(1); /* Active low slave not selected */ }/* End of if */ } /* End of while */ return 0; } /* End of main */ /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Main Controller

Module:

Project header

Desc.:

This file contains information useful to all modules in this block, namely

global variables and include files **********************************************************/ #ifndef PROJ_HDR_H #define PROJ_HDR_H /* Include Files */ #include #include #include #include /* Module Includes */ #include "spi.h"

Desc.:

This is the main program section of the Ambient Light microcontroller **********************************************************/ #include "proj_hdr.h"

/* if this SPI slave is

{

unsigned char NMEA_FLAGS;

Module:

/* Enable global interrupts */

selected */

unsigned char NMEA_SENTENCE[]; unsigned char NMEA_SENT_ptr;

Block:

/* Initialize SPI as slave */ /*

while(1) {

#endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display

volatile volatile volatile volatile volatile volatile

Bill Bai

/* Include project header file */

/* SPI Slave Select Macros */ #define ACC_SS_0 (PORTD &= ~0x08)

/* Set Accelerometer SS

#define ACC_SS_1 (PORTD |= 0x08)

/* Set Accelerometer SS

#define #define #define #define

/* /* /* /*

low */ int main(void) { /* Local Variables */ unsigned char cmd = 0; /* Initialize software modules */

high */ RNG_SS_0 RNG_SS_1 GPS_SS_0 GPS_SS_1

(PORTD (PORTD (PORTD (PORTD

&= |= &= |=

~0x10) 0x10) ~0x20) 0x20)

Set Set Set Set

Range SS low */ Range SS high */ GPS SS low */ GPS SS high */

Page 48 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

#define AMB_SS_0 (PORTD &= ~0x40)

/* Set Ambient SS low

#define AMB_SS_1 (PORTD |= 0x40)

/* Set Ambient SS high

#define DIS_SS_0 (PORTD &= ~0x80)

/* Set Display SS low

*/

Bill Bai

Main microcontroller **********************************************************/ #include "proj_hdr.h"

*/ */ #define DIS_SS_1 (PORTD |= 0x80)

/* Set Display SS high

*/ #endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Main Controller

Module:

SPI bus header

Desc.:

This file contains the function prototype and variable definitions for the SPI

bus functions **********************************************************/ #ifndef SPI_H #define SPI_H /* SPI Defines */ #define DDR_SPI #define PORT_SPI PORTB #define PIN_SPI PINB #define DD_MOSI #define DD_MISO #define DD_SCK #define DD_SSN

DDRB 3 4 5 2

/* SPI Function Prototypes */ void SPI_MasterInit(void); void SPI_putc(char cData); void SPI_SlaveInit(void); char SPI_getc(void); #endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Main Controller

Module:

SPI bus functions

Desc.:

This file contains the source code for the SPI bus functions **********************************************************/ #include "proj_hdr.h" /* Initialize SPI for master mode */ void SPI_MasterInit(void) { /* Configure SSn, MOSI, and SCK as output */ DDR_SPI |= (1<
Main Controller

Module:

Main program

Desc.:

This is the main program section of the

/* Include project header file */

/* Global Variables */ /* Accelerometer variables */ volatile unsigned char X_AXIS = 2; /* volatile unsigned char Y_AXIS = 3; /* volatile unsigned char Z_AXIS = 4; /* /* Range Finder variables */ volatile unsigned char RANGE = 5; /* /* Ambient Light variables */ volatile unsigned char LIGHT = 6; /* /* GPS variables */ volatile unsigned char HALTITUDE = 7; /* Altitude in meters */ volatile unsigned char LALTITUDE = 7; /* Altitude in meters */ volatile unsigned char HSPEED = 8; /* volatile unsigned char LSPEED = 8; /* volatile unsigned char HBEARING = 9; the vehicle */ volatile unsigned char LBEARING = 9; the vehicle */ volatile unsigned char HOURS = 10; /* volatile unsigned char MINUTES = 11; current hour */ volatile unsigned char SECONDS = 12; current hour */

X-axis acceleration */ Y-axis acceleration */ Z-axis acceleration */ Range finder distance */ Ambient light level */

Speed in kilometers per hour */ Speed in kilometers per hour */ /* Bearing (Heading) of /* Bearing (Heading) of Hour of the current time */ /* Minutes of the /* Seconds of the

/* Sliding window average arrays */ //#define SLIDING #ifdef SLIDING #define LENGTH 10 /* Make arrays 10 in size */ volatile unsigned char X_ARRAY[LENGTH]; volatile unsigned char Y_ARRAY[LENGTH]; volatile unsigned char Z_ARRAY[LENGTH]; volatile unsigned char R_ARRAY[LENGTH]; volatile unsigned char L_ARRAY[LENGTH]; volatile unsigned char ARRAY_COUNT = 0; /* Function Prototypes */ unsigned char avg(unsigned char []); /* Calculate the average of the array */ void add(unsigned char [], unsigned char); /* Add a new value to the array */ #endif int main(void) { /* Local Variables */ unsigned char hbyte = 0; unsigned char lbyte = 0;

/* Upper byte */ /* Lower byte */

/* Initialize software modules */ SPI_MasterInit(); /* Initialize SPI */ /* I/O Initialization */ DDRD = 0xFF; /* Set PortD outputs */ /* Set all slave selects to high (not selected) */ ACC_SS_1; /* Accelerometer slave select high (not selected) */ GPS_SS_1; /* GPS slave select high (not selected) */ AMB_SS_1; /* Ambient slave select high (not selected) */ RNG_SS_1; /* Range slave select high (not selected) */ DIS_SS_1; /* Display slave select high (not selected) */ sei();

/* Enable global interrupts */

while(1) { /* Query the sensor blocks for sensor data */ #ifdef SLIDING /* Check if array counter needs to roll over */ if( ARRAY_COUNT == LENGTH ) { ARRAY_COUNT = 0; } #endif /* Query the Accelerometer block */ ACC_SS_0; /* Accelerometer slave select low (selected) */ _delay_us(25); /* Delay for 25 us */ /* X-axis */ SPI_putc('X'); /* Query ACC block for X-axis */ _delay_us(25); /* Delay for 25 us */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(25); /* Delay for 25 us */ X_AXIS = SPI_getc(); /* Read Xaxis value from SPI */ /* Y-axis */ SPI_putc('Y'); /* Query ACC block for Y-axis */ _delay_us(25); /* Delay for 25 us */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(25); /* Delay for 25 us */ Y_AXIS = SPI_getc(); /* Read Yaxis value from SPI */ /* Z-axis */ SPI_putc('Z'); /* Query ACC block for Z-axis */ _delay_us(25);

Page 49 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

/* Delay for 25 us */

/* Delay for 25 us */

SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(25); /* Delay for 25 us */ Z_AXIS = SPI_getc(); /* Read Zaxis value from SPI */ ACC_SS_1; /* Accelerometer slave select high (not selected) */ /* Query the Ambient Light block */ AMB_SS_0; /* Ambient slave select low (selected) */ _delay_us(25); /* Delay for 25 us */ /* Light Level */ SPI_putc('L'); /* Query AMB block for Light level */ _delay_us(25); /* Delay for 25 us */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(25); /* Delay for 25 us */ LIGHT = SPI_getc(); /* Read Light value from SPI */ AMB_SS_1; /* Ambient slave select high (not selected) */ /* Query the Range block */ RNG_SS_0; /* Range slave select low (selected) */ _delay_us(25); /* Delay for 25 us */ /* Range */ SPI_putc('R'); /* Query RNG block for range distance */ _delay_us(150); /* Delay for 25 us */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(25); /* Delay for 25 us */ RANGE = SPI_getc(); /* Read Range value from SPI */ RNG_SS_1; /* Range slave select high (not selected) */ #ifdef SLIDING ARRAY_COUNT++; Increment array counter */ #endif /* Query the GPS block */ GPS_SS_0; /* GPS slave select high (selected) */ _delay_us(50); /* Delay for 25 us */ /* Altitude */ SPI_putc('A'); /* Query GPS block for altitude */ _delay_us(50); /* Delay for 25 us */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(50); /* Delay for 25 us */ HALTITUDE = SPI_getc(); /* Read Altitude high byte value from SPI */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(50); /* Delay for 25 us */ LALTITUDE = SPI_getc(); /* Read Altitude low byte value from SPI */ /* Speed */ SPI_putc('V'); /* Query GPS block for speed */ _delay_us(50); /* Delay for 25 us */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(50); /* Delay for 25 us */ HSPEED = SPI_getc(); /* Read Speed high byte value from SPI */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(50); /* Delay for 25 us */ LSPEED = SPI_getc(); /* Read Speed low byte value from SPI */ /* Bearing */ SPI_putc('B'); /* Query GPS block for Bearing */ _delay_us(50); /* Delay for 25 us */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(50); /* Delay for 25 us */ HBEARING = SPI_getc(); /* Read Bearing high byte value from SPI */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(50); /* Delay for 25 us */ LBEARING = SPI_getc(); /* Read Bearing low byte value from SPI */ /* Time */ /* Hour */ SPI_putc('H'); /* Query GPS block for Minutes */ _delay_us(50);

Bill Bai

SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(50); /* Delay for 25 us */ HOURS = SPI_getc(); /* Read Hours value from SPI */ /* Minutes */ SPI_putc('M'); /* Query GPS block for Minutes */ _delay_us(50); /* Delay for 25 us */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(50); /* Delay for 25 us */ MINUTES = SPI_getc(); /* Read Minutes value from SPI */ /* Seconds */ SPI_putc('S'); /* Query GPS block for Seconds */ _delay_us(50); /* Delay for 25 us */ SPI_putc(NULL); /* Dummy send to clock SPI */ _delay_us(50); /* Delay for 25 us */ SECONDS = SPI_getc(); /* Read Seconds value from SPI */ GPS_SS_1; /* GPS slave select high (not selected) */ /* Send data to Display Controller */ #ifdef SLIDING /* Calculate averages */ X_AXIS = avg(X_ARRAY); Y_AXIS = avg(Y_ARRAY); Z_AXIS = avg(Z_ARRAY); LIGHT = avg(L_ARRAY); RANGE = avg(R_ARRAY); #endif DIS_SS_0;

/* Display slave select low

(selected) */

/*

_delay_us(25); /* Delay for 25 us */ /* X-axis */ SPI_putc('x'); /* Prepare Display Controller for X-axis value */ _delay_us(25); /* Delay for 25 us */ SPI_putc(X_AXIS); /* Send X-axis value to Display Controller */ _delay_us(25); /* Delay for 25 us */ /* Y-axis */ SPI_putc('y'); /* Prepare Display Controller for Y-axis value */ _delay_us(25); /* Delay for 25 us */ SPI_putc(Y_AXIS); /* Send Y-axis value to Display Controller */ _delay_us(25); /* Delay for 25 us */ /* Z-axis */ SPI_putc('z'); /* Prepare Display Controller for Z-axis value */ _delay_us(25); /* Delay for 25 us */ SPI_putc(Z_AXIS); /* Send Z-axis value to Display Controller */ _delay_us(25); /* Delay for 25 us */ /* Ambient Light */ SPI_putc('l'); /* Prepare Display Controller for Ambient Light value */ _delay_us(25); /* Delay for 25 us */ SPI_putc(LIGHT); /* Send Ambient Light value to Display Controller */ _delay_us(25); /* Delay for 25 us */ /* Range */ SPI_putc('r'); /* Prepare Display Controller for Range value */ _delay_us(25); /* Delay for 25 us */ SPI_putc(RANGE); /* Send Range value to Display Controller */ _delay_us(25); /* Delay for 25 us */ /* Altitude */ SPI_putc('a'); /* Prepare Display Controller for Altitude value */ _delay_us(25); /* Delay for 25 us */ SPI_putc( HALTITUDE ); /* Send high byte of Altitude to Display Controller */ _delay_us(25); /* Delay for 25 us */ SPI_putc( LALTITUDE ); /* Send low byte of Altitude to Display Controller */ _delay_us(25); /* Delay for 25 us */ /* Speed */ SPI_putc('v'); /* Prepare Display Controller for Speed value */ _delay_us(25); /* Delay for 25 us */ SPI_putc( HSPEED ); /* Send high byte of Speed to Display Controller */ _delay_us(25); /* Delay for 25 us */ SPI_putc( LSPEED );

Page 50 of 57

Date: April 18, 2011 Lab Section: Monday 1:30

ECET 396 Prof. Barnett

/* Send low byte of Speed to Display Controller */ _delay_us(25); /* Delay for 25 us */ /* Bearing */ SPI_putc('b'); /* Prepare Display Controller for Bearing value */ _delay_us(25); /* Delay for 25 us */ SPI_putc( HBEARING ); /* Send high byte of Bearing to Display Controller */ _delay_us(25); /* Delay for 25 us */ SPI_putc( LBEARING ); /* Send low byte of Bearing to Display Controller */ _delay_us(25); /* Delay for 25 us */ /* Time */ /* Hour */ SPI_putc('h'); /* Prepare Display Controller for Hours value */ _delay_us(25); /* Delay for 25 us */ SPI_putc(HOURS); /* Send Hours value to Display Controller */ _delay_us(25); /* Delay for 25 us */ /* Minutes */ SPI_putc('m'); /* Prepare Display Controller for Minutes value */ _delay_us(25); /* Delay for 25 us */ SPI_putc(MINUTES); /* Send Minutes value to Display Controller */ _delay_us(25); /* Delay for 25 us */ /* Seconds */ SPI_putc('s'); /* Prepare Display Controller for Seconds value */ _delay_us(25); /* Delay for 25 us */ SPI_putc(SECONDS); /* Send Seconds value to Display Controller */ _delay_us(25); /* Delay for 25 us */ DIS_SS_1; /* Display slave select high (not selected) */ } /* End of while */ return 0; } /* End of main */ #ifdef SLIDING /* Find the average value of the array */ unsigned char avg(unsigned char array[]) { unsigned char avg = 0; /* Local average variable */ unsigned char i = 0; /* Local counter variable */ for(i=0;i
Range Finder

Module:

Project header

Desc.:

This file contains information useful to all modules in this block, namely

Bill Bai

the code over to the WinAVR compiler. **********************************************************/ #ifndef USI_H #define USI_H /* Set SPI bus mode */ #define SPI_MODE 0 /* Sample on leading _rising_ edge, setup on trailing _falling_ edge. */ //#define SPI_MODE 1 /* Sample on leading _falling_ edge, setup on trailing _rising_ edge. */ /* USI port and pin definitions. */ #define USI_OUT_REG PORTB port output register. #define USI_IN_REG PINB port input register. #define USI_DIR_REG DDRB port direction register. #define USI_CLOCK_PIN 2 clock I/O pin. #define USI_SELECT_PIN 3 #define USI_DATAIN_PIN 0 data input pin. #define USI_DATAOUT_PIN 1 data output pin.

//!< USI //!< USI //!< USI //!< USI //!< USI //!< USI

/* USI slave select input */ #define USI_SS ((USI_IN_REG & (1<> USI_SELECT_PIN) /* Speed configuration: * Bits per second = CPUSPEED / PRESCALER / (COMPAREVALUE+1) / 2. * Maximum = CPUSPEED / 64. * 8MHz / 64 = 125kHz * 125kHz = 8MHz / 8 / (3+1) / 2 * Prescaler = 8 * Compare Value = 3 */ #define TC0_PRESCALER_VALUE 8 //!< Must be 1, 8, 64, 256 or 1024. #define TC0_COMPARE_VALUE 3 //!< Must be 0 to 255. Minimum 31 with prescaler CLK/1. /* Prescaler value converted to bit settings. */ #if TC0_PRESCALER_VALUE == 1 #define TC0_PS_SETTING (1<
Range Finder

Module:

Universal Serial Interface functions

Desc.:

This file contains the source code for the USI functions. This code is originally

global variables and include files **********************************************************/ #ifndef PROJ_HDR_H #define PROJ_HDR_H

from the AVR Appnote AVR319 - Using the USI

/* Include Files */ #include #include #include /* Module Includes */ #include "adc.h" #include "usi.h"

module for

/* ADC Global Variables */ extern volatile char RANGE;

/*! \brief Data input register buffer. * * Incoming bytes are stored in this byte until the next transfer is complete. * This byte can be used the same way as the SPI data register in the native * SPI module, which means that the byte must be read before the next transfer * completes and overwrites the current value. */ unsigned char storedUSIDR;

SPI communications.

over to the WinAVR compiler. **********************************************************/ #include "proj_hdr.h"

#endif /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Range Finder

Module:

Universal Serial Interface header

Desc.:

This file contains the global variables for the USI functions. This code

is originally from the AVR Appnote AVR319 - Using the USI module for SPI communications. have ported

I have ported

the code

I

/*! \brief Driver status bit structure. * * This struct contains status flags for the driver. * The flags have the same meaning as the corresponding status flags * for the native SPI module. The flags should not be changed by the user. * The driver takes care of updating the flags when required. */ struct usidriverStatus_t {

Page 51 of 57

Date: April 18, 2011 Lab Section: Monday 1:30 unsigned char masterMode : 1;

ECET 396 Prof. Barnett //!< True if in master

mode. unsigned char transferComplete : 1; //!< True when transfer completed. unsigned char writeCollision : 1; attempted during transfer. };

Bill Bai

USI_DIR_REG &= ~(1<
//!< True if put // Configure USI to 3-wire slave mode with overflow interrupt. USICR = (1<
volatile struct usidriverStatus_t USI_SPI_status; //!< The driver status bits. /*! \brief Timer/Counter 0 Compare Match Interrupt handler. * * This interrupt handler is only enabled when transferring data * in master mode. It toggles the USI clock pin, i.e. two interrupts * results in one clock period on the clock pin and for the USI counter. */ /*#pragma vector=TIMER0_COMP_vect */ /* Compiler specific directive */ /*__interrupt void timer0comp_handler()*/ ISR(TIMER0_COMPA_vect) { USICR |= (1<
// Init driver status register. USI_SPI_status.masterMode = 0; USI_SPI_status.transferComplete = 0; USI_SPI_status.writeCollision = 0; storedUSIDR = 0; } /* Changes USI MISO between input and output when slave is selected or not */ void USI_SPI_SSn(unsigned char mode) { if( mode == 0 ) /* Slave is selected */ { USI_DIR_REG |= (1<
Range Finder

Module:

Analog to Digital converter header

Desc.:

This file contains the function prototypes and variable definitions for the ADC functions **********************************************************/

Page 52 of 57

Date: April 18, 2011 Lab Section: Monday 1:30 #ifndef ADC_H #define ADC_H /* ADC function prototypes */ void adc_init(void); /* Initialize ADC functionality */ ISR(ADC_vect); /* ADC finished conversion interrupt */ /* ADC Macros */ #define ADC_START (ADCSRA |= (1<
Range Finder

Module:

Analog to Digital converter Functions

Desc.:

This file contains the source code for the ADC functions **********************************************************/ #include "proj_hdr.h" /* Initialize ADC functionality */ void adc_init(void) { ADMUX |= (0<
ECET 396 Prof. Barnett

Bill Bai

while(1) { if( !USI_SS )

/* if this SPI slave is

selected */ { USI_SPI_SSn(0); /* Active low slave selected */ cmd = USI_SPI_getc(); if( cmd == 'R' ) /* if the X axis is requested */ { USI_SPI_putc(RANGE); // Send temp value to SPI and increment USI_SPI_wait(); // wait for transmission to finish } else{} /* all other requests, do nothing */ } else /* if not selected, do nothing */ { USI_SPI_SSn(1); /* Active low slave not selected */ }/* End of if */ } /* End of while */ return 0; } /* End of main */

/* Start ADC Conversion */

} /* ADC finished conversion interrupt */ ISR(ADC_vect) { RANGE = ADCH; /* Read ADC value into Range variable */ ADC_START; /* Start next ADC conversion */ } /*********************************************************** Bill Bai Purdue ECET Senior Project Portable Heads Up Display Block:

Range Finder

Module:

Main program

Desc.:

This is the main program section of the accelerometer microcontroller 1 **********************************************************/ #include "proj_hdr.h"

/* Include project header file */

/* Global Variables for ADC readings */ volatile char RANGE = 0; /* Range to object */ int main(void) { /* Local Variables */ unsigned char cmd = 0; /* Initialize software modules */ adc_init(); /* Initialize ADC */ USI_SPI_initslave(); /* Initialize SPI as slave */ sei();

10.4.

/* Enable global interrupts */

Datasheets

SUP500F GPS Module: http://www.sparkfun.com/products/9758 ADXL335 Accelerometer: http://www.sparkfun.com/products/9269 Sharp GP2Y0A02YK0F Range Finder: http://www.sparkfun.com/products/8958

Page 53 of 57

Portable Heads Up Display

Page 9 of 57 collecting information for the system from the outside world: the GPS, accelerometer, range ..... http://www.nxp.com/acrobat_download2/literature/9398/39340011.pdf. 12. ..... This function waits until the transfer complete flag is set.

1MB Sizes 0 Downloads 54 Views

Recommend Documents

Heads Up Concussion.pdf
Page 1 of 1. Page 1 of 1. Heads Up Concussion.pdf. Heads Up Concussion.pdf. Open. Extract. Open with. Sign In. Main menu. Displaying Heads Up Concussion.pdf. Page 1 of 1.

Heads Up Concussion.pdf
Page 1 of 1. Heads Up Concussion.pdf. Heads Up Concussion.pdf. Open. Extract. Open with. Sign In. Details. Comments. General Info. Type. Dimensions. Size.

9 Heads
... college in California United States It offers courses in fashion entertainment beauty .... real clothes, the art of illustration, and computers and fashion drawing.

Multiple heads cutting unit
Mar 22, 1999 - incises and goes though the leather, the skin or the synthetic material, obtaining the half-?nished product in the shape and. siZe desired. During the outlet of the Water jet, the head,. Which stands above the Work top, is continuously

9 Heads
The Fashion Institute of Design amp Merchandising FIDM is a for profit college in California United States It offers courses in fashion entertainment beauty.

[DOWNLOAD] Heads eBook
Heads by Jesse Jarnow The Portable Document Format ( commonly referred to as PDF) is a file format used to present documents in a manner independent of ... LSD-slinging graffiti writers of Central Park, the Dead-loving AI scientists.

Method and apparatus for driving the display device, display system ...
Feb 5, 1998 - 345/100. AND DATA PROCESSING DEVICE. 5,604,511 A ... Foreign Application Priority Data. It is an object to .... DATA DRIVER. I l. 'IIII'IIIII'I IJ.

Optically written display
May 23, 2007 - tion-in-part of application No. ... 6,844,387, which is a division of application No. ... liquid crystal silicon devices, polysilicon LCDs, electron.

Method and apparatus for driving the display device, display system ...
Feb 5, 1998 - 345/206. THE DISPLAY DEVICE, DISPLAY SYSTEM,. 5,251,051 A * 10/1993 Fujiiyoshi et a1. .. 345/100. AND DATA PROCESSING DEVICE.

Privacy-enhanced display device
Jan 15, 2009 - 5,463,428 A 10/1995 Ligtg? et al'. Darrell L. Lelgh ... 5,963,371 A 10/1999 Needham et al. .... This is a particular problem for laptop computers.

Symmetrical Eggs - Instant Display
www.instantdisplay.co.uk. ------------------. ----. #. Page 2. Symmetrical Eggs noh up). ------------------- draw the design and colour the eggs so each side. |looks the same? |- www.instantdisplay.co.uk. Page 3. Symmetrical Eggs. Can you draw the de

Display Devices
Reduces number of electrons leaving the Cathode Brightness control ... repeatedly by directing electron beam to the same screen points .... Desktop workstation.

heads or tails? across down -
Spill. 65. Wind-driven clouds. 67. Go from point A to, I ... 34. Kicks. 37. Green box that might be near a Redbox? 38. ... Energy drink that sponsors NASCAR racer.