Test session

Dependencies:   FatFileSystem MCP23017 WattBob_TextLCD mbed

Fork of Assignment_2_herpe by Xavier Herpe

Revision:
1:adcb8ab84d62
Child:
2:42d97c99e877
diff -r aaddc17011a9 -r adcb8ab84d62 XG_2.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/XG_2.cpp	Tue Mar 07 16:58:32 2017 +0000
@@ -0,0 +1,431 @@
+// XAVIER GOUESNARD 
+// H00258183                                     
+// Assignment 2
+// MSc Embeded Systems 2016/2017
+// Heriot-Watt University
+
+#include "mbed.h"
+#include "MCP23017.h"
+#include "WattBob_TextLCD.h"
+#include "SDFileSystem.h"
+#include "FATFileSystem.h"
+
+#define     BACK_LIGHT_ON(INTERFACE)     INTERFACE->write_bit(1,BL_BIT)
+#define     BACK_LIGHT_OFF(INTERFACE)    INTERFACE->write_bit(0,BL_BIT)
+
+// Pointers to LCD screen and SD card
+MCP23017            *par_port;  // pointer to 16-bit parallel I/O chip
+WattBob_TextLCD     *lcd;       // pointer to 2*16 character LCD object
+FILE                *fp;        // Pointer to SD card object
+
+
+//=====================================================================================
+//  I/O ports allocation
+//=====================================================================================
+DigitalIn TTL(p17); // TTL input for frequency measurement
+DigitalIn switch_1(p18); // Switch 1 input
+DigitalIn switch_2(p19); // Switch 2 input
+DigitalIn switch_off(p11); // Switch used to close SD file and stop cyclic executive
+AnalogIn analogue_in_1(p15); // POT value
+AnalogIn analogue_in_2(p16); // LDR value
+PwmOut servo(p21); // Servo output
+DigitalOut TestPin(p20); // Pin only used to test program and measure time
+SDFileSystem sd(p5, p6, p7, p8, "sd"); // The pinout on the mbed Cool Components workshop board
+
+
+//=====================================================================================
+// Internal objects declaration
+// ====================================================================================
+BusOut LEDs(LED4, LED3, LED2, LED1); // Address the four LEDs to a single bus
+Timer timer; // Timer used to measure frequency in task 1
+Timer DoNothing; // Timer used to measure how long the program does nothing
+Ticker ticker; // Ticker used as clock for cyclic executive program
+
+
+//=====================================================================================
+// Constants declaration
+//=====================================================================================
+const int SampFreq = 100; // Sampling frequency is 10kHz (100us)
+
+
+//=====================================================================================
+// Variables declaration
+//=====================================================================================
+
+// Variables for cyclic executive program
+long int ticks = 0; // Used to define what task to call in the cyclic executive program
+int NoTask = 0; // Used to return how long the program does nothing in ms
+int NoTaskCount = 0; // Variable incremented until one total cycle of 10 seconds is reached
+
+// Variables for tasks 1 and 2
+int period = 0; // Returned period of the TTL input signal
+int frequency = 0; // Returned frequency of the TTL signal
+
+// Varibles for task 4
+int switch_1_val = 0; // Used to return how many times the switch is high
+int switch_2_val = 0;
+bool switch_1_state = 0; // Used to define whether the debounced switch is ON or OFF
+bool switch_2_state = 0;
+
+// Variables for task 5
+float analogue_1_val = 0; // Used to return the filtered analogue input
+float analogue_2_val = 0;
+
+int analogue_1_int = 0; // Used to convert float to int (results in quicker display on LCD in task 6)
+int analogue_2_int = 0;
+
+// Variable for task 7
+int LogCount = 0; // Used to define logging number
+
+// Variable used for task 8
+int BinCount = 0; // Used to increment a binary display on LEDs. Goes from 0 to 15 and then is reset
+bool BinEnable = 0; // Used to tell task 5 to display binary pattern on LEDs every 1.5s
+int IncCheck = 0; // Check increment to see if 6 cycles have elapsed to light LEDs ( 6 * 250us = 1.5s)
+
+
+//=====================================================================================
+// Task declaration
+//=====================================================================================
+
+void CyclEx();
+
+void Task1(); // Measure TTL input frequency
+void Task2(); // Show frequency on LCD screen
+void Task3(); // Show speed on servo dial
+void Task4(); // Read and debounce two digital inputs
+void Task5(); // Read and filter two analogue inputs
+void Task6(); // Display digital and analogue inputs on LCD screen
+void Task7(); // Log speed, analogue and digital inputs on SD card
+void Task8(); // Display error message on LCD screen and display binary pattern on LEDs
+
+void WaitRisEdge(); // Subroutine to detect rising edge
+void WaitFalEdge(); // Subroutine to detect falling edge
+
+void Stop(); // Close log file and stop cyclic executive
+
+
+//=====================================================================================
+// Main program
+//=====================================================================================
+
+int main()
+{
+
+    // LCD Screen Initialisation
+    par_port = new MCP23017(p9, p10, 0x40); // initialise 16-bit I/O chip
+    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
+
+    // EXEL log file initialisation
+    fp = fopen("/sd/log.xls", "w"); // pointer to log in text file called "log". (Use "a" to not delete file)
+    fprintf(fp, "This file is the property of Xavier Gouesnard\n\n");
+
+    // DoNothing timer reset
+    DoNothing.reset();
+    
+    // Internal ticker set to 25ms. Every 25ms, the scheduler is called and selects the task to run
+    ticker.attach(&CyclEx, 0.025); // Period set to 25ms
+    while(1)// Run until system shuts down
+    {
+         
+    } 
+}
+
+// Where tasks are scheduled based on an EXEL sheet
+void CyclEx()
+{   
+    // Stop timer when a new task starts 
+    DoNothing.stop();
+    
+    if(ticks % 80 == 4) // Occures every 80 clock cycles (2 seconds). Starts with an offset of 4 clock cycles
+    {
+        Task1(); 
+    }    
+
+    else if(ticks % 200 == 8) // Occures every 200 clock cycles (5 seconds). Starts with an offset of 8 clock cycles
+    {       
+        Task2();      
+    }
+    else if(ticks % 240 == 7) // Occures every 240 clock cycles (6 seconds). Starts with an offset of 7 clock cycles
+    {
+        Task3();    
+    }
+    else if(ticks % 4 == 0) // Occures every 4 clock cycles (0.1 seconds). Starts with an offset of 0 clock cycles
+    {
+        Task4(); 
+    }
+    else if(ticks % 10 == 1) // Occures every 10 clock cycles (0.25 seconds). Starts with an offset of 1 clock cycles
+    {   
+        Task5(); 
+    }
+    else if(ticks % 40 == 3) // Occures every 40 clock cycles (1 seconds). Starts with an offset of 3 clock cycles
+    {
+        Task6(); 
+    }
+    else if(ticks % 400 == 10) // Occures every 400 clock cycles (10 seconds). Starts with an offset of 10 clock cycles
+    {
+        Task7(); 
+    }
+    else if(ticks % 160 == 6) // Occures every 160 clock cycles (4 seconds). Starts with an offset of 6 clock cycles
+    {  
+        Task8(); 
+    }
+    
+    if (switch_off == 1) // Pin used to log data on SD card and stop Cyclic executive program
+         {
+             Stop();
+         }
+    ticks++;
+    
+    // Start timer when one task is ended 
+    DoNothing.start();
+    NoTaskCount++;
+    
+    // When one full cycle of 10 seconds is finished, return how long the program was doing nothing (lazy program)
+    if (NoTaskCount == 400)
+    {
+        NoTask = DoNothing.read_ms();
+        NoTaskCount = 0;
+        DoNothing.reset();
+    }
+}
+
+
+//=====================================================================================
+// Tasks
+//=====================================================================================
+
+// Task 1: Measure TTL input frequency
+void Task1()
+{
+    timer.reset();
+    
+    // If the input signal is low, wait for a rising edge to start counting
+    if (TTL == 0)
+    {
+        WaitRisEdge(); // Call subroutine to wait for rising edge
+        timer.start(); // Start timer
+        while(TTL == 1) // Keep counting as long as signal is high
+        {
+            wait_us(SampFreq);
+        }
+    }
+    
+    // If the input signal is high, wait for a falling edge to start counting
+    else if (TTL == 1)
+    {
+        WaitFalEdge(); // Call subroutine to wait for falling edge
+        timer.start(); // Start timer
+        while(TTL == 0) // Keep counting as long as signal is high
+        {
+            wait_us(SampFreq);
+        }
+    }
+
+    timer.stop(); // Stop counting when signal changes
+    period = timer.read_us()*2; // Convert the time into a period
+    frequency = 1000000/period; // Convert the period into a frequency
+}
+
+
+
+// Task 2: display the measured frequency on LCD screen
+void Task2()
+{
+    lcd->cls(); // clear display
+    lcd->locate(0,0); // set cursor to location (0,0) - top left corner
+    lcd->printf("%d Hz",frequency); // print the frequency calculated in task 1
+}
+
+
+
+// Task 3: show speed on servo output dial
+void Task3()
+{
+    servo.period(0.02); // servo requires a 20ms period
+    // To rotate the servo from -90 to +90 degrees, the pulse width must varies between 600us to 2300us
+    // The pulse width is calculated from the speed measured in task one
+    // 50Hz is equivalent to -90 degrees and 100Hz is equivalent to 90 degrees
+    // 1Hz change is equal to 34us pulse width change, so pulse width = ((frequency - 50)*34) + 600
+    servo.pulsewidth_us(2300-((frequency - 50)*34));
+    wait_ms(1); // Leave the servo some time to reach its position
+}
+
+
+
+// Task 4: Read two digital inputs (debounced)
+void Task4()
+{
+    switch_1_val = 0;
+    switch_2_val = 0;
+
+    // Read each switch three consecutive times with 100us between readings
+    for(int i=0; i<3; i++)
+    {
+        if (switch_1 == 1) // Increment variable if switch 1 is pressed
+        {
+            switch_1_val++;
+        }
+
+        if (switch_2 == 1) // Increment variable if switch 2 is pressed
+        {
+            switch_2_val++;
+        }
+
+        wait_us(SampFreq);
+    }
+    // Check how many times switch 1 has been high
+    // if it has been high more than twice, then switch 1 state = 1
+    if (switch_1_val > 1)
+    {
+        switch_1_state = 1;
+    }
+    else
+    {
+        switch_1_state = 0;
+    }
+
+    // Check how many times switch 1 has been high
+    // if it has been high more than twice, then switch 2 state = 1
+    if (switch_2_val > 1)
+    {
+        switch_2_state = 1;
+    }
+
+    else
+    {
+        switch_2_state = 0;
+    }
+}
+
+
+
+// Task 5: Read two analogue inputs (filtered)
+void Task5()
+{
+    analogue_1_val = 0; // Reset variables
+    analogue_2_val = 0;
+
+    // Takes four readings of each analogue input. Readings occure every 0.1ms
+    // Because the analogue.read() function returns a value from 0 to 1,
+    // we need to multiply the readings by 3.3 to cover 0V to 3.3V
+    for(int i=0; i<4;i++)
+    {
+        analogue_1_val = analogue_1_val + (analogue_in_1*3.3);
+        analogue_2_val = analogue_2_val + (analogue_in_2*3.3);
+        wait_us(SampFreq);
+    }
+
+    analogue_1_val = (analogue_1_val / 4);
+    analogue_2_val = (analogue_2_val / 4);
+    
+    analogue_1_int = analogue_1_val * 10; // Convert floating point into an integer to reduce display delay
+    analogue_2_int = analogue_2_val * 10;
+    
+    // This section of task 5 is used to take over part of task 8.
+    // Since the LEDs pattern has to be incremented every 1.5s, the pattern is
+    // incremented every 6 cycles, which correspond to 1.5s.
+    if(BinEnable == 1)
+    {
+        IncCheck++; 
+        
+        if(IncCheck == 6) // Corresponds to 1.5s. Increment binary pattern
+        {
+            LEDs = BinCount;
+            BinCount++;
+            IncCheck = 0;
+
+            if (BinCount > 15) // Used to reset variable once maximum 4-bit binary value is reached
+            {
+                BinCount = 0;
+            }  
+        }  
+    }
+}
+
+
+
+// Task 6: Display analogue and digital values on LCD screen
+void Task6()
+{
+   // lcd->cls(); // clear display (takes too long)
+    lcd->locate(0,0); // set cursor to location (0,0) - top left corner
+    lcd->printf("%d %d%d%d",analogue_1_int,analogue_2_int,switch_1_state,switch_2_state);
+}
+
+
+
+// Task 7: Log values on SD card
+void Task7()
+{    
+     LogCount++; //Used to print the logging number in file. Starts from 1
+     fprintf(fp, "Log:  %d,   Speed: %dHz,   Switch_1: %d,   Switch_2: %d,   POT: %.2fVolts,   LDR: %.2fVolts\n",LogCount,frequency,switch_1_state,switch_2_state,analogue_1_val,analogue_2_val);
+}
+
+
+
+// Task 8: Show error message and light LEDs
+void Task8()
+{  
+    // If switch_1 = 1 and POT value > 3V, display error message
+    if(switch_1_state == 1 && analogue_1_val > 3)
+    {
+        //lcd->cls(); // clear display
+        lcd->locate(0,0); // set cursor to location (0,0) - top left corner
+        lcd->printf(".ERREUR");
+    }
+    
+    // If switch 2 is high, return a command to task 5 to do the incrementing pattern every 1.5 seconds
+    if(switch_2_state == 1)
+    {
+        BinEnable = 1;
+    }
+    
+    // If switch 2 is low, stop sending a command to task 5 and light off LEDs
+    else
+    {
+        LEDs = 0;
+        BinEnable = 0;
+        BinCount = 0;
+    }
+}
+
+
+
+// Stop function to stop cyclic executive and close log file
+void Stop()
+{
+    ticker.detach();
+    fprintf(fp, "\n The program did nothing for %d ms, which corresponds to %d percent of the time  \n",NoTask, NoTask/100);    
+    fprintf(fp, "\n PROGRAM STOPPED");
+    fclose(fp);
+    
+}
+
+
+
+//=====================================================================================
+// Subroutines
+//=====================================================================================
+
+// Wait for rising edge
+void WaitRisEdge()
+{
+    // As soon as it gets high, the subroutine will end and the timer will start
+    while(TTL == 0)
+    {        
+            wait_us(SampFreq);        
+    }
+}
+
+
+// Wait for falling edge
+void WaitFalEdge()
+{
+    // As soon as it gets low, the subroutine will end and the timer will start
+    while(TTL == 1)
+    {
+        wait_us(SampFreq);
+    }
+}
\ No newline at end of file