## Introduction

Our project is a 3-dimensional game control for a video game displayed on a black and white television set.

### Motivation and Overview

In the recent push in technology, many new computer and game interfaces have been created, many of which include wireless control. Our unit is a novel method for 3-dimensional control. The interface we have designed for this project has many other possible applications other than video game control. This may include 3-dimensional drawing or animation. For instance, instead of using a scroll mouse to zoom into and out of an image, it would be possible using 3-dimensional control to simply draw all of the dimensions of the figure out in air without zooming. Because of the limited time available to complete this project, however, we have written a video game to demonstrate how our interface functions and how it may be used.

The project is to realize a user-friendly control, in which the user simply grabs a ball and moves it in a three-dimensional space. The exact coordinates of the position of the ball are then calculated and outputted onto video using a 3-D to 2-D projection method that we have developed.

## High Level Design

The three-dimensional video game project was inspired by a desire to
utilize sensors which track in three dimensions. Several recent technologies may serve as inspiration. In particular, the hugely popular Wii gaming system uses motions in all three dimensions for play. While the Wii served as inspiration, our interface is an original concept and more closely resembles a three-dimensional take with non-wireless sensing hardware because of hardware limitations.

### The Concept

The controller consists of a ping-pong ball mounted in the center of a triangular board by three stretch sensors. The user controls the game by holding the ping-pong ball and moving it in the space above the board as desired to control the video game. We use a 3-D to 2-D projection method that directly maps the position of the ping pong ball to a position on the screen. The geometry of the board is shown in the appendix.

The output from the control unit is converted to 2D coordinates, which are used to generate video code displayed on a black and white TV. The overall data-path for the system is shown below.

Figure: Design Flowchart

### Background Mathematics

The calculations used to compute our 3D to 2D projection were based on several known parameters and equations expressing the board's geometric properties. The equations, and our setup are as follows, a diagram showing the correspondence of the variable to the board is available in the appendix:

Figure: Photograph of controller.

From these equations, with only x, y, and z being unknown, it was possible to use Mathematica to solve this system. The resulting equations are used to calculate the absolute positions of our coordinate system (given z2 and z3 are both zero):

### Hardware-Software Balance

Implementing this data-path successfully requires a delicate combination of hardware and software. The two important functions of the software are (1) to calculate the 3D coordinate position using the data from the control unit and project it to two dimensions, and (2) to generate the video code. The main hardware components are the control unit, two Mega32 CPUs, and a black and white TV. Because one Mega32 CPU cannot carry out both functions mentioned above within one frame refresh of the tv, we have used two CPUs in the project. One Mega32 CPU is dedicated for 3-dimensional coordinate detection and 3D-to-2D projection. The resultant 2D coordinate data is transmitted to the second Mega32 CPU. The second CPU, in turn, plots the video game output to the black-and-white TV.

IEEE standards are not relevant to our project because we have no wireless components.

## Hardware Design

The game controller is an essential hardware aspect for this project. The controller design was entirely original. The sensors used for position dectection are strech sensors whose resistances change as they are stretched (stretch sensor). The controller base is an equilateral triangle built from hardboard. A 4-inch length of stretch sensor is bolted to each corner of the triangle and tied to Vcc rail of the Mega32. The other end of the stretch sensors are each tied to one end of a 3-kΩ resistor and secured to a ping-pong ball. The other ends of the resistors are connected to the MCU ground rail. The voltages across the 3-kΩ resistors are fed into the A/D input of the MCU. The combination of the stretch sensors and resistors creates three voltage dividers. The voltages read at the A/D input of the MCU increases when the stretch sensor is less stretched, As a result, the voltage across the 3-kΩ resistors become higher. The sensors are sized to have an initial position in which all three are slightly extended. The ability to compute the absolute position is lost if any one sensor goes slack. This defines a playable space above the triangular frame. The following images show the hardware components:

Figure: Our STK500 setup

Figure:Our custom PC board.

Our hardware also contains a crucial set of two communicating Mega32 microcontrollers. The first Mega32 is mounted in a custom PC board while the second is on a STK500. Both are powered with AC 9-12V power supplies. The transmitting (first) Mega32 receives the voltage divider signals on Port A; Ports C and D of this MCU transmit calculated position data to the receiving Mega32's Ports A and C, respectively. These connections allow the transfer of the calculated x, y, and z positions. Pins B.0-B.3 of the transmitting and receiving MCUs are connected for synchronized communication signals. Additionally, Pin B.4 of the recieving end is linked to switch 0 on the STK500 to signal "walk mode" vs. "fly mode" of the game.
Finally the video code generated by the receiving microcontroller is outputted to a black and white television through the DAC circuit shown in the appendix and via a RCA phone jack.

## Software Design

The software for this project is composed of three main portions: MCU communications, mathematical calculations, and video code.

### Positioning Mathematics

All mathematical calculations used to determine exact position of the ping pong ball and the locations of the video output are performed on the Mega32 connected to the sensing system. By moving the mathematical calculations off of the video MCU, this allows more time for the video MCU to run, allowing it to print more video code.

The first step in calculating the position of the ping pong ball is to retrieve the data from the sensing system. First, the sensing system must be calibrated in order to provide a direct mapping between the A/D conversion and the distance the ping pong ball is from each of the three corners of the control interface base. This is simply done by entering values into six arrays. Three of the arrays contain the distance of the ping pong ball from each of the three corners of the control base. The other three arrays are the values that are read from the ADC inputs that correspond to the distances in the first three distance arrays. A direct mapping between the ADC values and the real distances are made by making linear extrapolations between every two data points in the distance arrays. Once the calibration is complete, the distance may be found in every subsequent use of the control system. The ADC inputs on Ports A.0-A.2 are then read by the code and the real distances are found based on the extrapolations and the calibration values.
Once the distances are found, the distance calculations must be made to determine the real (x,y,z) coordinate values of the ping pong balls. The equations are those shown in the High Level Design of this web page. However, rather than using floating mathematics to calculate the (x,y,z) values, fixed point arithmetic is used to reduce the number of clock cycles used by the MCU in order to decrease the amount of time it takes to perform these operations. The fixed point arithmetic functions we used are by courtesy of Bruce Land.

Once the fixed point values of the (x,y,z) positions are found, we must project these values onto a 2-D coordinate system to be sent to the video code. In our projection scheme, movement of the ball in the x-y plane projects onto the screen as semi-3-D motion where an object is moved upon a 3-D platform. Movement in the z-direction would cause the object to appear to lift from the platform. However, because of the noise existing in our hardware sensing system, we require a push-button be pushed to have the object move in the z-direction. Therefore, when the button is pushed, the video code is in “fly mode”. Otherwise, it is in “walk mode”. If this method of showing movement in the z-direction were not used, there would be too much noise and the video code would become very jittery and thus the interface would become difficult to use.

When all of the calculations for the 3-D to 2-D projection are completed and the result is scaled to the tv monitor pixel coordinate, the data is sent to the video Mega32. There are three sets of data that must be sent. They are labeled in variables as x_draw, y_draw, and y_track. The reason three values are required is because of the 3-D to 2-D mapping we have implemented. The x_draw is identical in both fly mode and walk mode. The two y values that are sent differentiates fly mode from walk mode in the video code. Y_track is the y position of the object at all times regardless of what mode the video code is in. Y_draw is the y position plus the z position. The rationale behind this is that when the object is moving in the z-direction, it appears to be moving in the y-direction on the tv monitor.

### Communications

The communications code is based on a Master/Slave scheme. The MCU connected to the sensing system is the Master while the MCU connected to the tv is the Slave. The Master and the Slave communicate to each other using 4 bits to signal data ready, data received, and the data to be sent.
The following sequence is performed during the communications process:

1. Master calculates data
2. Master sets data ready bit to 1
3. Slave sees that data ready bit is 1
4. Slave receives and stores data
5. Slave sets data received bit to 1
6. Master sets data ready bit to 0
7. Slave sets data received bit to 0
8. Repeat

Based on this sequence, the data can be appropriately sent from the Master to the Slave. Otherwise, it is possible for the Master to begin to recalculate the data before the Slave has had a chance to finish fetching it.
In addition to this, another sequence is used to determine what data is to be sent from the Master to the Slave. This is necessary because three sets of 8-bit data must be sent to the Slave while only two ports are available for use in communication. To implement this, a series of switch-case statements is used in which the Slave sets two data bits to different values and the Master sends data based on those two values. The data bits are set by the Slave cycles through its values so that at any given time two out of the three data values are being transmitted. By using this method, it is ensured that the data sent is appropriately synchronized. Otherwise, the Slave may store the data from the two ports to incorrect variables because it would not know which two out of three data values are being sent at the moment.

### Video

After the coordinate data has been sent to the video MCU, it is sent to be drawn onto the TV monitor. The video code uses several functions that Bruce Land wrote for our video game lab.

The object’s position is based on (x_draw, y_track) when the code is in “walk mode”, or when the button is not pushed. Similarly, when the button is pushed and the code is in “fly mode”, the object’s position is based on (x_draw, y_draw). In “fly mode”, the object’s shadow, whose position is (x_draw, y_track), is also drawn onto the screen in order to show the user how high in the z-direction the object actually is based on the z-position of the controller.

The video game we wrote is based loosely off of the arcade game Pac-man. The character controlled by the player is a pac-man-like figure that runs around the screen eating objects. Certain objects would increase the score while others would decrease the score. If the score ever reached a negative value, the pac-man dies. Some objects that the pac-man eats lay in the z=0 plane (directly on the platform), and some lay at a certain z value. The objects that are not directly on the plane have their (x,y) position on the platform indicated by a “shadow”.

Our game deviates from the original Pac-man because there are no ghosts and no maze. The reason behind removing the maze is because our character can move at all angles and in all directions. Limiting the direction of movement would reduce the usefulness of our control unit. If the player obtains a certain score, he would move onto the next level.

To add character to pac-man and also emphasize the range of motion, the character turns right, left, toward the user, and away from the user depending on the direction of travel. This is evaluated by keeping track of one set of previous x and y values and comparing them to the next set to be drawn. In the x direction, if the previous x value was less than the current x value, and the change in x is greater than the change in y, the left-facing character is drawn. Likewise, if the previous x value was greater than the current x value, and the change in x is greater than the change in y, then the right-facingcharacter is display. Detecting forward and back motion is slightly more complex because to add the illusion of 3D to the screen a change in y requires a change in x also. To detect a change in y, it is required that the delta x is smaller than the delta y. If this were true, then if the previous y value were less than the current y value, the character faces away from the user. If the opposite were true, the character faces the user. (Note: the origin for the TV is the upper lefthand corner and thus y increases down the screen).

## Challenges Encountered

During the weeks we worked on this project we encountered several problems.

The first challenge was to gather useful data from the controller. On a data printout to hyperterm we encountered the strange error that only two of the three ADC conversions would appear correct at a time. After much time spent examining the ADC section of the Mega32 manual and attempts at varying code structure, we had assured ourselves that the software was functioning correctly but a solution still escaped us. Turning to hardware and tracing our signal path using an oscilloscope we finally discovered a potential source of error. The voltage dividers responding to the stretch sensors' changes in resistance had been designed based on an initial estimation of the range of resistance the sensors would provide. However, it was found that the 1-kΩ resistors we had originally used did not have enough resistance for there to be a significant voltage drop across to be measured. To solve this problem, we swapped the 1-kΩ resistors with 3-kΩ resistors. As a result, reasonable A to D values were observed.

Another issue which haunted us throughout the project was the stabilization of the position. This issue presented itself at nearly ever level of design. During the beginning of this project, the ADC values that were read from the sensing interface was extremely unstable. After spending much time testing various aspects of our system, it was found that this was caused by the poor conductivity of the stretch sensors that we used. In our setup, we connected the stretch sensors to the voltage divider circuit by crimping terminals to the ends of the sensors and connected to the rest of the circuit. The sensors are not made of conductive material and thus the crimps did not have enough contacts to the sensors to read stable values. To solve this problem, we wrapped stripped copper wire around the extra sensor beyond the crimp to increase the surface area of the sensor that is in contact with conductive material. After this was done, the ADC yielded results that were much more stable.

An interesting problem that still remains unresolved is that a slight delay is required in the function that fetches the video code coordinates. If the delay were removed, the figure drawn onto the screen becomes extremely jumpy, to the extent that the game is unplayable.

## Results

The results of our three dimensional controller unit were excellent. The sensor is highly sensitive to motions in all three dimensions and the speed of printout to hyperterm is well beyond a human's fastest change in direction. The communication system between the two MCUs is also highly responsive and responds instantaneously by human standards. The video code executes sufficiently quickly so as to print to the screen without flickering, tearing, or printing debris, but is not organized to optimize the code execution time for the greatest possible amount of video content displayed.

There is no major safety concern associated with our project. The STK500 and the custom PC board are both running off of 9-12 V AC power supplies and these are isolated by their power supplies. The controller board's safety is loosely implemented. The current board setup could provide at worst a mild shock but we have never witnessed this in our many hours of play. If we were to try to modify the design for distribution this could be completely eliminated by insulating the wires on the edges of the stretch sensors. The game did not interfere at all with other projects nearby.

The controller and game were both designed to be very useable by both the designers and other users. As with most gaming systems, the first few times the game is played using the new control system some adjustment will be need. After a very short period of time, however, the user grows accustomed to the motion and boundaries of motion of the controller. Based on our design, the feel of the rubberish stretch sensors and the feel of the ping-pong ball in the hand are appealing and could be as comfortable during prolonged use as any repetitive motion can be.

Overall, our project was successful.

## Conclusions

The overall expectations we had for project were met at its completion, however, there are several small details which were not what we expected to encounter and there are several things we might do differently if repeating our work.

By the end of our project the stretch sensors were processing motion at levels of speed and smoothness which met all expectations. Dealing with these stretch sensors and building the mechanical device of the control unit, however, took far more project time than we anticipated. The cause of the extra time needed was the delicacy of the sensors. Once set up the sensors were sturdy and only one breakage occurred but finding the optimal length and method of securing the sensors was trickier than planned.

The concept behind the video code would also be modified, if not replaced, if we repeated the project. While we successfully implemented the 3D to 2D conversion and made an entertaining game, the success of our sensors in detecting motion led us to feel that the two dimensional video display in which individual pixels are easily resolved by eye was not a demonstration method which did justice to the data being decoded from user motion.

### Potential for Elaboration

There are many other interfaces which could be controlled via our system. Some exciting possibilities would be a robotic arm, a helicopter controller, virtual reality game control, or control for a GUI for 3D drawings and models (e.g. protein structure, mathematical graphs, CAD drawings). Another exciting possibility for continuing this project would be to redesign the controller in such a way that it provides tactile feedback to the user indicating resistance etc. from the simulated region in which you are moving.

### Intellectual Property

The design for our controller was conceived solely from our own intellectual property. No parts sampled required signing of a non-disclosure form, and we were not reverse engineering any product. A patent search revealed only only vaguely similar products (closest product found). This indicates that there may be patent opportunities for our design. On the software side of the design, some code used for video display and the fixed point arithmetic operations was written by Bruce Land. The remainder was entirely original. The only potential legal considerations that needs to be considered for the technology we have choosen to use is the similarity of our video game character to the classic video game character PACMAN.

### Ethical Considerations

At all times during the design and construction of this project the IEEE Code of Ethics was followed. First and foremost this required us to be constantly mindful of the safety of other lab members and any potential users. This entailed careful construction of all parts to be free from sharp edges of wire or wood. All AC power supplies were isolated at all times. Above and beyond physical health, we were mindful to always be kind and courteous in lab even in times of stress.

Additionally, we constantly sought to promote technologies by truthfully representing our problems to those with more expertise, namely our TA and professor. We were also eager to accept ideas and even criticism from TAs, our professor, and our peers. We accurately represent our results and setbacks publicly on this website and we were happy to explain our work to anyone who approached us about it. We have also been very careful to provide all external credit to others whose work contributed to the final success of this project. Our system seeks to treat all users equally to the greatest extent possible and is based only on ability to view the monitor and move the controller.

No parts we used in our construction are monitor by outside organizations. If we were to use this product outside of an academic setting we would be sure to address any complications resulting from the similarity to the Pac-man game licensed in the U.S. by Midway.

## Appendix

Schematics:

Figure: Coordinates of platform.

Figure: Game controller voltage dividers

Figure: DAC circuit between Mega32 and TV, courtesy of Bruce Land.

Figure: Dimensions of controller base. Units are in inches.

### References

Bruce Land's Video Code

Bruce Land's Fixed pt

ATMEL Mega32 datasheet

476 webpage

Tools Used

Mathematica was used to solve the linear equations and extract the equations used for finding the (x,y,z) exact position.

CodeVision was used for C coding.

Macromedia Dreamweaver was used to assemble this webpage.

### Cost/Parts List

We both worked on every aspect of this project. They include:

-Soldering/Hardware Setup

-Assembling the control unit

-Video/game code

-Mathematical calculations code

-Testing

-Website

### Acknowledgements

Thanks to AMTEL.

Thanks to our friends and family for putting up with us during this project and the support and understanding why we haven't had much time to spend with you.

Last but not least, thanks to Bruce Land and the ECE476 TAs for your time and patience throughout this project and providing us with the opportunity for this experience.

### Source Code

Calculations code

//  A to D test code

// NOTE -- You MUST MOUNT the Aref jumper

#include <Mega32.h>

#include <stdio.h>

#include <math.h>

#include <delay.h>

//I like these definitions

#define begin {

#define end   }

#define t1 10

#define x2 -1.708

#define x3 1.708

#define y2 3.084

#define y3 3.084

#define  x3sqr float2fix(2.917)

#define  y2sqr float2fix(9.511)

#define  y3sqr float2fix(9.511)

unsigned char time1;

float searchDist(char Ain, int sel);

void initialize();

void fetchData();

void getCoords();

char Ain1, Ain2, Ain3;            //raw A to D number

float d1, d2, d3;

float x, y, z;

int fix_x, fix_y, fix_z;

int scalex_x, scalex_y, scalex_z;

int scaley_x, scaley_y, scaley_z;

int x_track, y_track;

int x_draw, y_draw;

int fly_mode;

int CoordSend;

float float_x;

int fixd1, fixd2, fixd3;

int sqd1, sqx, sqy, sqroot;

int d1sqr, d2sqr, d3sqr;

int fix_x1, fix_x2, fix_x3, fix_y1, fix_y2, fix_y3;

int num_x, den_x, num_y, den_y;

int MuxCtrl;

int FirstData;

/*// inches

flash float dist1[15] = {5.5,6,6.5,7,7.5,8,8.5,9};

flash float v1[15] = {108,96,90,79,68,58,54,44};

flash float dist2[15] = {5,5.5,6,6.5,7,7.5,8};

flash float v2[15] = {102,87,80,73,66,56,52};

flash float dist3[15] = {5,5.5,6,6.5,7,7.5,8,8.5};

flash float v3[15] = {118,108,99,92,82,69,59,55};      */

// 3 inches

flash float dist1[15] = {1.83,2,2.167,2.33,2.5,2.67,2.83,3};

flash float volt1[15] = {108,96,90,79,68,58,54,44};

flash float dist2[15] = {1.67,1.83,2,2.167,2.33,2.5,2.67,2.83};

flash float volt2[15] = {102,87,80,73,66,56,52};

flash float dist3[15] = {1.67,1.83,2,2.167,2.33,2.5,2.67,2.83};

flash float volt3[15] = {118,108,99,92,82,69,59,55};

#pragma regalloc+

char syncON, syncOFF;

int LineCount;

int time;

char screen[1600];

//=== fixed conversion macros =========================================

#define int2fix(a)   (((int)(a))<<8)            //Convert char to fix. a is a char

//#define fix2int(a)   ((signed char)((a)>>8))    //Convert fix to char. a is an int

#define float2fix(a) ((int)((a)*256.0))         //Convert float to fix. a is a float

#define fix2float(a) ((float)(a)/256.0)         //Convert fix to float. a is an int

#define multfixSlow(a,b) ((int)((((long)(a))*((long)(b)))>>8)) //multiply two fixed #

//lsqrt is in math.h

#define sqrtfixSlow(a)   (lsqrt(((long)(a))<<8))   //square root

//==Fast fixed multiply=================================

char fix2int(int a)

begin

#asm

ldd r30, Y+1 ;moves the high byte of the input to low byte

#endasm

end

//==Fast fixed multiply=================================

int multfix(int a,int b)

begin

#asm

;*********************************************************************

;*

;* FUNCTION

;*     muls16x16_24

;* DECRIPTION

;*     Signed multiply of two 16bits numbers with 24bits result.

;* USAGE

;*     r31:r30:rxx = r23:r22 * r21:r20

;**********************************************************************

;push r20

;push r21

mov  r24, r20

mov  r25, r21

LDD  R23,Y+3

LDD  R21,Y+1

muls   r23, r21             ; (signed)ah * (signed)bh

mov           r31, r0         ;r18, r0

mul           r22, r20             ; al * bl

mov     r30, r1         ;movw     r17:r16, r1:r0

;mov     r16, r0

mulsu  r23, r20             ; (signed)ah * bl

mulsu  r21, r22             ; (signed)bh * al

;pop r21

;pop r20

mov r20, r24

mov r21, r25

#endasm

end

//========================================================

int sqrtfix(int aa)

begin

// do not change the order of these variables

// the compiler puts them in

// r16:17, r18, r19, r20:21

int a;

char nextbit, ahigh;

int root ;

a = aa;

#asm("mov r19, r17")     //set: ahigh = a>>8

//

// range sort to get integer part and to

// check for weird bits near the top of the range

if (ahigh >= 0x40)     //bigger than 64?

begin

if (a > 0x7e8f)    //>=126.562 = 11.25^2

begin

root = 0x0b40;  // 11

nextbit = 0x10 ;

end

else if (ahigh >= 0x79)    //>=121

begin

root = 0x0b00;  // 11

nextbit = 0x40 ;

end

else if (ahigh >= 0x64)    //>=100

begin

root = 0x0a00;  // 10

nextbit = 0x80 ;

end

else if (ahigh >= 0x51)    //>=81

begin

root = 0x0900;  // 9

nextbit = 0x80 ;

end

else   //64

begin

root = 0x0800;      //8

nextbit = 0x80 ;

end

end

else if  (ahigh >= 0x10)  //16    //smaller than 64 and bigger then 16

begin

if (ahigh >= 0x31)  //49

begin

root = 0x0700;      //7

nextbit = 0x80 ;

end

else if (ahigh >= 0x24)  //36

begin

root = 0x0600;      //6

nextbit = 0x80 ;

end

else if (ahigh >= 0x19)  //25

begin

root = 0x0500;      //5

nextbit = 0x80 ;

end

else //16

begin

root = 0x0400;      //4

nextbit = 0x80 ;

end

end

else       //smaller than 16

begin

if (ahigh >= 0x09)  //9

begin

root = 0x0300;      //3

nextbit = 0x80 ;

end

else if (ahigh >= 0x04)  //4

begin

root = 0x0200;      //2

nextbit = 0x80 ;

end

else if (ahigh >= 0x01)  //1

begin

root = 0x0100;      //1

nextbit = 0x80 ;

end

else     //less than one

begin

root = 0;

nextbit = 0x80 ;

end

end

// now get the low order bits

// while (nextbit)

// begin

#asm

beginloop:

;tst r18   ;dont need-- lsr at bottom of loop sets current SREG

breq endit ; jumps out of loop if nextbit is zero

;r21:r20 contains root because of compiler trick

; root = nextbit + root;

;adc r21, r19    ; dont need: never any carry

;

; p =  multfix(root,root);

mov r22, r20            ;load root into other mult input

mov r23, r21

;

muls   r23, r21             ; (signed)ah * (signed)bh

mov           r31, r0         ;r18, r0

mul           r22, r20             ; al * bl

mov     r30, r1         ;movw     r17:r16, r1:r0

mulsu  r23, r20             ; (signed)ah * bl

mulsu  r21, r22             ; (signed)bh * al

; p is in r30:31

;

; if (p >= a) root = root - nextbit ;

cp  r30, r16            ; compare root^2 with a

cpc r31, r17

brlt nosub

sub r20, r18            ; if r^2 >= a form r=r-nextbit

;sbc r21, r19           ; dont need--high byte always zero

nosub:

; nextbit = nextbit>>1 ;

;lsr r19                 ;shift nextbit right

;ror r18                  ;simplify--high byte always zero

lsr r18

rjmp beginloop

endit:

#endasm

// end

return root ;

end

//========================================================

int mult_opt(int a, int b)

begin

#asm

;push r20

;push r21

mov  r24,r20

mov  r25,r21

ldd  R23,Y+3

ldd r21,Y+1

muls      r23, r21      ; (signed)ah * (signed)bh

mov              r31, r0              ;

mul              r22, r20      ; al * bl

mov       r30, r1              ;

;mov      r16, r0

mulsu     r23, r20      ; (signed)ah * bl

mulsu     r21, r22      ; (signed)bh * al

mov r20,r24

mov r21,r25

;pop r21

;pop r20

#endasm

end

//========================================================

int reciprocalfix(int dd)

begin

signed char count, neg ;    //r16, r17

int x, d ;    //r18:19, r20:21

d=dd ;

#asm

clr r16     ;count = 0;

clr r17     ;neg = 0;

;only works with + numbers

;if (d & 0x8000)

;begin

;     neg = 1;

;     d = -d ;

;end

tst r21     ;d negative?

brpl notneg

ldi r17, 1    ; neg = 1;  negative flag

clr r18       ; d = -d ;

clr r19

sub r18, r20

sbc r19, r21

mov r20, r18

mov r21, r19

notneg:

#endasm

// range reduction

// bigger than one

while (d>0x0100)

begin

--count ;

d >>= 1 ;

end

// less than 1/2

while (d<0x0080)

begin

++count ;

d <<= 1 ;

end

// Newton interation

//x = 0x02ea - (d<<1) ;

//x = multfix(x, 0x0201 + ~multfix(d,x));

//x = multfix(x, 0x0200-multfix(d,x));

#asm

; form initial x

ldi r22, 0xea ;load the constant 2.914

ldi r23, 0x02

mov r24, r20  ; copy d

mov r25, r21

lsl r24       ; and form 2*d

rol r25

sub r22, r24  ; form 2.914-2*d

sbc r23, r25

mov r18, r22  ; store x

mov r19, r23

;mov r22, r18    ; load x

;mov r23, r19

;mov r21,r21

muls      r23, r21      ; (signed)ah * (signed)bh

mov              r31, r0              ;

mul              r22, r20      ; al * bl

mov       r30, r1              ;

;mov      r16, r0

mulsu     r23, r20      ; (signed)ah * bl

mulsu     r21, r22      ; (signed)bh * al

com r30

com r31

ldi r24, 0x01

ldi r25, 0x02

mov r23, r19

mov r21,r31

muls      r23, r21      ; (signed)ah * (signed)bh

mov              r31, r0              ;

mul              r22, r20      ; al * bl

mov       r30, r1              ;

;mov      r16, r0

mulsu     r23, r20      ; (signed)ah * bl

mulsu     r21, r22      ; (signed)bh * al

; range expansion

; if (count>0)  x = x<<count ;

; else if (count<0) x = x>>(-count) ;

tst r16

breq recipEnd

brmi recipNeg

lsl r30

rol r31

dec r16

breq recipEnd

lsl r30

rol r31

dec r16

breq recipEnd

lsl r30

rol r31

dec r16

breq recipEnd

lsl r30

rol r31

dec r16

breq recipEnd

lsl r30

rol r31

dec r16

breq recipEnd

lsl r30

rol r31

dec r16

breq recipEnd

lsl r30

rol r31

dec r16

rjmp  recipEnd

recipNeg:

lsr r31

ror r30

inc r16

breq recipEnd

lsr r31

ror r30

inc r16

breq recipEnd

lsr r31

ror r30

inc r16

breq recipEnd

lsr r31

ror r30

inc r16

breq recipEnd

lsr r31

ror r30

inc r16

breq recipEnd

lsr r31

ror r30

inc r16

breq recipEnd

lsr r31

ror r30

inc r16

breq recipEnd

lsr r31

ror r30

inc r16

recipEnd:

; fix sign

; if (neg==1) x=-x;

tst r17  ;neg flag set?

breq recip1  ;if not, do nothing

clr r24

clr r25

sub r24, r30

sbc r25, r31

mov r30, r24

mov r31, r25

recip1:

; return x  in r30:31

#endasm

end

//========================================================

int divfix(int nn, int dd)

begin

signed char count, neg ;    //r16, r17

int x, d ;    //r18:19, r20:21

int n ;

d=dd ;

n=nn ;

#asm

clr r16     ;count = 0;

clr r17     ;neg = 0;

;only works with + numbers

;if (d & 0x8000)

;begin

;     neg = 1;

;     d = -d ;

;end

tst r21     ;d negative?

brpl Dnotneg

ldi r17, 1    ; neg = 1;  negative flag

clr r18       ; d = -d ;

clr r19

sub r18, r20

sbc r19, r21

mov r20, r18

mov r21, r19

Dnotneg:

#endasm

// range reduction

// bigger than one

while (d>0x0100)

begin

--count ;

d >>= 1 ;

end

// less than 1/2

while (d<0x0080)

begin

++count ;

d <<= 1 ;

end

// Newton interation

//x = 0x02ea - (d<<1) ;

//x = multfix(x, 0x0201 + ~multfix(d,x));

//x = multfix(x, 0x0200-multfix(d,x));

#asm

; form initial x

ldi r22, 0xea ;load the constant 2.914

ldi r23, 0x02

mov r24, r20  ; copy d

mov r25, r21

lsl r24       ; and form 2*d

rol r25

sub r22, r24  ; form 2.914-2*d

sbc r23, r25

mov r18, r22  ; store x

mov r19, r23

;mov r22, r18    ; load x

;mov r23, r19

;mov r21,r21

muls      r23, r21      ; (signed)ah * (signed)bh

mov              r31, r0              ;

mul              r22, r20      ; al * bl

mov       r30, r1              ;

;mov      r16, r0

mulsu     r23, r20      ; (signed)ah * bl

mulsu     r21, r22      ; (signed)bh * al

com r30

com r31

ldi r24, 0x01

ldi r25, 0x02

mov r23, r19

mov r21,r31

muls      r23, r21      ; (signed)ah * (signed)bh

mov              r31, r0              ;

mul              r22, r20      ; al * bl

mov       r30, r1              ;

;mov      r16, r0

mulsu     r23, r20      ; (signed)ah * bl

mulsu     r21, r22      ; (signed)bh * al

; range expansion

; if (count>0)  x = x<<count ;

; else if (count<0) x = x>>(-count) ;

tst r16

breq DrecipEnd

brmi DrecipNeg

lsl r30

rol r31

dec r16

breq DrecipEnd

lsl r30

rol r31

dec r16

breq DrecipEnd

lsl r30

rol r31

dec r16

breq DrecipEnd

lsl r30

rol r31

dec r16

breq DrecipEnd

lsl r30

rol r31

dec r16

breq DrecipEnd

lsl r30

rol r31

dec r16

breq DrecipEnd

lsl r30

rol r31

dec r16

rjmp  DrecipEnd

DrecipNeg:

lsr r31

ror r30

inc r16

breq DrecipEnd

lsr r31

ror r30

inc r16

breq DrecipEnd

lsr r31

ror r30

inc r16

breq DrecipEnd

lsr r31

ror r30

inc r16

breq DrecipEnd

lsr r31

ror r30

inc r16

breq DrecipEnd

lsr r31

ror r30

inc r16

breq DrecipEnd

lsr r31

ror r30

inc r16

breq DrecipEnd

lsr r31

ror r30

inc r16

DrecipEnd:

; fix sign

; if (neg==1) x=-x;

tst r17  ;neg flag set?

breq Drecip1  ;if not, do nothing

clr r24

clr r25

sub r24, r30

sbc r25, r31

mov r30, r24

mov r31, r25

Drecip1:

; x = multfix(x,nn) ;

mov r22, r30

mov r23, r31

ldd r21,Y+7

muls      r23, r21      ; (signed)ah * (signed)bh

mov              r31, r0              ;

mul              r22, r20      ; al * bl

mov       r30, r1              ;

;mov      r16, r0

mulsu     r23, r20      ; (signed)ah * bl

mulsu     r21, r22      ; (signed)bh * al

#endasm

end

//========================================================

signed char cIn; //an input integer

float fIn;       //an input float

char fInString[16];

signed int cInFix, fInFix, prod, root, ratio, s, c;

interrupt [TIM0_COMP] void timer0_compare(void)

begin

//Decrement the time if not already zero

if (time1>0)

--time1;

end

float searchDist(char Ain, int sel)

{

int k;

float currDistance, nextDistance, nextVoltage;

float prevDistance;

float prevVoltage;

int m, b;

for(k = 0; k < 13; k++)

{

if(sel == 1)

{

prevVoltage = volt1[k];

prevDistance = dist1[k];

nextVoltage = volt1[k+1];

nextDistance = dist1[k+1];

}

else if(sel == 2)

{

prevVoltage = volt2[k];

prevDistance = dist2[k];

nextVoltage = volt2[k+1];

nextDistance = dist2[k+1];

}

else

{

prevVoltage = volt3[k];

prevDistance = dist3[k];

nextVoltage = volt3[k+1];

nextDistance = dist3[k+1];

}

// value found; extrapolate

if((Ain <= prevVoltage) && (Ain > nextVoltage))

{

m = divfix(( float2fix(nextDistance) - float2fix(prevDistance)),(float2fix(nextVoltage) - float2fix(prevVoltage)));

b = float2fix(nextDistance) - mult_opt(m,float2fix(nextVoltage));

currDistance = fix2float(mult_opt(m,float2fix(Ain))+ b);

}

else

{

prevDistance = nextDistance;

prevVoltage = nextVoltage;

}

}

return currDistance;

}

void main(void)

begin

initialize();

while (1)

begin

if(time1 == 0)

{

fetchData();

time1 = t1;

}

if(MuxCtrl == 3)

{

getCoords();

}

end

end

// find exact position (x,y,z)

void getCoords()

{

PORTB.1 = 0;    // data not ready

num_x = ((mult_opt(d1sqr,fix_y2))-(mult_opt(d3sqr,fix_y2))-(mult_opt(d1sqr,fix_y3))+(mult_opt(d2sqr,fix_y3)));

den_x = float2fix(21.0699);

fix_x = divfix(num_x,den_x);

num_y = ((mult_opt(-d1sqr,fix_x2))+(mult_opt(d3sqr,fix_x2))+(mult_opt(d1sqr,fix_x3))-(mult_opt(d2sqr,fix_x3)) + float2fix(42.455));

den_y = float2fix(21.0699);

fix_y = divfix(num_y, den_y);

sqd1 = mult_opt(fixd1,fixd1);

sqx = mult_opt(fix_x,fix_x);

sqy = mult_opt(fix_y,fix_y);

sqroot = sqd1 - sqx - sqy;

if(sqroot < 0)

sqroot = 0;

fix_z = sqrtfix(sqroot);

if(fix_z < 0)

fix_z = 0;

x_draw = ((mult_opt(fix_x,(scalex_x<<8))+(165<<8)) >>6)-550;

y_draw = (mult_opt(fix_y,(scaley_y<<8))>>2) -(mult_opt(fix_z, scaley_z<<8)>>8)-330;

y_track = (mult_opt(fix_y,(scaley_y<<8))>>2)-330;

printf("x_draw: %d, y_draw: %d, y_track: %d\n\r", (x_draw>>2)+50, (y_draw>>2)+20, (y_track>>2)+20);

// B.2 = fly mode bit 1

// B.3 = fly mode bit 0

// a/d chip is the Master

if(PINB.0 == 0)   //was last data received?

{

if((PINB.2 == 0) && (PINB.2 == 0)) // walk mode

{

PORTC = x_draw;

PORTD = y_draw;

}

else

{

if((PINB.2 == 0) && (PINB.3 == 1))

{

CoordSend = 1;

}

else if((PINB.2 == 1) && (PINB.3 == 0))

{

CoordSend = 2;

}

else if((PINB.2 == 1) && (PINB.3 == 1))

{

CoordSend = 3;

}

switch (CoordSend)

begin

case 1:

PORTC = x_draw;

PORTD = y_draw;

break;

case 2:

PORTC = y_track;

PORTD = y_draw;

break;

case 3:

PORTC = y_track;

PORTD = x_draw;

break;

end

}

}

if(PINB.0 == 1)

{

PORTB.1 = 0;

}

}

// gets data from a/d input

void fetchData()

{

switch(MuxCtrl)

begin

case 1:

d1 = searchDist(Ain1, 1);

fixd1 = float2fix(d1);

d1sqr = mult_opt(fixd1,fixd1);

MuxCtrl++;

break;

case 2:

d2 = searchDist(Ain2, 2);

d2sqr = mult_opt(fixd2,fixd2);

fixd2 = float2fix(d2);

MuxCtrl++;

break;

case 3:

d3 = searchDist(Ain3, 3);

fixd3 = float2fix(d3);

d3sqr = mult_opt(fixd3,fixd3);

MuxCtrl = 1;

break;

end

}

void initialize()

{

//set up timer 0 for 1 mSec timebase

TIMSK=2;           //turn on timer 0 cmp match ISR

OCR0 = 250;        //set the compare re to 250 time ticks

//prescalar to 64 and turn on clear-on-match

TCCR0=0b00001011;

DDRA = 0x00; //input (data from controller)

DDRC = 0xFF; //outputs

DDRD = 0xFF;

DDRB.0 = 0;

DDRB.1 = 1;

DDRB.2 = 0;

DDRB.3 = 0;

fix_x2 = float2fix(x2);

fix_x3 = float2fix(x3);

fix_y2 = float2fix(y2);

fix_y3 = float2fix(y3);

scalex_x = 50;

scalex_y = -1;

scalex_z = 0;

scaley_x = 0;

scaley_y = 3;

scaley_z = 50;

//init the UART

UCSRB = 0x18;

UBRRL = 103;

printf("starting...\n\r");

MuxCtrl = 1;

time1 = t1;

//crank up the ISRs

#asm

sei

#endasm

}

Video code

//video gen with fixed pint animationi

//D.5 is sync:1000 ohm + diode to 75 ohm resistor

//D.6 is video:330 ohm + diode to 75 ohm resistor

#pragma regalloc-    //I allocate the registers myself

#pragma optsize-     //optimize for speed

#include <Mega32.h>

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include <delay.h>

//cycles = 63.625 * 16 Note NTSC is 63.55

//but this line duration makes each frame exactly 1/60 sec

//which is nice for keeping a realtime clock

#define lineTime 1018

#define begin {

#define end   }

#define ScreenTop 30

#define ScreenBot 230

#define g 2

#define right 1

#define left 2

#define forward 3

#define backward 4

int fly_mode;

int neg = -1;

int y_track;

int wPlatform, fPlatform;

int x_draw, y_draw,sx_draw,sy_draw,sy_track;

int prev_x_draw, prev_y_track,prev2_y_track,prev2_x_draw;

int delt_x_draw, delt_y_track;

char O_pos;

int calcO;

int open;

int dir;

int off;

int eat;

int fheight;

int check;

int feat;

void initialize();

void getCoords();

int MuxCtrl;

int CoordCtrl;

int Align;

// 3 inches

flash float dist1[15] = {1.83,2,2.167,2.33,2.5,2.67,2.83,3};

flash float volt1[15] = {108,96,90,79,68,58,54,44};

flash float dist2[15] = {1.67,1.83,2,2.167,2.33,2.5,2.67,2.83};

flash float volt2[15] = {102,87,80,73,66,56,52};

flash float dist3[15] = {1.67,1.83,2,2.167,2.33,2.5,2.67,2.83};

flash float volt3[15] = {118,108,99,92,82,69,59,55};

//NOTE that v1 to v8 and i must be in registers!

register char v1 @4;

register char v2 @5;

register char v3 @6;

register char v4 @7;

register char v5 @8;

register char v6 @9;

register char v7 @10;

register char v8 @11;

register int i @12;

#pragma regalloc+

char syncON, syncOFF;

int LineCount;

int time;

char screen[1600];

/*  //platform

video_line(33,70,93,70,1);

video_line(53,30,113,30,1);

video_line(33,70,53,30,1);

video_line(93,70,113,30,1);

//3D

video_line(33,70,33,74,1);

video_line(93,70,93,74,1);

video_line(113,30,113,34,1);

video_line(33,74,93,74,1);

video_line(93,74,113,34,1);   */

flash char x_pacpt1 [22] = {45,50,55,60,65,70,75,80,85,90,94,45,50,55,60,65,70,75,80,85,90,94};

flash char y_pacpt1 [22] = {77,79,81,89,77,75,77,79,81,79,77,73,70,78,70,73,75,73,70,88,80,83};

flash char x_pacpt2 [22] = {45,50,55,60,65,70,75,80,85,90,94,96,98,96,94,90,85,80,75,70};

flash char y_pacpt2 [22] = {46,44,42,50,59,40,58,50,53,50,52,54,57,61,66,59,53,62,55,60};

flash char y_base2 [22]  = {77,83,83,85,79,75,78,88,78,80,75,85,85,81,83,88,75,72,80,73};

//=== fixed conversion macros =========================================

#define int2fix(a)   (((int)(a))<<8)            //Convert char to fix. a is a char

//#define fix2int(a)   ((signed char)((a)>>8))    //Convert fix to char. a is an int

#define float2fix(a) ((int)((a)*256.0))         //Convert float to fix. a is a float

#define fix2float(a) ((float)(a)/256.0)         //Convert fix to float. a is an int

#define multfixSlow(a,b) ((int)((((long)(a))*((long)(b)))>>8)) //multiply two fixed #

//Point plot lookup table

flash char pos[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};

//================================

//3x5 font numbers, then letters

//packed two per definition for fast

//copy to the screen at x-position divisible by 4

flash char smallbitmap[40][5]={

//0

0b11101110,

0b10101010,

0b10101010,

0b10101010,

0b11101110,

//1

0b01000100,

0b11001100,

0b01000100,

0b01000100,

0b11101110,

//2

0b11101110,

0b00100010,

0b11101110,

0b10001000,

0b11101110,

//3

0b11101110,

0b00100010,

0b11101110,

0b00100010,

0b11101110,

//4

0b10101010,

0b10101010,

0b11101110,

0b00100010,

0b00100010,

//5

0b11101110,

0b10001000,

0b11101110,

0b00100010,

0b11101110,

//6

0b11001100,

0b10001000,

0b11101110,

0b10101010,

0b11101110,

//7

0b11101110,

0b00100010,

0b01000100,

0b10001000,

0b10001000,

//8

0b11101110,

0b10101010,

0b11101110,

0b10101010,

0b11101110,

//9

0b11101110,

0b10101010,

0b11101110,

0b00100010,

0b01100110,

//:

0b00000000,

0b01000100,

0b00000000,

0b01000100,

0b00000000,

//=

0b00000000,

0b11101110,

0b00000000,

0b11101110,

0b00000000,

//blank

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//A

0b11101110,

0b10101010,

0b11101110,

0b10101010,

0b10101010,

//B

0b11001100,

0b10101010,

0b11101110,

0b10101010,

0b11001100,

//C

0b11101110,

0b10001000,

0b10001000,

0b10001000,

0b11101110,

//D

0b11001100,

0b10101010,

0b10101010,

0b10101010,

0b11001100,

//E

0b11101110,

0b10001000,

0b11101110,

0b10001000,

0b11101110,

//F

0b11101110,

0b10001000,

0b11101110,

0b10001000,

0b10001000,

//G

0b11101110,

0b10001000,

0b10001000,

0b10101010,

0b11101110,

//H

0b10101010,

0b10101010,

0b11101110,

0b10101010,

0b10101010,

//I

0b11101110,

0b01000100,

0b01000100,

0b01000100,

0b11101110,

//J

0b00100010,

0b00100010,

0b00100010,

0b10101010,

0b11101110,

//K

0b10001000,

0b10101010,

0b11001100,

0b11001100,

0b10101010,

//L

0b10001000,

0b10001000,

0b10001000,

0b10001000,

0b11101110,

//M

0b10101010,

0b11101110,

0b11101110,

0b10101010,

0b10101010,

//N

0b00000000,

0b11001100,

0b10101010,

0b10101010,

0b10101010,

//O

0b01000100,

0b10101010,

0b10101010,

0b10101010,

0b01000100,

//P

0b11101110,

0b10101010,

0b11101110,

0b10001000,

0b10001000,

//Q

0b01000100,

0b10101010,

0b10101010,

0b11101110,

0b01100110,

//R

0b11101110,

0b10101010,

0b11001100,

0b11101110,

0b10101010,

//S

0b11101110,

0b10001000,

0b11101110,

0b00100010,

0b11101110,

//T

0b11101110,

0b01000100,

0b01000100,

0b01000100,

0b01000100,

//U

0b10101010,

0b10101010,

0b10101010,

0b10101010,

0b11101110,

//V

0b10101010,

0b10101010,

0b10101010,

0b10101010,

0b01000100,

//W

0b10101010,

0b10101010,

0b11101110,

0b11101110,

0b10101010,

//X

0b00000000,

0b10101010,

0b01000100,

0b01000100,

0b10101010,

//Y

0b10101010,

0b10101010,

0b01000100,

0b01000100,

0b01000100,

//Z

0b11101110,

0b00100010,

0b01000100,

0b10001000,

0b11101110,

//-

0b00000000,

0b00000000,

0b11101110,

0b00000000,

0b00000000

};

// see: http://instruct1.cit.cornell.edu/courses/ee476/FinalProjects/s2005

/dp93/index.html

flash char ascii[131][7] = {

//0

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//1

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//2

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//3

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//4

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//5

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//6

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//7

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//8

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//9

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//10

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//11

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//12

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//13

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//14

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//15

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//16

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//17

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//18

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//19

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//20

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//21

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//22

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//23

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//24

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//25

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//26

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//27

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//28

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//29

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//30

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//31

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//32 Space

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//33 Exclamation !

0b01100000,

0b01100000,

0b01100000,

0b01100000,

0b00000000,

0b00000000,

0b01100000,

//34 Quotes "

0b01010000,

0b01010000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//35 Number #

0b00000000,

0b01010000,

0b11111000,

0b01010000,

0b11111000,

0b01010000,

0b00000000,

//36 Dollars \$

0b01110000,

0b10100000,

0b10100000,

0b01110000,

0b00101000,

0b00101000,

0b01110000,

//37 Percent %

0b01000000,

0b10101000,

0b01010000,

0b00100000,

0b01010000,

0b10101000,

0b00010000,

//38 Ampersand &

0b00100000,

0b01010000,

0b10100000,

0b01000000,

0b10101000,

0b10010000,

0b01101000,

//39 Single Quote '

0b01000000,

0b01000000,

0b01000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//40 Left Parenthesis (

0b00010000,

0b00100000,

0b01000000,

0b01000000,

0b01000000,

0b00100000,

0b00010000,

//41 Right Parenthesis )

0b01000000,

0b00100000,

0b00010000,

0b00010000,

0b00010000,

0b00100000,

0b01000000,

//42 Star *

0b00010000,

0b00111000,

0b00010000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//43 Plus +

0b00000000,

0b00100000,

0b00100000,

0b11111000,

0b00100000,

0b00100000,

0b00000000,

//44 Comma ,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00010000,

0b00010000,

//45 Minus -

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b11111000,

0b00000000,

0b00000000,

//46 Period .

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00010000,

// 47 Backslahs /

0b00000000,

0b00001000,

0b00010000,

0b00100000,

0b01000000,

0b10000000,

0b00000000,

// 48 Zero

0b01110000,

0b10001000,

0b10011000,

0b10101000,

0b11001000,

0b10001000,

0b01110000,

//49 One

0b00100000,

0b01100000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b01110000,

//50 two

0b01110000,

0b10001000,

0b00001000,

0b00010000,

0b00100000,

0b01000000,

0b11111000,

//51 Three

0b11111000,

0b00010000,

0b00100000,

0b00010000,

0b00001000,

0b10001000,

0b01110000,

//52 Four

0b00010000,

0b00110000,

0b01010000,

0b10010000,

0b11111000,

0b00010000,

0b00010000,

//53 Five

0b11111000,

0b10000000,

0b11110000,

0b00001000,

0b00001000,

0b10001000,

0b01110000,

//54 Six

0b01000000,

0b10000000,

0b10000000,

0b11110000,

0b10001000,

0b10001000,

0b01110000,

//55 Seven

0b11111000,

0b00001000,

0b00010000,

0b00100000,

0b01000000,

0b10000000,

0b10000000,

//56 Eight

0b01110000,

0b10001000,

0b10001000,

0b01110000,

0b10001000,

0b10001000,

0b01110000,

//57 Nine

0b01110000,

0b10001000,

0b10001000,

0b01111000,

0b00001000,

0b00001000,

0b00010000,

//58 :

0b00000000,

0b00000000,

0b00100000,

0b00000000,

0b00000000,

0b00000000,

0b00100000,

//59 ;

0b00000000,

0b00000000,

0b00100000,

0b00000000,

0b00000000,

0b00100000,

0b00100000,

//60 <

0b00000000,

0b00011000,

0b01100000,

0b10000000,

0b01100000,

0b00011000,

0b00000000,

//61 =

0b00000000,

0b00000000,

0b01111000,

0b00000000,

0b01111000,

0b00000000,

0b00000000,

//62 >

0b00000000,

0b11000000,

0b00110000,

0b00001000,

0b00110000,

0b11000000,

0b00000000,

//63 ?

0b00110000,

0b01001000,

0b00010000,

0b00100000,

0b00100000,

0b00000000,

0b00100000,

//64 @

0b01110000,

0b10001000,

0b10111000,

0b10101000,

0b10010000,

0b10001000,

0b01110000,

//65 A

0b01110000,

0b10001000,

0b10001000,

0b10001000,

0b11111000,

0b10001000,

0b10001000,

//B

0b11110000,

0b10001000,

0b10001000,

0b11110000,

0b10001000,

0b10001000,

0b11110000,

//C

0b01110000,

0b10001000,

0b10000000,

0b10000000,

0b10000000,

0b10001000,

0b01110000,

//D

0b11110000,

0b10001000,

0b10001000,

0b10001000,

0b10001000,

0b10001000,

0b11110000,

//E

0b11111000,

0b10000000,

0b10000000,

0b11111000,

0b10000000,

0b10000000,

0b11111000,

//F

0b11111000,

0b10000000,

0b10000000,

0b11111000,

0b10000000,

0b10000000,

0b10000000,

//G

0b01110000,

0b10001000,

0b10000000,

0b10011000,

0b10001000,

0b10001000,

0b01110000,

//H

0b10001000,

0b10001000,

0b10001000,

0b11111000,

0b10001000,

0b10001000,

0b10001000,

//I

0b01110000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b01110000,

//J

0b00111000,

0b00010000,

0b00010000,

0b00010000,

0b00010000,

0b10010000,

0b01100000,

//K

0b10001000,

0b10010000,

0b10100000,

0b11000000,

0b10100000,

0b10010000,

0b10001000,

//L

0b10000000,

0b10000000,

0b10000000,

0b10000000,

0b10000000,

0b10000000,

0b11111000,

//M

0b10001000,

0b11011000,

0b10101000,

0b10101000,

0b10001000,

0b10001000,

0b10001000,

//N

0b10001000,

0b10001000,

0b11001000,

0b10101000,

0b10011000,

0b10001000,

0b10001000,

//O

0b01110000,

0b10001000,

0b10001000,

0b10001000,

0b10001000,

0b10001000,

0b01110000,

//P

0b11110000,

0b10001000,

0b10001000,

0b11110000,

0b10000000,

0b10000000,

0b10000000,

//Q

0b01110000,

0b10001000,

0b10001000,

0b10001000,

0b10101000,

0b10010000,

0b01101000,

//R

0b11110000,

0b10001000,

0b10001000,

0b11110000,

0b10100000,

0b10010000,

0b10001000,

//S

0b01111000,

0b10000000,

0b10000000,

0b01110000,

0b00001000,

0b00001000,

0b11110000,

//T

0b11111000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

//U

0b10001000,

0b10001000,

0b10001000,

0b10001000,

0b10001000,

0b10001000,

0b01110000,

//V

0b10001000,

0b10001000,

0b10001000,

0b10001000,

0b10001000,

0b01010000,

0b00100000,

//W

0b10001000,

0b10001000,

0b10001000,

0b10101000,

0b10101000,

0b10101000,

0b01010000,

//X

0b10001000,

0b10001000,

0b01010000,

0b00100000,

0b01010000,

0b10001000,

0b10001000,

//Y

0b10001000,

0b10001000,

0b10001000,

0b01010000,

0b00100000,

0b00100000,

0b00100000,

//Z

0b11111000,

0b00001000,

0b00010000,

0b00100000,

0b01000000,

0b10000000,

0b11111000,

//91 [

0b11100000,

0b10000000,

0b10000000,

0b10000000,

0b10000000,

0b10000000,

0b11100000,

//92 \

0b00000000,

0b10000000,

0b01000000,

0b00100000,

0b00010000,

0b00001000,

0b00000000,

//93 ]

0b00111000,

0b00001000,

0b00001000,

0b00001000,

0b00001000,

0b00001000,

0b00111000,

//94 ^

0b00100000,

0b01010000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//95 _

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b11111000,

//96 `

0b10000000,

0b01000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//97 a

0b00000000,

0b01100000,

0b00010000,

0b01110000,

0b10010000,

0b01100000,

0b00000000,

//98 b

0b10000000,

0b10000000,

0b11100000,

0b10010000,

0b10010000,

0b11100000,

0b00000000,

//99 c

0b00000000,

0b00000000,

0b01110000,

0b10000000,

0b10000000,

0b01110000,

0b00000000,

// 100 d

0b00010000,

0b00010000,

0b01110000,

0b10010000,

0b10010000,

0b01110000,

0b00000000,

//101 e

0b00000000,

0b01100000,

0b10010000,

0b11110000,

0b10000000,

0b01110000,

0b00000000,

//102 f

0b00110000,

0b01000000,

0b11100000,

0b01000000,

0b01000000,

0b01000000,

0b00000000,

//103 g

0b00000000,

0b01100000,

0b10010000,

0b01110000,

0b00010000,

0b00010000,

0b01100000,

//104 h

0b10000000,

0b10000000,

0b11100000,

0b10010000,

0b10010000,

0b10010000,

0b00000000,

//105 i

0b00000000,

0b00100000,

0b00000000,

0b00100000,

0b00100000,

0b00100000,

0b00000000,

//106 j

0b00000000,

0b00010000,

0b00000000,

0b00010000,

0b00010000,

0b00010000,

0b01100000,

//107 k

0b10000000,

0b10010000,

0b10100000,

0b11000000,

0b10100000,

0b10010000,

0b00000000,

//108 l

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b00000000,

//109 m

0b00000000,

0b00000000,

0b01010000,

0b10101000,

0b10101000,

0b10101000,

0b00000000,

//110 n

0b00000000,

0b00000000,

0b01100000,

0b10010000,

0b10010000,

0b10010000,

0b00000000,

//111 o

0b00000000,

0b00000000,

0b01100000,

0b10010000,

0b10010000,

0b01100000,

0b00000000,

//112 p

0b00000000,

0b00000000,

0b01100000,

0b10010000,

0b11110000,

0b10000000,

0b10000000,

//113 q

0b00000000,

0b00000000,

0b01100000,

0b10010000,

0b11110000,

0b00010000,

0b00010000,

//114 r

0b00000000,

0b00000000,

0b10111000,

0b01000000,

0b01000000,

0b01000000,

0b00000000,

//115 s

0b00000000,

0b00000000,

0b01110000,

0b01000000,

0b00010000,

0b01110000,

0b00000000,

//116 t

0b01000000,

0b01000000,

0b11100000,

0b01000000,

0b01000000,

0b01000000,

0b00000000,

// 117u

0b00000000,

0b00000000,

0b10010000,

0b10010000,

0b10010000,

0b01100000,

0b00000000,

//118 v

0b00000000,

0b00000000,

0b10001000,

0b10001000,

0b01010000,

0b00100000,

0b00000000,

//119 w

0b00000000,

0b00000000,

0b10101000,

0b10101000,

0b01010000,

0b01010000,

0b00000000,

//120 x

0b00000000,

0b00000000,

0b10010000,

0b01100000,

0b01100000,

0b10010000,

0b00000000,

//121 y

0b00000000,

0b00000000,

0b10010000,

0b10010000,

0b01100000,

0b01000000,

0b10000000,

//122z

0b00000000,

0b00000000,

0b11110000,

0b00100000,

0b01000000,

0b11110000,

0b00000000,

//123 {

0b00100000,

0b01000000,

0b01000000,

0b10000000,

0b01000000,

0b01000000,

0b00100000,

//124 |

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

0b00100000,

//125 }

0b00100000,

0b00010000,

0b00010000,

0b00001000,

0b00010000,

0b00010000,

0b00100000,

//126 ~

0b00000000,

0b00000000,

0b01000000,

0b10101000,

0b00010000,

0b00000000,

0b00000000,

//127 DEL

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

//128 o invert

0b11111111,

0b11111111,

0b10011111,

0b01101111,

0b01101111,

0b10011111,

0b11111111,

0b00000000,

0b00000000,

0b00110000,

0b01001000,

0b10010000,

0b01100000,

0b00000000,

0b00000000,

0b00000000,

0b01001000,

0b01010000,

0b01100000,

0b10100000,

0b00000000

};

flash char pacpic[7][6] = {

// blank

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

0b00000000,

// right open

0b00000000,

0b01110000,

0b10001000,

0b10010000,

0b10001000,

0b01110000,

// right closed

0b00000000,

0b01110000,

0b10001000,

0b10011000,

0b10001000,

0b01110000,

// left open

0b00000000,

0b01110000,

0b10001000,

0b01001000,

0b10001000,

0b01110000,

// left closed

0b00000000,

0b01110000,

0b10001000,

0b11001000,

0b10001000,

0b01110000,

// front

0b00000000,

0b01110000,

0b10001000,

0b11111000,

0b10001000,

0b01110000,

// back

0b00000000,

0b01110000,

0b10001000,

0b10001000,

0b10001000,

0b01110000

};

//==================================

//This is the sync generator and raster generator. It MUST be entered from

//sleep mode to get accurate timing of the sync pulses

#pragma warn-

interrupt [TIM1_COMPA] void t1_cmpA(void)

begin

//start the Horizontal sync pulse

PORTD = syncON;

//update the curent scanline number

LineCount ++ ;

//begin inverted (Vertical) synch after line 247

if (LineCount==248)

begin

syncON = 0b00100000;

syncOFF = 0;

end

//back to regular sync after line 250

if (LineCount==251)

begin

syncON = 0;

syncOFF = 0b00100000;

end

//start new frame after line 262

if (LineCount==263)

begin

LineCount = 1;

end

delay_us(2); //adjust to make 5 us pulses

//end sync pulse

PORTD = syncOFF;

if (LineCount<ScreenBot && LineCount>=ScreenTop)

begin

//compute byte index for beginning of the next line

//left-shift 4 would be individual lines

// <<3 means line-double the pixels

//The 0xfff8 truncates the odd line bit

//i=(LineCount-ScreenTop)<<3 & 0xfff8; //

#asm

push r16

lds   r12, _LineCount

lds   r13, _Linecount+1

ldi   r16, 30

sub  r12, r16

ldi  r16,0

sbc  r13, r16

lsl  r12

rol  r13

lsl  r12

rol  r13

lsl  r12

rol  r13

mov  r16,r12

andi r16,0xf0

mov  r12,r16

pop r16

#endasm

//load 16 registers with screen info

#asm

push r14

push r15

push r16

push r17

push r18

push r19

push r26

push r27

ldi  r26,low(_screen)   ;base address of screen

ldi  r27,high(_screen)

ld   r4,x+          ;load 16 registers and inc pointer

ld   r5,x+

ld   r6,x+

ld   r7,x+

ld   r8,x+

ld   r9,x+

ld   r10,x+

ld   r11,x+

ld   r12,x+

ld   r13,x+

ld   r14,x+

ld   r15,x+

ld   r16,x+

ld   r17,x+

ld   r18,x+

ld   r19,x

pop  r27

pop  r26

#endasm

delay_us(4);  //adjust to center image on screen

//blast 16 bytes to the screen

#asm

;but first a macro to make the code shorter

;the macro takes a register number as a parameter

;and dumps its bits serially to portD.6

;the nop can be eliminated to make the display narrower

.macro videobits ;regnum

BST  @0,7

IN   R30,0x12

BLD  R30,6

nop

OUT  0x12,R30

BST  @0,6

IN   R30,0x12

BLD  R30,6

nop

OUT  0x12,R30

BST  @0,5

IN   R30,0x12

BLD  R30,6

nop

OUT  0x12,R30

BST  @0,4

IN   R30,0x12

BLD  R30,6

nop

OUT  0x12,R30

BST  @0,3

IN   R30,0x12

BLD  R30,6

nop

OUT  0x12,R30

BST  @0,2

IN   R30,0x12

BLD  R30,6

nop

OUT  0x12,R30

BST  @0,1

IN   R30,0x12

BLD  R30,6

nop

OUT  0x12,R30

BST  @0,0

IN   R30,0x12

BLD  R30,6

nop

OUT  0x12,R30

.endm

videobits r4 ;video line -- byte 1

videobits r5 ;byte 2

videobits r6 ;byte 3

videobits r7 ;byte 4

videobits r8 ;byte 5

videobits r9 ;byte 6

videobits r10 ;byte 7

videobits r11 ;byte 8

videobits r12 ;byte 9

videobits r13 ;byte 10

videobits r14 ;byte 11

videobits r15 ;byte 12

videobits r16 ;byte 13

videobits r17 ;byte 14

videobits r18 ;byte 15

videobits r19 ;byte 16

clt   ;clear video after the last pixel on the line

IN   R30,0x12

BLD  R30,6

OUT  0x12,R30

pop r19

pop r18

pop r17

pop r16

pop r15

pop r14

#endasm

end

end

#pragma warn+

//==================================

//plot one point

//at x,y with color 1=white 0=black 2=invert

#pragma warn-

void video_pt(char x, char y, char c)

begin

#asm

;  i=(x>>3) + ((int)y<<4) ;   the byte with the pixel in it

push r16

ldd r30,y+2          ;get x

lsr r30

lsr r30

lsr r30              ;divide x by 8

ldd r12,y+1          ;get y

lsl r12              ;mult y by 16

clr r13

lsl r12

rol r13

lsl r12

rol r13

lsl r12

rol r13

;v2 = screen[i];   r5

;v3 = pos[x & 7];  r6

;v4 = c            r7

ldi r30,low(_screen)

ldi r31,high(_screen)

ld r5,Z              ;get screen byte

ldd r26,y+2          ;get x

ldi r27,0

andi r26,0x07           ;form x & 7

ldi r30,low(_pos*2)

ldi r31,high(_pos*2)

lpm r6,Z

ld r16,y             ;get c

;if (v4==1) screen[i] = v2 | v3 ;

;if (v4==0) screen[i] = v2 & ~v3;

;if (v4==2) screen[i] = v2 ^ v3 ;

cpi r16,1

brne tst0

or  r5,r6

tst0:

cpi r16,0

brne tst2

com r6

and r5,r6

tst2:

cpi r16,2

brne writescrn

eor r5,r6

writescrn:

ldi r30,low(_screen)

ldi r31,high(_screen)

st Z, r5             ;write the byte back to the screen

pop r16

#endasm

end

#pragma warn+

//==Fast fixed multiply=================================

char fix2int(int a)

begin

#asm

ldd r30, Y+1 ;moves the high byte of the input to low byte

#endasm

end

//========================================================

int mult_opt(int a, int b)

begin

#asm

;push r20

;push r21

mov  r24,r20

mov  r25,r21

ldd  R23,Y+3

ldd r21,Y+1

muls      r23, r21      ; (signed)ah * (signed)bh

mov              r31, r0              ;

mul              r22, r20      ; al * bl

mov       r30, r1              ;

;mov      r16, r0

mulsu     r23, r20      ; (signed)ah * bl

mulsu     r21, r22      ; (signed)bh * al

mov r20,r24

mov r21,r25

;pop r21

;pop r20

#endasm

end

//========================================================

signed char cIn; //an input integer

float fIn;       //an input float

char fInString[16];

signed int cInFix, fInFix, prod, root, ratio;

//==================================

// put a big character on the screen

// c is index into bitmap

void video_putchar(char x, char y, char c)

begin

v7 = x;

for (v6=0;v6<7;v6++)

begin

v1 = ascii[c][v6];

v8 = y+v6;

video_pt(v7,   v8, (v1 & 0x80)==0x80);

video_pt(v7+1, v8, (v1 & 0x40)==0x40);

video_pt(v7+2, v8, (v1 & 0x20)==0x20);

video_pt(v7+3, v8, (v1 & 0x10)==0x10);

video_pt(v7+4, v8, (v1 & 0x08)==0x08);

end

end

//==================================

// put a string of big characters on the screen

void video_puts(char x, char y, char *str)

begin

char i ;

for (i=0; str[i]!=0; i++)

begin

video_putchar(x,y,str[i]);

x = x+6;

end

end

//==================================

// put a small character on the screen

// x-cood must be on divisible by 4

// c is index into bitmap

void video_smallchar(char x, char y, char c)

begin

i=((int)x>>3) + ((int)y<<4) ;

if (x == (x & 0xf8)) mask = 0x0f;     //f8

end

//==================================

// put a string of small characters on the screen

// x-cood must be on divisible by 4

void video_putsmalls(char x, char y, char *str)

begin

char i ;

x = x & 0b1111100 ; //make it divisible by 4

for (i=0; str[i]!=0; i++)

begin

if (str[i] == ' ')      // space

video_smallchar(x,y,12);

else if (str[i] == '-')      // minus

video_smallchar(x,y,39);

else if (str[i]>=0x30 && str[i]<=0x3a)

video_smallchar(x,y,str[i]-0x30);

else

video_smallchar(x,y,str[i]-0x40+12);

x = x+4;

end

end

//==================================

//plot a line

//at x1,y1 to x2,y2 with color 1=white 0=black 2=invert

//NOTE: this function requires signed chars

//Code is from David Rodgers,

//"Procedural Elements of Computer Graphics",1985

void video_line(char xpt1, char ypt1, char xpt2, char ypt2, char c)

begin

int e;

signed char dx,dy,j, temp;

signed char s1,s2, xchange;

signed char x,y;

x = xpt1;

y = ypt1;

dx = cabs(xpt2-xpt1);

dy = cabs(ypt2-ypt1);

s1 = csign(xpt2-xpt1);

s2 = csign(ypt2-ypt1);

xchange = 0;

if (dy>dx)

begin

temp = dx;

dx = dy;

dy = temp;

xchange = 1;

end

e = ((int)dy<<1) - dx;

for (j=0; j<=dx; j++)

begin

video_pt(x,y,c) ;

if (e>=0)

begin

if (xchange==1) x = x + s1;

else y = y + s2;

e = e - ((int)dx<<1);

end

if (xchange==1) y = y + s2;

else x = x + s1;

e = e + ((int)dy<<1);

end

end

//==================================

//return the value of one point

//at x,y with color 1=white 0=black 2=invert

char video_set(char x, char y)

begin

//The following construction

//detects exactly one bit at the x,y location

i=((int)x>>3) + ((int)y<<4) ;

return ( screen[i] & 1<<(7-(x & 0x7)));

end

//===draw pacman =======================

void draw_pac(char x, char y, char erase)

{

x = sx_draw;

if(!fly_mode)

{

y = sy_track;

}

else

{

y = sy_draw;

}

delt_x_draw = sx_draw - prev_x_draw;

delt_y_track = sy_track - prev_y_track;

// determine direction

// right

if(((delt_x_draw) > 0)

&& (((delt_y_track > 0)&&(delt_x_draw > delt_y_track))||((delt_y_track < 0)&&(-delt_y_track < delt_x_draw))))

{

dir = right;

}

// face left

else if(((delt_x_draw) < 0)

&& (((delt_y_track > 0)&&(-delt_x_draw > delt_y_track))||((delt_y_track < 0)&&(-delt_y_track < -delt_x_draw))))

{

dir = left;

}

// face forward

else if(((delt_y_track) > 0)

&& (((delt_x_draw > 0)&&(delt_y_track > delt_x_draw))||((delt_x_draw < 0)&&(-delt_x_draw < delt_y_track))))

{

dir = forward;

}

// face backward

else if(((delt_y_track) < 0)

&& (((delt_x_draw > 0)&&(-delt_y_track > delt_x_draw))||((delt_x_draw < 0)&&(-delt_x_draw < -delt_y_track))))

{

dir = backward;

}

if(erase)

{

v7 = x;

for (v6=0;v6<6;v6++)

{

v1 = pacpic[0][v6];

v8 = y+v6;

video_pt(v7,   v8, (v1 & 0x80)==0x80);

video_pt(v7+1, v8, (v1 & 0x40)==0x40);

video_pt(v7+2, v8, (v1 & 0x20)==0x20);

video_pt(v7+3, v8, (v1 & 0x10)==0x10);

video_pt(v7+4, v8, (v1 & 0x08)==0x08);

video_pt(v7+5, v8, (v1 & 0x04)==0x04);

}

}

// face right

else if(dir == right)

{

v7 = x;

for (v6=0;v6<6;v6++)

{

if(open)

{

v1 = pacpic[1][v6];

}

else

{

v1 = pacpic[2][v6];

}

v8 = y+v6;

video_pt(v7,   v8, (v1 & 0x80)==0x80);

video_pt(v7+1, v8, (v1 & 0x40)==0x40);

video_pt(v7+2, v8, (v1 & 0x20)==0x20);

video_pt(v7+3, v8, (v1 & 0x10)==0x10);

video_pt(v7+4, v8, (v1 & 0x08)==0x08);

video_pt(v7+5, v8, (v1 & 0x04)==0x04);

}

}

// face left

else if(dir == left)

{

v7 = x;

for (v6=0;v6<6;v6++)

{

if(open)

{

v1 = pacpic[3][v6];

}

else

{

v1 = pacpic[4][v6];

}

v8 = y+v6;

video_pt(v7,   v8, (v1 & 0x80)==0x80);

video_pt(v7+1, v8, (v1 & 0x40)==0x40);

video_pt(v7+2, v8, (v1 & 0x20)==0x20);

video_pt(v7+3, v8, (v1 & 0x10)==0x10);

video_pt(v7+4, v8, (v1 & 0x08)==0x08);

video_pt(v7+5, v8, (v1 & 0x04)==0x04);

}

}

// face forward

else if(dir == forward)

{

v7 = x;

for (v6=0;v6<6;v6++)

{

v1 = pacpic[5][v6];

v8 = y+v6;

video_pt(v7,   v8, (v1 & 0x80)==0x80);

video_pt(v7+1, v8, (v1 & 0x40)==0x40);

video_pt(v7+2, v8, (v1 & 0x20)==0x20);

video_pt(v7+3, v8, (v1 & 0x10)==0x10);

video_pt(v7+4, v8, (v1 & 0x08)==0x08);

video_pt(v7+5, v8, (v1 & 0x04)==0x04);

}

}

// face backward

else if(dir == backward)

{

v7 = x;

for (v6=0;v6<6;v6++)

{

v1 = pacpic[6][v6];

v8 = y+v6;

video_pt(v7,   v8, (v1 & 0x80)==0x80);

video_pt(v7+1, v8, (v1 & 0x40)==0x40);

video_pt(v7+2, v8, (v1 & 0x20)==0x20);

video_pt(v7+3, v8, (v1 & 0x10)==0x10);

video_pt(v7+4, v8, (v1 & 0x08)==0x08);

video_pt(v7+5, v8, (v1 & 0x04)==0x04);

}

}

if(open)

{

open = 0;

}

else

{

open = 1;

}

}

// find exact position (x,y,z)

void getCoords()

{

// B.2 = fly mode bit 1

// B.3 = fly mode bit 0

// this is the slave

if(PINB.1 == 1)         // data ready

{

switch(CoordCtrl)

begin

case 1:

x_draw = PINA;      // read port

y_draw = PINC;

CoordCtrl++;

break;

case 2:

y_track = PINA;      // read port

y_draw = PINC;

CoordCtrl++;

break;

case 3:

y_track = PINA;

x_draw = PINC;

CoordCtrl = 1;

break;

end

//scaled values

sx_draw = mult_opt((x_draw>>2),(3<<8));

sy_draw = (mult_opt((y_draw>>2),(2<<8)))+45;

sy_track = (mult_opt((y_track>>2),(2<<8)))+45;

// boundaries

if(sy_draw <= 12)

{

sy_draw = 12;

}

else if(sy_draw >= 93)

{

sy_draw = 93;

}

if(sy_track <= 12)

{

sy_track = 12;

}

else if(sy_track >= 93)

{

sy_track = 93;

}

if(sx_draw <= 26)

{

sx_draw = 26;

}

else if(sx_draw >= 119)

{

sx_draw = 119;

}

if(sy_track <=68)

{

sy_track = 68;

}

// ground edge detection

if((sy_track<=70)&&(sy_track>=64))

{

wPlatform = 1;

}

else if((sy_track<=68))

{

wPlatform = 1;

}

else

wPlatform = 0;

if((sy_draw<=70)&&(sy_draw>=64))

{

fPlatform = 1;

}

else

fPlatform = 0;

if(!fly_mode && sy_track <64)

{

sy_track = 64;

}

// draw pac-man

if(fly_mode)

{

draw_pac(sx_draw,sy_draw, 0);

video_smallchar(sx_draw,sy_track,39);

}

else

{

// if(!wPlatform)

draw_pac(sx_draw,sy_track, 0);

}

if(CoordCtrl == 1)

{

PORTB.2 = 0;

PORTB.3 = 1;

//CoordCtrl++;

}

else if(CoordCtrl == 2)

{

PORTB.2 = 1;

PORTB.3 = 0;

//CoordCtrl++;

}

else if(CoordCtrl == 3)

{

PORTB.2 = 1;

PORTB.3 = 1;

//CoordCtrl = 1;

}

PORTB.0 = 1;         //got data

delay_ms(4);

video_line(25,70,126,70,1);

}

if(PINB.1 == 0)

{

PORTB.0 = 0;

}

prev_x_draw = sx_draw;

prev_y_track = sy_track;

prev2_y_track = prev_y_track;

prev2_x_draw = prev_x_draw;

}

//===simulation stuff==================================================

char cu1[]="3D PACMAN";

char xpos[] = "XPOS";

char ypos[] = "YPOS";

char zpos[] = "ZPOS";

char fly[] = "F";

char walk[] = "W";

char scor[] = "SCORE";

char lose[] = "GAME OVER"

char l1[] = "LEV1";

char l2[] = "LEV2";

char ts[10];

char strx[10], stry[10], strz[10], strscore[10];

//==================================

// set up the ports and timers

void main(void)

begin

int j = 0;

//init timer 1 to generate sync

OCR1A = lineTime; //One NTSC line

TCCR1B = 9;              //full speed; clear-on-match

TCCR1A = 0x00;     //turn off pwm and oc lines

TIMSK = 0x10;            //enable interrupt T1 cmp

//init ports

DDRD = 0xf0;             //video out and switches

//D.5 is sync:1000 ohm + diode to 75 ohm resistor

//D.6 is video:330 ohm + diode to 75 ohm resistor

DDRA = 0x00; //inputs

DDRC = 0x00;

DDRB.0 = 1;

DDRB.1 = 0;

DDRB.2 = 1;

DDRB.3 = 1;

PORTB.0 = 0; //ready for new data

neg = -1;

//initialize synch constants

LineCount = 1;

syncON = 0b00000000;

syncOFF = 0b00100000;

// A/D stuff

MuxCtrl = 1;

CoordCtrl = 1;

Align = 0;

wPlatform = 0;

fPlatform = 0;

calcO = 0;

open = 0;

dir = 3;

x_draw = 55;

y_track = 55;

y_draw = 55;

sx_draw = 55;

sy_draw = 55;

sy_track = 55;

fly_mode = 0;     // default: WALK MODE

time1 = 30;       //object timer

score=0;

check = 0;

off = 0;

gametime = 0;

eat = 0;

feat = 0;

fheight = 0;

//Oy=11;

//init the UART

UCSRB = 0x18;

UBRRL = 103;

//printf("starting...\n\r");

//Print "PACMAN"

video_puts(13,3,cu1);

//side lines

#define width 126

video_line(0,0,0,99,1);

video_line(width,0,width,99,1);

video_line(25,11,25,99,1);

//top line & bottom lines

video_line(0,0,width,0,1);

video_line(0,99,width,99,1);

video_line(0,11,width,11,1);

//horizon

video_line(25,70,width,70,1);

//video_

//enable sleep mode

MCUCR = 0b10000000;

#asm ("sei");

//The following loop executes once/video line during lines

//1-230, then does all of the frame-end processing

while(1)

begin

//stall here until next line starts

//sleep enable; mode=idle

//use sleep to make entry into sync ISR uniform time

#asm ("sleep");

//The following code executes during the vertical blanking

//Code here can be as long as

//a total of 60 lines x 63.5 uSec/line x 8 cycles/uSec

if (LineCount==231)

begin

draw_pac(sx_draw,sy_draw, 1);

video_smallchar(sx_draw,sy_track,12);

draw_pac(sx_draw,sy_track, 1);

draw_pac(prev2_x_draw,prev2_y_track,1);

getCoords();

// button 0 pushed puts this game in fly mode

if(PINB.4 == 0)

{

fly_mode = 1;

video_putsmalls(28,93,fly);

}

else

{

fly_mode = 0;

video_putsmalls(28,93,walk);

}

// detect when object is eaten

if((((sx_draw>=Ox)&&(sx_draw<=(Ox+5))&&(sy_track>=Oy)&&(sy_track<=(Oy+7)))

||(((sx_draw+5)>=Ox)&&((sx_draw+5)<=(Ox+5))&&(sy_track>=Oy)&&(sy_track<=(Oy+7)))

||(((sx_draw)>=Ox)&&(sx_draw<=(Ox+5))&&((sy_track+7)>=Oy)&&((sy_track+7)<=(Oy+7)))

||(((sx_draw+5)>=Ox)&&((sx_draw+5)<=(Ox+5))&&((sy_track+7)>=Oy)&&

((sy_track+7)<=(Oy+7))))&& (!wPlatform))

{

eat = 1;

}

else if((((sx_draw>=Xx)&&(sx_draw<=(Xx+5))&&(sy_track>=Xy)&&(sy_track<=(Xy+7)))

||(((sx_draw+5)>=Xx)&&((sx_draw+5)<=(Xx+5))&&(sy_track>=Oy)&&(sy_track<=(Xy+7)))

||(((sx_draw)>=Xx)&&(sx_draw<=(Xx+5))&&((sy_track+7)>=Xy)&&((sy_track+7)<=(Xy+7)))

||(((sx_draw+5)>=Xx)&&((sx_draw+5)<=(Xx+5))&&((sy_track+7)>=Xy)

&&((sy_track+7)<=(Xy+7))))&& (!wPlatform))

{

eat = 1;

}

else

{

eat = 0;

}

if((((sx_draw>=Ox)&&(sx_draw<=(Ox+5))&&(sy_draw>=Oy)&&(sy_draw<=(Oy+7)))

||(((sx_draw+5)>=Ox)&&((sx_draw+5)<=(Ox+5))&&(sy_draw>=Oy)&&(sy_draw<=(Oy+7)))

||(((sx_draw)>=Ox)&&(sx_draw<=(Ox+5))&&((sy_draw+7)>=Oy)&&((sy_draw+7)<=(Oy+7)))

||(((sx_draw+5)>=Ox)&&((sx_draw+5)<=(Ox+5))&&((sy_draw+7)>=Oy)&&((sy_draw+7)<=(Oy+7))))&& (!wPlatform))

{

feat = 1;

}

else if((((sx_draw>=Xx)&&(sx_draw<=(Xx+5))&&(sy_draw>=Xy)&&(sy_draw<=(Xy+7)))

||(((sx_draw+5)>=Xx)&&((sx_draw+5)<=(Xx+5))&&(sy_draw>=Xy)&&(sy_draw<=(Xy+7)))

||(((sx_draw)>=Xx)&&(sx_draw<=(Xx+5))&&((sy_draw+7)>=Oy)&&((sy_draw+7)<=(Oy+7)))

||(((sx_draw+5)>=Xx)&&((sx_draw+5)<=(Xx+5))&&((sy_draw+7)>=Xy)&&((sy_draw+7)<=(Xy+7))))&& (!wPlatform))

{

feat = 1;

}

else

{

feat = 0;

}

{

fheight = 1;

}

else

{

fheight = 0;

}

//erase object

video_putchar(Ox,Oy,127);

video_putchar(80,60,127);

//objects

if(score <=5)                // Level 1

begin

video_putsmalls(4,13,l1);

if(gametime<300)

{

gametime++;

if(j<22)

{

Ox = x_pacpt1[j];

Oy = y_pacpt1[j];

}

else

j = 0;

video_putchar(Ox,Oy,111);   //O

if((video_set(((char)(sx_draw)),((char)(sy_track + 6)))!=0))

{

off = 1;

}

if((eat==1)&&(!fPlatform))

{

score+=2;

video_putchar(Ox,Oy,127);     // erase figure

gametime=300;

calcO = 0;

}

}

else if(gametime == 300)

{

j++;

gametime++;

}

else if ((300<gametime) && (gametime<500))

{

gametime++;

if(j<22)

{

Xx = x_pacpt1[j];

Xy = y_pacpt1[j];

}

else

j = 0;

video_putchar(Xx,Xy,120);    //X

if((eat==1)&&(!fPlatform))

{

score--;

video_putchar(Xx,Xy,127);     // erase figure

gametime=0;

}

}

else if(gametime == 500)

{

j++;

video_putchar(Xx,Xy,127);     // erase figure

gametime = 0;

}

end

else if((15<score))            // Level 2

begin

video_putsmalls(4,13,l2);

if(gametime<300)

{

gametime++;

if(j<22)

{

Ox = x_pacpt2[j];

Oy = y_pacpt2[j];

}

else

j = 0;

video_putchar(Ox,Oy,111);   //O

if((video_set(((char)(sx_draw)),((char)(sy_track + 6)))!=0))

{

off = 1;

}

if((feat==1)&&(!fPlatform))

{

score+=2;

video_putchar(Ox,Oy,127);     // erase figure

gametime=300;

calcO = 0;

}

// if(time1%10 == 0){score++;}//temp

}

else if(gametime == 300)

{

j++;

gametime++;

}

else if ((300<gametime) && (gametime<500))

{

gametime++;

if(j<22)

{

Xx = x_pacpt2[j];

Xy = y_pacpt2[j];

}

else

j = 0;

video_putchar(Xx,Xy,120);    //X

if((feat==1)&& (fly_mode==0))

{

score--;

gametime=0;

}

}

else if(gametime == 500)

{

j++;

video_putchar(Xx,Xy,127);     // erase figure

gametime = 0;

}

end

else                          // Level 3

begin

end

if(score < 0)

{

video_puts(45,50,lose);

break;

}

video_putsmalls(4,38,scor);

sprintf(strz, "%04d", score);

video_putsmalls(4,45,strz);

end  //line 231

end  //while

end  //main

Working hard or hardly working?

Sneak attack by Bruce with his camera...we are concentrating!

An amazing solder job by Aylin

The entire system

The mess that amazingly worked.

The user interface