The interrupt uses timer 1.
The interrupt is used to regulate the sync generation. Since
a uniform pulse is required every 63.5 microseconds for horizontal
sync, we run the clock full-speed at 16 MHz, and interrupt on
compare match after 1018 timer ticks. This means each frame is
exactly 1/60th of a second. The image content is generated during
lines 1 to 230. Most of our code executes within line 231-262.
Thus we have a very limited time to make calculations and graph
to the screen. The mcu is put to sleep right before the interrupt
is to occur. This helps keep the sync accurate. The logic for
counting lines, inverting horizontal sync to vertical sync, and running
the i/o port is contained within the 5 microsecond pulse time.
Debounce State Machines
Our software design is divided into three distinct
debounce state machines. Each machine controls separate functions of the keys
of the keypad. While it is possible to combine the second state machine with the third,
we have decided to separate the task for readability and less risk running into bugs.
Our keypad state machines utilize the basic structure of the
debounce state machine that was used in the first lab of the semester. By adding a few new
states, we are able to maneuver through the states well enough to run our tasks. Beside the
regular four states (‘maybePush’, ‘Pushed’, ‘maybeNotPushed’, ‘noPush’), state ‘Idle’ is
added to turn off the state machine when the state machine is not being used. State ‘INIT’
is a simple preliminary state to initialize character arrays and flags back to its original
values before starting a new cycle of debouncing. Finally, one last new state is state
‘recorded’. This state is added to avoid recording the keypad button pushed more than once
if a ‘slow’ user presses the buttons for a long period of time.
We design 3 state machines for our graphing calculator module.
State machine 1 and 2 will be used for scientific mode and state machine 1 and 3 will
be used during graphing mode. The general diagram of the state machines is as follows:
Click on figure for larger picture
From one state to another, a function called call_keypad()
must be called to poll user’s input during that frame cycle time. This program is taken
from ECE476 website and has been provided for us for lab 5.
State Machine 1
State machine 1 is essentially a debounce state machine that controls the first keypad.
In order to interpret the keys within the keypad, we make use of a look up table to represent
an operand by a number. In the program, the operand can easily be interpreted for calculation.
Below is the lookup table numtblone that represents the keys for keypad 1.
Both in scientific and graphing mode, state machine 1 will
record user’s input in a character array to be parsed later on after user completed the entry.
When the input is an operand, program will save the location of the operand in the character
array on another variable ‘oploc’. The program also avoids recording and displaying the simple
operands available on this keypad more than once.
State Machine 2
State machine 2 is active only during scientific mode.
It contains our trigonometric functions and other functionalities that we implemented
in our calculator. Similar format is applied to this state machine. The numtbltwo
corresponds to different tasks or functions of the different keys on the pad.
When user desires to compute a trigonometric function,
state machine 2 will go to the state “printTrig”. This state will simply print the desired
trig function to the screen, record the number representation of the trig function to the
char array, and updates the appropriate x and y location of the TV.
Along with this, the state machine checks when a user
completes entering the function and wish to calculate the result. When ‘enter’ is pressed
by user, state machine 1 will be turned off because it is no longer polling for user’s input.
In the mean time, state machine 2 will go to a couple states that will solve the function
and display the appropriate result to the TV. Since putting all the calculation in one cycle
damages the NTSC signal, we have decided to separate this duty into two different states:
“ParseA” and “ParseB”.
The state “ParseA” will simply parse the first input A from
the char array. The ending and the start of the next input is indicated by the location of
the operand variable, ‘oploc’. A series of ‘if’ statements are needed to provide some
error-checking to stop the program from performing calculation on invalid inputs.
Finally, the C-provided function atof() is used to convert this char array variables into
a float. The next state “ParseB” also be behaves the same way and when both inputs are
safely parsed, calculation is performed and displayed to the TV.
Besides this functionality, the state machine 2 will also go
to a series of states when user demands program to ‘clear’ the TV screen. To further avoid
signal damage on the TV, the ‘clearscreen’ states are separated into three states. In other
words, the clear screen function needs 3 frame cycle to be accomplished.
The delete button will set the state to ‘deleteOnScreen’.
This state simply moves the character array index location back one and it will also display
a blank character on top of the previous character to “delete” the input.
Finally, when user changes the mode from scientific to graphing,
state machine 2 will immediately set to idle and state machine 3 (which takes care of the
functionalities in graphing mode) will be set in motion.
State Machine 3
State machine 3 behaves very similarly to state machine 2.
However, this state machine will only be active during graphing mode. It will stay
in idle state during scientific mode. Upon entering the graphing mode, the state will
head straight the ‘clearScreen’ states to remove the scientific mode display and change
gear to graphing mode display.
When a user enters a function, the program will display the
function and start polling the user to enter the A, B and C inputs explained in the high
level design to complete the function variables to be graphed. The parameter inputs are
parsed in a similar way as the inputs in scientific mode. Once all the parameters are recorded,
the state will automatically goes to a series of states that will graph the function. There are
3 GraphInit states that will set up the axes, labels, and calculate the desired viewing window. It
will then enter the actual Graph state, which will continuously call GraphFunction to draw one point
at a time. When the graphing is done, the state machine will go into GraphDone state and wait for
the user to input before returning to the inital graphing mode state.
convertxCoord(float xCoord, float xVal)
This function simply converts the calculated values to
TV x coordinate values
convertyCoord(float yCoord, float yVal)
This function simply converts the calculated values to
TV y coordinate values
graphFunction(float inputA, float inputB, float inputC, float xCoord, char graphCommand)
This function takes as input the x-Coordinates and parameters, calculates the y
Coordinate, translates both x and y to TV coordinates and either plots a point or
draws a line on the screen.
calculate(float A, float B, int command)
This is the heart of the calculator, it uses either series approximations or math.h to
power(float A, float B)
This calculates A^B.
Error Checking Functions
This function simply takes in an input ‘err’ that represents 1 out of the 3 possible
errors: ‘Undef’ (undefined result), ‘syntax error’ (when user enters a syntax error)
or ‘invalid entry’ (when user enters an input outside the boundary of trig
boundCheck(float inptoCheck, char cmd)
This boundary checking function is necessary for trigonometric computation.
Due to the approximation, we can only calculate the trigonometric functions
accurate within +/- 2.5pi, inverse trig functions to within +/- 1, and ln functions
Note: Most of the display functions have been previously coded and optimized by prof. Land.
These functions are:
video_line(char x1, char y1, char x2, char y2, char c)
This function simply connects a line between the two points provided
video_smallchar(char x, char y, char c)
This function displays a specified character from the bitmap.
video_pt(char x, char y, char c)
This function draws a point on the specified location.
However, to produce some of the operand functions that we need,
we rearranged smallbitmap to contain more functions. As a result, we needed to modify the
function that display these characters according the position of the characters in the bitmap.
video_putsmalls(char x, char y, char *str)
This function utilizes the ascii characters to locate the
correct character in the bitmap. The previous bitmap only contains the number 0-9 and
colon(‘:’) (ascii 0x30 to 0x3A) and the capitalized alphabet (ascii 0x41 to 0x90).
The modified bitmap is expanded to contain the characters from ascii 0x20 to 0x3A and the
Click on figure for larger picture