Upload
sonike-selah-malik
View
224
Download
0
Embed Size (px)
Citation preview
7/28/2019 Embedded Control Blimp Report Final Report
1/36
Car-Gondola ReportEmbedded Control
Sam Ellis
Sonike Hendricks
Eric Fish
Michael Fredericks
Section 4 - Side B
7/28/2019 Embedded Control Blimp Report Final Report
2/36
2
Abstract 3
Purpose and Objectives 3
Overview of Contoller 4
Hardware Description 5
overview
speed controllerservo motor
compass
ranger
lcd/keypad
accelerometer
serial bus
pin connections from priority table
Software Description 8
Overview
Initialization - Ports, PCA, ADC, XBR0
Use of the PCA
Pulse Streams
Setting the Crossbar
I2C Read and Write
Use of I2C (SMB)
Reading Analog Input, A/D Results
Keypad input & LCD output
Control loops
Timing
Results & Conclusions 12
Analysis of results
Description of gondola performance
What was Learned
Problems Encountered & Solution
References 15
Participation 15
Code 16
Flowchart 34
Pseudocode 35
Schematic 36
7/28/2019 Embedded Control Blimp Report Final Report
3/36
3
Abstract
At the beginning of this semester long project we introduced ourselves to the SciLabs C8051 microprocessor and
created a user interactive game of hexadecimal-binary conversion, call the Hex-Bin Game. Since the completion of this
project we have moved on to implementing new microcontroller features like the programmable counter array and
serial communications along with C code control algorithms to create embedded control systems for our smart car. Later
we will be implementing these control systems templates on the Gondola. The basic building blocks learned in our
previous experience with the C8051 microcontroller will also be utilized including timers, interrupts and analog to digita
conversion. This report documents the development of a closed loop hardware-software system intending to control the
steering and velocity of the smart car based on sensor data. These sensors include an ultrasonic compass, electronic
compass and accelerometer. Initially we explored proportional control for our car with addition of derivative control on
our Gondola to improve control response. Proportional control Source code was developed to appropriately initialize
our microcontroller, read data from the sensors via I2C serial communication and output appropriate pulse width signals
to the motors. Implementation of an LCD display and numerical keypad allows for user inputs of heading and contro
gains. The goals of the system were to achieve a desired heading and velocity based on the range and current heading of
the Car. In addition to a desired heading the Gondola was desired altitude based on the range and current heading.
Lastly data was collected and plotted for a given desired heading to quantify the performance of the system comparing
various gain constants. Specifics towards the objectives and purpose of our project will be discussed next.
Purpose and Objectives Labs
Our Car and Gondola embedded control system can be divided into two main subsystems. The steering and
heading subsystem is responsible for steering the car given the heading from our electronic compass. The drive and
range subsystem is responsible for controlling the car speed based object distance to our ultrasonic ranger. Our
hardware objectives were quite short requiring only the configuration of the steering servo, speed controller, electronic
compass, ultrasonic ranger, accelerometer, LCD screen and numeric pad.
For our steer and heading subsystem we had to initialize and configure the programmable counter array for
pulse width modulation. We then calibrated the servo pulse width for extreme left, extreme right and center positions
A program was developed to control the steering servo via the laptop keypad. Next the I2C serial bus was initialized and
configured to read data from the electronic compass indicating the Cars heading. A control algorithm will use the
heading to control the pulse width signal of the steering servo. This algorithm will also need to be modified to control
the heading of the Gondola.
For our drive and range subsystem we had to initialize and configure the programmable counter array for pulse
width modulation as before. The speed controller needs to be calibrated for neutral, maximum speed forward and
maximum speed in reverse. We also must develop a program to test control of drive motor via the laptop keypad. Next
the I2C serial bus is initialized and configured to read data from the ultrasonic ranger indicating the distance above the
7/28/2019 Embedded Control Blimp Report Final Report
4/36
4
Car. A control algorithm will use this range to control the velocity of the drive motor. This algorithm will also need to be
modified to control the altitude of the Gondola.
The microcontroller requires a minimum operation voltage so a voltage divider must be utilized to monitor the
battery voltage. An analog-digital conversion must also be initialized and configured to convert this signal for display on
the LCD display. The LCD display and numeric pad must also be initialized and configured to receive user inputs and
display desired data. After initializing and configuring the accelerometer the x-coordinate and y-coordinate accelerationdata would be used to control the steering servo and speed controller. Unusually the x-coordinate acceleration data wil
control both heading and velocity in our algorithm.
Once completing all the control systems for the Car, source code needs to be developed for controlling components
of the Gondola; tail fan speed controller, right thrust fan speed controller, left thrust fan speed controller, thrust angle
servo, ultrasonic range, and electronic compass. The steering and propulsion subsystems of the Gondola and Car have
similar functionality and modifying our source code should also reflect this.
A proportional plus derivative control algorithm is to be used for the Gondola to increase dampening of the system,and increase system response. The numeric keypad will allow for input of the desired heading, proportional and
derivative gain values for the heading, and proportional and derivative gain values for the altitude. On the LCD the
battery voltage, desired head, current heading will be displayed along with all fan pulse widths. Collect data that shows
how the gondolas response is affected by the values of the proportional and derivative gains.
Overview of Microcontroller
In this laboratory the Silicon Labs C8051F020 microcontroller has proven its diversity in embedded contro
applications. A few specifications features include 64k bytes of internal flash and 4k bytes of internal RAM, RS232 and
serial communication. There are seven digital input/output ports but we will only be utilizing ports 0, 1, 2 and 3. Each
port has eight pins, one bit each, where 0V is logic FALSE and +3V is logic TRUE. The microcontroller is capable of analog
digital conversion on Port 1. It is also capable of serial communication via the I2C Bus, pulse width modulation via five
capture and compare modules, and interrupt service routines via up to five timers. Using a SDCC Compiler we wil
program the microcontroller in C code. Conveniently there are an abundant number of useful special registry functions
used to initialize and calibrate the microcontrollers plethora of features.
7/28/2019 Embedded Control Blimp Report Final Report
5/36
5
Hardware Description
Overview
Labs three through six introduced many new and complicated hardware components necessary to the
completion of the respective labs. First were the speed controller and the servo motor, which were built in to the smart
car, but needed to be attached to the microcontroller. The next additions were the compass and the ranger, which
needed to be wired to a specific section of the smart car. After, the LCD/keypad was introduced, and wired to the car to
provide input and feedback without having to use the serial monitor. Finally, the accelerometer was the last piece of
hardware needed to be wired to the car. When the gondola needed to be used, it incorporated all the previous
hardware except for the accelerometer, and everything had been previously wired inside the shell.
Pin Connections from Priority Table
Before going into detail on the description of various hardware components, it is important to understand the
hierarchy of pin connections. To comprehend the pin structure, the back of the lab manual provides a Priority Crossbar
Decode Table. By using this table appropriately, correct pin connections are ensured. For example, if 4 Capture
Compare Modules needed to be used, they would want to occupy port 0 and pins 0 to 3. However, some other registers
take precedence over the CCMs. If UART0EN and SPI0EN both need to be enabled, this will offset the CCMs to now take
up port 0 (pins 6 and 7) and port 1 (pins 0 and 1). More information about the crossbar will be discussed in the software
section.
Serial Bus
The Serial Bus (also referred to as the IC Bus) is used to control the compass, ranger, accelerometer, and
LCD/keypad. For the completed labs, it always used synchronous communication at 100 kHz. The Serial Bus needs 2
wires to run properly, one for transferring data and the other for the clock. There are two entities that connect to the
Serial Bus: the master or the slave. The microcontroller will always be the master, whereas the other hardware will be
the slaves. For the labs that included the use of any of the hardware mentioned previously, each component needs to
be wired to both the data line and the clock line. Also, a set of pull-up resistors is mandatory for the hardware to work
properly. Only one set of these resistors is required, but all the hardware must be connected to them. The connection
of the Serial Bus to individual components will be discussed later in this section.
Speed Controller
The Speed Controller is used to drive the back wheels of the smart car from labs 3 to 5. It is driven by pulse
width modulation using the programmable counter array. The back wheels are set in motion by varying the pulse width,
and able to range from full reverse to full forward. The Drive Motor has a 20 millisecond period, and wheel speed is
changed by varying the percentage of time the signal is high. The percentage of time the signal is high in one period is
known as the duty cycle. For the smart car, 1.1 milliseconds corresponds to full reverse, 1.5 milliseconds corresponds to
7/28/2019 Embedded Control Blimp Report Final Report
6/36
6
neutral, and 1.9 milliseconds corresponds to full forward. These values are then calculated into pulse widths at 2030,
2760, and 3500, respectively. One important fact to note about the Drive Motor is that it should always be initialized to
neutral for at least one second upon starting the code. The only connection needed to be made between the
microcontroller and the Drive Motor was to run a single wire from the Speed Controller to the corresponding port and
pin.
Servo Motor
The Servo Motor was very similar to the Drive Motor. It operated with a 20 millisecond period, and front wheel
orientation was varied in the same manner as back wheel speed. The Servo Motor should also always start in the
neutral position, set at a pulse width of around 2693. If the smart car is turning full left, the pulse width gets set to
2143, and the pulse width gets set to 3173 for full right turning. The pulse width varies in between these two extremes
to produce a smooth turning for the smart car. Similar to the Drive Motor, the only wiring needed to be done was to run
a single wire from the Servo Motor connection to the corresponding port and pin. Both the Servo and Drive Motors had
all of the hardware built into the smart car, only leaving the connection to the microcontroller to ensure proper
functioning.
Ranger
The ranger was used to receive feedback on how far away an object was from the smart car. It was initialized to
read and output values in centimeters as was necessary for the labs. The ranger sends out a high frequency sound
waves at about 0.9 feet per millisecond which reflect off surfaces and bounce back. If the ranger receives an echo, it
computes the distance from the time taken for the signals cycle . When the ranger was initialized correctly, it was
accurate until less than 3 centimeters, where it started encountering problems. This was not an issue though as the labs
never required a reading less than 3 centimeters to be completed. One important aspect about correct operation of the
ranger was to ensure it did not send out a signal faster than every 65 milliseconds. If the ranger sent out signals faster,
the signals would interfere and cause false outputs. The ranger was plugged into a special proto board located on the
side of the smart car, but needed to be wired to the microcontroller. The ranger had 5 pins, 4 of which were connected
to ensure a working component. The last pin was used to check the current software iteration on the ranger. The
ranger needed to be connected to power, ground, system data, and the system clock. The latter two connections
communicated with the serial bus, whereas the former two were necessary to power the ranger. In addition to these 4
connections, a 10 micro-Farad capacitor needed to be connected between the power and ground leads. Also, it was
mandatory that the data and clock connections each ran through a respective pull-up resistor.
Compass
The compass was used to determine the direction of the smart car in reference to magnetic north. When
connected correctly, it reads a value between 0 and 3599 determined by the smart cars current orientation. The
numbering system relates to 10 times the degree value of the rotation from north. So, for example, if the smart car is
7/28/2019 Embedded Control Blimp Report Final Report
7/36
7
heading east, the compass value would read 900, corresponding to 90 degrees. The compass was also connected to the
same proto board that the ranger was connected to. Similar to the ranger, the compass also required 4 connections to
run properly. The compass needed to be connected to power, ground, system data, and system clock. It is important to
note that the compass has a total of 9 pins, but only pins 1, 2, 3, and 9 need to be connected. Finally, the system data
and system clock line both need to be brought through the same pull-up resistors that the ranger went through.
LCD/Keypad
The LCD and Keypad come assembled together as one unit. The LCD has a total capacity to display 80 characters
4 rows of 20 characters each. The keypad contains the numbers 0 through 9, as well as the star (*) and the pound
symbol (#). The LCD/Keypad has a very similar setup to the two previous hardware devices. It needs to be connected to
power, ground, system data, and system clock. Just like the ranger and compass, the data and clock lines for the
LCD/Keypad need to be fed through a set of pull-up resistors. These pull-up resistors should be the same ones as used
for the previous two components, therefore, there should only be one set of pull-up resistors used on the
microcontroller.
Accelerometer
The accelerometer is used to determine the current tilt of the smart car. It uses a 3 axis system to be able to
determine acceleration on all 3 axes. The z-axis points straight down into the accelerometer. The x- and y-axes are
parallel to the plane of the accelerometer, offset by 90 degrees from each other. Unfortunately, the accelerometer
being used in the lab is somewhat unreliable and reports a lot of noise. To overcome this issue, multiple readings need
to be averaged together to receive a more accurate estimate. This process should be done between 8 and 16 times per
reading, and while not a very sophisticated method, it gets the job done appropriately. The accelerometer has a similar
wiring pattern to the previous hardware. It has a total of 8 pins, but only 4 are required to run the accelerometer in the
manner necessary for the lab. It requires power, ground, system data, and system clock. Also, the data and clock lines
need to be fed through the pull up resistors discussed previously.
7/28/2019 Embedded Control Blimp Report Final Report
8/36
8
Software Description
Overview
Much of the code for labs 3, 4, 5 and 6 is the same. This is due to the fact that the circuit elements and coding
goals are largely the same over all three labs. Input from an electronic compass is used to control the direction of the
vehicle for all three labs, with the difference lying in the type of hardware used to control the direction. In labs 3, 4 and
5, the ranger is used to control the servo mounted on the front axle of the car, which controlled the cars direction. In
lab 6, this input is used to control the motor on the rear fan of the gondola. This meant that the code could be imported
without changes. The code to control the speed of the vehicle changed slightly as the data acquisition device changed.
In labs 3, 4 and 6, input was gathered from an ultrasonic ranger, while in lab 5, an accelerometer was used. This led to
slight modifications in the pulse width calculations, but left the bulk of the code unchanged. The final coding aspect to
this project was implementing the LCD display and keypad. This device served the same function in all three labs. The
user had to be able to enter gain values and a desired heading before operation, and should then be able to see the
current battery voltage state during operation. This code remained largely constant throughout the project, with some
additional input being necessary for lab 6 to implement the additional gains.
Initialization Ports, PCA, ADC, XBR0
Port initialization function sets the output pins for CEX0, CEX1, CEX2, and CEX3 in push pull mode. These are on port 1,
pins 0-3. The other pins on port one are set. Port 1 pin 5 is set for analog input. Then port 0 is set.
XBR0 initialization is just setting XBR0 to 0x27. This ensures that CEX0, CEX1, CEX2 and CEX3 are all working correctly.
PCA initialization sets the PCA interrupt to be enabled with SYSCLK/12. It also sets CCM0, CCM1, CCM2 and CCM3 in 16
bit compare mode, as well as enabling the PCA counter.
The ADC initialization function sets Vref to the internal reference voltage, and also enables the AD converter.
Use of the PCA
The Programmable Counter Array, or PCA, was used in each lab to generate the pulse streams to control the
direction and speed of the vehicles and to serve as a timer to control when functions are called. In order to streamline
the transition between labs, certain standards were created. In the initialization function for the PCA, the system uses
SYSCLK/12 as the counter for the interrupt service routine. Each capture compare module is initialized to a standard 16
bit compare mode, as seen in the code below:
PCA0MD = 0x81; //PCA interrupt enable with SYSCLK/12
PCA0CPM0 = 0xC2; //CCM0 in 16-bit compare mode
PCA0CN = 0x40; //Enable PCA counter
7/28/2019 Embedded Control Blimp Report Final Report
9/36
9
This PCA initialization function remains largely the same for each of the labs. When generating a pulse width signal to
control the servos and motors, the code sets the corresponding CCM. In each of the labs, CCM 0 was the CCM that
controlled the heading of the vehicle, and CCM 2 controlled the speed. During labs 3, 4 and 5, CCMs 1 and 3 were not
used. In lab 6, CCM 1 controlled the angle of the thrust fans, and CCM 3 controlled the speed of the right thrust fan
while CCM 2 controlled the speed of the left thrust fan. The PCA ISR also served as a timer to allow the software to
avoid overloading different components such as the LCD display. This was done through a 20 ms pause function.
Pulse Streams
The method used to control the actions of the servo and the motors is known as Pulse Width Modulation, or
PWM. This refers to the fact that the PCA will send either a low or a high signal depending on the relation between the
current value and that stored in the CCM. By changing the values stored in the CCM, the amount of time that the signal
is high, or the Pulse Width, can be changed. The PCA outputs a high signal if the count is higher than the value stored in
the CCM. The PCA outputs as many unique signals as there are unique CCMs. Each pulse width is bounded based on the
physical requirements for the device in question. In lab 6 all devices had a minimum pulse width of 2000 and a
maximum pulse width of 3500. In order to avoid damage to the devices all pulse widths must be within this range. In
order to set a pulse width, the CCM must be loaded with the desired value. If the pulse width is known, then the CCM
must be set to the maximum value minus the desired value. This ensures that the PCA will only return a high signal over
the desired duration. As each CCM has both a high and a low byte, each of these must be set in order to set the CCM
properly. A sample PW setting is shown below:
PCA0CPL2 = 0xFFFF - PW; //sets low byte, PW = 2750
PCA0CPH2 = (0xFFFF - PW) >> 8; //sets high byte, PW = 2750
In the example above, the 2nd CCM is being set to a value of 62785 (65535 2750). As the counter overflows at 65536,
this ensures that the PCA will send a high signal for 2750 counts, creating a pulse width of 2750. In labs 3, 4, 5 and 6, the
pulse width was a function of how far from the desired heading the car was. This is known as proportional damping, and
was applicable due to the high amounts of natural damping due to friction. The formula to find the desired pulse width
to control the car was therefore;
PW = PW_NEUTRAL + Kp * (DESIRED_VALUE ACTUAL_VALUE)
where Kp is a calculated gain value and the data for the values is either heading or acceleration, and range. For lab 6,
the lack of significant amounts of friction required the addition of a derivative gain term in order to mimic the damping
effects of friction. Thus the formula to find pulse width became:
PW = PW_NEUTRAL + Kp*(DESIRED_VALUEACTUAL_VALUE) + Kd*(ERROR-PREVIOUS_ERROR)
7/28/2019 Embedded Control Blimp Report Final Report
10/36
10
By adding the final term, the PW can be controlled both in terms of the current heading and the current error value.
This makes the gondola much less likely to swing in circles, and much quicker to settle on the desired heading.
I2C Read and Write
The two options for I2C data transfer are reading and writing. These functions allow the master to receive and
send data respectively, and have functions to carry out these commands hard coded into the i2c.h file. The exact
functions can be found on pages 149 and 150 of the lab manual. In these labs the write command is useless so we will
focus on the read command. In this action, the master sends a data array to the slave location. This array is written to,
and the data in it is analyzed. This process repeats until there is no more data to be read. An example in which the
compass is read is shown below:
i2c_read_data(0xC0, 0x02, Data_heading, 2);
heading =(((unsigned int)Data_heading[0]
7/28/2019 Embedded Control Blimp Report Final Report
11/36
11
Reading a keypad input is very easy. All that needs to be done, is call the read key function. This gets the input on the
keypad. If nothing was pressed, it repeats after a short pause. After a key is pressed, the value is returned. If the
integer value is wanted, this value should be reduced by 48.
To print out on the LCD output, simply call the lcd_print() function. If variables are being output, they need to be in
character format.=
Control Loops
In order to control the gondola in lab 6, PD error correction was used. Once the initial error was calculated, both a
derivative and proportional error were added. This means the gondola should move quickly to the intended direction,
not overshoot very far, and if it does overshoot, it should come back quickly and not oscillate very much. However, if
any of the gain values are too large or too small, the gondola may move too quickly and spin in circles, oscillate very
quickly, and/or never reach its intended heading.
Timing
All of the timing for this system was done using PCA interrupts. Three counters were used; r_count, countsrange, and
countsheading. Each of these was incremented about every 20 miliseconds. This was set by setting the PCA0L and
PCA0H to 28672. After r_count got larger than 4 (80 ms) it was reset to zero and a flag to get the new range was set.
7/28/2019 Embedded Control Blimp Report Final Report
12/36
12
Results & Conclusions
Analysis of Results
Desired heading for all trials is XX. Data has been collect for the error vs. time of the heading control algorithm
We are using a proportional plus derivative algorithm which has two gain term Kp and Kd. These will be adjusted and the
changes in system response will be observed. The gain values have been adjusted according to the table below:
Case Kp Kd
1 0.1 0
2 5 0
3 0.1 10
4 0.5 70
5 3 70
6 3 180
7 12 70
8 12 180
Table 1
After inputting the suggested proportional and derivative gains, a graph was generated that included every case
The cases can be broken down into three main sub-groups based on the pattern the respective line followed in the
graph. With a high derivative gain and relatively low proportional gain, the line approached the optimal value slowly,
and never exceeded it. This pattern equates to the gondola slowly rotating toward its desired heading, but never
surpassing it. Another case was a dampening sinusoidal wave, which bounced over and under the optimal value until
the gondola landed appropriately at its desired heading. This case corresponds to a relatively high proportional gain,
with a smaller derivative gain. The final case was when the gondola simply ended up spinning in circles and never
remaining at the optimal value. In this instance, the proportional gain was very high compared to the derivative gain, so
the gondola would pick up too much rotational speed upon approaching its desired heading. In the end, a couple more
cases were tried to find the optimal setting for the different gains. The best set of gains determined was setting 4 for
the proportional gain and 30 for the derivative gain. Using these values, the gondola quickly approached the desired
heading and slowed down just in time to rest at the desired value. These plots are located in Figure XX on the following
page.
7/28/2019 Embedded Control Blimp Report Final Report
13/36
13
0
500
1000
1500
2000
2500
3000
3500
4000
1 917
25
33
41
49
57
65
73
81
89
97
105
113
121
129
137
145
15
3
161
169
177
185
193
201
209
CurrentHeading(degrees*
10)
Time (each data point corresponds to 20 milliseconds)
Current Heading versus Time
optimal
kp=0.1, kd=0kp=5, kd=0
kp=0.1, kd=10
kp=0.5, kd=70
kp=3, kd=70
kp=3, kp=180
kp=12, kd=70
kp=12, kd=180
kp=2, kd=35
kp=4, kd=20
kp=4,kd=30
kp=30, kd=70
7/28/2019 Embedded Control Blimp Report Final Report
14/36
14
Description of gondola performance
The Cars feedback system used the accelerometer data to the errors from the neutral position drive the Car up
a wooden ramp to this position. The x-coordinate steers the Car while driving it up the ramp until the yaw is neutral. The
y-coordinate drive the Car up the ramp until the tilt has reached the neutral position. The gains of the proportiona
control loops can be adjusted by user input via the numeric keypad. This control loop was quite predictable and we
encountered no major problems in getting our Car to behave as desired.
The Gondolas first control algorithm is the thrust loop which will cause the blimp to hover at a predetermined
altitude. Two thrust fans set vertically by the thrust angle servo propel the Gondola. On the Blimp, the Gondola is
expected to achieve the desired altitude with a quick response time and minimized system over shoot. The second
control loop will achieve the Gondolas desired heading. This loop drives the tail fan to achieve a desired heading
similarly to the previous loop with quick response and minimized overshoot. The algorithm also required the shortest
path be taken to acquire the heading. The desired heading and control algorithm gain terms are entered by the used via
the numeric keypad. The Gondola attempts to satisfy both conditions as fast as possible within the limits set by the
control loop. After trouble shooting some problems we were able to get the Gondola to function as expected. These
problems will be discussed in detail below.
For completeness the control algorithms will be explained. In our applications the proportion gain is linearly
modulates speed or position of a motor between neutral and extreme states given the error from the desired position. A
small proportional gain will result in slow response time however a large gain value will result in unwanted oscillations
as the system overshoots its target infinitely. This is where the derivative gain term is useful in damping the response of
the proportional gain as the loop approaches its target. The change in error over time is calculated and multiplied by the
differential gain helping decreased system overshoot for a high proportional gain term.
What was Learned
Over this semester we have learned a tremendous amount about building and programming embedded contro
systems. There is much more to learn however the consensus is that we have enough knowledge to explore advanced
systems independently. I personally feel like this class has expanded my engineering breath and that I will be able to
utilize a lot of this knowledge in my professional career. We are able to safely create hardware configurations from
schematics, initialize and calibrate the microcontroller, write C code to communicate with all of our systems with
functions to execute desired control and finally quantify the performance of the system.
Problems Encountered & Solution
We had a problem getting our PCA signals to the right capture and compare modules on the Gondola. We are
not sure if it was a hardware issue but the motors would sometimes behave erratically requiring the Gondola to be
shutdown with the program recompiled and reloaded. There were also issues with our heading control loop which
would infinitely overshoot the desired heading. We tried changing the battery multiple times but this did not resolve the
7/28/2019 Embedded Control Blimp Report Final Report
15/36
15
problem. We eventually resolved these issues by making adjustments to our initialization values and control loop but
the specific solution is unknown.
References
P. Schoch, A. Gutin, S. Lee, C. Sankar, LITEC Lab Manual Version 14.2, 2012
Participation
We had great participation from our group and we all learned valuable information from this
class.
Sam Ellis was responsible for the hardware description, data collection and analysis, and
schematics.
Eric Fish was responsible for the Lab code and software description, data analysis.
Michael Fredericks was responsible for the software description and flow chart.
Sonike Hendricks was responsible for the abstract, purpose and objectives, overview of micro
controller, data and analysis.
Sam Ellis Sonike Hendricks
________________________________ ________________________________
Eric Fish Michael Fredericks
________________________________ ________________________________
7/28/2019 Embedded Control Blimp Report Final Report
16/36
16
Source Code
Car Code Lab 5
#include// include files.#include#include#include
#define MOTOR_PW_MIN 2030 //2030 = 1.1 ms pulsewidth is min
// ( ( 1.1/20 ) * 36863 per pulse )#define MOTOR_PW_MAX 3500 //3500 = 1.9 ms pulsewidth is max// ( (1.9/20) * 36863 per pulse )
#define MOTOR_PW_NEUT 2760 //2760 = 1.5 ms pulsewidth is off
//----------------------------------------------------------------------------- // 8051 Initialization Functions//----------------------------------------------------------------------------- void Port_Init(void);void PCA_Init (void);void SMB_Init(void);void XBR0_Init(void);void Interrupt_Init(void);
void ADC_Init(void);void Drive_Motor(void); //controls the speed of vehiclevoid Start_Ping(); //start ping functionunsignedint ReadRanger(); //read ranger functionunsignedint getHeading(void); //read compassvoid steer(void); //control heading of vehiclechar read_key(void); //get LCD inputvoid pause(void); //wait 20 msunsignedchar read_AD_input(void); //read input from the voltagevoid get_tilt(void); //read the accelerometer
//-----------------------------------------------------------------------------
// Global Variables//----------------------------------------------------------------------------- unsignedint MOTOR_PW = 0; //initial motor power is 0unsignedint countsrange = 0; //used for general timingunsignedint range = 0; //int for storing data from ranger
unsignedint PCA_START_1 = 28672; //pca start for 20 ms pulsesignedint errorrange; //error in the current range
__sbit __at 0xB3 LED; //LED to see on/off__sbit __at 0xB6 SS; //Slide Switch for on/off
signedint avg_gx = 0; //x-axis accelerometersignedint avg_gy = 0; //y-axis accelerometer
signedint temp_gy = 0;unsignedchar countsheading = 0;unsignedchar Data_heading[4]; // Data_heading is an array with a length of 2unsignedint HEADING_PW_MIN = 2143; //limitsunsignedint HEADING_PW_MAX = 3173;unsignedint PW = 0;float k = .1; //gainchar keypad, keypad1, keypad2, keypad3; //used for inputsunsignedchar output;float voltage;int i = 0;
7/28/2019 Embedded Control Blimp Report Final Report
17/36
17
//----------------------------------------------------------------------------- // Main Function//----------------------------------------------------------------------------- void main(void){
// initialize all systemsSys_Init();putchar(' '); //the quotes in this line may not format correctly
Port_Init();XBR0_Init();PCA_Init();Interrupt_Init();SMB_Init();ADC_Init();Accel_Init();LED = 1;
//print beginning messageprintf("\r\nEmbedded Control Drive Motor Control\r\n");
//Enter gain, pauses used to avoid breaking keypad
lcd_clear();pause();lcd_print("Please enter a desired gain: ");
keypad1 = read_key(); //calls read key function to read inputkeypad2 = read_key();keypad3 = read_key();
k = 0;k += (keypad1-48)/10.0; //sets gain valuek += (keypad2-48)/100.0;k += (keypad3-48)/1000.0;
printf_fast_f("k: %4.2f\r\n", k);pause();
lcd_clear();pause();
//print gain values to LCD and SDClcd_print("%c%c%c", keypad1,keypad2,keypad3);printf("gain is %c%c%c \r\n",keypad1,keypad2,keypad3);
pause();
lcd_clear();
pause();
//set initial valueMOTOR_PW = MOTOR_PW_NEUT; //turn motor off
//set ititial heading valuescountsheading = 0;PW = 2725;PCA0CPL0 = 0xFFFF - PW; //initially set the wheels to go straight
PCA0CPH0 = (0xFFFF - PW) >> 8;
7/28/2019 Embedded Control Blimp Report Final Report
18/36
18
//add code to set the servo motor in neutral for one secondwhile(countsrange < 50 ){
MOTOR_PW = MOTOR_PW_NEUT;}
printf("Running\r\n");
while(1){
if(!SS) // if the slide switch is in the on position{
LED = 0;//read Ranger
if(!(countsrange % 4)){
printf("i am here \r\n");
steer(); //call steering function to get a headingand set the wheels properly
printf("The Range is: %u\r\n", range);
output = read_AD_input();//calculates the voltagevoltage = output/255.0;voltage *=30; //gain to adjust voltage value
if(countsrange > 20){
//print voltage gain and heading to LCDkeypad = (int)(voltage/10)+48;
//setup for printing to LCDkeypad1 = ((int)voltage%10)+48;keypad2 = ((int)(voltage*10)%10)+48;keypad3 = ((int)(voltage*100)%10)+48;lcd_clear();
lcd_print("Drive PW:%u", MOTOR_PW);lcd_print("\nSteer PW:%u", PW);lcd_print("\nVoltage: %c%c", keypad, keypad1);lcd_print(".%c%c", keypad2, keypad3 );lcd_print("\naccelX:%d", avg_gx);lcd_print(" accelY:%d", avg_gy);countsrange = 0;printf_fast_f("Voltage: %4.2f", voltage);
}}
}
elseif (SS) //if the slide switch is in the off position{LED = 1;MOTOR_PW = MOTOR_PW_NEUT;PCA0CPL2 = 0xFFFF - MOTOR_PW;PCA0CPH2 = (0xFFFF - MOTOR_PW) >> 8;while(countsrange < 100);printf("turn on the Slide Switch to run\r\n");output = read_AD_input();//same as above for voltagevoltage = output/255.0;voltage *=30;keypad = (int)(voltage/10)+48;
7/28/2019 Embedded Control Blimp Report Final Report
19/36
19
keypad1 = ((int)voltage%10)+48;keypad2 = ((int)(voltage*10)%10)+48;keypad3 = ((int)(voltage*100)%10)+48;lcd_clear();lcd_print("Voltage: %c%c", keypad, keypad1);lcd_print(".%c%c", keypad2, keypad3 );countsrange = 0;printf_fast_f("Voltage: %4.2f", voltage);
}
}
}
//----------------------------------------------------------------------------- // Drive_Motor//----------------------------------------------------------------------------- //// Vary the pulsewidth based on the user input to change the speed// of the drive motor.//
void Drive_Motor(){printf("drivemotor\r\n");if (avg_gx < 60 || avg_gx > 0xFE00) //if the car is tilting in the x direction{
avg_gx = 60 - avg_gx;MOTOR_PW = MOTOR_PW_NEUT + 6*(avg_gx);//function to control driveprintf("MOTOR_PW = %d\r\n", MOTOR_PW);if (MOTOR_PW > MOTOR_PW_MAX) //limits range of PW values
MOTOR_PW = MOTOR_PW_MAX;PCA0CPL2 = 0xFFFF - MOTOR_PW; //set CCM to the PW valuePCA0CPH2 = (0xFFFF - MOTOR_PW) >> 8;
}elseif (avg_gy > 50 || avg_gy < 20) //if the car is tilting in the y direction
{MOTOR_PW = MOTOR_PW_NEUT + (450); //function to control driveprintf("MOTOR_PW = %d\r\n", MOTOR_PW);PCA0CPL2 = 0xFFFF - MOTOR_PW;PCA0CPH2 = (0xFFFF - MOTOR_PW) >> 8;
}
else//if object is in desired range{
MOTOR_PW = MOTOR_PW_NEUT; //motor is not runningprintf("MOTOR_PW = %d\r\n", MOTOR_PW);PCA0CPL2 = 0xFFFF - MOTOR_PW;PCA0CPH2 = (0xFFFF - MOTOR_PW) >> 8;
}
}
//----------------------------------------------------------------------------- // Port_Init//----------------------------------------------------------------------------- //// Set up ports for input and output//
7/28/2019 Embedded Control Blimp Report Final Report
20/36
20
void Port_Init(){
P1MDOUT |= 0x05; ;//set output pin for CEX0, CEX2 in push-pull modeP1MDIN &= ~0x80;P1MDOUT &= ~0x80;P1 |= 0x80;P0MDOUT |= 0x03;
}
void ADC_Init(void)
{REF0CN = 0x03; //set Vref to internal ref voltageADC1CN = 0x80; //enable AD converter
}
unsignedchar read_AD_input(void){
AMX1SL = 7;ADC1CN = ADC1CN & ~0x20;ADC1CN = ADC1CN | 0x10;
while ((ADC1CN & 0x20) == 0x00); // while the conversion is not completed
return ADC1;}
//----------------------------------------------------------------------------- // Interrupt_Init//----------------------------------------------------------------------------- //// Set up ports for input and output//void Interrupt_Init(void){
// IE set via glogbal EA assignmentEA = 1; // enable global interrupts// EIE1
EIE1 |= 0x08; //enable PCA interrupt}
//----------------------------------------------------------------------------- // XBR0_Init//----------------------------------------------------------------------------- //// Set up the crossbar//void XBR0_Init(void){
XBR0 = 0x27; //configure crossbar with UART, SPI, SMBus, and CEX channels as// in worksheet
}
//----------------------------------------------------------------------------- // PCA_Init//----------------------------------------------------------------------------- //// Set up Programmable Counter Array//void PCA_Init(void){
// reference to the sample code in Example 4.5 -// Pulse Width Modulation implemented us-ing the PCA
7/28/2019 Embedded Control Blimp Report Final Report
21/36
21
// (Programmable Counter Array, p. 50 in Lab Manual.// Use a 16 bit counter with SYSCLK/12.PCA0MD = 0x81; //PCA interrupt enable with SYSCLK/12PCA0CPM0 = 0xC2; //CCM0 in 16-bit compare modePCA0CPM2 = 0xC2; //CCM2 in 16-bit compare modePCA0CN = 0x40; //Enable PCA counter
}
//----------------------------------------------------------------------------- // SMB_Init
//----------------------------------------------------------------------------- //// Set up SMBUS//
void SMB_Init(void){
SMB0CR = 0x93; //Set SCL to 100kHzENSMB = 1; //Enble SMBUS (Bit 6 of SMB0CN)
}
//-----------------------------------------------------------------------------
// PCA_ISR//----------------------------------------------------------------------------- //// Interrupt Service Routine for Programmable Counter Array Overflow Interrupt//void PCA_ISR ( void ) __interrupt 9{
// reference to the sample code in Example 4.5 -// Pulse Width Modulation implemented using the PCA// (Programmable Counter Array)if (CF){
CF = 0; //clear overflow flag
countsrange++; //increment wait countercountsheading ++; //reading counter
PCA0L = PCA_START_1; //low byte of start count, 20msPCA0H = PCA_START_1; //high byte of start count, 20, ms
}
PCA0CN &= 0xC0; //handle other PCA interrupt sources
}
unsignedint getHeading(void){ //get the acceleration data
i = 0;avg_gx = 0;avg_gy = 0;while(i < 8){ //need several headings to average
pause();get_tilt();i++;
}avg_gx = avg_gx/8;avg_gy = avg_gy/8;
printf("%u, %u\r\n", avg_gx, avg_gy); //print the accelerations
7/28/2019 Embedded Control Blimp Report Final Report
22/36
22
if(avg_gy > 50) //set the PW depending on acceleration{
PW = 2725 - 2*(avg_gy - 50);}elseif (avg_gy < 30 || avg_gy > 0xFE00){
temp_gy = 30-avg_gy;printf("%u\r\n\r\n", temp_gy);PW = 2725 + (3*temp_gy);printf("%u, %u, %u\r\n", PW, 2725, temp_gy);
}else
PW = 2725; //neutral PW
Drive_Motor(); //drive the motor after the acceleration data has beencalculated
return PW;}
void steer(void){
if(SS){ //if the slide switch is in the off positionPW = 2725; //set the wheels to centerPCA0CPL0 = 0xFFFF - PW;PCA0CPH0 = (0xFFFF - PW) >> 8;
printf("returning? \r\n");return; //then do nothing
}if(countsheading >= 3){ //otherwise make sure that there is a new compass reading
countsheading = 0;printf("getheading\r\n");PW = getHeading(); //get a new headingprintf("got heading %d\r\n", PW);
}printf("afterif \r\n");
if(PW < HEADING_PW_MIN) PW = HEADING_PW_MIN; //if it is less than the min limit,set it to the min limitif(PW > HEADING_PW_MAX) PW = HEADING_PW_MAX; //same with max limitPCA0CPL0 = 0xFFFF - PW; //output the desired PW
PCA0CPH0 = (0xFFFF - PW) >> 8;}
char read_key(void){
keypad = read_keypad();pause(); // This pauses for 1 PCA0 counter clock cycle (20ms)
//If the keypad is read too frequently, it will// lock up and stop responding. Must power down to reset.
while (keypad == -1){keypad = read_keypad();pause();
}
if (keypad != -1) // keypad = -1 if no key is pressed{ // Note: fast read results in multiple lines on terminal
// A longer delay will reduce multiple keypad reads but a// better approach is to wait for a -1 between keystrokes.
pause();while (read_keypad() != -1)
7/28/2019 Embedded Control Blimp Report Final Report
23/36
23
{pause();
}}
return keypad;}
void pause(void){
int n_counts = countsheading;
while (countsheading - n_counts < 1);// 1 count -> (65536-PCA_START) x 12/22118400 =20ms}
void get_tilt(void){ //i2c read function that gets the acceleration data fromthe accelerometer
i2c_read_data(0x30, 0x28|0x80, Data_heading, 4);avg_gx += ((Data_heading[1] > 4);avg_gy += ((Data_heading[3] > 4);
}
7/28/2019 Embedded Control Blimp Report Final Report
24/36
24
Gondola Code Lab 6
#include// include files.#include#include#include
//----------------------------------------------------------------------------- // 8051 Initialization Functions
//----------------------------------------------------------------------------- void Port_Init(void); //port initialization functionvoid PCA_Init (void); //initialize PCAvoid SMB_Init(void); //initialize system busvoid XBR0_Init(void); //set up the crossbarvoid Interrupt_Init(void); //set up interruptsvoid Input(void); //get input for gains and headingvoid Drive_Motor(void); //function for controlling 2 outside fansvoid Start_Ping(); //start ping functionunsignedint ReadRanger(); //read ranger functionunsignedint getHeading(void); //heading control functionvoid steer(void); //function for controlling back fanchar read_key(void); //reads inputs on the keypad
void pause(void); //wait 20 msvoid ADC_Init(void); //initializes voltage readunsignedchar read_AD_input(void);int PD_Calc(int desired, int actual, int previous); //calculate fan speedunsignedchar inputGains(void);void resetKeys(void); //reset char variables for sequential inputchar read_input(void); //get input from LCD keypad
//----------------------------------------------------------------------------- // Global Variables//----------------------------------------------------------------------------- unsignedint MOTOR_PW = 0; //initial motor power is 0unsignedint countsrange = 0; //used for general timingunsignedint r_count = 0; //ranger counter
unsignedchar new_range = 0; //flag for pinging for a new rangeunsignedint range = 0; //int for storing data from ranger
//unsigned int PCA_START_1 = 28672; //pca start for 20 ms pulsesignedint errorrange;
unsignedchar countsheading = 0;unsignedchar Data_heading[2]; // Data_heading is an array with a length of 2unsignedint heading; // the heading returned in degrees between 0 and 3599unsignedint PW = 0;unsignedint desiredHeading = 0; //set desired heading here (in this case E)signedint errorheading;unsignedchar kp; //gain for steering fan
unsignedchar kd; //derivative gain for steering fanunsignedchar kpd; //proportional gain for height fanunsignedchar kdd; //derivative gain for height fanchar keypad, keypad1, keypad2, keypad3;float voltage;
//----------------------------------------------------------------------------- // Main Function//----------------------------------------------------------------------------- void main(void){
// initialize board
7/28/2019 Embedded Control Blimp Report Final Report
25/36
25
Sys_Init();putchar(' '); //the quotes in this line may not format correctlyPort_Init();XBR0_Init();PCA_Init();Interrupt_Init();SMB_Init();ADC_Init();
PCA0CPL1 = 0xFFFF - 2750; //set thrust fan angle
PCA0CPH1 = (0xFFFF - 2750) >> 8; //set thrust fan angle
printf("rudders set\r\n");
//print beginning messageprintf("\r\nEmbedded Control Drive Motor Control\r\n");
Input(); //get inputs from keyboard
//add code to set the servo motor in neutral for one secondwhile(countsrange < 50 ){
MOTOR_PW = 2750;}
printf("Running\r\n");printf("Error Heading will be displayed after inputs\r\n");
while(1){
//read Rangerif (new_range == 1) //print range{
steer(); //call steering function to get a heading and set thefan properly
new_range = 0;range = ReadRanger();Drive_Motor();Start_Ping();//printf("The Range is: %u\r\n", range);keypad = read_AD_input();voltage = keypad/255.0;voltage *=27;
if(countsrange > 20){
//set the keypad for voltage displaykeypad = (int)(voltage/10)+48;
keypad1 = ((int)voltage%10)+48;keypad2 = ((int)(voltage*10)%10)+48;keypad3 = ((int)(voltage*100)%10)+48;countsrange = 0;
}}
}
}
7/28/2019 Embedded Control Blimp Report Final Report
26/36
26
//Input
void Input(){
//Enter gainslcd_clear();pause();lcd_print("Please enter a desired gain kp kd kpd kdd: ");printf("Please enter a desired gain kp kd kpd kdd: ");
desiredHeading = 0;
kp = inputGains();//reset to avoid overloading keypadpause();resetKeys();pause();
kd = inputGains();//reset to avoid overloading keypad
pause();resetKeys();pause();
kpd = inputGains();//reset to avoid overloading keypad
pause();resetKeys();pause();
kdd = inputGains();//reset to avoid overloading keypad
pause();resetKeys();pause();
//enter desired heading, pauses to avoid overloadpause();lcd_clear();pause();lcd_print("Please enter a desired heading in degrees: ");pause();pause();pause();
pause();keypad1 = getchar();pause();pause();
keypad2 = getchar();pause();pause();keypad3 = getchar();pause();
pause();pause();
printf("direction is %c%c%c \r\n",keypad1,keypad2,keypad3);
//calculate desired heading
7/28/2019 Embedded Control Blimp Report Final Report
27/36
27
desiredHeading += (keypad1-48)*100;desiredHeading += (keypad2-48)*10;desiredHeading += (keypad3-48)*1;
while (desiredHeading >= 3600) //set heading to useful value if user messes up{
desiredHeading -= 3600;}
pause();
lcd_clear();pause();pause();//print headingprintf("\r\n\n %d %d %d %d \r\nHeading:%d", kp, kd, kpd, kdd, desiredHeading);printf("Now printing error in Heading below\r\n");
lcd_print("Your heading is: %c%c%c ", keypad1, keypad2,keypad3);
//set initial valueMOTOR_PW = 2750; //neutral
//set ititial heading values
countsheading = 0;PW = 2750;PCA0CPL0 = 0xFFFF - PW; //set heading fan to neutral
PCA0CPH0 = (0xFFFF - PW) >> 8;PCA0CPL2 = 0xFFFF - 2750; //set thrust fans to neutralPCA0CPH2 = (0xFFFF - 2750) >> 8;PCA0CPL3 = 0xFFFF - 2750; //set thrust fans to neutralPCA0CPH3 = (0xFFFF - 2750) >> 8;
}
//----------------------------------------------------------------------------- // Drive_Motor//----------------------------------------------------------------------------- //
// Vary the pulsewidth based on the user input to change the speed// of the drive motor.//void Drive_Motor(){
if (range >= 55){
errorrange = 50 - range; //errorrange is the distance from thedesired distance
if (errorrange < -40) //if the object is too far away{
errorrange = -40; //cap the value of errorrange}
//if (MOTOR_PW > MOTOR_PW_MIN)MOTOR_PW = PD_Calc(50, range, errorrange); //function to controldrive
if (MOTOR_PW < 2500 || MOTOR_PW < -1) {MOTOR_PW = 2500;
}//set thrust fans to calculated PWPCA0CPL2 = 0xFFFF - MOTOR_PW;PCA0CPH2 = (0xFFFF - MOTOR_PW) >> 8;PCA0CPL3 = PCA0CPL2;PCA0CPH3 = PCA0CPH2;
}
7/28/2019 Embedded Control Blimp Report Final Report
28/36
28
elseif (range 30) //if the object is too close{
errorrange = 30; //cap the value of errorrange}//if (MOTOR_PW < MOTOR_PW_MIN)
MOTOR_PW = PD_Calc(50, range, errorrange); //function to controldrive
if (MOTOR_PW > 3000) {MOTOR_PW = 3000;
}PCA0CPL2 = 0xFFFF - MOTOR_PW;PCA0CPH2 = (0xFFFF - MOTOR_PW) >> 8;PCA0CPL3 = PCA0CPL2;PCA0CPH3 = PCA0CPH2;
}
else //if object is in desired range{
MOTOR_PW = 2750; //motor is not runningPCA0CPL2 = 0xFFFF - MOTOR_PW;PCA0CPH2 = (0xFFFF - MOTOR_PW) >> 8;PCA0CPL3 = 0xFFFF - MOTOR_PW;PCA0CPH3 = (0xFFFF - MOTOR_PW) >> 8;
}
}
//----------------------------------------------------------------------------- // ReadRanger//----------------------------------------------------------------------------- //
// Read the Ranging device every 80 ms// return a distance in cm (stored in an int)//
unsignedint ReadRanger() //read ranger function{
unsignedchar Data[2];unsignedint range = 0;unsignedchar addrrange = 0xE0; // the addrrangeess of the ranger is 0xE0
//read datai2c_read_data(addrrange, 0x02 , Data, 2); // read two bytes, starting at reg 2range = (((unsignedint)Data[0]
7/28/2019 Embedded Control Blimp Report Final Report
29/36
29
{
unsignedchar Data[1];unsignedint range = 0;unsignedchar addrrange = 0xE0; // the addrrangeess of the ranger is 0xE0
//Send ping (before reading?)Data[0] = 0x51 ; // write 0x51 to reg 0 of the ranger - ranging mode incentimeters:i2c_write_data(addrrange, 0x00, Data, 1) ; // write one byte of data to reg 0 at
addrrange}//----------------------------------------------------------------------------- // Port_Init//----------------------------------------------------------------------------- //// Set up ports for input and output//void Port_Init(){
P1MDOUT |= 0x0F; ;//set output pin for CEX0, CEX1, CEX2, CEX3 in push-pull modeP1MDIN &= ~0x20;P1MDOUT &= ~0x80;
P1 |= 0x20;P0MDOUT |= 0x03;}
void ADC_Init(void){
REF0CN = 0x03; //set Vref to internal ref voltageADC1CN = 0x80; //enable AD converter
}
unsignedchar read_AD_input(void){
AMX1SL = 5;ADC1CN = ADC1CN & ~0x20;
ADC1CN = ADC1CN | 0x10;
while ((ADC1CN & 0x20) == 0x00); //while conversion is not done, wait
return ADC1;}
//----------------------------------------------------------------------------- // Interrupt_Init//----------------------------------------------------------------------------- //// Set up ports for input and output//
void Interrupt_Init(void){// IE set via glogbal EA assignmentEA = 1; // enable global interrupts// EIE1EIE1 |= 0x08; //enable PCA interrupt
}
//----------------------------------------------------------------------------- // XBR0_Init//----------------------------------------------------------------------------- //
7/28/2019 Embedded Control Blimp Report Final Report
30/36
30
// Set up the crossbar//void XBR0_Init(void){
XBR0 = 0x27; //configure crossbar with UART, SPI, SMBus, and CEX channels as// in worksheet
}
//----------------------------------------------------------------------------- // PCA_Init
//----------------------------------------------------------------------------- //// Set up Programmable Counter Array//void PCA_Init(void){
// reference to the sample code in Example 4.5 -// Pulse Width Modulation implemented using the PCA// (Programmable Counter Array, p. 50 in Lab Manual.// Use a 16 bit counter with SYSCLK/12.PCA0MD = 0x81; //PCA interrupt enable with SYSCLK/12PCA0CPM0 = 0xC2; //CCM0 in 16-bit compare modePCA0CPM1 = 0xC2; //CCM1 in 16-bit compare mode
PCA0CPM2 = 0xC2; //CCM2 in 16-bit compare modePCA0CPM3 = 0xC2; //CCM3 in 16-bit compare modePCA0CN = 0x40; //Enable PCA counter
}
//----------------------------------------------------------------------------- // SMB_Init//----------------------------------------------------------------------------- //// Set up SMBUS//
void SMB_Init(void){
SMB0CR = 0x93; //Set SCL to 100kHzENSMB = 1; //Enble SMBUS (Bit 6 of SMB0CN)
}
//----------------------------------------------------------------------------- // PCA_ISR//----------------------------------------------------------------------------- //// Interrupt Service Routine for Programmable Counter Array Overflow Interrupt//void PCA_ISR ( void ) __interrupt 9{
// reference to the sample code in Example 4.5 -// Pulse Width Modulation implemented using the PCA// (Programmable Counter Array)if (CF){
CF = 0; //clear overflow flag
r_count++; //increment pulse countercountsrange++; //increment wait countercountsheading ++; //reading counter
PCA0L = 28672; //low byte of start count, 20ms
7/28/2019 Embedded Control Blimp Report Final Report
31/36
31
PCA0H = 28672; //high byte of start count, 20, ms
if (r_count >= 4) // 4 overflows is about 80 ms{
new_range = 1; //flag to get a new ranger_count = 0;
}
}
PCA0CN &= 0xC0; //handle other PCA interrupt sources
}
unsignedint getHeading(void){
Data_heading[0] = 0;Data_heading[1] = 0;i2c_read_data(0xC0, 0x02, Data_heading, 2); // read two byte, starting at reg 2//printf("Data[0] = %U\r\n", Data[0]);//printf("Data[1] = %U\r\n", Data[1]);heading =(((unsignedint)Data_heading[0] = 3){ //otherwise make sure that there is a new compass readingcountsheading = 0;heading = getHeading(); //get a new headingprintf("%d\r\n", heading);
}elsereturn; //if there is not a new heading do nothing
//printf("got heading %d\r\n", heading);PW = PD_Calc(desiredHeading, heading, errorheading); //calculate a new PW value//printf("PW errorheading %d\r\n", PW); //print it outif(PW < 2000) PW = 2000; //if it is less than the min limit, set it to the min
limitif(PW > 3500) PW = 3500; //same with max limit//printf("%u\r\n", PW);PCA0CPL0 = 0xFFFF - PW; //output the desired PW
PCA0CPH0 = (0xFFFF - PW) >> 8;MOTOR_PW = PW;
}
char read_key(void){char key = read_keypad();
pause(); // This pauses for 1 PCA0 counter clock cycle (20ms)// If the keypad is read too frequently (no delay), it will// lock up and stop responding. Must power down to reset.
while (key == -1){
key = read_keypad();pause();
}
7/28/2019 Embedded Control Blimp Report Final Report
32/36
32
if (key != -1) // keypad = -1 if no key is pressed{ // Note: fast read results in multiple lines on terminal
// A longer delay will reduce multiple keypad reads but a// better approach is to wait for a -1 between keystrokes.
pause();while (read_keypad() != -1){
pause();}
//lcd_clear();
//lcd_print("Your key was:\n %c, = Hex %X", keypad, keypad);//printf("\n\rYour key was: %c, = Hex %X", keypad, keypad);// printf("\r\nDec: %u", keypad);}
return key;}
int PD_Calc(int desired, int actual, int previous){
int temp_motorpw;if(previous == errorheading){ //if the readings are the same, recalculate
errorheadingerrorheading = desired - actual;
if(errorheading > 1800) errorheading -= 3600;if(errorheading < -1800) errorheading += 3600;//calculate motor pw using proportional and derivative controltemp_motorpw =
(long)2750+(long)kp*(long)errorheading+(long)kd*(long)(errorheading-previous);}
else{errorrange = desired - actual;//calculate motor pw using proportional and derivative controltemp_motorpw =
(long)(2750)+(long)kpd*(long)errorrange+(long)kdd*(long)(errorrange-previous);}
return temp_motorpw;}
unsignedchar inputGains(void){unsignedchar k = 0;
unsignedchar key1, key2, key3;//input gain from computerpause();key1 = getchar();pause();key2 = getchar();
pause();pause();key3 = getchar();pause();
k += (key3-48);k += (key2-48)* 10;k += (key1-48)* 100;
//print gain valuespause();lcd_print(" %c%c%c", (key1),(key2),(key3));
7/28/2019 Embedded Control Blimp Report Final Report
33/36
33
pause();printf("4");printf("k= %d",k);
return k;}
void resetKeys(void){//set all reset all characters to allow new information to be usedkeypad = 0;
keypad1 = 0;keypad2 = 0;keypad3 = 0;
}
void pause(void){
//wait for 1 ccountint n_counts = countsheading;
while (countsheading - n_counts < 1);// 1 count -> (65536-PCA_START) x 12/22118400 =20ms
}
\
7/28/2019 Embedded Control Blimp Report Final Report
34/36
34
Flowchart & Pseudocode
Figure 2 Flow Chart
7/28/2019 Embedded Control Blimp Report Final Report
35/36
35
Pseudo Code:
Globals and function prototypesMain
Initialize everything
Get a heading and k input from LCD/Keypad
Set initial PW of motor to neutral for 1 second
start while (1) loopif get a new heading
Call Steering function
Read ranger
Drive fan speed motor
Drive functions based off of ranger value
Start ping
Print the range value
port initializationsXBR0 initPCA init
set 16 bit compare module SYSCLK/12PCA ISR
count up to 40 ms to get new headingADC_Init
read_AD_inputdo an ADCheading function
address of sensordata arrayheadingread (address, start register, data array, number bytes)combine two data valuesreturn heading
steering function
if 40ms has passed
call heading function
print heading
calculate error
set PWM value //sets tail fan motor speed
7/28/2019 Embedded Control Blimp Report Final Report
36/36
Schematic
Car Schematic - Lab 5
Figure 3 La5 Schematic
Gondola Schematic Lab 6
Figure 4 La5 6chematic