Xavier Gouesnard / Mbed 2 deprecated Assignment_2_XG

Dependencies:   FatFileSystem MCP23017 WattBob_TextLCD mbed

Fork of Assignment_2_herpe by Xavier Herpe

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers XG_2.cpp Source File

XG_2.cpp

00001 // XAVIER GOUESNARD 
00002 // H00258183                                     
00003 // Assignment 2
00004 // MSc Embeded Systems 2016/2017
00005 // Heriot-Watt University
00006 
00007 #include "mbed.h"
00008 #include "MCP23017.h"   
00009 #include "WattBob_TextLCD.h"
00010 #include "SDFileSystem.h"
00011 #include "FATFileSystem.h"
00012 
00013 #define     BACK_LIGHT_ON(INTERFACE)     INTERFACE->write_bit(1,BL_BIT)
00014 #define     BACK_LIGHT_OFF(INTERFACE)    INTERFACE->write_bit(0,BL_BIT)
00015 
00016 // Pointers to LCD screen and SD card
00017 MCP23017            *par_port;  // pointer to 16-bit parallel I/O chip
00018 WattBob_TextLCD     *lcd;       // pointer to 2*16 character LCD object
00019 FILE                *fp;        // Pointer to SD card object
00020 
00021 
00022 //=====================================================================================
00023 //  I/O ports allocation
00024 //=====================================================================================
00025 DigitalIn TTL(p17); // TTL input for frequency measurement
00026 DigitalIn switch_1(p18); // Switch 1 input
00027 DigitalIn switch_2(p19); // Switch 2 input
00028 DigitalIn switch_off(p11); // Switch used to close SD file and stop cyclic executive
00029 AnalogIn analogue_in_1(p15); // POT value
00030 AnalogIn analogue_in_2(p16); // LDR value
00031 PwmOut servo(p21); // Servo output
00032 DigitalOut TestPin(p20); // Pin only used to test program and measure time
00033 SDFileSystem sd(p5, p6, p7, p8, "sd"); // The pinout on the mbed Cool Components workshop board
00034 DigitalIn  switch_pin(p14, PullDown);
00035 
00036 //=====================================================================================
00037 // Internal objects declaration
00038 // ====================================================================================
00039 BusOut LEDs(LED4, LED3, LED2, LED1); // Address the four LEDs to a single bus
00040 Timer timer; // Timer used to measure frequency in task 1
00041 Timer DoNothing; // Timer used to measure how long the program does nothing
00042 Ticker ticker; // Ticker used as clock for cyclic executive program
00043 
00044 
00045 //=====================================================================================
00046 // Constants declaration
00047 //=====================================================================================
00048 const int SampFreq = 100; // Sampling frequency is 10kHz (100us)
00049 
00050 //=====================================================================================
00051 // Variables declaration
00052 //=====================================================================================
00053 
00054 // Variables for cyclic executive program
00055 long int ticks = 0; // Used to define what task to call in the cyclic executive program
00056 int NoTask = 0; // Used to return how long the program does nothing in ms
00057 int NoTaskCount = 0; // Variable incremented until one total cycle of 10 seconds is reached
00058 
00059 // Variables for tasks 1 and 2
00060 int period = 0; // Returned period of the TTL input signal
00061 int frequency = 0; // Returned frequency of the TTL signal
00062 
00063 // Varibles for task 4
00064 int switch_1_val = 0; // Used to return how many times the switch is high
00065 int switch_2_val = 0;
00066 bool switch_1_state = 0; // Used to define whether the debounced switch is ON or OFF
00067 bool switch_2_state = 0;
00068 
00069 // Variables for task 5
00070 float analogue_1_val = 0; // Used to return the filtered analogue input
00071 float analogue_2_val = 0;
00072 
00073 int analogue_1_int = 0; // Used to convert float to int (results in quicker display on LCD in task 6)
00074 int analogue_2_int = 0;
00075   
00076 // Variable for task 7
00077 int LogCount = 0; // Used to define logging number
00078 
00079 // Variable used for task 8
00080 int BinCount = 0; // Used to increment a binary display on LEDs. Goes from 0 to 15 and then is reset
00081 bool BinEnable = 0; // Used to tell task 5 to display binary pattern on LEDs every 1.5s
00082 int IncCheck = 0; // Check increment to see if 6 cycles have elapsed to light LEDs ( 6 * 250us = 1.5s)
00083 
00084 
00085 //=====================================================================================
00086 // Task declaration
00087 //=====================================================================================
00088 
00089 void CyclEx();
00090 
00091 void Task1(); // Measure TTL input frequency
00092 void Task2(); // Show frequency on LCD screen
00093 void Task3(); // Show speed on servo dial
00094 void Task4(); // Read and debounce two digital inputs
00095 void Task5(); // Read and filter two analogue inputs
00096 void Task6(); // Display digital and analogue inputs on LCD screen
00097 void Task7(); // Log speed, analogue and digital inputs on SD card
00098 void Task8(); // Display error message on LCD screen and display binary pattern on LEDs
00099 
00100 void WaitRisEdge(); // Subroutine to detect rising edge
00101 void WaitFalEdge(); // Subroutine to detect falling edge
00102 
00103 void Stop(); // Close log file and stop cyclic executive
00104 
00105 
00106 //=====================================================================================
00107 // Main program
00108 //=====================================================================================
00109 
00110 int main()
00111 {
00112 
00113     // LCD Screen Initialisation
00114     par_port = new MCP23017(p9, p10, 0x40); // initialise 16-bit I/O chip
00115     lcd = new WattBob_TextLCD(par_port); // initialise 2*26 char display
00116     par_port->write_bit(1,BL_BIT); // turn LCD backlight ON
00117     lcd->cls(); // clear display
00118 
00119     // EXEL log file initialisation
00120     fp = fopen("/sd/log.xls", "w"); // pointer to log in text file called "log". (Use "a" to not delete file)
00121     fprintf(fp, "This file is the property of Xavier Gouesnard\n\n");
00122 
00123     // DoNothing timer reset
00124     DoNothing.reset();
00125     
00126     // Internal ticker set to 25ms. Every 25ms, the scheduler is called and selects the task to run
00127     ticker.attach(&CyclEx, 0.025); // Period set to 25ms
00128     while(1)// Run until system shuts down
00129     {
00130          
00131     } 
00132 }
00133 
00134 // Where tasks are scheduled based on an EXEL sheet
00135 void CyclEx()
00136 {   
00137     // Stop timer when a new task starts 
00138     DoNothing.stop();
00139     
00140     if(ticks % 80 == 4) // Occures every 80 clock cycles (2 seconds). Starts with an offset of 4 clock cycles
00141     {
00142         Task1(); 
00143     }    
00144 
00145     else if(ticks % 200 == 8) // Occures every 200 clock cycles (5 seconds). Starts with an offset of 8 clock cycles
00146     {       
00147         Task2();      
00148     }
00149     else if(ticks % 240 == 7) // Occures every 240 clock cycles (6 seconds). Starts with an offset of 7 clock cycles
00150     {
00151         Task3();    
00152     }
00153     else if(ticks % 4 == 0) // Occures every 4 clock cycles (0.1 seconds). Starts with an offset of 0 clock cycles
00154     {
00155         Task4(); 
00156     }
00157     else if(ticks % 10 == 1) // Occures every 10 clock cycles (0.25 seconds). Starts with an offset of 1 clock cycles
00158     {   
00159         Task5(); 
00160     }
00161     else if(ticks % 40 == 3) // Occures every 40 clock cycles (1 seconds). Starts with an offset of 3 clock cycles
00162     {
00163         Task6(); 
00164     }
00165     else if(ticks % 400 == 10) // Occures every 400 clock cycles (10 seconds). Starts with an offset of 10 clock cycles
00166     {
00167         Task7(); 
00168     }
00169     else if(ticks % 160 == 6) // Occures every 160 clock cycles (4 seconds). Starts with an offset of 6 clock cycles
00170     {  
00171         Task8(); 
00172     }
00173     
00174     if (switch_off == 1) // Pin used to log data on SD card and stop Cyclic executive program
00175          {
00176              Stop();
00177          }
00178     ticks++;
00179     
00180     // Start timer when one task is ended 
00181     DoNothing.start();
00182     NoTaskCount++;
00183     
00184     // When one full cycle of 10 seconds is finished, return how long the program was doing nothing (lazy program)
00185     if (NoTaskCount == 400)
00186     {
00187         NoTask = DoNothing.read_ms();
00188         NoTaskCount = 0;
00189         DoNothing.reset();
00190     }
00191 }
00192 
00193 
00194 //=====================================================================================
00195 // Tasks
00196 //=====================================================================================
00197 
00198 // Task 1: Measure the freqeuncy of a 3.3v square wave signal
00199 void Task1()
00200 {
00201 task 1
00202 
00203     timer.reset();
00204     while(freqCountPin == 0) {}
00205     timer.start();      
00206     while(freqCountPin == 1) {}
00207     timer.stop();
00208     frequency =  2000000 / timer.read_us()
00209 
00210 
00211 // Task 2: display the measured frequency on LCD screen
00212 void Task2()
00213 {
00214     lcd->cls(); // clear display
00215     lcd->locate(0,0); // set cursor to location (0,0) - top left corner
00216     lcd->printf("%d Hz",frequency); // print the frequency calculated in task 1
00217 }
00218 
00219 
00220 
00221 // Task 3: show speed on servo output dial
00222 void Task3()
00223 {
00224     servo.period(0.02); // servo requires a 20ms period
00225     // To rotate the servo from -90 to +90 degrees, the pulse width must varies between 600us to 2300us
00226     // The pulse width is calculated from the speed measured in task one
00227     // 50Hz is equivalent to -90 degrees and 100Hz is equivalent to 90 degrees
00228     // 1Hz change is equal to 34us pulse width change, so pulse width = ((frequency - 50)*34) + 600
00229     servo.pulsewidth_us(2300-((frequency - 50)*34));
00230     wait_ms(1); // Leave the servo some time to reach its position
00231 }
00232 
00233 
00234 
00235 // Task 4: Read two digital inputs (debounced)
00236 void Task4()
00237 {
00238     switch_1_val = 0;
00239     switch_2_val = 0;
00240 
00241     // Read each switch three consecutive times with 100us between readings
00242     for(int i=0; i<3; i++)
00243     {
00244         if (switch_1 == 1) // Increment variable if switch 1 is pressed
00245         {
00246             switch_1_val++;
00247         }
00248 
00249         if (switch_2 == 1) // Increment variable if switch 2 is pressed
00250         {
00251             switch_2_val++;
00252         }
00253 
00254         wait_us(SampFreq);
00255     }
00256     // Check how many times switch 1 has been high
00257     // if it has been high more than twice, then switch 1 state = 1
00258     if (switch_1_val > 1)
00259     {
00260         switch_1_state = 1;
00261     }
00262     else
00263     {
00264         switch_1_state = 0;
00265     }
00266 
00267     // Check how many times switch 1 has been high
00268     // if it has been high more than twice, then switch 2 state = 1
00269     if (switch_2_val > 1)
00270     {
00271         switch_2_state = 1;
00272     }
00273 
00274     else
00275     {
00276         switch_2_state = 0;
00277     }
00278 }
00279 
00280 
00281 
00282 // Task 5: Read two analogue inputs (filtered)
00283 void Task5()
00284 {
00285     analogue_1_val = 0; // Reset variables
00286     analogue_2_val = 0;
00287 
00288     // Takes four readings of each analogue input. Readings occure every 0.1ms
00289     // Because the analogue.read() function returns a value from 0 to 1,
00290     // we need to multiply the readings by 3.3 to cover 0V to 3.3V
00291     for(int i=0; i<4;i++)
00292     {
00293         analogue_1_val = analogue_1_val + (analogue_in_1*3.3);
00294         analogue_2_val = analogue_2_val + (analogue_in_2*3.3);
00295         wait_us(SampFreq);
00296     }
00297 
00298     analogue_1_val = (analogue_1_val / 4);
00299     analogue_2_val = (analogue_2_val / 4);
00300     
00301     analogue_1_int = analogue_1_val * 10; // Convert floating point into an integer to reduce display delay
00302     analogue_2_int = analogue_2_val * 10;
00303     
00304     // This section of task 5 is used to take over part of task 8.
00305     // Since the LEDs pattern has to be incremented every 1.5s, the pattern is
00306     // incremented every 6 cycles, which correspond to 1.5s.
00307     if(BinEnable == 1)
00308     {
00309         IncCheck++; 
00310         
00311         if(IncCheck == 6) // Corresponds to 1.5s. Increment binary pattern
00312         {
00313             LEDs = BinCount;
00314             BinCount++;
00315             IncCheck = 0;
00316 
00317             if (BinCount > 15) // Used to reset variable once maximum 4-bit binary value is reached
00318             {
00319                 BinCount = 0;
00320             }  
00321         }  
00322     }
00323 }
00324 
00325 
00326 
00327 // Task 6: Display analogue and digital values on LCD screen
00328 void Task6()
00329 {
00330    // lcd->cls(); // clear display (takes too long)
00331     lcd->locate(0,0); // set cursor to location (0,0) - top left corner
00332     lcd->printf("%d %d%d%d",analogue_1_int,analogue_2_int,switch_1_state,switch_2_state);
00333 }
00334 
00335 
00336 
00337 // Task 7: Log values on SD card
00338 void Task7()
00339 {    
00340      LogCount++; //Used to print the logging number in file. Starts from 1
00341      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);
00342 }
00343 
00344 
00345 
00346 // Task 8: Show error message and light LEDs
00347 void Task8()
00348 {  
00349     // If switch_1 = 1 and POT value > 3V, display error message
00350     if(switch_1_state == 1 && analogue_1_val > 3)
00351     {
00352         //lcd->cls(); // clear display
00353         lcd->locate(0,0); // set cursor to location (0,0) - top left corner
00354         lcd->printf(".ERREUR");
00355     }
00356     
00357     // If switch 2 is high, return a command to task 5 to do the incrementing pattern every 1.5 seconds
00358     if(switch_2_state == 1)
00359     {
00360         BinEnable = 1;
00361     }
00362     
00363     // If switch 2 is low, stop sending a command to task 5 and light off LEDs
00364     else
00365     {
00366         LEDs = 0;
00367         BinEnable = 0;
00368         BinCount = 0;
00369     }
00370 }
00371 
00372 
00373 
00374 // Stop function to stop cyclic executive and close log file
00375 void Stop()
00376 {
00377     ticker.detach();
00378     fprintf(fp, "\n The program did nothing for %d ms, which corresponds to %d percent of the time  \n",NoTask, NoTask/100);    
00379     fprintf(fp, "\n PROGRAM STOPPED");
00380     fclose(fp);
00381     
00382 }
00383 
00384 
00385 
00386 //=====================================================================================
00387 // Subroutines
00388 //=====================================================================================
00389 
00390 // Wait for rising edge
00391 void WaitRisEdge()
00392 {
00393     // As soon as it gets high, the subroutine will end and the timer will start
00394     while(TTL == 0)
00395     {        
00396             wait_us(SampFreq);        
00397     }
00398 }
00399 
00400 
00401 // Wait for falling edge
00402 void WaitFalEdge()
00403 {
00404     // As soon as it gets low, the subroutine will end and the timer will start
00405     while(TTL == 1)
00406     {
00407         wait_us(SampFreq);
00408     }
00409 }