Example software of using the mbed-rtos to control a simple vehicle's on board computer

Dependencies:   MCP23017 WattBob_TextLCD mbed-rtos mbed

Committer:
sk398
Date:
Thu Sep 01 09:08:51 2016 +0000
Revision:
10:95793013ef87
Parent:
9:c236eaaacf08
Final working version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sk398 7:f09208f9a4f7 1 /* #####################################################################
sk398 7:f09208f9a4f7 2 main.cpp
sk398 7:f09208f9a4f7 3 ---------
sk398 7:f09208f9a4f7 4
sk398 7:f09208f9a4f7 5 Embedded Software - Assignment 3
sk398 7:f09208f9a4f7 6 --------------------------------
sk398 7:f09208f9a4f7 7
sk398 7:f09208f9a4f7 8 Written by: Steven Kay
sk398 7:f09208f9a4f7 9
sk398 7:f09208f9a4f7 10 Date: March 2016
sk398 7:f09208f9a4f7 11
sk398 9:c236eaaacf08 12 Function: This code operates to simulate the operation of a Car's
sk398 9:c236eaaacf08 13 control system. It does so by taking external input for
sk398 9:c236eaaacf08 14 elements of a Car; Light Indicators, Engine State and Pedal values
sk398 9:c236eaaacf08 15 and using a simple Car Simulation model, derives a speed
sk398 9:c236eaaacf08 16 from which several tasks are included to act upon.
sk398 9:c236eaaacf08 17 An average speed is generated at a given frequency
sk398 9:c236eaaacf08 18 and a total distance is estimated using this average speed.
sk398 9:c236eaaacf08 19 Output comes in the form of LED's when specific indicators
sk398 9:c236eaaacf08 20 are true, and on a LCD screen and Servo Wiper to indicate speed.
sk398 9:c236eaaacf08 21 Furthermore, a PC Connection is established and a data dump of
sk398 9:c236eaaacf08 22 current Accelerometer, Brake and Average speed is presented
sk398 9:c236eaaacf08 23 to the user every 20 seconds.
sk398 9:c236eaaacf08 24
sk398 9:c236eaaacf08 25 This system is constructed using the MBED-RTOS and
sk398 9:c236eaaacf08 26 as such, each Task has an associated frequency, found in main, below.
sk398 9:c236eaaacf08 27 Note that no priority is given to the tasks and no
sk398 9:c236eaaacf08 28 extra scheduler controls the synchronisation of tasks,
sk398 7:f09208f9a4f7 29
sk398 7:f09208f9a4f7 30 ##################################################################### */
sk398 7:f09208f9a4f7 31
sk398 0:f7d6ed1dfe3e 32 #include "mbed.h"
sk398 0:f7d6ed1dfe3e 33 #include "rtos.h"
sk398 4:b4bcb329a930 34 #include "MCP23017.h"
sk398 4:b4bcb329a930 35 #include "WattBob_TextLCD.h"
sk398 4:b4bcb329a930 36
sk398 7:f09208f9a4f7 37 // ============================================================================
sk398 7:f09208f9a4f7 38 // Define Statements
sk398 7:f09208f9a4f7 39 // ============================================================================
sk398 8:6fad4bd89240 40
sk398 8:6fad4bd89240 41 // LCD Definitions
sk398 4:b4bcb329a930 42 #define BACK_LIGHT_ON(INTERFACE) INTERFACE->write_bit(1,BL_BIT)
sk398 4:b4bcb329a930 43 #define BACK_LIGHT_OFF(INTERFACE) INTERFACE->write_bit(0,BL_BIT)
sk398 4:b4bcb329a930 44
sk398 8:6fad4bd89240 45 // General Logical Assignments
sk398 2:13a9394ba2e0 46 #define HIGH 1
sk398 2:13a9394ba2e0 47 #define LOW 0
sk398 2:13a9394ba2e0 48
sk398 8:6fad4bd89240 49 // Car Sim, Maximum Car Speed (mph)
sk398 8:6fad4bd89240 50 #define MAX_SPEED 100
sk398 8:6fad4bd89240 51
sk398 2:13a9394ba2e0 52 // ============================================================================
sk398 2:13a9394ba2e0 53 // MBED Pin Assignments
sk398 2:13a9394ba2e0 54 // ============================================================================
sk398 7:f09208f9a4f7 55
sk398 7:f09208f9a4f7 56 // System Inputs
sk398 8:6fad4bd89240 57 // ----------------------------------------------------------------------------
sk398 8:6fad4bd89240 58
sk398 8:6fad4bd89240 59 // Analog Channels
sk398 7:f09208f9a4f7 60 AnalogIn Brake(p19); // Brake Pedal
sk398 7:f09208f9a4f7 61 AnalogIn Accelerometer(p20); // Accelerator Pedal
sk398 0:f7d6ed1dfe3e 62
sk398 8:6fad4bd89240 63 // Digitial Channels
sk398 7:f09208f9a4f7 64 DigitalIn EngineState(p18); // Engine State Switch
sk398 7:f09208f9a4f7 65 DigitalIn LeftIndicator(p17); // Left Indicator Switch
sk398 7:f09208f9a4f7 66 DigitalIn RightIndicator(p16); // Right Indicator Switch
sk398 7:f09208f9a4f7 67 DigitalIn SideLightIndicator(p15); // Side Light Indicator
sk398 7:f09208f9a4f7 68
sk398 1:cdf851858518 69
sk398 7:f09208f9a4f7 70 // System Outputs
sk398 8:6fad4bd89240 71 // ----------------------------------------------------------------------------
sk398 8:6fad4bd89240 72
sk398 8:6fad4bd89240 73 // LED Indicators (Steady State)
sk398 7:f09208f9a4f7 74 DigitalOut EngineStateInd(LED1); // Engine State LED
sk398 7:f09208f9a4f7 75 DigitalOut SideLightInd(LED2); // Side Light LED
sk398 1:cdf851858518 76
sk398 8:6fad4bd89240 77 // LED Indicators (Flashing)
sk398 7:f09208f9a4f7 78 PwmOut LeftLightInd(LED3); // Left Indicator LED
sk398 7:f09208f9a4f7 79 PwmOut RightLightInd(LED4); // Right Indicator LED
sk398 7:f09208f9a4f7 80 PwmOut OverSpeedInd(p22); // OverSpeed LED
sk398 2:13a9394ba2e0 81
sk398 8:6fad4bd89240 82 // Servo Output
sk398 7:f09208f9a4f7 83 PwmOut AvSpeedWiper(p21); // Average Speed Wiper
sk398 2:13a9394ba2e0 84
sk398 8:6fad4bd89240 85 // USB Connection to PC
sk398 7:f09208f9a4f7 86 Serial PCConn(USBTX,USBRX); // Connection to PC
sk398 4:b4bcb329a930 87
sk398 8:6fad4bd89240 88 // LCD Objects
sk398 7:f09208f9a4f7 89 MCP23017 *par_port; // Object pointing to Expander
sk398 7:f09208f9a4f7 90 WattBob_TextLCD *lcd; // LCD Connection
sk398 4:b4bcb329a930 91
sk398 2:13a9394ba2e0 92 // ============================================================================
sk398 2:13a9394ba2e0 93 // Global Data Structure Declerations
sk398 2:13a9394ba2e0 94 // ============================================================================
sk398 7:f09208f9a4f7 95
sk398 8:6fad4bd89240 96 // Raw Data Structure
sk398 8:6fad4bd89240 97 // ----------------------------------------------------------------------------
sk398 9:c236eaaacf08 98
sk398 9:c236eaaacf08 99 // CarRawData is a global memory area and contaims an instance of the Raw data
sk398 9:c236eaaacf08 100 // populated by Task1 and can be accessed through locking Mutex - rawDataMutex
sk398 2:13a9394ba2e0 101 typedef struct
sk398 2:13a9394ba2e0 102 {
sk398 2:13a9394ba2e0 103 bool EngineState;
sk398 2:13a9394ba2e0 104 float RawAccelerometer;
sk398 2:13a9394ba2e0 105 float RawBraking;
sk398 8:6fad4bd89240 106 } CarRawData;
sk398 2:13a9394ba2e0 107
sk398 9:c236eaaacf08 108 // Create Mutex to control access to CarRawData instance
sk398 8:6fad4bd89240 109 Mutex rawDataMutex;
sk398 9:c236eaaacf08 110
sk398 9:c236eaaacf08 111 // Create Instance of CarRawData
sk398 8:6fad4bd89240 112 CarRawData rawData;
sk398 2:13a9394ba2e0 113
sk398 8:6fad4bd89240 114 // Speed Data Structure
sk398 8:6fad4bd89240 115 // ----------------------------------------------------------------------------
sk398 9:c236eaaacf08 116
sk398 9:c236eaaacf08 117 // CarSpeedData is a global memory area and contains an instance of the calculated
sk398 9:c236eaaacf08 118 // raw speed values and the index to the next available element in the array to be
sk398 9:c236eaaacf08 119 // written to. rawSpeed is calculated by the CarSim and can be accessed through
sk398 9:c236eaaacf08 120 // locking Mutex - SpeedMutex
sk398 2:13a9394ba2e0 121 typedef struct
sk398 2:13a9394ba2e0 122 {
sk398 5:4f2a072ed289 123 float rawSpeed[3];
sk398 5:4f2a072ed289 124 int counter;
sk398 8:6fad4bd89240 125 } CarSpeedData;
sk398 4:b4bcb329a930 126
sk398 9:c236eaaacf08 127 // Create Mutex to control access to CarSpeedData instance
sk398 9:c236eaaacf08 128 Mutex SpeedMutex;
sk398 8:6fad4bd89240 129
sk398 9:c236eaaacf08 130 // Create instance of CarSpeedData
sk398 8:6fad4bd89240 131 CarSpeedData speedData;
sk398 2:13a9394ba2e0 132
sk398 8:6fad4bd89240 133 // Filtered Data Structure
sk398 8:6fad4bd89240 134 // ----------------------------------------------------------------------------
sk398 2:13a9394ba2e0 135
sk398 9:c236eaaacf08 136 float AverageSpeed;
sk398 9:c236eaaacf08 137 float totalDistance;
sk398 2:13a9394ba2e0 138
sk398 9:c236eaaacf08 139 // Create Mutex to control access to FilteredData
sk398 9:c236eaaacf08 140 Mutex filteredDataMutex;
sk398 4:b4bcb329a930 141
sk398 8:6fad4bd89240 142 // Mail Queue Structure
sk398 8:6fad4bd89240 143 // ----------------------------------------------------------------------------
sk398 9:c236eaaacf08 144
sk398 9:c236eaaacf08 145 // PCDumpData is a global memory area which is populated by Taak7 and used as
sk398 9:c236eaaacf08 146 // the structure within a MailQueue. Data contained is a copy from the current
sk398 9:c236eaaacf08 147 // state of the Control System at a given instance of time.
sk398 7:f09208f9a4f7 148 typedef struct
sk398 7:f09208f9a4f7 149 {
sk398 7:f09208f9a4f7 150 float currentAverageSpeed;
sk398 7:f09208f9a4f7 151 float currentAccelerometer;
sk398 7:f09208f9a4f7 152 float currentBraking;
sk398 9:c236eaaacf08 153 } PCDumpData;
sk398 9:c236eaaacf08 154
sk398 9:c236eaaacf08 155 // Construct a 100 Element Mail Queue structure
sk398 9:c236eaaacf08 156 Mail<PCDumpData,100> Memory_Dump;
sk398 7:f09208f9a4f7 157
sk398 9:c236eaaacf08 158 // Define a Counter to trakc number of entries to Mail Queue
sk398 9:c236eaaacf08 159 int MailQueueCounter;
sk398 7:f09208f9a4f7 160
sk398 9:c236eaaacf08 161 // Create Mutex to control access to the MailQueueCounter variable
sk398 7:f09208f9a4f7 162 Mutex MailMutex;
sk398 7:f09208f9a4f7 163
sk398 8:6fad4bd89240 164
sk398 2:13a9394ba2e0 165 // ============================================================================
sk398 2:13a9394ba2e0 166 // Car Simulation
sk398 2:13a9394ba2e0 167 // ============================================================================
sk398 2:13a9394ba2e0 168
sk398 9:c236eaaacf08 169 // The CarSimulator Task updates the rawSpeed parameter at a frequenct of 20Hz
sk398 2:13a9394ba2e0 170 void CarSimulator(void const *arg)
sk398 2:13a9394ba2e0 171 {
sk398 5:4f2a072ed289 172 float newSpeed;
sk398 5:4f2a072ed289 173
sk398 9:c236eaaacf08 174 // Load Shared resources into local variables within the Task
sk398 9:c236eaaacf08 175 // Shared Resources are; Accelerometer value, Braking value and Engine State
sk398 8:6fad4bd89240 176 rawDataMutex.lock();
sk398 8:6fad4bd89240 177 float currentAccelerometer = rawData.RawAccelerometer;
sk398 8:6fad4bd89240 178 float currentBrake = rawData.RawBraking;
sk398 8:6fad4bd89240 179 bool currentEngineState = rawData.EngineState;
sk398 8:6fad4bd89240 180 rawDataMutex.unlock();
sk398 5:4f2a072ed289 181
sk398 9:c236eaaacf08 182 // Run simple model which estimates the speed, as a fraction of the MAX SPEED
sk398 9:c236eaaacf08 183 // based on the percentage of either accelerator or brake pressed by the user
sk398 9:c236eaaacf08 184 // Further, newSpeed is set to 0 if the currentEngineState is equal to 0 (Engine off)
sk398 5:4f2a072ed289 185 newSpeed = currentAccelerometer*MAX_SPEED*(1-currentBrake)*currentEngineState;
sk398 2:13a9394ba2e0 186
sk398 9:c236eaaacf08 187 // Check Speed Counter's range, if out of bounds of array length, reset Counter
sk398 9:c236eaaacf08 188 // to 0
sk398 9:c236eaaacf08 189 // Data contained within Shared Resource therefore the SpeedMutex is used to control access
sk398 5:4f2a072ed289 190 SpeedMutex.lock();
sk398 8:6fad4bd89240 191 if(speedData.counter > 2)
sk398 2:13a9394ba2e0 192 {
sk398 8:6fad4bd89240 193 speedData.counter = 0;
sk398 4:b4bcb329a930 194 }
sk398 4:b4bcb329a930 195
sk398 9:c236eaaacf08 196 // Output a rawSpeed value to the next available index of rawSpeed[] and increment Counter
sk398 8:6fad4bd89240 197 speedData.rawSpeed[speedData.counter] = newSpeed;
sk398 9:c236eaaacf08 198 speedData.counter = speedData.counter++;
sk398 5:4f2a072ed289 199 SpeedMutex.unlock();
sk398 2:13a9394ba2e0 200 }
sk398 2:13a9394ba2e0 201
sk398 2:13a9394ba2e0 202 // ============================================================================
sk398 2:13a9394ba2e0 203 // Control System Tasks
sk398 2:13a9394ba2e0 204 // ============================================================================
sk398 2:13a9394ba2e0 205
sk398 9:c236eaaacf08 206 // Task1_ReadRawData gathers external inputs and updates the rawData structure
sk398 9:c236eaaacf08 207 // It operates at a frequency of 10Hz
sk398 2:13a9394ba2e0 208 void Task1_ReadRawData(void const *arg)
sk398 2:13a9394ba2e0 209 {
sk398 9:c236eaaacf08 210 // Lock Shared Resource - rawData
sk398 9:c236eaaacf08 211 // Update rawData elements directly from AnalogIn channel values
sk398 9:c236eaaacf08 212 // Unlock Shares Resource
sk398 8:6fad4bd89240 213 rawDataMutex.lock();
sk398 8:6fad4bd89240 214 rawData.RawBraking = Brake.read();
sk398 8:6fad4bd89240 215 rawData.RawAccelerometer = Accelerometer.read();
sk398 8:6fad4bd89240 216 rawDataMutex.unlock();
sk398 2:13a9394ba2e0 217 }
sk398 2:13a9394ba2e0 218
sk398 2:13a9394ba2e0 219
sk398 9:c236eaaacf08 220 // Task2_ReadEngineState updates the rawData structure and operates ar a frequency of 2Hz
sk398 2:13a9394ba2e0 221 void Task2_ReadEngineState(void const *arg)
sk398 2:13a9394ba2e0 222 {
sk398 9:c236eaaacf08 223 // Get external input from DigitalIn Channel and store in local variable
sk398 4:b4bcb329a930 224 bool currentEngineState = EngineState.read();
sk398 9:c236eaaacf08 225
sk398 9:c236eaaacf08 226 // Lock Shared Resource - rawData
sk398 9:c236eaaacf08 227 // Take a copy of the local variable currentEngineState and store into Global memory
sk398 9:c236eaaacf08 228 // Unlock Shared Resource
sk398 8:6fad4bd89240 229 rawDataMutex.lock();
sk398 8:6fad4bd89240 230 rawData.EngineState = currentEngineState;
sk398 8:6fad4bd89240 231 rawDataMutex.unlock();
sk398 2:13a9394ba2e0 232
sk398 9:c236eaaacf08 233 // Conduct logical check on local varialbe currentEngineState
sk398 9:c236eaaacf08 234 // if currentEngineState is HIGH, set EngineStateInd to HIGH
sk398 9:c236eaaacf08 235 // else set EngineStateInd LOW
sk398 2:13a9394ba2e0 236 if(currentEngineState)
sk398 2:13a9394ba2e0 237 {
sk398 2:13a9394ba2e0 238 EngineStateInd = HIGH;
sk398 2:13a9394ba2e0 239 }
sk398 2:13a9394ba2e0 240 else
sk398 2:13a9394ba2e0 241 {
sk398 2:13a9394ba2e0 242 EngineStateInd = LOW;
sk398 2:13a9394ba2e0 243 }
sk398 2:13a9394ba2e0 244 }
sk398 5:4f2a072ed289 245
sk398 5:4f2a072ed289 246
sk398 9:c236eaaacf08 247 // Task3_CalcAvSpeed updates the AverageSpeed global varialbe and operates at a frequency of 5Hz
sk398 4:b4bcb329a930 248 void Task3_CalcAvSpeed(void const *arg)
sk398 4:b4bcb329a930 249 {
sk398 9:c236eaaacf08 250 // Initialise local variable as 0.0
sk398 4:b4bcb329a930 251 float speedTotal = 0.0;
sk398 5:4f2a072ed289 252
sk398 9:c236eaaacf08 253 // Lock Shared Resource - speedData
sk398 9:c236eaaacf08 254 // Calculate total from array of rawSpeed values and store locally
sk398 9:c236eaaacf08 255 // Unlock Shared Resource
sk398 9:c236eaaacf08 256 SpeedMutex.lock();
sk398 4:b4bcb329a930 257 for(int num = 0; num < 3; num++)
sk398 4:b4bcb329a930 258 {
sk398 8:6fad4bd89240 259 speedTotal = speedTotal + speedData.rawSpeed[num];
sk398 4:b4bcb329a930 260 }
sk398 9:c236eaaacf08 261 SpeedMutex.unlock();
sk398 2:13a9394ba2e0 262
sk398 9:c236eaaacf08 263 // Lock Shared Resource - AverageSpeed
sk398 9:c236eaaacf08 264 // Calculate average from local variable speedTotal and store result Globally into AverageSpeed
sk398 9:c236eaaacf08 265 // Unlock Shared Resource
sk398 9:c236eaaacf08 266 filteredDataMutex.lock();
sk398 9:c236eaaacf08 267 AverageSpeed = (speedTotal/3);
sk398 9:c236eaaacf08 268 filteredDataMutex.unlock();
sk398 4:b4bcb329a930 269 }
sk398 4:b4bcb329a930 270
sk398 5:4f2a072ed289 271
sk398 9:c236eaaacf08 272 // Task4_UpdateRCWiper takes the AverageSpeed global variable at a given time and outputs
sk398 9:c236eaaacf08 273 // a representation of this through a Servo. It operates at a frequenct of 1Hz
sk398 4:b4bcb329a930 274 void Task4_UpdateRCWiper(void const *arg)
sk398 2:13a9394ba2e0 275 {
sk398 9:c236eaaacf08 276 // Lock Shared Resource - AverageSpeed
sk398 9:c236eaaacf08 277 // Take local copy of AverageSpeed
sk398 9:c236eaaacf08 278 // Unlock Shared Resource
sk398 9:c236eaaacf08 279 filteredDataMutex.lock();
sk398 9:c236eaaacf08 280 float currentAverageSpeed = AverageSpeed;
sk398 9:c236eaaacf08 281 filteredDataMutex.unlock();
sk398 2:13a9394ba2e0 282
sk398 9:c236eaaacf08 283 // Update Servo Position based upon the local copy of AverageSpeed
sk398 9:c236eaaacf08 284
sk398 9:c236eaaacf08 285 // Servo must be controlled in the range of 1000us to 2000us
sk398 9:c236eaaacf08 286 // Thus a base value of 1000 is included, and as currentAverageSpeed cannot exceed 100,
sk398 9:c236eaaacf08 287 // This is simply scaled by 10, to give a maximum of 2000, which allows Servo to operate
sk398 9:c236eaaacf08 288 // Over full operational range
sk398 5:4f2a072ed289 289 AvSpeedWiper.pulsewidth_us(1000+(10*currentAverageSpeed));
sk398 2:13a9394ba2e0 290 }
sk398 2:13a9394ba2e0 291
sk398 0:f7d6ed1dfe3e 292
sk398 9:c236eaaacf08 293 // Task5_OverspeedLED takes the 0th Element of the rawSpeed global variable and computes
sk398 9:c236eaaacf08 294 // a logical assessment to detect when the speed is greater than a preset of 70mph and
sk398 9:c236eaaacf08 295 // indicate results through an LED. It operates at a frequency of 0.5Hz
sk398 4:b4bcb329a930 296 void Task5_OverspeedLED(void const *arg)
sk398 0:f7d6ed1dfe3e 297 {
sk398 9:c236eaaacf08 298 // Lock Shared Resource - speedData
sk398 9:c236eaaacf08 299 // Take local copy of rawSpeed[0]
sk398 9:c236eaaacf08 300 // // Unlock Shares Resource
sk398 5:4f2a072ed289 301 SpeedMutex.lock();
sk398 8:6fad4bd89240 302 float currentInstSpeed = speedData.rawSpeed[speedData.counter];
sk398 5:4f2a072ed289 303 SpeedMutex.unlock();
sk398 4:b4bcb329a930 304
sk398 9:c236eaaacf08 305 // Using local copy of rawSpeed[0], if this is above preset threshold of 70,
sk398 9:c236eaaacf08 306 // OverSpeedInd is set HIGH, else it is set LOW
sk398 4:b4bcb329a930 307 if(currentInstSpeed > 70.0)
sk398 4:b4bcb329a930 308 {
sk398 4:b4bcb329a930 309 OverSpeedInd = HIGH;
sk398 1:cdf851858518 310 }
sk398 1:cdf851858518 311 else
sk398 1:cdf851858518 312 {
sk398 4:b4bcb329a930 313 OverSpeedInd = LOW;
sk398 4:b4bcb329a930 314 }
sk398 4:b4bcb329a930 315 }
sk398 4:b4bcb329a930 316
sk398 4:b4bcb329a930 317
sk398 9:c236eaaacf08 318 // Task6_UpdateOdometer takes the AverageSpeed global variable and calculates the
sk398 9:c236eaaacf08 319 // distance travelled by the Car over a known time increment (the delta of time between this task being ran)
sk398 9:c236eaaacf08 320 // Once calculated, the distance is stored globally and also, in conjunction with AverageSpeed, displayed onto
sk398 9:c236eaaacf08 321 // a LCD screen. It operates at a frequency of 2Hz
sk398 5:4f2a072ed289 322 void Task6_UpdateOdometer(void const *arg)
sk398 6:572b9755f2c1 323 {
sk398 9:c236eaaacf08 324 // Lock Shared Varialbe - AverageSpeed
sk398 9:c236eaaacf08 325 // Take local copy of AverageSpeed
sk398 9:c236eaaacf08 326 // Unlock Shared Variable
sk398 9:c236eaaacf08 327 filteredDataMutex.lock();
sk398 9:c236eaaacf08 328 float currentAverageSpeed = AverageSpeed;
sk398 9:c236eaaacf08 329 filteredDataMutex.unlock();
sk398 5:4f2a072ed289 330
sk398 9:c236eaaacf08 331 // Compute newTotalDistance from current TotalDistance and average speed
sk398 9:c236eaaacf08 332
sk398 9:c236eaaacf08 333 // distance = oldDistance +(currentAverageSpeed*timeIncrement)
sk398 9:c236eaaacf08 334 // Note that timeIncrement (0.5 second) is converted from seconds to hours,
sk398 9:c236eaaacf08 335 // To remain consistant with mph units
sk398 9:c236eaaacf08 336
sk398 9:c236eaaacf08 337 // NOTE
sk398 9:c236eaaacf08 338 // totalDistance does not need to be protected by a Mutex as this is the only task which updates
sk398 9:c236eaaacf08 339 // or uses the variable. It is global in order to keep track of a rolling total
sk398 6:572b9755f2c1 340 totalDistance = totalDistance + (currentAverageSpeed*(0.5/3600));
sk398 6:572b9755f2c1 341
sk398 9:c236eaaacf08 342 // Output totalDistance and currentAverageSpeed to LCD
sk398 5:4f2a072ed289 343 lcd -> cls();
sk398 5:4f2a072ed289 344 lcd -> locate(0,0);
sk398 5:4f2a072ed289 345 lcd -> printf("Dist: %8.2f",totalDistance);
sk398 5:4f2a072ed289 346 lcd -> locate(1,0);
sk398 5:4f2a072ed289 347 lcd -> printf("Speed: %3.1f mph",currentAverageSpeed);
sk398 5:4f2a072ed289 348 }
sk398 5:4f2a072ed289 349
sk398 5:4f2a072ed289 350
sk398 9:c236eaaacf08 351 // Task7_SendToMailQueue takes global variables; AverageSpeed, RawAccelerometer and RawBraking and
sk398 9:c236eaaacf08 352 // creates a structure from them, then puts an instanc of this structure onto a Mail Queue, incrementing
sk398 9:c236eaaacf08 353 // a globally defined Counter as it does such. It operates with a frequency of 0.2Hz
sk398 5:4f2a072ed289 354 void Task7_SendToMailQueue(void const *arg)
sk398 5:4f2a072ed289 355 {
sk398 9:c236eaaacf08 356 // Lock Shared Resource - AverageSpeed
sk398 9:c236eaaacf08 357 // Take local copy of AverageSpeed
sk398 9:c236eaaacf08 358 // Unlock Shared Resource
sk398 9:c236eaaacf08 359 filteredDataMutex.lock();
sk398 9:c236eaaacf08 360 float currentAverageSpeed = AverageSpeed;
sk398 9:c236eaaacf08 361 filteredDataMutex.unlock();
sk398 5:4f2a072ed289 362
sk398 9:c236eaaacf08 363 // Lock Shared Resource - rawData
sk398 9:c236eaaacf08 364 // Take local copy of RawAccelerometer and RawBraking
sk398 9:c236eaaacf08 365 // Unlock Shared Resource
sk398 8:6fad4bd89240 366 rawDataMutex.lock();
sk398 8:6fad4bd89240 367 float currentAccelerometer = rawData.RawAccelerometer;
sk398 8:6fad4bd89240 368 float currentBrake = rawData.RawBraking;
sk398 8:6fad4bd89240 369 rawDataMutex.unlock();
sk398 5:4f2a072ed289 370
sk398 9:c236eaaacf08 371 // Allocate Memory for instance of PCDumpData structure
sk398 9:c236eaaacf08 372 PCDumpData *currentPCDump = Memory_Dump.alloc();
sk398 9:c236eaaacf08 373
sk398 9:c236eaaacf08 374 // Populate instance of PCDumpData with local copies of desired variables
sk398 7:f09208f9a4f7 375 currentPCDump -> currentAverageSpeed = currentAverageSpeed;
sk398 7:f09208f9a4f7 376 currentPCDump -> currentAccelerometer = currentAccelerometer;
sk398 7:f09208f9a4f7 377 currentPCDump -> currentBraking = currentBrake;
sk398 7:f09208f9a4f7 378
sk398 9:c236eaaacf08 379 // Push instance of PCDumpData onto Mail Queue
sk398 7:f09208f9a4f7 380 Memory_Dump.put(currentPCDump);
sk398 7:f09208f9a4f7 381
sk398 9:c236eaaacf08 382 // Lock Shared Resource - MailQueueCounter
sk398 9:c236eaaacf08 383 // Increment MailQueueCounter
sk398 9:c236eaaacf08 384 // Unlock Shared Resource
sk398 7:f09208f9a4f7 385 MailMutex.lock();
sk398 7:f09208f9a4f7 386 MailQueueCounter++;
sk398 7:f09208f9a4f7 387 MailMutex.unlock();
sk398 5:4f2a072ed289 388 }
sk398 5:4f2a072ed289 389
sk398 5:4f2a072ed289 390
sk398 9:c236eaaacf08 391 // Task8_DumpSerial takes all of the instances of PCDumpData which have been pushed onto the Mail Queue
sk398 9:c236eaaacf08 392 // removes them from the Mail Queue and dumps their values over a PC serial connection. Once complete, the
sk398 9:c236eaaacf08 393 // counter which stores the number of elements in the Mail Queue is reset to 0. It operates at a frequency of 0.05Hz
sk398 5:4f2a072ed289 394 void Task8_DumpSerial(void const *arg)
sk398 5:4f2a072ed289 395 {
sk398 9:c236eaaacf08 396 // Lock Shared Resource - MailQueueCounter
sk398 9:c236eaaacf08 397 // Take local copy of MailQueueCounter
sk398 9:c236eaaacf08 398 // Unlock Shared Resource
sk398 7:f09208f9a4f7 399 MailMutex.lock();
sk398 7:f09208f9a4f7 400 int currentQueueCounter = MailQueueCounter;
sk398 7:f09208f9a4f7 401 MailMutex.unlock();
sk398 5:4f2a072ed289 402
sk398 9:c236eaaacf08 403 // Prompt State of Memory Dump
sk398 7:f09208f9a4f7 404 PCConn.printf("Memory Dump\r\n");
sk398 5:4f2a072ed289 405
sk398 9:c236eaaacf08 406 // For each instance of PCDumpData found in the Mail Queue, import the structure and store locally
sk398 9:c236eaaacf08 407 // Then print the contained values and free the element of the Mail Queue
sk398 9:c236eaaacf08 408 // Repeat for all indexes of the Mail Queue
sk398 7:f09208f9a4f7 409 for(int num = 0; num < currentQueueCounter; num++)
sk398 7:f09208f9a4f7 410 {
sk398 7:f09208f9a4f7 411 osEvent evt = Memory_Dump.get();
sk398 7:f09208f9a4f7 412 if(evt.status == osEventMail)
sk398 7:f09208f9a4f7 413 {
sk398 9:c236eaaacf08 414 PCDumpData *currentPCDump = (PCDumpData*)evt.value.p;
sk398 7:f09208f9a4f7 415
sk398 7:f09208f9a4f7 416 PCConn.printf("Av Speed: %f\r\nAcceler: %f\r\nBrake: %f\r\n\r\n", currentPCDump -> currentAverageSpeed,
sk398 7:f09208f9a4f7 417 currentPCDump -> currentAccelerometer,
sk398 7:f09208f9a4f7 418 currentPCDump -> currentBraking);
sk398 7:f09208f9a4f7 419 Memory_Dump.free(currentPCDump);
sk398 7:f09208f9a4f7 420 }
sk398 7:f09208f9a4f7 421 }
sk398 7:f09208f9a4f7 422
sk398 9:c236eaaacf08 423 // Lock Shared Resource - MailQueueCounter
sk398 9:c236eaaacf08 424 // Reset MailQueueCounter
sk398 9:c236eaaacf08 425 // Unlock Shared Resource
sk398 7:f09208f9a4f7 426 MailMutex.lock();
sk398 7:f09208f9a4f7 427 MailQueueCounter = 0;
sk398 7:f09208f9a4f7 428 MailMutex.unlock();
sk398 5:4f2a072ed289 429 }
sk398 5:4f2a072ed289 430
sk398 5:4f2a072ed289 431
sk398 9:c236eaaacf08 432 // Task9_ReadSideLight takes external input from SideLightIndicator and conducts a logical test.
sk398 9:c236eaaacf08 433 // It operates at a frequency of 1Hz
sk398 4:b4bcb329a930 434 void Task9_ReadSideLight(void const *arg)
sk398 4:b4bcb329a930 435 {
sk398 9:c236eaaacf08 436 // If SideLightIndicator is HIGH, set SideLightInd to HIGH, else set to LOW
sk398 4:b4bcb329a930 437 if(SideLightIndicator)
sk398 4:b4bcb329a930 438 {
sk398 4:b4bcb329a930 439 SideLightInd = HIGH;
sk398 4:b4bcb329a930 440 }
sk398 4:b4bcb329a930 441 else
sk398 4:b4bcb329a930 442 {
sk398 4:b4bcb329a930 443 SideLightInd = LOW;
sk398 1:cdf851858518 444 }
sk398 1:cdf851858518 445 }
sk398 0:f7d6ed1dfe3e 446
sk398 2:13a9394ba2e0 447
sk398 9:c236eaaacf08 448 // Task10_ReadIndicatorLights takes external input from LeftIndicator and RightIndicator and conducts a
sk398 9:c236eaaacf08 449 // logical test. It operates at a frequency of 0.5Hz
sk398 4:b4bcb329a930 450 void Task10_ReadIndicatorLights(void const *arg)
sk398 0:f7d6ed1dfe3e 451 {
sk398 9:c236eaaacf08 452
sk398 9:c236eaaacf08 453 // If LeftIndicator Only is HIGH, flash LeftLightInd at a frequency of 1Hz, 50% Duty
sk398 1:cdf851858518 454 if(LeftIndicator && !RightIndicator)
sk398 1:cdf851858518 455 {
sk398 2:13a9394ba2e0 456 LeftLightInd.period(1.0);
sk398 2:13a9394ba2e0 457 LeftLightInd.pulsewidth(0.5);
sk398 2:13a9394ba2e0 458
sk398 2:13a9394ba2e0 459 RightLightInd.period(1.0);
sk398 2:13a9394ba2e0 460 RightLightInd.pulsewidth(0.0);
sk398 1:cdf851858518 461 }
sk398 1:cdf851858518 462
sk398 9:c236eaaacf08 463 // If RightIndicator Only is HIGH, flash RightLightInd at a frequency of 1Hz, 50% Duty
sk398 1:cdf851858518 464 else if(!LeftIndicator && RightIndicator)
sk398 0:f7d6ed1dfe3e 465 {
sk398 2:13a9394ba2e0 466 LeftLightInd.period(1.0);
sk398 2:13a9394ba2e0 467 LeftLightInd.pulsewidth(0.0);
sk398 2:13a9394ba2e0 468
sk398 2:13a9394ba2e0 469 RightLightInd.period(1.0);
sk398 2:13a9394ba2e0 470 RightLightInd.pulsewidth(0.5);
sk398 1:cdf851858518 471 }
sk398 1:cdf851858518 472
sk398 9:c236eaaacf08 473 // If LeftIndicator and RightIndicator are HIGH, flash LeftLightInd and RightLightInd
sk398 9:c236eaaacf08 474 // at a frequency of 2Hz, 50% Duty
sk398 1:cdf851858518 475 else if(LeftIndicator && RightIndicator)
sk398 1:cdf851858518 476 {
sk398 2:13a9394ba2e0 477 LeftLightInd.period(0.5);
sk398 2:13a9394ba2e0 478 RightLightInd.period(0.5);
sk398 0:f7d6ed1dfe3e 479
sk398 2:13a9394ba2e0 480 LeftLightInd.pulsewidth(0.25);
sk398 2:13a9394ba2e0 481 RightLightInd.pulsewidth(0.25);
sk398 2:13a9394ba2e0 482 }
sk398 9:c236eaaacf08 483 // Else, turn off both LeftLightInd and RightLightInd
sk398 2:13a9394ba2e0 484 else
sk398 2:13a9394ba2e0 485 {
sk398 2:13a9394ba2e0 486 LeftLightInd.period(1.0);
sk398 2:13a9394ba2e0 487 LeftLightInd.pulsewidth(0.0);
sk398 2:13a9394ba2e0 488
sk398 2:13a9394ba2e0 489 RightLightInd.period(1.0);
sk398 2:13a9394ba2e0 490 RightLightInd.pulsewidth(0.0);
sk398 0:f7d6ed1dfe3e 491 }
sk398 1:cdf851858518 492 }
sk398 3:8192bbde17b3 493
sk398 3:8192bbde17b3 494
sk398 3:8192bbde17b3 495 void InitSystem()
sk398 3:8192bbde17b3 496 {
sk398 9:c236eaaacf08 497 // Set AvSpeedWiper to 50Hz frequency, for Servo
sk398 4:b4bcb329a930 498 AvSpeedWiper.period_ms(20);
sk398 4:b4bcb329a930 499
sk398 9:c236eaaacf08 500 // Initiate LCD by lighting Backlight
sk398 9:c236eaaacf08 501 par_port->write_bit(1,BL_BIT);
sk398 3:8192bbde17b3 502
sk398 9:c236eaaacf08 503 // Initiate all Global variables to 0
sk398 8:6fad4bd89240 504 rawData.EngineState = 0;
sk398 8:6fad4bd89240 505 rawData.RawAccelerometer = 0.0;
sk398 8:6fad4bd89240 506 rawData.RawBraking = 0.0;
sk398 8:6fad4bd89240 507 speedData.counter = 0;
sk398 8:6fad4bd89240 508 speedData.rawSpeed[0] = 0.0;
sk398 8:6fad4bd89240 509 speedData.rawSpeed[1] = 0.0;
sk398 8:6fad4bd89240 510 speedData.rawSpeed[2] = 0.0;
sk398 9:c236eaaacf08 511 AverageSpeed = 0.0;
sk398 6:572b9755f2c1 512 totalDistance = 0.0;
sk398 7:f09208f9a4f7 513 MailQueueCounter = 0;
sk398 4:b4bcb329a930 514 }
sk398 3:8192bbde17b3 515
sk398 9:c236eaaacf08 516
sk398 2:13a9394ba2e0 517 // ============================================================================
sk398 2:13a9394ba2e0 518 // Entry Point Thread
sk398 2:13a9394ba2e0 519 // ============================================================================
sk398 1:cdf851858518 520
sk398 9:c236eaaacf08 521 // Entry Point Thread, this shall be the initialiser for the Car System and
sk398 9:c236eaaacf08 522 // Contains all of the Tasks and their associated properties, such as frequency.
sk398 1:cdf851858518 523 int main()
sk398 1:cdf851858518 524 {
sk398 9:c236eaaacf08 525 // Construct Objects for LCD
sk398 4:b4bcb329a930 526 par_port = new MCP23017(p9, p10, 0x40); // initialise 16-bit I/O chip
sk398 4:b4bcb329a930 527 lcd = new WattBob_TextLCD(par_port); // initialise 2*26 char display
sk398 4:b4bcb329a930 528
sk398 9:c236eaaacf08 529 // Set PC Connection Baud Rate
sk398 4:b4bcb329a930 530 PCConn.baud(115200);
sk398 4:b4bcb329a930 531
sk398 9:c236eaaacf08 532 // Initialise System, including Global Variables
sk398 3:8192bbde17b3 533 InitSystem();
sk398 3:8192bbde17b3 534
sk398 9:c236eaaacf08 535 // Construct Tasks as RtosTimer objects
sk398 4:b4bcb329a930 536 RtosTimer CarSim(CarSimulator,osTimerPeriodic);
sk398 4:b4bcb329a930 537 RtosTimer Task1(Task1_ReadRawData,osTimerPeriodic);
sk398 4:b4bcb329a930 538 RtosTimer Task2(Task2_ReadEngineState,osTimerPeriodic);
sk398 4:b4bcb329a930 539 RtosTimer Task3(Task3_CalcAvSpeed,osTimerPeriodic);
sk398 4:b4bcb329a930 540 RtosTimer Task4(Task4_UpdateRCWiper,osTimerPeriodic);
sk398 4:b4bcb329a930 541 RtosTimer Task5(Task5_OverspeedLED,osTimerPeriodic);
sk398 5:4f2a072ed289 542 RtosTimer Task6(Task6_UpdateOdometer,osTimerPeriodic);
sk398 5:4f2a072ed289 543 RtosTimer Task7(Task7_SendToMailQueue,osTimerPeriodic);
sk398 5:4f2a072ed289 544 RtosTimer Task8(Task8_DumpSerial,osTimerPeriodic);
sk398 4:b4bcb329a930 545 RtosTimer Task9(Task9_ReadSideLight,osTimerPeriodic);
sk398 4:b4bcb329a930 546 RtosTimer Task10(Task10_ReadIndicatorLights,osTimerPeriodic);
sk398 4:b4bcb329a930 547
sk398 9:c236eaaacf08 548 // Staert RtosTimer objects, with the required frequency
sk398 5:4f2a072ed289 549 CarSim.start(50); // 20Hz
sk398 5:4f2a072ed289 550 Task1.start(100); // 10Hz
sk398 5:4f2a072ed289 551 Task2.start(500); // 2Hz
sk398 5:4f2a072ed289 552 Task3.start(200); // 5Hz
sk398 5:4f2a072ed289 553 Task4.start(1000); // 1Hz
sk398 5:4f2a072ed289 554 Task5.start(2000); // 0.5Hz
sk398 5:4f2a072ed289 555 Task6.start(500); // 2Hz
sk398 5:4f2a072ed289 556 Task7.start(5000); // 0.2Hz
sk398 5:4f2a072ed289 557 Task8.start(20000); // 0.05Hz
sk398 5:4f2a072ed289 558 Task9.start(1000); // 1Hz
sk398 5:4f2a072ed289 559 Task10.start(2000); // 0.5Hz
sk398 1:cdf851858518 560
sk398 9:c236eaaacf08 561 // Ensure that RtosTimer runs within Infinite loop
sk398 1:cdf851858518 562 Thread::wait(osWaitForever);
sk398 1:cdf851858518 563
sk398 0:f7d6ed1dfe3e 564
sk398 0:f7d6ed1dfe3e 565 }