chad

Dependencies:   MCP23017 WattBob_TextLCD mbed-rtos mbed

Revision:
20:aeb7b7044c31
Parent:
19:1fecb6fa14a2
diff -r 1fecb6fa14a2 -r aeb7b7044c31 main.cpp
--- a/main.cpp	Tue Apr 04 13:47:53 2017 +0000
+++ b/main.cpp	Mon Mar 26 10:42:42 2018 +0000
@@ -1,16 +1,41 @@
-// Paramater Allocation
+// Frazer Legge - H001262392
+// Embedded Software - Assignment 3
 // 
+// This program operates a simulation of a car control system.
+// THe simulation is completed through the use of external controls,
+// ignition, sidelights switch, idicator switches, accelerator and 
+// brake pedals. 
+// The simulation calculates Average speed and total distance travelled.
+// The simulation outputs are onboard LEDs to show ignition, sidelights,
+// indicators and overspeed indicator. The system shows the distance 
+// traveled and average speed of the car on the LCD. A USB dump is also 
+// done showing the average speed, accelerator and brake positions.
+
 
-#include "main.h"
+#include "mbed.h"
+#include "rtos.h"
+#include "MCP23017.h"
+#include "WattBob_TextLCD.h"
+
 
-// Pointers to LCD Screen
-MCP23017            *par_port;  // pointer to 16-bit parallel I/O chip
-WattBob_TextLCD     *lcd;       // pointer to 2*16 character LCD object
+// LCD Definition
+#define     BACK_LIGHT_ON(INTERFACE)    INTERFACE->write_bit(1,BL_BIT)
+#define     BACK_LIGHT_OFF(INTERFACE)    INTERFACE->write_bit(0,BL_BIT)
+
+// Car Sim Max/Min speed (mph)
+#define MAX_SPEED 100
+#define MIN_SPEED 0
 
 // Serial Connection
-
 Serial pc(USBTX, USBRX,115200);
 
+// ============================================================================
+// MBED Pin Assignments
+// ============================================================================
+//
+
+// System Inputs
+// ----------------------------------------------------------------------------
 // Analogue Input
 AnalogIn Accel(p15);            // Accelerator Pedal Input
 AnalogIn Brake(p16);            // Brake Pedal Input
@@ -21,35 +46,487 @@
 DigitalIn Indi_L(p13);          // Left indicator switch
 DigitalIn Indi_R(p14);          // Right idicator switch
 
-// Analogue Output
-Servo SpeedIndicator(p21);          // Speed Indicator Servo
+// System Outputs
+// ----------------------------------------------------------------------------
+// PWM Output
+PwmOut SpeedIndicator(p21);     // Speed Indicator Servo
+PwmOut Indi_L_LED(LED3);        // Left Indicator LED
+PwmOut Indi_R_LED(LED4);        // Right Indicator LED
 
 // Digital Output
 DigitalOut Ignit_LED(LED1);     // Ignition LED Indicator
 DigitalOut SideL_LED(LED2);     // Side Light Indicator
-DigitalOut Indi_L_LED(LED3);    // Left Indicator LED
-DigitalOut Indi_R_LED(LED4);    // Right Indicator LED
+DigitalOut OverS_LED(p17);        // Overspeed LED (REDBOX)
+
+// Pointers to LCD Screen
+MCP23017            *par_port;  // pointer to 16-bit parallel I/O chip
+WattBob_TextLCD     *lcd;       // pointer to 2*16 character LCD object
+
+// ============================================================================
+// Data Structure 
+// ============================================================================
+//
+
+// Raw Data Structure
+// ----------------------------------------------------------------------------
+
+// RawData is a global memory section that contains an instance of the raw input
+// data from speedControl.
+
+typedef struct
+{
+    bool EngineState;
+    float RawAccel;
+    float RawBrake;
+} RawData;
+
+// Create MUTEX to contol access to RawData 
+Mutex RawDataMutex;
+
+// Create instance of RawData
+RawData rawData;
+
+// Speed Data Structure
+// ----------------------------------------------------------------------------
+
+// Speed data is a global memory section that contains an instance of the 
+// calculated car speed.  
 
-DigitalOut O_S_LED(p18);        // Overspeed LED (REDBOX)
+typedef struct
+{
+    float rawSpeed[3];
+    int counter;
+} CarSpeedData;
+
+// Create MUTEX to control access to CarSpeedData
+
+Mutex SpeedDataMutex;
+
+// Create insance of CarSpeedData
+CarSpeedData speedData;
 
-/*typedef struct {
+// Filtered Data Structure
+// ----------------------------------------------------------------------------
+typedef struct
+{
+    float AvgSpeed; 
+    float TotalDist;
+} FilteredData;
+
+// Create MUTEX to control access to FilterData
+Mutex filteredDataMutex;
+
+// Create instance of FilteredData
+FilteredData filteredData;
+
+// Mail Queue Structure
+// ----------------------------------------------------------------------------
+
+// PCDump is a global memory section that is populated in Mail_queue. The data 
+// is coppied from the current state of the control system every 5 seconds.
+
+typedef struct 
+{
     float   speed;
     float   accelerator;
     float   brake;
-} mail_t;
+} PCDump;
+
+// Create 100 element Mail Queue
+Mail<PCDump, 100> Memory_dump;
+
+// Counter to track number of elements in mail
+int MailCounter;
+
+// Create MUTEX to control access to MailQueueCounter
+Mutex MailMutex;
+ 
+// ============================================================================
+// Car Simulation
+// ============================================================================ 
+ 
+// The CarSim task updates the rawSpeed float at freq of 20Hz
 
-Mail<mail_t, 100> mail_box;*/
+void CarSim(void const *arg) 
+{ 
+    float NewSpeed;
+    
+    // Deposit global variables to local variables
+    RawDataMutex.lock();
+    bool currentEngineState = rawData.EngineState;
+    float currentAccel = rawData.RawAccel;
+    float currentBrake = rawData.RawBrake;
+    RawDataMutex.unlock();
+    
+    // Calulate current speed as an fraction of the MAX_SPEED based on the 
+    // percentage of accelerator and brake. 
+    // Speed is set to 0 if Engine State is changed to 0;
+    NewSpeed = currentAccel*MAX_SPEED*(1-currentBrake)*currentEngineState;
+    
+    // Check Counter. If outside array set to 0
+    // Data within shared resource therefore MUTEX is used.
+    SpeedDataMutex.lock();
+    
+    if (speedData.counter > 2)
+    {
+        speedData.counter = 0; 
+    }
+    
+    // Output rawSpeed value to next index of rawSpeed. 
+    // Increment counter
+    speedData.rawSpeed[speedData.counter] = NewSpeed;
+    speedData.counter++;
+    SpeedDataMutex.unlock();
+}
+    
+// ============================================================================
+// Controller Tasks
+// ============================================================================    
+
+// Speed Control (Task 1) reads external analog inputs and updates rawData.
+// Operating freq of 10Hz
+
+void SpeedControl(void const *arg) 
+{ 
+    // Deposit global variables to local variables
+    RawDataMutex.lock();
+    rawData.RawAccel = Accel.read();
+    rawData.RawBrake = Brake.read();
+    RawDataMutex.unlock();
+}
+
+// Ignition(Task 2) reads the state of an "ignition switch". 
+// Updates to rawData.
+// Operating freq of 2Hz.
+
+void Ignition(void const *arg) 
+{
+    // Get Switch state and store locally
+    bool currentEngineState = Ignit.read();
+    
+    // Deposit Local data to global under locked state
+    RawDataMutex.lock();
+    rawData.EngineState = currentEngineState;
+    RawDataMutex.unlock();
+    
+    // Logic check on Engine state
+    if (currentEngineState == 1)
+    { 
+        Ignit_LED = 1;
+    }
+    else
+    { 
+        Ignit_LED = 0;
+    }
+}
+
+// Speed_Avg (Task 3) Calculates the average speed of the car over 3 speed 
+// samples.
+// Operation freq of 5Hz
 
+void Speed_Avg(void const *arg) 
+{ 
+    // Init local float as 0
+    float speed_T = 0.0;
+    
+    // Deposit gloabal data to local data under locked state
+    SpeedDataMutex.lock();
+    for (int i = 0; i < 3; i++)
+    { 
+        speed_T = speed_T + speedData.rawSpeed[i];
+    } 
+    SpeedDataMutex.unlock();
+    
+    // Deposit local data to global data under locked state
+    filteredDataMutex.lock();
+    filteredData.AvgSpeed = (speed_T/3);
+    filteredDataMutex.unlock();
+}
+
+// Speed_Indi (Task 4) shows a representation of the car speed through a servo
+// Operation freq of 1Hz
+
+void Speed_Indi(void const *arg) 
+{
+    // Deposit gloabal data to local data under locked state
+    filteredDataMutex.lock();
+    float currentAvgSpeed = filteredData.AvgSpeed;
+    filteredDataMutex.unlock();
+    
+    // Update Servo
+    // Operates between 1000us and 2000us pwm
+    // ie -> 10 * 50(mph) will give middle positioning
+    SpeedIndicator.pulsewidth_us(1000+(10*currentAvgSpeed));
+}
  
-float Accel_Reg;
-float Brake_Reg;
+// OverSpeed (Task 5) illuminates an LED indicator to show that the car is above
+// 70mph.
+// Opperation freq of 0.5Hz
+
+void OverSpeed(void const *arg) 
+{ 
+    // Deposit gloabal data to local data under locked state
+    SpeedDataMutex.lock();
+    float currentSpeed = speedData.rawSpeed[1];
+    SpeedDataMutex.unlock();
+    
+    // Use locally stored current speed to show if car is travelling over 70mph
+    if (currentSpeed > 70.0)
+    {
+        OverS_LED = 1;
+    }
+    else
+    { 
+        OverS_LED = 0;
+    }
+} 
+
+// Display (Taks 6) shows the total distance traveled and the average speed on 
+// the LCD.
+// Operation freq of 2Hz
+
+void Display(void const *arg) 
+{ 
+    // Local distance variable
+    float currentTotalDist;
+    
+    // Deposit gloabal data to local data under locked state
+    filteredDataMutex.lock();
+    float currentAvgSpeed = filteredData.AvgSpeed;
+    float current_TotalDist = filteredData.TotalDist;
+    filteredDataMutex.unlock();
+    
+    // Update distance traveled
+    // Polling every 0.5 seconds therefore convereted from 0.5s to hours
+    // MUTEX not protected as TotalDist is only used for this function 
+    currentTotalDist = current_TotalDist + (currentAvgSpeed*(0.5/3600)); 
+    
+    filteredDataMutex.lock();
+    filteredData.TotalDist = currentTotalDist;
+    filteredDataMutex.unlock();
+    
+    // Output on LCD
+    lcd->locate(0,0);
+    lcd->printf("D: %f",currentTotalDist);
+    lcd->locate(1,0); 
+    lcd->printf("S: %f",currentAvgSpeed);
+}
+
+// Mail_Queue (Task 7) sends gloabal variable to a MAIL structure. 
+// A counter is incremented to track the variables. 
+// Operation freq of 0.2Hz.
+
+void Mail_Queue(void const *arg) 
+{ 
+    // Deposit gloabal data to local data under locked state
+    RawDataMutex.lock();
+    float currentAccel = rawData.RawAccel;
+    float currentBrake = rawData.RawBrake;
+    RawDataMutex.unlock();
+    
+    filteredDataMutex.lock();
+    float currentAvgSpeed = filteredData.AvgSpeed;
+    filteredDataMutex.lock();
 
-float p;
+    // Allocate and populate PCDump Struct
+    PCDump *currentPCDump = Memory_dump.alloc();
+    
+    currentPCDump->brake = currentBrake;
+    currentPCDump->accelerator = currentAccel;
+    currentPCDump->speed = currentAvgSpeed; 
+    
+    // PCDump struct pushed to mail queue
+    Memory_dump.put(currentPCDump);
+    
+    // Lock mail MUTEX and increment counter
+    MailMutex.lock();
+    MailCounter++;
+    MailMutex.unlock();
+} 
+
+// Mail_Print (Task 8) sends the MAIL queue to a terminal over USB serial. 
+// When finished MAIL counter is reset.
+// Operation freq of 0.05Hz.
+
+void Mail_Print(void const *arg) 
+{ 
+    // Deposit gloabal data to local data under locked state
+    MailMutex.lock();
+    int currentMCount = MailCounter;
+    MailMutex.unlock();
+    
+    // Terminal header notifying dump
+    pc.printf("Mail Dump\n\r"); 
+    
+    // Print each record in MAIL queue. MAIL queue is deposited locally then 
+    // values are printed and elements freed in MAIL queue. 
+    for (int i = 0; i < currentMCount; i++)
+    {
+        osEvent evnt = Memory_dump.get();
+        if (evnt.status == osEventMail)
+        {
+            PCDump *currentPCDump = (PCDump*)evnt.value.p;
+            
+            pc.printf("AvgSpeed: %f\n\rAccel: %f\n\rBrake: %f\n\rCounter: %i\n\n\r",currentPCDump->speed,currentPCDump->accelerator,currentPCDump->brake,i);
+            
+            Memory_dump.free(currentPCDump);
+        }
+    }
+    
+    // Reset counter under locked state
+    MailMutex.lock();
+    MailCounter = 0;
+    MailMutex.unlock();
+}
+
+// Side_Light (Task 9) checks the state of the side light and sets the LED
+// indicator
+// Operation freq of 1Hz
+
+void Side_Light(void const *arg) 
+{ 
+    if(SideL == 1)
+    { 
+        SideL_LED = 1;
+    } 
+    else 
+    {
+        SideL_LED = 0;
+    } 
+} 
+
+// Indicator (Task 10) checks the left and right indicator switches.
+// Illuminates either left or right LED accordingly.
+// If both high then LEDs flash in hazard mode.
 
-float Avg_Speed;
-float Speed_In;
-float Speed_0;
-float Speed_1;
-float Speed_2;
+void Indicator(void const *arg) 
+{ 
+    // If Left switch is high then flash left LED at 1Hz
+    if (Indi_L == 1 && Indi_R == 0)
+    { 
+        Indi_L_LED.period(1.0);
+        Indi_L_LED.pulsewidth(0.5);
+        
+        Indi_R_LED.period(1.0);
+        Indi_R_LED.pulsewidth(0.0);
+    }
+    
+    // If Right switch is high then flash right LED at 1Hz
+    else if (Indi_L == 0 && Indi_R == 1)
+    { 
+        Indi_L_LED.period(1.0);
+        Indi_L_LED.pulsewidth(0.0);
+        
+        Indi_R_LED.period(1.0);
+        Indi_R_LED.pulsewidth(0.5);
+    }
+    
+    // If Left & Right switch is high then flash both LEDs at 2Hz
+    else if (Indi_L == 1 && Indi_R == 1)
+    { 
+        Indi_L_LED.period(0.5);
+        Indi_R_LED.period(0.5);
+        Indi_L_LED.pulsewidth(0.25);
+        Indi_R_LED.pulsewidth(0.25);
+    }
+    
+    // If Left & Right switch is low then no flash
+    else if (Indi_L == 0 && Indi_R == 0)
+    { 
+        Indi_L_LED.period(1.0);
+        Indi_L_LED.pulsewidth(0.0);
+        
+        Indi_R_LED.period(1.0);
+        Indi_R_LED.pulsewidth(0.0);
+    }
+}
+
+void ledFlasher(void const *arg)
+{
+    Ignit_LED =! Ignit_LED;
+}
+
 
-float dist;
+// ============================================================================
+// Init System
+// ============================================================================ 
+    
+void Init()
+{
+    // Servo freq set
+    SpeedIndicator.period_ms(50);
+    // Global Variables zeroed
+    rawData.EngineState = 0;
+    rawData.RawAccel = 0.0;
+    rawData.RawBrake = 0.0;
+    speedData.rawSpeed[0] = 0.0;
+    speedData.rawSpeed[1] = 0.0;
+    speedData.rawSpeed[2] = 0.0;
+    speedData.counter = 0;
+    filteredData.AvgSpeed = 0.0;
+    filteredData.TotalDist = 0.0;
+    MailCounter = 0;
+}
+
+// ============================================================================
+// Main Thread
+// ============================================================================
+
+int main()
+{ 
+    par_port = new MCP23017(p9, p10, 0x40); // initialise 16-bit I/O chip
+    par_port->config(0x0F00, 0x0F00, 0x0F00);
+
+    lcd = new WattBob_TextLCD(par_port);    // initialise 2*26 char display
+    par_port->write_bit(1,BL_BIT);          // turn LCD backlight ON
+
+    lcd->cls();                             // clear display
+     
+    Init();                                 // Run init void
+    
+    Ignit_LED = 0; 
+    
+    
+    //while(1)
+    //{
+    //    Ignit_LED =! Ignit_LED;
+    //    wait(1);
+        //Ignit_LED = 0;
+        //wait(1);
+        
+    //}
+    
+    //SideL_LED = 1;
+    
+    RtosTimer ledFlash(ledFlasher, osTimerPeriodic);
+    ledFlash.start(1000);
+    // Timer Objects
+    //RtosTimer Car_Sim(CarSim,osTimerPeriodic);
+    //RtosTimer Task1(SpeedControl,osTimerPeriodic);
+    //RtosTimer Task2(Ignition,osTimerPeriodic);
+    //RtosTimer Task3(Speed_Avg,osTimerPeriodic);
+    //RtosTimer Task4(Speed_Indi,osTimerPeriodic);
+    //RtosTimer Task5(OverSpeed,osTimerPeriodic);
+    //RtosTimer Task6(Display,osTimerPeriodic);
+    //RtosTimer Task7(Mail_Queue,osTimerPeriodic);
+    //RtosTimer Task8(Mail_Print,osTimerPeriodic);
+    //RtosTimer Task9(Side_Light,osTimerPeriodic);
+    //RtosTimer Task10(Indicator,osTimerPeriodic);
+    
+    // Start RTOS Timer objects
+
+    //Car_Sim.start(50);                      // 20Hz
+    //Task1.start(100);                       // 10Hz
+    //Task2.start(500);                       // 2Hz
+    //Task3.start(200);                       // 5Hz
+    //Task4.start(1000);                      // 1Hz
+    //Task5.start(2000);                      // 0.5Hz
+    //Task6.start(500);                       // 2Hz
+    //Task7.start(5000);                      // 0.2Hz
+    //Task8.start(20000);                     // 0.05Hz
+    //Task9.start(1000);                      // 1Hz
+    //Task10.start(2000);                     // 2Hz
+
+    Thread::wait(osWaitForever);            // Forever loop
+       
+}
\ No newline at end of file